VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/ConsoleImplConfigCommon.cpp@ 105163

Last change on this file since 105163 was 105163, checked in by vboxsync, 5 months ago

Linux/Network: Do not attach netfilter to wrong names or multiple times, bugref:10713

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 220.6 KB
Line 
1/* $Id: ConsoleImplConfigCommon.cpp 105163 2024-07-05 14:26:46Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation - VM Configuration Bits.
4 *
5 * @remark We've split out the code that the 64-bit VC++ v8 compiler finds
6 * problematic to optimize so we can disable optimizations and later,
7 * perhaps, find a real solution for it (like rewriting the code and
8 * to stop resemble a tonne of spaghetti).
9 */
10
11/*
12 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
13 *
14 * This file is part of VirtualBox base platform packages, as
15 * available from https://www.virtualbox.org.
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation, in version 3 of the
20 * License.
21 *
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, see <https://www.gnu.org/licenses>.
29 *
30 * SPDX-License-Identifier: GPL-3.0-only
31 */
32
33
34/*********************************************************************************************************************************
35* Header Files *
36*********************************************************************************************************************************/
37#define LOG_GROUP LOG_GROUP_MAIN_CONSOLE
38#include "LoggingNew.h"
39
40// VBoxNetCfg-win.h needs winsock2.h and thus MUST be included before any other
41// header file includes Windows.h.
42#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
43# include <VBox/VBoxNetCfg-win.h>
44#endif
45
46#include "ConsoleImpl.h"
47#include "DisplayImpl.h"
48#include "NvramStoreImpl.h"
49#include "BusAssignmentManager.h"
50#ifdef VBOX_WITH_SHARED_CLIPBOARD
51# include "GuestShClPrivate.h"
52#endif
53#ifdef VBOX_WITH_DRAG_AND_DROP
54# include "GuestImpl.h"
55# include "GuestDnDPrivate.h"
56#endif
57#include "VMMDev.h"
58#include "Global.h"
59#ifdef VBOX_WITH_PCI_PASSTHROUGH
60# include "PCIRawDevImpl.h"
61#endif
62
63// generated header
64#include "SchemaDefs.h"
65
66#include "AutoCaller.h"
67
68#include <iprt/base64.h>
69#include <iprt/buildconfig.h>
70#include <iprt/ctype.h>
71#include <iprt/dir.h>
72#include <iprt/file.h>
73#include <iprt/param.h>
74#include <iprt/path.h>
75#include <iprt/string.h>
76#include <iprt/system.h>
77#if 0 /* enable to play with lots of memory. */
78# include <iprt/env.h>
79#endif
80#include <iprt/stream.h>
81
82#include <iprt/http.h>
83#include <iprt/socket.h>
84#include <iprt/uri.h>
85
86#include <VBox/vmm/vmmr3vtable.h>
87#include <VBox/vmm/vmapi.h>
88#include <VBox/err.h>
89#include <VBox/param.h>
90#include <VBox/settings.h> /* For MachineConfigFile::getHostDefaultAudioDriver(). */
91#include <VBox/vmm/pdmapi.h> /* For PDMR3DriverAttach/PDMR3DriverDetach. */
92#include <VBox/vmm/pdmusb.h> /* For PDMR3UsbCreateEmulatedDevice. */
93#include <VBox/vmm/pdmdev.h> /* For PDMAPICMODE enum. */
94#include <VBox/vmm/pdmstorageifs.h>
95#include <VBox/version.h>
96#ifdef VBOX_WITH_SHARED_CLIPBOARD
97# include <VBox/HostServices/VBoxClipboardSvc.h>
98#endif
99#ifdef VBOX_WITH_GUEST_PROPS
100# include <VBox/HostServices/GuestPropertySvc.h>
101# include <VBox/com/defs.h>
102# include <VBox/com/array.h>
103# include <vector>
104#endif /* VBOX_WITH_GUEST_PROPS */
105#include <VBox/intnet.h>
106
107#include <VBox/com/com.h>
108#include <VBox/com/string.h>
109#include <VBox/com/array.h>
110
111#ifdef VBOX_WITH_NETFLT
112# if defined(RT_OS_SOLARIS)
113# include <zone.h>
114# elif defined(RT_OS_LINUX)
115# include <unistd.h>
116# include <sys/ioctl.h>
117# include <sys/socket.h>
118# include <linux/types.h>
119# include <linux/if.h>
120# elif defined(RT_OS_FREEBSD)
121# include <unistd.h>
122# include <sys/types.h>
123# include <sys/ioctl.h>
124# include <sys/socket.h>
125# include <net/if.h>
126# include <net80211/ieee80211_ioctl.h>
127# endif
128# if defined(RT_OS_WINDOWS)
129# include <iprt/win/ntddndis.h>
130# include <devguid.h>
131# else
132# include <HostNetworkInterfaceImpl.h>
133# include <netif.h>
134# include <stdlib.h>
135# endif
136#endif /* VBOX_WITH_NETFLT */
137
138#ifdef VBOX_WITH_AUDIO_VRDE
139# include "DrvAudioVRDE.h"
140#endif
141#ifdef VBOX_WITH_AUDIO_RECORDING
142# include "DrvAudioRec.h"
143#endif
144#include "NetworkServiceRunner.h"
145#ifdef VBOX_WITH_EXTPACK
146# include "ExtPackManagerImpl.h"
147#endif
148
149
150/*********************************************************************************************************************************
151* Internal Functions *
152*********************************************************************************************************************************/
153
154/* Darwin compile kludge */
155#undef PVM
156
157/**
158 * Helper that calls CFGMR3InsertString and throws an RTCError if that
159 * fails (C-string variant).
160 * @param pNode See CFGMR3InsertString.
161 * @param pcszName See CFGMR3InsertString.
162 * @param pcszValue The string value.
163 */
164void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const char *pcszValue)
165{
166 int vrc = mpVMM->pfnCFGMR3InsertString(pNode, pcszName, pcszValue);
167 if (RT_FAILURE(vrc))
168 throw ConfigError("CFGMR3InsertString", vrc, pcszName);
169}
170
171/**
172 * Helper that calls CFGMR3InsertString and throws an RTCError if that
173 * fails (Utf8Str variant).
174 * @param pNode See CFGMR3InsertStringN.
175 * @param pcszName See CFGMR3InsertStringN.
176 * @param rStrValue The string value.
177 */
178void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const Utf8Str &rStrValue)
179{
180 int vrc = mpVMM->pfnCFGMR3InsertStringN(pNode, pcszName, rStrValue.c_str(), rStrValue.length());
181 if (RT_FAILURE(vrc))
182 throw ConfigError("CFGMR3InsertStringLengthKnown", vrc, pcszName);
183}
184
185/**
186 * Helper that calls CFGMR3InsertString and throws an RTCError if that
187 * fails (Bstr variant).
188 *
189 * @param pNode See CFGMR3InsertStringN.
190 * @param pcszName See CFGMR3InsertStringN.
191 * @param rBstrValue The string value.
192 */
193void Console::InsertConfigString(PCFGMNODE pNode, const char *pcszName, const Bstr &rBstrValue)
194{
195 InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue));
196}
197
198/**
199 * Helper that calls CFGMR3InsertStringFV and throws an RTCError if that fails.
200 * @param pNode See CFGMR3InsertStringF.
201 * @param pcszName See CFGMR3InsertStringF.
202 * @param pszFormat See CFGMR3InsertStringF.
203 * @param ... See CFGMR3InsertStringF.
204 */
205void Console::InsertConfigStringF(PCFGMNODE pNode, const char *pcszName, const char *pszFormat, ...)
206{
207 va_list va;
208 va_start(va, pszFormat);
209 int vrc = mpVMM->pfnCFGMR3InsertStringFV(pNode, pcszName, pszFormat, va);
210 va_end(va);
211 if (RT_FAILURE(vrc))
212 throw ConfigError("CFGMR3InsertStringFV", vrc, pcszName);
213}
214
215
216/**
217 * Helper that calls CFGMR3InsertPassword and throws an RTCError if that
218 * fails (Utf8Str variant).
219 * @param pNode See CFGMR3InsertPasswordN.
220 * @param pcszName See CFGMR3InsertPasswordN.
221 * @param rStrValue The string value.
222 */
223void Console::InsertConfigPassword(PCFGMNODE pNode, const char *pcszName, const Utf8Str &rStrValue)
224{
225 int vrc = mpVMM->pfnCFGMR3InsertPasswordN(pNode, pcszName, rStrValue.c_str(), rStrValue.length());
226 if (RT_FAILURE(vrc))
227 throw ConfigError("CFGMR3InsertPasswordLengthKnown", vrc, pcszName);
228}
229
230/**
231 * Helper that calls CFGMR3InsertBytes and throws an RTCError if that fails.
232 *
233 * @param pNode See CFGMR3InsertBytes.
234 * @param pcszName See CFGMR3InsertBytes.
235 * @param pvBytes See CFGMR3InsertBytes.
236 * @param cbBytes See CFGMR3InsertBytes.
237 */
238void Console::InsertConfigBytes(PCFGMNODE pNode, const char *pcszName, const void *pvBytes, size_t cbBytes)
239{
240 int vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pcszName, pvBytes, cbBytes);
241 if (RT_FAILURE(vrc))
242 throw ConfigError("CFGMR3InsertBytes", vrc, pcszName);
243}
244
245/**
246 * Helper that calls CFGMR3InsertInteger and throws an RTCError if that
247 * fails.
248 *
249 * @param pNode See CFGMR3InsertInteger.
250 * @param pcszName See CFGMR3InsertInteger.
251 * @param u64Integer See CFGMR3InsertInteger.
252 */
253void Console::InsertConfigInteger(PCFGMNODE pNode, const char *pcszName, uint64_t u64Integer)
254{
255 int vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pcszName, u64Integer);
256 if (RT_FAILURE(vrc))
257 throw ConfigError("CFGMR3InsertInteger", vrc, pcszName);
258}
259
260/**
261 * Helper that calls CFGMR3InsertNode and throws an RTCError if that fails.
262 *
263 * @param pNode See CFGMR3InsertNode.
264 * @param pcszName See CFGMR3InsertNode.
265 * @param ppChild See CFGMR3InsertNode.
266 */
267void Console::InsertConfigNode(PCFGMNODE pNode, const char *pcszName, PCFGMNODE *ppChild)
268{
269 int vrc = mpVMM->pfnCFGMR3InsertNode(pNode, pcszName, ppChild);
270 if (RT_FAILURE(vrc))
271 throw ConfigError("CFGMR3InsertNode", vrc, pcszName);
272}
273
274/**
275 * Helper that calls CFGMR3InsertNodeF and throws an RTCError if that fails.
276 *
277 * @param pNode See CFGMR3InsertNodeF.
278 * @param ppChild See CFGMR3InsertNodeF.
279 * @param pszNameFormat Name format string, see CFGMR3InsertNodeF.
280 * @param ... Format arguments.
281 */
282void Console::InsertConfigNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, const char *pszNameFormat, ...)
283{
284 va_list va;
285 va_start(va, pszNameFormat);
286 int vrc = mpVMM->pfnCFGMR3InsertNodeF(pNode, ppChild, "%N", pszNameFormat, &va);
287 va_end(va);
288 if (RT_FAILURE(vrc))
289 throw ConfigError("CFGMR3InsertNodeF", vrc, pszNameFormat);
290}
291
292/**
293 * Helper that calls CFGMR3RemoveValue and throws an RTCError if that fails.
294 *
295 * @param pNode See CFGMR3RemoveValue.
296 * @param pcszName See CFGMR3RemoveValue.
297 */
298void Console::RemoveConfigValue(PCFGMNODE pNode, const char *pcszName)
299{
300 int vrc = mpVMM->pfnCFGMR3RemoveValue(pNode, pcszName);
301 if (RT_FAILURE(vrc))
302 throw ConfigError("CFGMR3RemoveValue", vrc, pcszName);
303}
304
305/**
306 * Gets an extra data value, consulting both machine and global extra data.
307 *
308 * @throws HRESULT on failure
309 * @returns pStrValue for the callers convenience.
310 * @param pVirtualBox Pointer to the IVirtualBox interface.
311 * @param pMachine Pointer to the IMachine interface.
312 * @param pszName The value to get.
313 * @param pStrValue Where to return it's value (empty string if not
314 * found).
315 */
316DECL_HIDDEN_THROW(Utf8Str *) GetExtraDataBoth(IVirtualBox *pVirtualBox, IMachine *pMachine, const char *pszName, Utf8Str *pStrValue)
317{
318 pStrValue->setNull();
319
320 Bstr bstrName(pszName);
321 Bstr bstrValue;
322 HRESULT hrc = pMachine->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
323 if (FAILED(hrc))
324 throw hrc;
325 if (bstrValue.isEmpty())
326 {
327 hrc = pVirtualBox->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
328 if (FAILED(hrc))
329 throw hrc;
330 }
331
332 if (bstrValue.isNotEmpty())
333 *pStrValue = bstrValue;
334 return pStrValue;
335}
336
337
338/**
339 * Updates the device type for a LED.
340 *
341 * @param penmSubTypeEntry The sub-type entry to update.
342 * @param enmNewType The new type.
343 */
344void Console::i_setLedType(DeviceType_T *penmSubTypeEntry, DeviceType_T enmNewType)
345{
346 /*
347 * ASSUMES no race conditions here wrt concurrent type updating.
348 */
349 if (*penmSubTypeEntry != enmNewType)
350 {
351 *penmSubTypeEntry = enmNewType;
352 ASMAtomicIncU32(&muLedGen);
353 }
354}
355
356
357/**
358 * Allocate a set of LEDs.
359 *
360 * This grabs a maLedSets entry and populates it with @a cLeds.
361 *
362 * @returns Index into maLedSets.
363 * @param cLeds The number of LEDs in the set.
364 * @param fTypes Bitmask of DeviceType_T values, e.g.
365 * RT_BIT_32(DeviceType_Network).
366 * @param ppaSubTypes When not NULL, subtypes for each LED and return the
367 * array pointer here.
368 */
369uint32_t Console::i_allocateDriverLeds(uint32_t cLeds, uint32_t fTypes, DeviceType_T **ppaSubTypes)
370{
371 Assert(cLeds > 0);
372 Assert(cLeds < 1024); /* Adjust if any driver supports >=1024 units! */
373 Assert(!(fTypes & (RT_BIT_32(DeviceType_Null) | ~(RT_BIT_32(DeviceType_End) - 1))));
374
375 /* Preallocate the arrays we need, bunching them together. */
376 AssertCompile((unsigned)DeviceType_Null == 0);
377 PPDMLED volatile *papLeds = (PPDMLED volatile *)RTMemAllocZ( (sizeof(PPDMLED) + (ppaSubTypes ? sizeof(**ppaSubTypes) : 0))
378 * cLeds);
379 AssertStmt(papLeds, throw E_OUTOFMEMORY);
380
381 /* Take the LED lock in allocation mode and see if there are more LED set entries availalbe. */
382 {
383 AutoWriteLock alock(mLedLock COMMA_LOCKVAL_SRC_POS);
384 uint32_t const idxLedSet = mcLedSets;
385 if (idxLedSet < RT_ELEMENTS(maLedSets))
386 {
387 /* Initialize the set and return the index. */
388 PLEDSET pLS = &maLedSets[idxLedSet];
389 pLS->papLeds = papLeds;
390 pLS->cLeds = cLeds;
391 pLS->fTypes = fTypes;
392 if (ppaSubTypes)
393 *ppaSubTypes = pLS->paSubTypes = (DeviceType_T *)&papLeds[cLeds];
394 else
395 pLS->paSubTypes = NULL;
396
397 mcLedSets = idxLedSet + 1;
398 LogRel2(("return idxLedSet=%d (mcLedSets=%u out of max %zu)\n", idxLedSet, mcLedSets, RT_ELEMENTS(maLedSets)));
399 return idxLedSet;
400 }
401 }
402
403 RTMemFree((void *)papLeds);
404 AssertFailed();
405 throw ConfigError("AllocateDriverPapLeds", VERR_OUT_OF_RANGE, "Too many LED sets");
406}
407
408
409/**
410 * @throws ConfigError and std::bad_alloc.
411 */
412void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, uint32_t fTypes, uint32_t cLeds, DeviceType_T **ppaSubTypes,
413 Console::MediumAttachmentMap *pmapMediumAttachments,
414 const char *pcszDevice, unsigned uInstance)
415{
416 PCFGMNODE pLunL0;
417 InsertConfigNode(pCtlInst, "LUN#999", &pLunL0);
418 InsertConfigString(pLunL0, "Driver", "MainStatus");
419 PCFGMNODE pCfg;
420 InsertConfigNode(pLunL0, "Config", &pCfg);
421 uint32_t const iLedSet = i_allocateDriverLeds(cLeds, fTypes, ppaSubTypes);
422 InsertConfigInteger(pCfg, "iLedSet", iLedSet);
423
424 InsertConfigInteger(pCfg, "HasMediumAttachments", pmapMediumAttachments != NULL);
425 if (pmapMediumAttachments)
426 {
427 AssertPtr(pcszDevice);
428 InsertConfigStringF(pCfg, "DeviceInstance", "%s/%u", pcszDevice, uInstance);
429 }
430 InsertConfigInteger(pCfg, "First", 0);
431 InsertConfigInteger(pCfg, "Last", cLeds - 1);
432}
433
434
435/**
436 * @throws ConfigError and std::bad_alloc.
437 */
438void Console::i_attachStatusDriver(PCFGMNODE pCtlInst, DeviceType_T enmType, uint32_t cLeds /*= 1*/)
439{
440 Assert(enmType > DeviceType_Null && enmType < DeviceType_End);
441 i_attachStatusDriver(pCtlInst, RT_BIT_32(enmType), cLeds, NULL, NULL, NULL, 0);
442}
443
444
445/**
446 * Construct the VM configuration tree (CFGM).
447 *
448 * This is a callback for VMR3Create() call. It is called from CFGMR3Init() in
449 * the emulation thread (EMT). Any per thread COM/XPCOM initialization is done
450 * here.
451 *
452 * @returns VBox status code.
453 * @param pUVM The user mode VM handle.
454 * @param pVM The cross context VM handle.
455 * @param pVMM The VMM ring-3 vtable.
456 * @param pvConsole Pointer to the VMPowerUpTask object.
457 *
458 * @note Locks the Console object for writing.
459 */
460/*static*/ DECLCALLBACK(int)
461Console::i_configConstructor(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvConsole)
462{
463 LogFlowFuncEnter();
464
465 AssertReturn(pvConsole, VERR_INVALID_POINTER);
466 ComObjPtr<Console> pConsole = static_cast<Console *>(pvConsole);
467
468 AutoCaller autoCaller(pConsole);
469 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
470
471 /* lock the console because we widely use internal fields and methods */
472 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
473
474 /*
475 * Set the VM handle and do the rest of the job in an worker method so we
476 * can easily reset the VM handle on failure.
477 */
478 pConsole->mpUVM = pUVM;
479 pVMM->pfnVMR3RetainUVM(pUVM);
480 int vrc;
481 try
482 {
483 vrc = pConsole->i_configConstructorInner(pUVM, pVM, pVMM, &alock);
484 }
485 catch (...)
486 {
487 vrc = VERR_UNEXPECTED_EXCEPTION;
488 }
489 if (RT_FAILURE(vrc))
490 {
491 pConsole->mpUVM = NULL;
492 pVMM->pfnVMR3ReleaseUVM(pUVM);
493 }
494
495 return vrc;
496}
497
498
499/**
500 * Worker for configConstructor.
501 *
502 * @return VBox status code.
503 * @return VERR_PLATFORM_ARCH_NOT_SUPPORTED if the machine's platform architecture is not supported.
504 * @param pUVM The user mode VM handle.
505 * @param pVM The cross context VM handle.
506 * @param pVMM The VMM vtable.
507 * @param pAlock The automatic lock instance. This is for when we have
508 * to leave it in order to avoid deadlocks (ext packs and
509 * more).
510 */
511int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock)
512{
513 ComPtr<IMachine> const pMachine = i_machine();
514
515 ComPtr<IPlatform> pPlatform;
516 HRESULT hrc = pMachine->COMGETTER(Platform)(pPlatform.asOutParam());
517 AssertComRCReturn(hrc, VERR_COM_VM_ERROR);
518
519 PlatformArchitecture_T platformArch;
520 hrc = pPlatform->COMGETTER(Architecture)(&platformArch);
521 AssertComRCReturn(hrc, VERR_COM_VM_ERROR);
522
523 switch (platformArch)
524 {
525 case PlatformArchitecture_x86:
526 return i_configConstructorX86(pUVM, pVM, pVMM, pAlock);
527
528#ifdef VBOX_WITH_VIRT_ARMV8
529 case PlatformArchitecture_ARM:
530 return i_configConstructorArmV8(pUVM, pVM, pVMM, pAlock);
531#endif
532 default:
533 break;
534 }
535
536 return VERR_PLATFORM_ARCH_NOT_SUPPORTED;
537}
538
539
540/**
541 * Configures an audio driver via CFGM by getting (optional) values from extra data.
542 *
543 * @param pVirtualBox Pointer to IVirtualBox instance.
544 * @param pMachine Pointer to IMachine instance.
545 * @param pLUN Pointer to CFGM node of LUN (the driver) to configure.
546 * @param pszDrvName Name of the driver to configure.
547 * @param fAudioEnabledIn IAudioAdapter::enabledIn value.
548 * @param fAudioEnabledOut IAudioAdapter::enabledOut value.
549 *
550 * @throws ConfigError or HRESULT on if there is trouble.
551 */
552void Console::i_configAudioDriver(IVirtualBox *pVirtualBox, IMachine *pMachine, PCFGMNODE pLUN, const char *pszDrvName,
553 bool fAudioEnabledIn, bool fAudioEnabledOut)
554{
555#define H() AssertLogRelMsgStmt(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), \
556 throw ConfigError(__FUNCTION__, VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR, "line: " RT_XSTR(__LINE__)))
557
558 InsertConfigString(pLUN, "Driver", "AUDIO");
559
560 PCFGMNODE pCfg;
561 InsertConfigNode(pLUN, "Config", &pCfg);
562 InsertConfigString(pCfg, "DriverName", pszDrvName);
563 InsertConfigInteger(pCfg, "InputEnabled", fAudioEnabledIn);
564 InsertConfigInteger(pCfg, "OutputEnabled", fAudioEnabledOut);
565
566 Utf8Str strTmp;
567 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
568 const uint64_t fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
569 if (fDebugEnabled)
570 {
571 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
572
573 Utf8Str strDebugPathOut;
574 GetExtraDataBoth(pVirtualBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
575 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut.c_str());
576 }
577
578 /*
579 * PCM input parameters (playback + recording).
580 * We have host driver specific ones as: VBoxInternal2/Audio/<DrvName>/<Value>
581 * And global ones for all host drivers: VBoxInternal2/Audio/<Value>
582 */
583 for (unsigned iDir = 0; iDir < 2; iDir++)
584 {
585 static const struct
586 {
587 const char *pszExtraName;
588 const char *pszCfgmName;
589 } s_aToCopy[] =
590 { /* PCM parameters: */
591 { "PCMSampleBit", "PCMSampleBit" },
592 { "PCMSampleHz", "PCMSampleHz" },
593 { "PCMSampleSigned", "PCMSampleSigned" },
594 { "PCMSampleSwapEndian", "PCMSampleSwapEndian" },
595 { "PCMSampleChannels", "PCMSampleChannels" },
596 /* Buffering stuff: */
597 { "PeriodSizeMs", "PeriodSizeMs" },
598 { "BufferSizeMs", "BufferSizeMs" },
599 { "PreBufferSizeMs", "PreBufferSizeMs" },
600 };
601
602 PCFGMNODE pDirNode = NULL;
603 const char *pszDir = iDir == 0 ? "In" : "Out";
604 for (size_t i = 0; i < RT_ELEMENTS(s_aToCopy); i++)
605 {
606 char szExtra[128];
607 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s/%s%s", pszDrvName, s_aToCopy[i].pszExtraName, pszDir);
608 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp); /* throws hrc */
609 if (strTmp.isEmpty())
610 {
611 RTStrPrintf(szExtra, sizeof(szExtra), "VBoxInternal2/Audio/%s%s", s_aToCopy[i].pszExtraName, pszDir);
612 GetExtraDataBoth(pVirtualBox, pMachine, szExtra, &strTmp);
613 if (strTmp.isEmpty())
614 continue;
615 }
616
617 uint32_t uValue;
618 int vrc = RTStrToUInt32Full(strTmp.c_str(), 0, &uValue);
619 if (RT_SUCCESS(vrc))
620 {
621 if (!pDirNode)
622 InsertConfigNode(pCfg, pszDir, &pDirNode);
623 InsertConfigInteger(pDirNode, s_aToCopy[i].pszCfgmName, uValue);
624 }
625 else
626 LogRel(("Ignoring malformed 32-bit unsigned integer config value '%s' = '%s': %Rrc\n", szExtra, strTmp.c_str(), vrc));
627 }
628 }
629
630 PCFGMNODE pLunL1;
631 InsertConfigNode(pLUN, "AttachedDriver", &pLunL1);
632 InsertConfigString(pLunL1, "Driver", pszDrvName);
633 InsertConfigNode(pLunL1, "Config", &pCfg);
634
635#ifdef RT_OS_WINDOWS
636 if (strcmp(pszDrvName, "HostAudioWas") == 0)
637 {
638 Bstr bstrTmp;
639 HRESULT hrc = pMachine->COMGETTER(Id)(bstrTmp.asOutParam()); H();
640 InsertConfigString(pCfg, "VmUuid", bstrTmp);
641 }
642#endif
643
644#if defined(RT_OS_WINDOWS) || defined(RT_OS_LINUX)
645 if ( strcmp(pszDrvName, "HostAudioWas") == 0
646 || strcmp(pszDrvName, "PulseAudio") == 0)
647 {
648 Bstr bstrTmp;
649 HRESULT hrc = pMachine->COMGETTER(Name)(bstrTmp.asOutParam()); H();
650 InsertConfigString(pCfg, "VmName", bstrTmp);
651 }
652#endif
653
654 LogFlowFunc(("szDrivName=%s\n", pszDrvName));
655
656#undef H
657}
658
659/**
660 * Applies the CFGM overlay as specified by VBoxInternal/XXX extra data
661 * values.
662 *
663 * @returns VBox status code.
664 * @param pRoot The root of the configuration tree.
665 * @param pVirtualBox Pointer to the IVirtualBox interface.
666 * @param pMachine Pointer to the IMachine interface.
667 */
668/* static */
669int Console::i_configCfgmOverlay(PCFGMNODE pRoot, IVirtualBox *pVirtualBox, IMachine *pMachine)
670{
671 /*
672 * CFGM overlay handling.
673 *
674 * Here we check the extra data entries for CFGM values
675 * and create the nodes and insert the values on the fly. Existing
676 * values will be removed and reinserted. CFGM is typed, so by default
677 * we will guess whether it's a string or an integer (byte arrays are
678 * not currently supported). It's possible to override this autodetection
679 * by adding "string:", "integer:" or "bytes:" (future).
680 *
681 * We first perform a run on global extra data, then on the machine
682 * extra data to support global settings with local overrides.
683 */
684 int vrc = VINF_SUCCESS;
685 bool fFirst = true;
686 try
687 {
688 /** @todo add support for removing nodes and byte blobs. */
689 /*
690 * Get the next key
691 */
692 SafeArray<BSTR> aGlobalExtraDataKeys;
693 SafeArray<BSTR> aMachineExtraDataKeys;
694 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
695 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
696
697 // remember the no. of global values so we can call the correct method below
698 size_t cGlobalValues = aGlobalExtraDataKeys.size();
699
700 hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
701 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
702
703 // build a combined list from global keys...
704 std::list<Utf8Str> llExtraDataKeys;
705
706 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
707 llExtraDataKeys.push_back(Utf8Str(aGlobalExtraDataKeys[i]));
708 // ... and machine keys
709 for (size_t i = 0; i < aMachineExtraDataKeys.size(); ++i)
710 llExtraDataKeys.push_back(Utf8Str(aMachineExtraDataKeys[i]));
711
712 size_t i2 = 0;
713 for (std::list<Utf8Str>::const_iterator it = llExtraDataKeys.begin();
714 it != llExtraDataKeys.end();
715 ++it, ++i2)
716 {
717 const Utf8Str &strKey = *it;
718
719 /*
720 * We only care about keys starting with "VBoxInternal/" (skip "G:" or "M:")
721 */
722 if (!strKey.startsWith("VBoxInternal/"))
723 continue;
724
725 const char *pszExtraDataKey = strKey.c_str() + sizeof("VBoxInternal/") - 1;
726
727 // get the value
728 Bstr bstrExtraDataValue;
729 if (i2 < cGlobalValues)
730 // this is still one of the global values:
731 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(), bstrExtraDataValue.asOutParam());
732 else
733 hrc = pMachine->GetExtraData(Bstr(strKey).raw(), bstrExtraDataValue.asOutParam());
734 if (FAILED(hrc))
735 LogRel(("Warning: Cannot get extra data key %s, hrc = %Rhrc\n", strKey.c_str(), hrc));
736
737 if (fFirst)
738 {
739 fFirst = false;
740 LogRel(("Extradata overrides:\n"));
741 }
742 LogRel((" %s=\"%ls\"%s\n", strKey.c_str(), bstrExtraDataValue.raw(), i2 < cGlobalValues ? " (global)" : ""));
743
744 /*
745 * The key will be in the format "Node1/Node2/Value" or simply "Value".
746 * Split the two and get the node, delete the value and create the node
747 * if necessary.
748 */
749 PCFGMNODE pNode;
750 const char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
751 if (pszCFGMValueName)
752 {
753 /* terminate the node and advance to the value (Utf8Str might not
754 offically like this but wtf) */
755 *(char *)pszCFGMValueName = '\0';
756 ++pszCFGMValueName;
757
758 /* does the node already exist? */
759 pNode = mpVMM->pfnCFGMR3GetChild(pRoot, pszExtraDataKey);
760 if (pNode)
761 mpVMM->pfnCFGMR3RemoveValue(pNode, pszCFGMValueName);
762 else
763 {
764 /* create the node */
765 vrc = mpVMM->pfnCFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
766 if (RT_FAILURE(vrc))
767 {
768 AssertLogRelMsgRC(vrc, ("failed to insert node '%s'\n", pszExtraDataKey));
769 continue;
770 }
771 Assert(pNode);
772 }
773 }
774 else
775 {
776 /* root value (no node path). */
777 pNode = pRoot;
778 pszCFGMValueName = pszExtraDataKey;
779 pszExtraDataKey--;
780 mpVMM->pfnCFGMR3RemoveValue(pNode, pszCFGMValueName);
781 }
782
783 /*
784 * Now let's have a look at the value.
785 * Empty strings means that we should remove the value, which we've
786 * already done above.
787 */
788 Utf8Str strCFGMValueUtf8(bstrExtraDataValue);
789 if (strCFGMValueUtf8.isNotEmpty())
790 {
791 uint64_t u64Value;
792
793 /* check for type prefix first. */
794 if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("string:")))
795 vrc = mpVMM->pfnCFGMR3InsertString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str() + sizeof("string:") - 1);
796 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("integer:")))
797 {
798 vrc = RTStrToUInt64Full(strCFGMValueUtf8.c_str() + sizeof("integer:") - 1, 0, &u64Value);
799 if (RT_SUCCESS(vrc))
800 vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
801 }
802 else if (!strncmp(strCFGMValueUtf8.c_str(), RT_STR_TUPLE("bytes:")))
803 {
804 char const *pszBase64 = strCFGMValueUtf8.c_str() + sizeof("bytes:") - 1;
805 ssize_t cbValue = RTBase64DecodedSize(pszBase64, NULL);
806 if (cbValue > 0)
807 {
808 void *pvBytes = RTMemTmpAlloc(cbValue);
809 if (pvBytes)
810 {
811 vrc = RTBase64Decode(pszBase64, pvBytes, cbValue, NULL, NULL);
812 if (RT_SUCCESS(vrc))
813 vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pszCFGMValueName, pvBytes, cbValue);
814 RTMemTmpFree(pvBytes);
815 }
816 else
817 vrc = VERR_NO_TMP_MEMORY;
818 }
819 else if (cbValue == 0)
820 vrc = mpVMM->pfnCFGMR3InsertBytes(pNode, pszCFGMValueName, NULL, 0);
821 else
822 vrc = VERR_INVALID_BASE64_ENCODING;
823 }
824 /* auto detect type. */
825 else if (RT_SUCCESS(RTStrToUInt64Full(strCFGMValueUtf8.c_str(), 0, &u64Value)))
826 vrc = mpVMM->pfnCFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
827 else
828 vrc = mpVMM->pfnCFGMR3InsertString(pNode, pszCFGMValueName, strCFGMValueUtf8.c_str());
829 AssertLogRelMsgRCBreak(vrc, ("failed to insert CFGM value '%s' to key '%s'\n",
830 strCFGMValueUtf8.c_str(), pszExtraDataKey));
831 }
832 }
833 }
834 catch (ConfigError &x)
835 {
836 // InsertConfig threw something:
837 return x.m_vrc;
838 }
839 return vrc;
840}
841
842/**
843 * Dumps the API settings tweaks as specified by VBoxInternal2/XXX extra data
844 * values.
845 *
846 * @returns VBox status code.
847 * @param pVirtualBox Pointer to the IVirtualBox interface.
848 * @param pMachine Pointer to the IMachine interface.
849 */
850/* static */
851int Console::i_configDumpAPISettingsTweaks(IVirtualBox *pVirtualBox, IMachine *pMachine)
852{
853 {
854 SafeArray<BSTR> aGlobalExtraDataKeys;
855 HRESULT hrc = pVirtualBox->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
856 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
857 bool hasKey = false;
858 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); i++)
859 {
860 Utf8Str strKey(aGlobalExtraDataKeys[i]);
861 if (!strKey.startsWith("VBoxInternal2/"))
862 continue;
863
864 Bstr bstrValue;
865 hrc = pVirtualBox->GetExtraData(Bstr(strKey).raw(),
866 bstrValue.asOutParam());
867 if (FAILED(hrc))
868 continue;
869 if (!hasKey)
870 LogRel(("Global extradata API settings:\n"));
871 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
872 hasKey = true;
873 }
874 }
875
876 {
877 SafeArray<BSTR> aMachineExtraDataKeys;
878 HRESULT hrc = pMachine->GetExtraDataKeys(ComSafeArrayAsOutParam(aMachineExtraDataKeys));
879 AssertMsg(SUCCEEDED(hrc), ("Machine::GetExtraDataKeys failed with %Rhrc\n", hrc));
880 bool hasKey = false;
881 for (size_t i = 0; i < aMachineExtraDataKeys.size(); i++)
882 {
883 Utf8Str strKey(aMachineExtraDataKeys[i]);
884 if (!strKey.startsWith("VBoxInternal2/"))
885 continue;
886
887 Bstr bstrValue;
888 hrc = pMachine->GetExtraData(Bstr(strKey).raw(),
889 bstrValue.asOutParam());
890 if (FAILED(hrc))
891 continue;
892 if (!hasKey)
893 LogRel(("Per-VM extradata API settings:\n"));
894 LogRel((" %s=\"%ls\"\n", strKey.c_str(), bstrValue.raw()));
895 hasKey = true;
896 }
897 }
898
899 return VINF_SUCCESS;
900}
901
902
903/**
904 * Ellipsis to va_list wrapper for calling setVMRuntimeErrorCallback.
905 */
906void Console::i_atVMRuntimeErrorCallbackF(uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
907{
908 va_list va;
909 va_start(va, pszFormat);
910 i_atVMRuntimeErrorCallback(NULL, this, fFlags, pszErrorId, pszFormat, va);
911 va_end(va);
912}
913
914/* XXX introduce RT format specifier */
915static uint64_t formatDiskSize(uint64_t u64Size, const char **pszUnit)
916{
917 if (u64Size > INT64_C(5000)*_1G)
918 {
919 *pszUnit = "TB";
920 return u64Size / _1T;
921 }
922 else if (u64Size > INT64_C(5000)*_1M)
923 {
924 *pszUnit = "GB";
925 return u64Size / _1G;
926 }
927 else
928 {
929 *pszUnit = "MB";
930 return u64Size / _1M;
931 }
932}
933
934/**
935 * Checks the location of the given medium for known bugs affecting the usage
936 * of the host I/O cache setting.
937 *
938 * @returns VBox status code.
939 * @param pMedium The medium to check.
940 * @param pfUseHostIOCache Where to store the suggested host I/O cache setting.
941 */
942int Console::i_checkMediumLocation(IMedium *pMedium, bool *pfUseHostIOCache)
943{
944#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
945 /*
946 * Some sanity checks.
947 */
948 RT_NOREF(pfUseHostIOCache);
949 ComPtr<IMediumFormat> pMediumFormat;
950 HRESULT hrc = pMedium->COMGETTER(MediumFormat)(pMediumFormat.asOutParam()); H();
951 ULONG uCaps = 0;
952 com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
953 hrc = pMediumFormat->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)); H();
954
955 for (ULONG j = 0; j < mediumFormatCap.size(); j++)
956 uCaps |= mediumFormatCap[j];
957
958 if (uCaps & MediumFormatCapabilities_File)
959 {
960 Bstr bstrFile;
961 hrc = pMedium->COMGETTER(Location)(bstrFile.asOutParam()); H();
962 Utf8Str const strFile(bstrFile);
963
964 Bstr bstrSnap;
965 ComPtr<IMachine> pMachine = i_machine();
966 hrc = pMachine->COMGETTER(SnapshotFolder)(bstrSnap.asOutParam()); H();
967 Utf8Str const strSnap(bstrSnap);
968
969 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
970 int vrc2 = RTFsQueryType(strFile.c_str(), &enmFsTypeFile);
971 AssertMsgRCReturn(vrc2, ("Querying the file type of '%s' failed!\n", strFile.c_str()), vrc2);
972
973 /* Any VM which hasn't created a snapshot or saved the current state of the VM
974 * won't have a Snapshot folder yet so no need to log anything about the file system
975 * type of the non-existent directory in such cases. */
976 RTFSTYPE enmFsTypeSnap = RTFSTYPE_UNKNOWN;
977 vrc2 = RTFsQueryType(strSnap.c_str(), &enmFsTypeSnap);
978 if (RT_SUCCESS(vrc2) && !mfSnapshotFolderDiskTypeShown)
979 {
980 LogRel(("File system of '%s' (snapshots) is %s\n", strSnap.c_str(), RTFsTypeName(enmFsTypeSnap)));
981 mfSnapshotFolderDiskTypeShown = true;
982 }
983 LogRel(("File system of '%s' is %s\n", strFile.c_str(), RTFsTypeName(enmFsTypeFile)));
984 LONG64 i64Size;
985 hrc = pMedium->COMGETTER(LogicalSize)(&i64Size); H();
986#ifdef RT_OS_WINDOWS
987 if ( enmFsTypeFile == RTFSTYPE_FAT
988 && i64Size >= _4G)
989 {
990 const char *pszUnit;
991 uint64_t u64Print = formatDiskSize((uint64_t)i64Size, &pszUnit);
992 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
993 N_("The medium '%s' has a logical size of %RU64%s "
994 "but the file system the medium is located on seems "
995 "to be FAT(32) which cannot handle files bigger than 4GB.\n"
996 "We strongly recommend to put all your virtual disk images and "
997 "the snapshot folder onto an NTFS partition"),
998 strFile.c_str(), u64Print, pszUnit);
999 }
1000#else /* !RT_OS_WINDOWS */
1001 if ( enmFsTypeFile == RTFSTYPE_FAT
1002 || enmFsTypeFile == RTFSTYPE_EXT
1003 || enmFsTypeFile == RTFSTYPE_EXT2
1004 || enmFsTypeFile == RTFSTYPE_EXT3
1005 || enmFsTypeFile == RTFSTYPE_EXT4)
1006 {
1007 RTFILE file;
1008 int vrc = RTFileOpen(&file, strFile.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
1009 if (RT_SUCCESS(vrc))
1010 {
1011 RTFOFF maxSize;
1012 /* Careful: This function will work only on selected local file systems! */
1013 vrc = RTFileQueryMaxSizeEx(file, &maxSize);
1014 RTFileClose(file);
1015 if ( RT_SUCCESS(vrc)
1016 && maxSize > 0
1017 && i64Size > (LONG64)maxSize)
1018 {
1019 const char *pszUnitSiz;
1020 const char *pszUnitMax;
1021 uint64_t u64PrintSiz = formatDiskSize((LONG64)i64Size, &pszUnitSiz);
1022 uint64_t u64PrintMax = formatDiskSize(maxSize, &pszUnitMax);
1023 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected", /* <= not exact but ... */
1024 N_("The medium '%s' has a logical size of %RU64%s "
1025 "but the file system the medium is located on can "
1026 "only handle files up to %RU64%s in theory.\n"
1027 "We strongly recommend to put all your virtual disk "
1028 "images and the snapshot folder onto a proper "
1029 "file system (e.g. ext3) with a sufficient size"),
1030 strFile.c_str(), u64PrintSiz, pszUnitSiz, u64PrintMax, pszUnitMax);
1031 }
1032 }
1033 }
1034#endif /* !RT_OS_WINDOWS */
1035
1036 /*
1037 * Snapshot folder:
1038 * Here we test only for a FAT partition as we had to create a dummy file otherwise
1039 */
1040 if ( enmFsTypeSnap == RTFSTYPE_FAT
1041 && i64Size >= _4G
1042 && !mfSnapshotFolderSizeWarningShown)
1043 {
1044 const char *pszUnit;
1045 uint64_t u64Print = formatDiskSize(i64Size, &pszUnit);
1046 i_atVMRuntimeErrorCallbackF(0, "FatPartitionDetected",
1047#ifdef RT_OS_WINDOWS
1048 N_("The snapshot folder of this VM '%s' seems to be located on "
1049 "a FAT(32) file system. The logical size of the medium '%s' "
1050 "(%RU64%s) is bigger than the maximum file size this file "
1051 "system can handle (4GB).\n"
1052 "We strongly recommend to put all your virtual disk images and "
1053 "the snapshot folder onto an NTFS partition"),
1054#else
1055 N_("The snapshot folder of this VM '%s' seems to be located on "
1056 "a FAT(32) file system. The logical size of the medium '%s' "
1057 "(%RU64%s) is bigger than the maximum file size this file "
1058 "system can handle (4GB).\n"
1059 "We strongly recommend to put all your virtual disk images and "
1060 "the snapshot folder onto a proper file system (e.g. ext3)"),
1061#endif
1062 strSnap.c_str(), strFile.c_str(), u64Print, pszUnit);
1063 /* Show this particular warning only once */
1064 mfSnapshotFolderSizeWarningShown = true;
1065 }
1066
1067#ifdef RT_OS_LINUX
1068 /*
1069 * Ext4 bug: Check if the host I/O cache is disabled and the disk image is located
1070 * on an ext4 partition.
1071 * This bug apparently applies to the XFS file system as well.
1072 * Linux 2.6.36 is known to be fixed (tested with 2.6.36-rc4).
1073 */
1074
1075 char szOsRelease[128];
1076 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOsRelease, sizeof(szOsRelease));
1077 bool fKernelHasODirectBug = RT_FAILURE(vrc)
1078 || (RTStrVersionCompare(szOsRelease, "2.6.36-rc4") < 0);
1079
1080 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
1081 && !*pfUseHostIOCache
1082 && fKernelHasODirectBug)
1083 {
1084 if ( enmFsTypeFile == RTFSTYPE_EXT4
1085 || enmFsTypeFile == RTFSTYPE_XFS)
1086 {
1087 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
1088 N_("The host I/O cache for at least one controller is disabled "
1089 "and the medium '%s' for this VM "
1090 "is located on an %s partition. There is a known Linux "
1091 "kernel bug which can lead to the corruption of the virtual "
1092 "disk image under these conditions.\n"
1093 "Either enable the host I/O cache permanently in the VM "
1094 "settings or put the disk image and the snapshot folder "
1095 "onto a different file system.\n"
1096 "The host I/O cache will now be enabled for this medium"),
1097 strFile.c_str(), enmFsTypeFile == RTFSTYPE_EXT4 ? "ext4" : "xfs");
1098 *pfUseHostIOCache = true;
1099 }
1100 else if ( ( enmFsTypeSnap == RTFSTYPE_EXT4
1101 || enmFsTypeSnap == RTFSTYPE_XFS)
1102 && !mfSnapshotFolderExt4WarningShown)
1103 {
1104 i_atVMRuntimeErrorCallbackF(0, "Ext4PartitionDetected",
1105 N_("The host I/O cache for at least one controller is disabled "
1106 "and the snapshot folder for this VM "
1107 "is located on an %s partition. There is a known Linux "
1108 "kernel bug which can lead to the corruption of the virtual "
1109 "disk image under these conditions.\n"
1110 "Either enable the host I/O cache permanently in the VM "
1111 "settings or put the disk image and the snapshot folder "
1112 "onto a different file system.\n"
1113 "The host I/O cache will now be enabled for this medium"),
1114 enmFsTypeSnap == RTFSTYPE_EXT4 ? "ext4" : "xfs");
1115 *pfUseHostIOCache = true;
1116 mfSnapshotFolderExt4WarningShown = true;
1117 }
1118 }
1119
1120 /*
1121 * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
1122 * Linux 2.6.18. See @bugref{8690}. Apparently the same problem as
1123 * documented in https://lkml.org/lkml/2007/2/1/14. We saw such
1124 * kernel oopses on Linux 2.6.18-416.el5. We don't know when this
1125 * was fixed but we _know_ that 2.6.18 EL5 kernels are affected.
1126 */
1127 bool fKernelAsyncUnreliable = RT_FAILURE(vrc)
1128 || (RTStrVersionCompare(szOsRelease, "2.6.19") < 0);
1129 if ( (uCaps & MediumFormatCapabilities_Asynchronous)
1130 && !*pfUseHostIOCache
1131 && fKernelAsyncUnreliable)
1132 {
1133 i_atVMRuntimeErrorCallbackF(0, "Linux2618TooOld",
1134 N_("The host I/O cache for at least one controller is disabled. "
1135 "There is a known Linux kernel bug which can lead to kernel "
1136 "oopses under heavy load. To our knowledge this bug affects "
1137 "all 2.6.18 kernels.\n"
1138 "Either enable the host I/O cache permanently in the VM "
1139 "settings or switch to a newer host kernel.\n"
1140 "The host I/O cache will now be enabled for this medium"));
1141 *pfUseHostIOCache = true;
1142 }
1143#endif
1144 }
1145#undef H
1146
1147 return VINF_SUCCESS;
1148}
1149
1150/**
1151 * Unmounts the specified medium from the specified device.
1152 *
1153 * @returns VBox status code.
1154 * @param pUVM The usermode VM handle.
1155 * @param pVMM The VMM vtable.
1156 * @param enmBus The storage bus.
1157 * @param enmDevType The device type.
1158 * @param pcszDevice The device emulation.
1159 * @param uInstance Instance of the device.
1160 * @param uLUN The LUN on the device.
1161 * @param fForceUnmount Whether to force unmounting.
1162 */
1163int Console::i_unmountMediumFromGuest(PUVM pUVM, PCVMMR3VTABLE pVMM, StorageBus_T enmBus, DeviceType_T enmDevType,
1164 const char *pcszDevice, unsigned uInstance, unsigned uLUN,
1165 bool fForceUnmount) RT_NOEXCEPT
1166{
1167 /* Unmount existing media only for floppy and DVD drives. */
1168 int vrc = VINF_SUCCESS;
1169 PPDMIBASE pBase;
1170 if (enmBus == StorageBus_USB)
1171 vrc = pVMM->pfnPDMR3UsbQueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
1172 else if ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
1173 || (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD))
1174 vrc = pVMM->pfnPDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "SCSI", &pBase);
1175 else /* IDE or Floppy */
1176 vrc = pVMM->pfnPDMR3QueryLun(pUVM, pcszDevice, uInstance, uLUN, &pBase);
1177
1178 if (RT_FAILURE(vrc))
1179 {
1180 if (vrc == VERR_PDM_LUN_NOT_FOUND || vrc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
1181 vrc = VINF_SUCCESS;
1182 AssertRC(vrc);
1183 }
1184 else
1185 {
1186 PPDMIMOUNT pIMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
1187 AssertPtrReturn(pIMount, VERR_INVALID_POINTER);
1188
1189 /* Unmount the media (but do not eject the medium!) */
1190 vrc = pIMount->pfnUnmount(pIMount, fForceUnmount, false /*=fEject*/);
1191 if (vrc == VERR_PDM_MEDIA_NOT_MOUNTED)
1192 vrc = VINF_SUCCESS;
1193 /* for example if the medium is locked */
1194 else if (RT_FAILURE(vrc))
1195 return vrc;
1196 }
1197
1198 return vrc;
1199}
1200
1201/**
1202 * Removes the currently attached medium driver form the specified device
1203 * taking care of the controlelr specific configs wrt. to the attached driver chain.
1204 *
1205 * @returns VBox status code.
1206 * @param pCtlInst The controler instance node in the CFGM tree.
1207 * @param pcszDevice The device name.
1208 * @param uInstance The device instance.
1209 * @param uLUN The device LUN.
1210 * @param enmBus The storage bus.
1211 * @param fAttachDetach Flag whether this is a change while the VM is running
1212 * @param fHotplug Flag whether the guest should be notified about the device change.
1213 * @param fForceUnmount Flag whether to force unmounting the medium even if it is locked.
1214 * @param pUVM The usermode VM handle.
1215 * @param pVMM The VMM vtable.
1216 * @param enmDevType The device type.
1217 * @param ppLunL0 Where to store the node to attach the new config to on success.
1218 */
1219int Console::i_removeMediumDriverFromVm(PCFGMNODE pCtlInst,
1220 const char *pcszDevice,
1221 unsigned uInstance,
1222 unsigned uLUN,
1223 StorageBus_T enmBus,
1224 bool fAttachDetach,
1225 bool fHotplug,
1226 bool fForceUnmount,
1227 PUVM pUVM,
1228 PCVMMR3VTABLE pVMM,
1229 DeviceType_T enmDevType,
1230 PCFGMNODE *ppLunL0)
1231{
1232 int vrc = VINF_SUCCESS;
1233 bool fAddLun = false;
1234
1235 /* First check if the LUN already exists. */
1236 PCFGMNODE pLunL0 = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
1237 AssertReturn(!RT_VALID_PTR(pLunL0) || fAttachDetach, VERR_INTERNAL_ERROR);
1238
1239 if (pLunL0)
1240 {
1241 /*
1242 * Unmount the currently mounted medium if we don't just hot remove the
1243 * complete device (SATA) and it supports unmounting (DVD).
1244 */
1245 if ( (enmDevType != DeviceType_HardDisk)
1246 && !fHotplug)
1247 {
1248 vrc = i_unmountMediumFromGuest(pUVM, pVMM, enmBus, enmDevType, pcszDevice, uInstance, uLUN, fForceUnmount);
1249 if (RT_FAILURE(vrc))
1250 return vrc;
1251 }
1252
1253 /*
1254 * Don't detach the SCSI driver when unmounting the current medium
1255 * (we are not ripping out the device but only eject the medium).
1256 */
1257 char *pszDriverDetach = NULL;
1258 if ( !fHotplug
1259 && ( (enmBus == StorageBus_SATA && enmDevType == DeviceType_DVD)
1260 || enmBus == StorageBus_SAS
1261 || enmBus == StorageBus_SCSI
1262 || enmBus == StorageBus_VirtioSCSI
1263 || enmBus == StorageBus_USB))
1264 {
1265 /* Get the current attached driver we have to detach. */
1266 PCFGMNODE pDrvLun = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u/AttachedDriver/", uLUN);
1267 if (pDrvLun)
1268 {
1269 char szDriver[128];
1270 RT_ZERO(szDriver);
1271 vrc = pVMM->pfnCFGMR3QueryString(pDrvLun, "Driver", &szDriver[0], sizeof(szDriver));
1272 if (RT_SUCCESS(vrc))
1273 pszDriverDetach = RTStrDup(&szDriver[0]);
1274
1275 pLunL0 = pDrvLun;
1276 }
1277 }
1278
1279 if (enmBus == StorageBus_USB)
1280 vrc = pVMM->pfnPDMR3UsbDriverDetach(pUVM, pcszDevice, uInstance, uLUN, pszDriverDetach,
1281 0 /* iOccurence */, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
1282 else
1283 vrc = pVMM->pfnPDMR3DriverDetach(pUVM, pcszDevice, uInstance, uLUN, pszDriverDetach,
1284 0 /* iOccurence */, fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG);
1285
1286 if (pszDriverDetach)
1287 {
1288 RTStrFree(pszDriverDetach);
1289 /* Remove the complete node and create new for the new config. */
1290 pVMM->pfnCFGMR3RemoveNode(pLunL0);
1291 pLunL0 = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
1292 if (pLunL0)
1293 {
1294 try
1295 {
1296 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
1297 }
1298 catch (ConfigError &x)
1299 {
1300 // InsertConfig threw something:
1301 return x.m_vrc;
1302 }
1303 }
1304 }
1305 if (vrc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
1306 vrc = VINF_SUCCESS;
1307 AssertRCReturn(vrc, vrc);
1308
1309 /*
1310 * Don't remove the LUN except for IDE/floppy/NVMe (which connects directly to the medium driver
1311 * even for DVD devices) or if there is a hotplug event which rips out the complete device.
1312 */
1313 if ( fHotplug
1314 || enmBus == StorageBus_IDE
1315 || enmBus == StorageBus_Floppy
1316 || enmBus == StorageBus_PCIe
1317 || (enmBus == StorageBus_SATA && enmDevType != DeviceType_DVD))
1318 {
1319 fAddLun = true;
1320 pVMM->pfnCFGMR3RemoveNode(pLunL0);
1321 }
1322 }
1323 else
1324 fAddLun = true;
1325
1326 try
1327 {
1328 if (fAddLun)
1329 InsertConfigNodeF(pCtlInst, &pLunL0, "LUN#%u", uLUN);
1330 }
1331 catch (ConfigError &x)
1332 {
1333 // InsertConfig threw something:
1334 return x.m_vrc;
1335 }
1336
1337 if (ppLunL0)
1338 *ppLunL0 = pLunL0;
1339
1340 return vrc;
1341}
1342
1343int Console::i_configMediumAttachment(const char *pcszDevice,
1344 unsigned uInstance,
1345 StorageBus_T enmBus,
1346 bool fUseHostIOCache,
1347 bool fBuiltinIOCache,
1348 bool fInsertDiskIntegrityDrv,
1349 bool fSetupMerge,
1350 unsigned uMergeSource,
1351 unsigned uMergeTarget,
1352 IMediumAttachment *pMediumAtt,
1353 MachineState_T aMachineState,
1354 HRESULT *phrc,
1355 bool fAttachDetach,
1356 bool fForceUnmount,
1357 bool fHotplug,
1358 PUVM pUVM,
1359 PCVMMR3VTABLE pVMM,
1360 DeviceType_T *paLedDevType,
1361 PCFGMNODE *ppLunL0)
1362{
1363 // InsertConfig* throws
1364 try
1365 {
1366 int vrc = VINF_SUCCESS;
1367 HRESULT hrc;
1368 Bstr bstr;
1369 PCFGMNODE pCtlInst = NULL;
1370
1371// #define RC_CHECK() AssertMsgReturn(RT_SUCCESS(vrc), ("vrc=%Rrc\n", vrc), vrc)
1372#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
1373
1374 LONG lDev;
1375 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
1376 LONG lPort;
1377 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
1378 DeviceType_T enmType;
1379 hrc = pMediumAtt->COMGETTER(Type)(&enmType); H();
1380 BOOL fNonRotational;
1381 hrc = pMediumAtt->COMGETTER(NonRotational)(&fNonRotational); H();
1382 BOOL fDiscard;
1383 hrc = pMediumAtt->COMGETTER(Discard)(&fDiscard); H();
1384
1385 if (enmType == DeviceType_DVD)
1386 fInsertDiskIntegrityDrv = false;
1387
1388 unsigned uLUN;
1389 PCFGMNODE pLunL0 = NULL;
1390 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
1391
1392 /* Determine the base path for the device instance. */
1393 if (enmBus != StorageBus_USB)
1394 pCtlInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
1395 else
1396 {
1397 /* If we hotplug a USB device create a new CFGM tree. */
1398 if (!fHotplug)
1399 pCtlInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "USB/%s/", pcszDevice);
1400 else
1401 pCtlInst = pVMM->pfnCFGMR3CreateTree(pUVM); /** @todo r=bird: Leaked in error paths! */
1402 }
1403 AssertReturn(pCtlInst, VERR_INTERNAL_ERROR);
1404
1405 if (enmBus == StorageBus_USB)
1406 {
1407 PCFGMNODE pCfg = NULL;
1408
1409 /* Create correct instance. */
1410 if (!fHotplug)
1411 {
1412 if (!fAttachDetach)
1413 InsertConfigNodeF(pCtlInst, &pCtlInst, "%d", lPort);
1414 else
1415 pCtlInst = pVMM->pfnCFGMR3GetChildF(pCtlInst, "%d/", lPort);
1416 }
1417
1418 if (!fAttachDetach)
1419 InsertConfigNode(pCtlInst, "Config", &pCfg);
1420
1421 uInstance = lPort; /* Overwrite uInstance with the correct one. */
1422
1423 /** @todo No LED after hotplugging. */
1424 if (!fHotplug && !fAttachDetach)
1425 {
1426 USBStorageDevice UsbMsd;
1427 UsbMsd.iPort = uInstance;
1428 vrc = RTUuidCreate(&UsbMsd.mUuid);
1429 AssertRCReturn(vrc, vrc);
1430
1431 InsertConfigStringF(pCtlInst, "UUID", "%RTuuid", &UsbMsd.mUuid);
1432
1433 mUSBStorageDevices.push_back(UsbMsd);
1434
1435 /** @todo This LED set is not freed if the device is unplugged. We could
1436 * keep the LED set index in the UsbMsd structure and clean it up in
1437 * i_detachStorageDevice. */
1438 /* Attach the status driver */
1439 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),
1440 8, &paLedDevType, &mapMediumAttachments, pcszDevice, 0);
1441 }
1442 }
1443
1444 vrc = i_removeMediumDriverFromVm(pCtlInst, pcszDevice, uInstance, uLUN, enmBus, fAttachDetach,
1445 fHotplug, fForceUnmount, pUVM, pVMM, enmType, &pLunL0);
1446 if (RT_FAILURE(vrc))
1447 return vrc;
1448 if (ppLunL0)
1449 *ppLunL0 = pLunL0;
1450
1451 Utf8StrFmt devicePath("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
1452 mapMediumAttachments[devicePath] = pMediumAtt;
1453
1454 ComPtr<IMedium> ptrMedium;
1455 hrc = pMediumAtt->COMGETTER(Medium)(ptrMedium.asOutParam()); H();
1456
1457 /*
1458 * 1. Only check this for hard disk images.
1459 * 2. Only check during VM creation and not later, especially not during
1460 * taking an online snapshot!
1461 */
1462 if ( enmType == DeviceType_HardDisk
1463 && ( aMachineState == MachineState_Starting
1464 || aMachineState == MachineState_Restoring))
1465 {
1466 vrc = i_checkMediumLocation(ptrMedium, &fUseHostIOCache);
1467 if (RT_FAILURE(vrc))
1468 return vrc;
1469 }
1470
1471 BOOL fPassthrough = FALSE;
1472 if (ptrMedium.isNotNull())
1473 {
1474 BOOL fHostDrive;
1475 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
1476 if ( ( enmType == DeviceType_DVD
1477 || enmType == DeviceType_Floppy)
1478 && !fHostDrive)
1479 {
1480 /*
1481 * Informative logging.
1482 */
1483 Bstr bstrFile;
1484 hrc = ptrMedium->COMGETTER(Location)(bstrFile.asOutParam()); H();
1485 Utf8Str strFile(bstrFile);
1486 RTFSTYPE enmFsTypeFile = RTFSTYPE_UNKNOWN;
1487 (void)RTFsQueryType(strFile.c_str(), &enmFsTypeFile);
1488 LogRel(("File system of '%s' (%s) is %s\n",
1489 strFile.c_str(), enmType == DeviceType_DVD ? "DVD" : "Floppy", RTFsTypeName(enmFsTypeFile)));
1490 }
1491
1492 if (fHostDrive)
1493 {
1494 hrc = pMediumAtt->COMGETTER(Passthrough)(&fPassthrough); H();
1495 }
1496 }
1497
1498 ComObjPtr<IBandwidthGroup> pBwGroup;
1499 Bstr bstrBwGroup;
1500 hrc = pMediumAtt->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
1501
1502 if (!pBwGroup.isNull())
1503 {
1504 hrc = pBwGroup->COMGETTER(Name)(bstrBwGroup.asOutParam()); H();
1505 }
1506
1507 /*
1508 * Insert the SCSI driver for hotplug events on the SCSI/USB based storage controllers
1509 * or for SATA if the new device is a CD/DVD drive.
1510 */
1511 if ( (fHotplug || !fAttachDetach)
1512 && ( enmBus == StorageBus_SCSI
1513 || enmBus == StorageBus_SAS
1514 || enmBus == StorageBus_USB
1515 || enmBus == StorageBus_VirtioSCSI
1516 || (enmBus == StorageBus_SATA && enmType == DeviceType_DVD && !fPassthrough)))
1517 {
1518 InsertConfigString(pLunL0, "Driver", "SCSI");
1519 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
1520 }
1521
1522 vrc = i_configMedium(pLunL0,
1523 !!fPassthrough,
1524 enmType,
1525 fUseHostIOCache,
1526 fBuiltinIOCache,
1527 fInsertDiskIntegrityDrv,
1528 fSetupMerge,
1529 uMergeSource,
1530 uMergeTarget,
1531 bstrBwGroup.isEmpty() ? NULL : Utf8Str(bstrBwGroup).c_str(),
1532 !!fDiscard,
1533 !!fNonRotational,
1534 ptrMedium,
1535 aMachineState,
1536 phrc);
1537 if (RT_FAILURE(vrc))
1538 return vrc;
1539
1540 if (fAttachDetach)
1541 {
1542 /* Attach the new driver. */
1543 if (enmBus == StorageBus_USB)
1544 {
1545 if (fHotplug)
1546 {
1547 USBStorageDevice UsbMsd;
1548 RTUuidCreate(&UsbMsd.mUuid);
1549 UsbMsd.iPort = uInstance;
1550 vrc = pVMM->pfnPDMR3UsbCreateEmulatedDevice(pUVM, pcszDevice, pCtlInst, &UsbMsd.mUuid, NULL);
1551 if (RT_SUCCESS(vrc))
1552 mUSBStorageDevices.push_back(UsbMsd);
1553 }
1554 else
1555 vrc = pVMM->pfnPDMR3UsbDriverAttach(pUVM, pcszDevice, uInstance, uLUN,
1556 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
1557 }
1558 else if ( !fHotplug
1559 && ( (enmBus == StorageBus_SAS || enmBus == StorageBus_SCSI || enmBus == StorageBus_VirtioSCSI)
1560 || (enmBus == StorageBus_SATA && enmType == DeviceType_DVD)))
1561 vrc = pVMM->pfnPDMR3DriverAttach(pUVM, pcszDevice, uInstance, uLUN,
1562 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
1563 else
1564 vrc = pVMM->pfnPDMR3DeviceAttach(pUVM, pcszDevice, uInstance, uLUN,
1565 fHotplug ? 0 : PDM_TACH_FLAGS_NOT_HOT_PLUG, NULL /*ppBase*/);
1566 AssertRCReturn(vrc, vrc);
1567
1568 /*
1569 * Make the secret key helper interface known to the VD driver if it is attached,
1570 * so we can get notified about missing keys.
1571 */
1572 PPDMIBASE pIBase = NULL;
1573 vrc = pVMM->pfnPDMR3QueryDriverOnLun(pUVM, pcszDevice, uInstance, uLUN, "VD", &pIBase);
1574 if (RT_SUCCESS(vrc) && pIBase)
1575 {
1576 PPDMIMEDIA pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
1577 if (pIMedium)
1578 {
1579 vrc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
1580 Assert(RT_SUCCESS(vrc) || vrc == VERR_NOT_SUPPORTED);
1581 }
1582 }
1583
1584 /* There is no need to handle removable medium mounting, as we
1585 * unconditionally replace everthing including the block driver level.
1586 * This means the new medium will be picked up automatically. */
1587 }
1588
1589 if (paLedDevType)
1590 i_setLedType(&paLedDevType[uLUN], enmType);
1591
1592 /* Dump the changed LUN if possible, dump the complete device otherwise */
1593 if ( aMachineState != MachineState_Starting
1594 && aMachineState != MachineState_Restoring)
1595 pVMM->pfnCFGMR3Dump(pLunL0 ? pLunL0 : pCtlInst);
1596 }
1597 catch (ConfigError &x)
1598 {
1599 // InsertConfig threw something:
1600 return x.m_vrc;
1601 }
1602
1603#undef H
1604
1605 return VINF_SUCCESS;
1606}
1607
1608int Console::i_configMedium(PCFGMNODE pLunL0,
1609 bool fPassthrough,
1610 DeviceType_T enmType,
1611 bool fUseHostIOCache,
1612 bool fBuiltinIOCache,
1613 bool fInsertDiskIntegrityDrv,
1614 bool fSetupMerge,
1615 unsigned uMergeSource,
1616 unsigned uMergeTarget,
1617 const char *pcszBwGroup,
1618 bool fDiscard,
1619 bool fNonRotational,
1620 ComPtr<IMedium> ptrMedium,
1621 MachineState_T aMachineState,
1622 HRESULT *phrc)
1623{
1624 // InsertConfig* throws
1625 try
1626 {
1627 HRESULT hrc;
1628 Bstr bstr;
1629 PCFGMNODE pCfg = NULL;
1630
1631#define H() \
1632 AssertMsgReturnStmt(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), if (phrc) *phrc = hrc, Global::vboxStatusCodeFromCOM(hrc))
1633
1634
1635 BOOL fHostDrive = FALSE;
1636 MediumType_T mediumType = MediumType_Normal;
1637 if (ptrMedium.isNotNull())
1638 {
1639 hrc = ptrMedium->COMGETTER(HostDrive)(&fHostDrive); H();
1640 hrc = ptrMedium->COMGETTER(Type)(&mediumType); H();
1641 }
1642
1643 if (fHostDrive)
1644 {
1645 Assert(ptrMedium.isNotNull());
1646 if (enmType == DeviceType_DVD)
1647 {
1648 InsertConfigString(pLunL0, "Driver", "HostDVD");
1649 InsertConfigNode(pLunL0, "Config", &pCfg);
1650
1651 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
1652 InsertConfigString(pCfg, "Path", bstr);
1653
1654 InsertConfigInteger(pCfg, "Passthrough", fPassthrough);
1655 }
1656 else if (enmType == DeviceType_Floppy)
1657 {
1658 InsertConfigString(pLunL0, "Driver", "HostFloppy");
1659 InsertConfigNode(pLunL0, "Config", &pCfg);
1660
1661 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
1662 InsertConfigString(pCfg, "Path", bstr);
1663 }
1664 }
1665 else
1666 {
1667 if (fInsertDiskIntegrityDrv)
1668 {
1669 /*
1670 * The actual configuration is done through CFGM extra data
1671 * for each inserted driver separately.
1672 */
1673 InsertConfigString(pLunL0, "Driver", "DiskIntegrity");
1674 InsertConfigNode(pLunL0, "Config", &pCfg);
1675 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
1676 }
1677
1678 InsertConfigString(pLunL0, "Driver", "VD");
1679 InsertConfigNode(pLunL0, "Config", &pCfg);
1680 switch (enmType)
1681 {
1682 case DeviceType_DVD:
1683 InsertConfigString(pCfg, "Type", "DVD");
1684 InsertConfigInteger(pCfg, "Mountable", 1);
1685 break;
1686 case DeviceType_Floppy:
1687 InsertConfigString(pCfg, "Type", "Floppy 1.44");
1688 InsertConfigInteger(pCfg, "Mountable", 1);
1689 break;
1690 case DeviceType_HardDisk:
1691 default:
1692 InsertConfigString(pCfg, "Type", "HardDisk");
1693 InsertConfigInteger(pCfg, "Mountable", 0);
1694 }
1695
1696 if ( ptrMedium.isNotNull()
1697 && ( enmType == DeviceType_DVD
1698 || enmType == DeviceType_Floppy)
1699 )
1700 {
1701 // if this medium represents an ISO image and this image is inaccessible,
1702 // the ignore it instead of causing a failure; this can happen when we
1703 // restore a VM state and the ISO has disappeared, e.g. because the Guest
1704 // Additions were mounted and the user upgraded VirtualBox. Previously
1705 // we failed on startup, but that's not good because the only way out then
1706 // would be to discard the VM state...
1707 MediumState_T mediumState;
1708 hrc = ptrMedium->RefreshState(&mediumState); H();
1709 if (mediumState == MediumState_Inaccessible)
1710 {
1711 Bstr loc;
1712 hrc = ptrMedium->COMGETTER(Location)(loc.asOutParam()); H();
1713 i_atVMRuntimeErrorCallbackF(0, "DvdOrFloppyImageInaccessible",
1714 N_("The image file '%ls' is inaccessible and is being ignored. "
1715 "Please select a different image file for the virtual %s drive."),
1716 loc.raw(),
1717 enmType == DeviceType_DVD ? "DVD" : "floppy");
1718 ptrMedium.setNull();
1719 }
1720 }
1721
1722 if (ptrMedium.isNotNull())
1723 {
1724 /* Start with length of parent chain, as the list is reversed */
1725 unsigned uImage = 0;
1726 ComPtr<IMedium> ptrTmp = ptrMedium;
1727 while (ptrTmp.isNotNull())
1728 {
1729 uImage++;
1730 ComPtr<IMedium> ptrParent;
1731 hrc = ptrTmp->COMGETTER(Parent)(ptrParent.asOutParam()); H();
1732 ptrTmp = ptrParent;
1733 }
1734 /* Index of last image */
1735 uImage--;
1736
1737# ifdef VBOX_WITH_EXTPACK
1738 if (mptrExtPackManager->i_isExtPackUsable(ORACLE_PUEL_EXTPACK_NAME))
1739 {
1740 /* Configure loading the VDPlugin. */
1741 static const char s_szVDPlugin[] = "VDPluginCrypt";
1742 PCFGMNODE pCfgPlugins = NULL;
1743 PCFGMNODE pCfgPlugin = NULL;
1744 Utf8Str strPlugin;
1745 hrc = mptrExtPackManager->i_getLibraryPathForExtPack(s_szVDPlugin, ORACLE_PUEL_EXTPACK_NAME, &strPlugin);
1746 // Don't fail, this is optional!
1747 if (SUCCEEDED(hrc))
1748 {
1749 InsertConfigNode(pCfg, "Plugins", &pCfgPlugins);
1750 InsertConfigNode(pCfgPlugins, s_szVDPlugin, &pCfgPlugin);
1751 InsertConfigString(pCfgPlugin, "Path", strPlugin);
1752 }
1753 }
1754# endif
1755
1756 hrc = ptrMedium->COMGETTER(Location)(bstr.asOutParam()); H();
1757 InsertConfigString(pCfg, "Path", bstr);
1758
1759 hrc = ptrMedium->COMGETTER(Format)(bstr.asOutParam()); H();
1760 InsertConfigString(pCfg, "Format", bstr);
1761
1762 if (mediumType == MediumType_Readonly)
1763 InsertConfigInteger(pCfg, "ReadOnly", 1);
1764 else if (enmType == DeviceType_Floppy)
1765 InsertConfigInteger(pCfg, "MaybeReadOnly", 1);
1766
1767 /* Start without exclusive write access to the images. */
1768 /** @todo Live Migration: I don't quite like this, we risk screwing up when
1769 * we're resuming the VM if some 3rd dude have any of the VDIs open
1770 * with write sharing denied. However, if the two VMs are sharing a
1771 * image it really is necessary....
1772 *
1773 * So, on the "lock-media" command, the target teleporter should also
1774 * make DrvVD undo TempReadOnly. It gets interesting if we fail after
1775 * that. Grumble. */
1776 if ( enmType == DeviceType_HardDisk
1777 && aMachineState == MachineState_TeleportingIn)
1778 InsertConfigInteger(pCfg, "TempReadOnly", 1);
1779
1780 /* Flag for opening the medium for sharing between VMs. This
1781 * is done at the moment only for the first (and only) medium
1782 * in the chain, as shared media can have no diffs. */
1783 if (mediumType == MediumType_Shareable)
1784 InsertConfigInteger(pCfg, "Shareable", 1);
1785
1786 if (!fUseHostIOCache)
1787 {
1788 InsertConfigInteger(pCfg, "UseNewIo", 1);
1789 /*
1790 * Activate the builtin I/O cache for harddisks only.
1791 * It caches writes only which doesn't make sense for DVD drives
1792 * and just increases the overhead.
1793 */
1794 if ( fBuiltinIOCache
1795 && (enmType == DeviceType_HardDisk))
1796 InsertConfigInteger(pCfg, "BlockCache", 1);
1797 }
1798
1799 if (fSetupMerge)
1800 {
1801 InsertConfigInteger(pCfg, "SetupMerge", 1);
1802 if (uImage == uMergeSource)
1803 InsertConfigInteger(pCfg, "MergeSource", 1);
1804 else if (uImage == uMergeTarget)
1805 InsertConfigInteger(pCfg, "MergeTarget", 1);
1806 }
1807
1808 if (pcszBwGroup)
1809 InsertConfigString(pCfg, "BwGroup", pcszBwGroup);
1810
1811 if (fDiscard)
1812 InsertConfigInteger(pCfg, "Discard", 1);
1813
1814 if (fNonRotational)
1815 InsertConfigInteger(pCfg, "NonRotationalMedium", 1);
1816
1817 /* Pass all custom parameters. */
1818 bool fHostIP = true;
1819 bool fEncrypted = false;
1820 hrc = i_configMediumProperties(pCfg, ptrMedium, &fHostIP, &fEncrypted); H();
1821
1822 /* Create an inverted list of parents. */
1823 uImage--;
1824 ComPtr<IMedium> ptrParentMedium = ptrMedium;
1825 for (PCFGMNODE pParent = pCfg;; uImage--)
1826 {
1827 ComPtr<IMedium> ptrCurMedium;
1828 hrc = ptrParentMedium->COMGETTER(Parent)(ptrCurMedium.asOutParam()); H();
1829 if (ptrCurMedium.isNull())
1830 break;
1831
1832 PCFGMNODE pCur;
1833 InsertConfigNode(pParent, "Parent", &pCur);
1834 hrc = ptrCurMedium->COMGETTER(Location)(bstr.asOutParam()); H();
1835 InsertConfigString(pCur, "Path", bstr);
1836
1837 hrc = ptrCurMedium->COMGETTER(Format)(bstr.asOutParam()); H();
1838 InsertConfigString(pCur, "Format", bstr);
1839
1840 if (fSetupMerge)
1841 {
1842 if (uImage == uMergeSource)
1843 InsertConfigInteger(pCur, "MergeSource", 1);
1844 else if (uImage == uMergeTarget)
1845 InsertConfigInteger(pCur, "MergeTarget", 1);
1846 }
1847
1848 /* Configure medium properties. */
1849 hrc = i_configMediumProperties(pCur, ptrCurMedium, &fHostIP, &fEncrypted); H();
1850
1851 /* next */
1852 pParent = pCur;
1853 ptrParentMedium = ptrCurMedium;
1854 }
1855
1856 /* Custom code: put marker to not use host IP stack to driver
1857 * configuration node. Simplifies life of DrvVD a bit. */
1858 if (!fHostIP)
1859 InsertConfigInteger(pCfg, "HostIPStack", 0);
1860
1861 if (fEncrypted)
1862 m_cDisksEncrypted++;
1863 }
1864 else
1865 {
1866 /* Set empty drive flag for DVD or floppy without media. */
1867 if ( enmType == DeviceType_DVD
1868 || enmType == DeviceType_Floppy)
1869 InsertConfigInteger(pCfg, "EmptyDrive", 1);
1870 }
1871 }
1872#undef H
1873 }
1874 catch (ConfigError &x)
1875 {
1876 // InsertConfig threw something:
1877 return x.m_vrc;
1878 }
1879
1880 return VINF_SUCCESS;
1881}
1882
1883/**
1884 * Adds the medium properties to the CFGM tree.
1885 *
1886 * @returns VBox status code.
1887 * @param pCur The current CFGM node.
1888 * @param pMedium The medium object to configure.
1889 * @param pfHostIP Where to return the value of the \"HostIPStack\" property if found.
1890 * @param pfEncrypted Where to return whether the medium is encrypted.
1891 */
1892int Console::i_configMediumProperties(PCFGMNODE pCur, IMedium *pMedium, bool *pfHostIP, bool *pfEncrypted)
1893{
1894 /* Pass all custom parameters. */
1895 SafeArray<BSTR> aNames;
1896 SafeArray<BSTR> aValues;
1897 HRESULT hrc = pMedium->GetProperties(NULL, ComSafeArrayAsOutParam(aNames), ComSafeArrayAsOutParam(aValues));
1898 if ( SUCCEEDED(hrc)
1899 && aNames.size() != 0)
1900 {
1901 PCFGMNODE pVDC;
1902 InsertConfigNode(pCur, "VDConfig", &pVDC);
1903 for (size_t ii = 0; ii < aNames.size(); ++ii)
1904 {
1905 if (aValues[ii] && *aValues[ii])
1906 {
1907 Utf8Str const strName = aNames[ii];
1908 Utf8Str const strValue = aValues[ii];
1909 size_t offSlash = strName.find("/", 0);
1910 if ( offSlash != strName.npos
1911 && !strName.startsWith("Special/"))
1912 {
1913 com::Utf8Str strFilter;
1914 hrc = strFilter.assignEx(strName, 0, offSlash);
1915 if (FAILED(hrc))
1916 break;
1917
1918 com::Utf8Str strKey;
1919 hrc = strKey.assignEx(strName, offSlash + 1, strName.length() - offSlash - 1); /* Skip slash */
1920 if (FAILED(hrc))
1921 break;
1922
1923 PCFGMNODE pCfgFilterConfig = mpVMM->pfnCFGMR3GetChild(pVDC, strFilter.c_str());
1924 if (!pCfgFilterConfig)
1925 InsertConfigNode(pVDC, strFilter.c_str(), &pCfgFilterConfig);
1926
1927 InsertConfigString(pCfgFilterConfig, strKey.c_str(), strValue);
1928 }
1929 else
1930 {
1931 InsertConfigString(pVDC, strName.c_str(), strValue);
1932 if ( strName.compare("HostIPStack") == 0
1933 && strValue.compare("0") == 0)
1934 *pfHostIP = false;
1935 }
1936
1937 if ( strName.compare("CRYPT/KeyId") == 0
1938 && pfEncrypted)
1939 *pfEncrypted = true;
1940 }
1941 }
1942 }
1943
1944 return hrc;
1945}
1946
1947
1948/**
1949 * Configure proxy parameters the Network configuration tree.
1950 *
1951 * Parameters may differ depending on the IP address being accessed.
1952 *
1953 * @returns VBox status code.
1954 *
1955 * @param virtualBox The VirtualBox object.
1956 * @param pCfg Configuration node for the driver.
1957 * @param pcszPrefix The prefix for CFGM parameters: "Primary" or "Secondary".
1958 * @param strIpAddr The public IP address to be accessed via a proxy.
1959 *
1960 * @thread EMT
1961 */
1962int Console::i_configProxy(ComPtr<IVirtualBox> virtualBox, PCFGMNODE pCfg, const char *pcszPrefix, const com::Utf8Str &strIpAddr)
1963{
1964/** @todo r=bird: This code doesn't handle cleanup correctly and may leak
1965 * when hitting errors or throwing exceptions (bad_alloc). */
1966 RTHTTPPROXYINFO ProxyInfo;
1967 ComPtr<ISystemProperties> systemProperties;
1968 ProxyMode_T enmProxyMode;
1969 HRESULT hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1970 if (FAILED(hrc))
1971 {
1972 LogRel(("CLOUD-NET: Failed to obtain system properties. hrc=%x\n", hrc));
1973 return false;
1974 }
1975 hrc = systemProperties->COMGETTER(ProxyMode)(&enmProxyMode);
1976 if (FAILED(hrc))
1977 {
1978 LogRel(("CLOUD-NET: Failed to obtain default machine folder. hrc=%x\n", hrc));
1979 return VERR_INTERNAL_ERROR;
1980 }
1981
1982 RTHTTP hHttp;
1983 int vrc = RTHttpCreate(&hHttp);
1984 if (RT_FAILURE(vrc))
1985 {
1986 LogRel(("CLOUD-NET: Failed to create HTTP context (vrc=%Rrc)\n", vrc));
1987 return vrc;
1988 }
1989
1990 char *pszProxyType = NULL;
1991
1992 if (enmProxyMode == ProxyMode_Manual)
1993 {
1994 /*
1995 * Unfortunately we cannot simply call RTHttpSetProxyByUrl because it never
1996 * exposes proxy settings. Calling RTHttpQueryProxyInfoForUrl afterward
1997 * won't help either as it uses system-wide proxy settings instead of
1998 * parameters we would have set with RTHttpSetProxyByUrl. Hence we parse
1999 * proxy URL ourselves here.
2000 */
2001 Bstr proxyUrl;
2002 hrc = systemProperties->COMGETTER(ProxyURL)(proxyUrl.asOutParam());
2003 if (FAILED(hrc))
2004 {
2005 LogRel(("CLOUD-NET: Failed to obtain proxy URL. hrc=%x\n", hrc));
2006 return false;
2007 }
2008 Utf8Str strProxyUrl = proxyUrl;
2009 if (!strProxyUrl.contains("://"))
2010 strProxyUrl = "http://" + strProxyUrl;
2011 const char *pcszProxyUrl = strProxyUrl.c_str();
2012 RTURIPARSED Parsed;
2013 vrc = RTUriParse(pcszProxyUrl, &Parsed);
2014 if (RT_FAILURE(vrc))
2015 {
2016 LogRel(("CLOUD-NET: Failed to parse proxy URL: %ls (vrc=%Rrc)\n", proxyUrl.raw(), vrc));
2017 return false;
2018 }
2019
2020 pszProxyType = RTUriParsedScheme(pcszProxyUrl, &Parsed);
2021 if (!pszProxyType)
2022 {
2023 LogRel(("CLOUD-NET: Failed to get proxy scheme from proxy URL: %s\n", pcszProxyUrl));
2024 return false;
2025 }
2026 RTStrToUpper(pszProxyType);
2027
2028 ProxyInfo.pszProxyHost = RTUriParsedAuthorityHost(pcszProxyUrl, &Parsed);
2029 if (!ProxyInfo.pszProxyHost)
2030 {
2031 LogRel(("CLOUD-NET: Failed to get proxy host name from proxy URL: %s\n", pcszProxyUrl));
2032 return false;
2033 }
2034 ProxyInfo.uProxyPort = RTUriParsedAuthorityPort(pcszProxyUrl, &Parsed);
2035 if (ProxyInfo.uProxyPort == UINT32_MAX)
2036 {
2037 LogRel(("CLOUD-NET: Failed to get proxy port from proxy URL: %s\n", pcszProxyUrl));
2038 return false;
2039 }
2040 ProxyInfo.pszProxyUsername = RTUriParsedAuthorityUsername(pcszProxyUrl, &Parsed);
2041 ProxyInfo.pszProxyPassword = RTUriParsedAuthorityPassword(pcszProxyUrl, &Parsed);
2042 }
2043 else if (enmProxyMode == ProxyMode_System)
2044 {
2045 vrc = RTHttpUseSystemProxySettings(hHttp);
2046 if (RT_FAILURE(vrc))
2047 {
2048 LogRel(("%s: RTHttpUseSystemProxySettings() failed: %Rrc", __FUNCTION__, vrc));
2049 RTHttpDestroy(hHttp);
2050 return vrc;
2051 }
2052 vrc = RTHttpQueryProxyInfoForUrl(hHttp, ("http://" + strIpAddr).c_str(), &ProxyInfo);
2053 RTHttpDestroy(hHttp);
2054 if (RT_FAILURE(vrc))
2055 {
2056 LogRel(("CLOUD-NET: Failed to get proxy for %s (vrc=%Rrc)\n", strIpAddr.c_str(), vrc));
2057 return vrc;
2058 }
2059
2060 switch (ProxyInfo.enmProxyType)
2061 {
2062 case RTHTTPPROXYTYPE_NOPROXY:
2063 /* Nothing to do */
2064 return VINF_SUCCESS;
2065 case RTHTTPPROXYTYPE_HTTP:
2066 pszProxyType = RTStrDup("HTTP");
2067 break;
2068 case RTHTTPPROXYTYPE_HTTPS:
2069 case RTHTTPPROXYTYPE_SOCKS4:
2070 case RTHTTPPROXYTYPE_SOCKS5:
2071 /* break; -- Fall through until support is implemented */
2072 case RTHTTPPROXYTYPE_UNKNOWN:
2073 case RTHTTPPROXYTYPE_INVALID:
2074 case RTHTTPPROXYTYPE_END:
2075 case RTHTTPPROXYTYPE_32BIT_HACK:
2076 LogRel(("CLOUD-NET: Unsupported proxy type %u\n", ProxyInfo.enmProxyType));
2077 RTHttpFreeProxyInfo(&ProxyInfo);
2078 return VERR_INVALID_PARAMETER;
2079 }
2080 }
2081 else
2082 {
2083 Assert(enmProxyMode == ProxyMode_NoProxy);
2084 return VINF_SUCCESS;
2085 }
2086
2087 /* Resolve proxy host name to IP address if necessary */
2088 RTNETADDR addr;
2089 RTSocketParseInetAddress(ProxyInfo.pszProxyHost, ProxyInfo.uProxyPort, &addr);
2090 if (addr.enmType != RTNETADDRTYPE_IPV4)
2091 {
2092 LogRel(("CLOUD-NET: Unsupported address type %u\n", addr.enmType));
2093 RTHttpFreeProxyInfo(&ProxyInfo);
2094 return VERR_INVALID_PARAMETER;
2095 }
2096
2097 InsertConfigString( pCfg, Utf8StrFmt("%sProxyType", pcszPrefix).c_str(), pszProxyType);
2098 InsertConfigInteger( pCfg, Utf8StrFmt("%sProxyPort", pcszPrefix).c_str(), ProxyInfo.uProxyPort);
2099 if (ProxyInfo.pszProxyHost)
2100 InsertConfigStringF( pCfg, Utf8StrFmt("%sProxyHost", pcszPrefix).c_str(), "%RTnaipv4", addr.uAddr.IPv4);
2101 if (ProxyInfo.pszProxyUsername)
2102 InsertConfigString( pCfg, Utf8StrFmt("%sProxyUser", pcszPrefix).c_str(), ProxyInfo.pszProxyUsername);
2103 if (ProxyInfo.pszProxyPassword)
2104 InsertConfigPassword(pCfg, Utf8StrFmt("%sProxyPassword", pcszPrefix).c_str(), ProxyInfo.pszProxyPassword);
2105
2106 RTHttpFreeProxyInfo(&ProxyInfo);
2107 RTStrFree(pszProxyType);
2108 return vrc;
2109}
2110
2111
2112/**
2113 * Construct the Network configuration tree
2114 *
2115 * @returns VBox status code.
2116 *
2117 * @param pszDevice The PDM device name.
2118 * @param uInstance The PDM device instance.
2119 * @param uLun The PDM LUN number of the drive.
2120 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
2121 * @param pCfg Configuration node for the device
2122 * @param pLunL0 To store the pointer to the LUN#0.
2123 * @param pInst The instance CFGM node
2124 * @param fAttachDetach To determine if the network attachment should
2125 * be attached/detached after/before
2126 * configuration.
2127 * @param fIgnoreConnectFailure
2128 * True if connection failures should be ignored
2129 * (makes only sense for bridged/host-only networks).
2130 * @param pUVM The usermode VM handle.
2131 * @param pVMM The VMM vtable.
2132 *
2133 * @note Locks this object for writing.
2134 * @thread EMT
2135 */
2136int Console::i_configNetwork(const char *pszDevice,
2137 unsigned uInstance,
2138 unsigned uLun,
2139 INetworkAdapter *aNetworkAdapter,
2140 PCFGMNODE pCfg,
2141 PCFGMNODE pLunL0,
2142 PCFGMNODE pInst,
2143 bool fAttachDetach,
2144 bool fIgnoreConnectFailure,
2145 PUVM pUVM,
2146 PCVMMR3VTABLE pVMM)
2147{
2148 RT_NOREF(fIgnoreConnectFailure);
2149 AutoCaller autoCaller(this);
2150 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
2151
2152 // InsertConfig* throws
2153 try
2154 {
2155 int vrc = VINF_SUCCESS;
2156 HRESULT hrc;
2157 Bstr bstr;
2158
2159#ifdef VBOX_WITH_CLOUD_NET
2160 /* We'll need device's pCfg for cloud attachments */
2161 PCFGMNODE pDevCfg = pCfg;
2162#endif /* VBOX_WITH_CLOUD_NET */
2163
2164#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
2165
2166 /*
2167 * Locking the object before doing VMR3* calls is quite safe here, since
2168 * we're on EMT. Write lock is necessary because we indirectly modify the
2169 * meAttachmentType member.
2170 */
2171 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2172
2173 ComPtr<IMachine> pMachine = i_machine();
2174
2175 ComPtr<IVirtualBox> virtualBox;
2176 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
2177
2178 ComPtr<IHost> host;
2179 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
2180
2181 BOOL fSniffer;
2182 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
2183
2184 NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
2185 hrc = aNetworkAdapter->COMGETTER(PromiscModePolicy)(&enmPromiscModePolicy); H();
2186 const char *pszPromiscuousGuestPolicy;
2187 switch (enmPromiscModePolicy)
2188 {
2189 case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
2190 case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-network"; break;
2191 case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
2192 default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
2193 }
2194
2195 if (fAttachDetach)
2196 {
2197 vrc = pVMM->pfnPDMR3DeviceDetach(pUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/);
2198 if (vrc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
2199 vrc = VINF_SUCCESS;
2200 AssertLogRelRCReturn(vrc, vrc);
2201
2202 /* Nuke anything which might have been left behind. */
2203 pVMM->pfnCFGMR3RemoveNode(pVMM->pfnCFGMR3GetChildF(pInst, "LUN#%u", uLun));
2204 }
2205
2206 Bstr networkName, trunkName, trunkType;
2207 NetworkAttachmentType_T eAttachmentType;
2208 hrc = aNetworkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
2209
2210#ifdef VBOX_WITH_NETSHAPER
2211 ComObjPtr<IBandwidthGroup> pBwGroup;
2212 Bstr bstrBwGroup;
2213 hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam()); H();
2214
2215 if (!pBwGroup.isNull())
2216 {
2217 hrc = pBwGroup->COMGETTER(Name)(bstrBwGroup.asOutParam()); H();
2218 }
2219#endif /* VBOX_WITH_NETSHAPER */
2220
2221 AssertMsg(uLun == 0, ("Network attachments with LUN > 0 are not supported yet\n"));
2222 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", uLun);
2223
2224 /*
2225 * Do not insert neither a shaper nor a sniffer if we are not attached to anything.
2226 * This way we can easily detect if we are attached to anything at the device level.
2227 */
2228#ifdef VBOX_WITH_NETSHAPER
2229 if (bstrBwGroup.isNotEmpty() && eAttachmentType != NetworkAttachmentType_Null)
2230 {
2231 InsertConfigString(pLunL0, "Driver", "NetShaper");
2232 InsertConfigNode(pLunL0, "Config", &pCfg);
2233 InsertConfigString(pCfg, "BwGroup", bstrBwGroup);
2234 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
2235 }
2236#endif /* VBOX_WITH_NETSHAPER */
2237
2238 if (fSniffer && eAttachmentType != NetworkAttachmentType_Null)
2239 {
2240 InsertConfigString(pLunL0, "Driver", "NetSniffer");
2241 InsertConfigNode(pLunL0, "Config", &pCfg);
2242 hrc = aNetworkAdapter->COMGETTER(TraceFile)(bstr.asOutParam()); H();
2243 if (!bstr.isEmpty()) /* check convention for indicating default file. */
2244 InsertConfigString(pCfg, "File", bstr);
2245 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL0);
2246 }
2247
2248 switch (eAttachmentType)
2249 {
2250 case NetworkAttachmentType_Null:
2251 break;
2252
2253 case NetworkAttachmentType_NAT:
2254 {
2255 ComPtr<INATEngine> natEngine;
2256 hrc = aNetworkAdapter->COMGETTER(NATEngine)(natEngine.asOutParam()); H();
2257 InsertConfigString(pLunL0, "Driver", "NAT");
2258 InsertConfigNode(pLunL0, "Config", &pCfg);
2259
2260 /* Configure TFTP prefix and boot filename. */
2261 hrc = virtualBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
2262 if (!bstr.isEmpty())
2263 InsertConfigStringF(pCfg, "TFTPPrefix", "%ls%c%s", bstr.raw(), RTPATH_DELIMITER, "TFTP");
2264 hrc = pMachine->COMGETTER(Name)(bstr.asOutParam()); H();
2265 InsertConfigStringF(pCfg, "BootFile", "%ls.pxe", bstr.raw());
2266
2267 hrc = natEngine->COMGETTER(Network)(bstr.asOutParam()); H();
2268 if (!bstr.isEmpty())
2269 InsertConfigString(pCfg, "Network", bstr);
2270 else
2271 {
2272 ULONG uSlot;
2273 hrc = aNetworkAdapter->COMGETTER(Slot)(&uSlot); H();
2274 InsertConfigStringF(pCfg, "Network", "10.0.%d.0/24", uSlot+2);
2275 }
2276 hrc = natEngine->COMGETTER(HostIP)(bstr.asOutParam()); H();
2277 if (!bstr.isEmpty())
2278 InsertConfigString(pCfg, "BindIP", bstr);
2279 ULONG mtu = 0;
2280 ULONG sockSnd = 0;
2281 ULONG sockRcv = 0;
2282 ULONG tcpSnd = 0;
2283 ULONG tcpRcv = 0;
2284 hrc = natEngine->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv); H();
2285 if (mtu)
2286 InsertConfigInteger(pCfg, "SlirpMTU", mtu);
2287 if (sockRcv)
2288 InsertConfigInteger(pCfg, "SockRcv", sockRcv);
2289 if (sockSnd)
2290 InsertConfigInteger(pCfg, "SockSnd", sockSnd);
2291 if (tcpRcv)
2292 InsertConfigInteger(pCfg, "TcpRcv", tcpRcv);
2293 if (tcpSnd)
2294 InsertConfigInteger(pCfg, "TcpSnd", tcpSnd);
2295 hrc = natEngine->COMGETTER(TFTPPrefix)(bstr.asOutParam()); H();
2296 if (!bstr.isEmpty())
2297 {
2298 RemoveConfigValue(pCfg, "TFTPPrefix");
2299 InsertConfigString(pCfg, "TFTPPrefix", bstr);
2300 }
2301 hrc = natEngine->COMGETTER(TFTPBootFile)(bstr.asOutParam()); H();
2302 if (!bstr.isEmpty())
2303 {
2304 RemoveConfigValue(pCfg, "BootFile");
2305 InsertConfigString(pCfg, "BootFile", bstr);
2306 }
2307 hrc = natEngine->COMGETTER(TFTPNextServer)(bstr.asOutParam()); H();
2308 if (!bstr.isEmpty())
2309 InsertConfigString(pCfg, "NextServer", bstr);
2310 BOOL fDNSFlag;
2311 hrc = natEngine->COMGETTER(DNSPassDomain)(&fDNSFlag); H();
2312 InsertConfigInteger(pCfg, "PassDomain", fDNSFlag);
2313 hrc = natEngine->COMGETTER(DNSProxy)(&fDNSFlag); H();
2314 InsertConfigInteger(pCfg, "DNSProxy", fDNSFlag);
2315 hrc = natEngine->COMGETTER(DNSUseHostResolver)(&fDNSFlag); H();
2316 InsertConfigInteger(pCfg, "UseHostResolver", fDNSFlag);
2317
2318 ULONG aliasMode;
2319 hrc = natEngine->COMGETTER(AliasMode)(&aliasMode); H();
2320 InsertConfigInteger(pCfg, "AliasMode", aliasMode);
2321
2322 BOOL fLocalhostReachable;
2323 hrc = natEngine->COMGETTER(LocalhostReachable)(&fLocalhostReachable); H();
2324 InsertConfigInteger(pCfg, "LocalhostReachable", fLocalhostReachable);
2325
2326 /* port-forwarding */
2327 SafeArray<BSTR> pfs;
2328 hrc = natEngine->COMGETTER(Redirects)(ComSafeArrayAsOutParam(pfs)); H();
2329
2330 PCFGMNODE pPFTree = NULL;
2331 if (pfs.size() > 0)
2332 InsertConfigNode(pCfg, "PortForwarding", &pPFTree);
2333
2334 for (unsigned int i = 0; i < pfs.size(); ++i)
2335 {
2336 PCFGMNODE pPF = NULL; /* /Devices/Dev/.../Config/PortForwarding/$n/ */
2337
2338 uint16_t port = 0;
2339 Utf8Str utf = pfs[i];
2340 Utf8Str strName;
2341 Utf8Str strProto;
2342 Utf8Str strHostPort;
2343 Utf8Str strHostIP;
2344 Utf8Str strGuestPort;
2345 Utf8Str strGuestIP;
2346 size_t pos, ppos;
2347 pos = ppos = 0;
2348#define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
2349 { \
2350 pos = str.find(",", ppos); \
2351 if (pos == Utf8Str::npos) \
2352 { \
2353 Log(( #res " extracting from %s is failed\n", str.c_str())); \
2354 continue; \
2355 } \
2356 res = str.substr(ppos, pos - ppos); \
2357 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
2358 ppos = pos + 1; \
2359 } /* no do { ... } while because of 'continue' */
2360 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
2361 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
2362 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
2363 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
2364 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
2365 strGuestPort = utf.substr(ppos, utf.length() - ppos);
2366#undef ITERATE_TO_NEXT_TERM
2367
2368 uint32_t proto = strProto.toUInt32();
2369 bool fValid = true;
2370 switch (proto)
2371 {
2372 case NATProtocol_UDP:
2373 strProto = "UDP";
2374 break;
2375 case NATProtocol_TCP:
2376 strProto = "TCP";
2377 break;
2378 default:
2379 fValid = false;
2380 }
2381 /* continue with next rule if no valid proto was passed */
2382 if (!fValid)
2383 continue;
2384
2385 InsertConfigNodeF(pPFTree, &pPF, "%u", i);
2386
2387 if (!strName.isEmpty())
2388 InsertConfigString(pPF, "Name", strName);
2389
2390 InsertConfigString(pPF, "Protocol", strProto);
2391
2392 if (!strHostIP.isEmpty())
2393 InsertConfigString(pPF, "BindIP", strHostIP);
2394
2395 if (!strGuestIP.isEmpty())
2396 InsertConfigString(pPF, "GuestIP", strGuestIP);
2397
2398 port = RTStrToUInt16(strHostPort.c_str());
2399 if (port)
2400 InsertConfigInteger(pPF, "HostPort", port);
2401
2402 port = RTStrToUInt16(strGuestPort.c_str());
2403 if (port)
2404 InsertConfigInteger(pPF, "GuestPort", port);
2405 }
2406 break;
2407 }
2408
2409 case NetworkAttachmentType_Bridged:
2410 {
2411#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
2412 hrc = i_attachToTapInterface(aNetworkAdapter);
2413 if (FAILED(hrc))
2414 {
2415 switch (hrc)
2416 {
2417 case E_ACCESSDENIED:
2418 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
2419 "Failed to open '/dev/net/tun' for read/write access. Please check the "
2420 "permissions of that node. Either run 'chmod 0666 /dev/net/tun' or "
2421 "change the group of that node and make yourself a member of that group. "
2422 "Make sure that these changes are permanent, especially if you are "
2423 "using udev"));
2424 default:
2425 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
2426 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
2427 N_("Failed to initialize Host Interface Networking"));
2428 }
2429 }
2430
2431 Assert((intptr_t)maTapFD[uInstance] >= 0);
2432 if ((intptr_t)maTapFD[uInstance] >= 0)
2433 {
2434 InsertConfigString(pLunL0, "Driver", "HostInterface");
2435 InsertConfigNode(pLunL0, "Config", &pCfg);
2436 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
2437 }
2438
2439#elif defined(VBOX_WITH_NETFLT)
2440 /*
2441 * This is the new VBoxNetFlt+IntNet stuff.
2442 */
2443 Bstr BridgedIfName;
2444 hrc = aNetworkAdapter->COMGETTER(BridgedInterface)(BridgedIfName.asOutParam());
2445 if (FAILED(hrc))
2446 {
2447 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(BridgedInterface) failed, hrc (0x%x)\n", hrc));
2448 H();
2449 }
2450
2451 Utf8Str BridgedIfNameUtf8(BridgedIfName);
2452 const char *pszBridgedIfName = BridgedIfNameUtf8.c_str();
2453
2454 ComPtr<IHostNetworkInterface> hostInterface;
2455 hrc = host->FindHostNetworkInterfaceByName(BridgedIfName.raw(),
2456 hostInterface.asOutParam());
2457 if (!SUCCEEDED(hrc))
2458 {
2459 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: FindByName failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
2460 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
2461 N_("Nonexistent host networking interface, name '%ls'"),
2462 BridgedIfName.raw());
2463 }
2464
2465# if defined(RT_OS_DARWIN)
2466 /* The name is in the format 'ifX: long name', chop it off at the colon. */
2467 char szTrunk[INTNET_MAX_TRUNK_NAME];
2468 RTStrCopy(szTrunk, sizeof(szTrunk), pszBridgedIfName);
2469 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
2470// Quick fix for @bugref{5633}
2471// if (!pszColon)
2472// {
2473// /*
2474// * Dynamic changing of attachment causes an attempt to configure
2475// * network with invalid host adapter (as it is must be changed before
2476// * the attachment), calling Detach here will cause a deadlock.
2477// * See @bugref{4750}.
2478// * hrc = aNetworkAdapter->Detach(); H();
2479// */
2480// return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS,
2481// N_("Malformed host interface networking name '%ls'"),
2482// BridgedIfName.raw());
2483// }
2484 if (pszColon)
2485 *pszColon = '\0';
2486 const char *pszTrunk = szTrunk;
2487
2488# elif defined(RT_OS_SOLARIS)
2489 /* The name is in the format 'ifX[:1] - long name, chop it off at space. */
2490 char szTrunk[256];
2491 strlcpy(szTrunk, pszBridgedIfName, sizeof(szTrunk));
2492 char *pszSpace = (char *)memchr(szTrunk, ' ', sizeof(szTrunk));
2493
2494 /*
2495 * Currently don't bother about malformed names here for the sake of people using
2496 * VBoxManage and setting only the NIC name from there. If there is a space we
2497 * chop it off and proceed, otherwise just use whatever we've got.
2498 */
2499 if (pszSpace)
2500 *pszSpace = '\0';
2501
2502 /* Chop it off at the colon (zone naming eg: e1000g:1 we need only the e1000g) */
2503 char *pszColon = (char *)memchr(szTrunk, ':', sizeof(szTrunk));
2504 if (pszColon)
2505 *pszColon = '\0';
2506
2507 const char *pszTrunk = szTrunk;
2508
2509# elif defined(RT_OS_WINDOWS)
2510 HostNetworkInterfaceType_T eIfType;
2511 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
2512 if (FAILED(hrc))
2513 {
2514 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
2515 H();
2516 }
2517
2518 if (eIfType != HostNetworkInterfaceType_Bridged)
2519 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
2520 N_("Interface ('%ls') is not a Bridged Adapter interface"),
2521 BridgedIfName.raw());
2522
2523 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
2524 if (FAILED(hrc))
2525 {
2526 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
2527 H();
2528 }
2529 Guid hostIFGuid(bstr);
2530
2531 INetCfg *pNc;
2532 ComPtr<INetCfgComponent> pAdaptorComponent;
2533 LPWSTR pszApp;
2534
2535 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
2536 Assert(hrc == S_OK);
2537 if (hrc != S_OK)
2538 {
2539 LogRel(("NetworkAttachmentType_Bridged: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
2540 H();
2541 }
2542
2543 /* get the adapter's INetCfgComponent*/
2544 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
2545 pAdaptorComponent.asOutParam());
2546 if (hrc != S_OK)
2547 {
2548 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
2549 LogRel(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)\n", hrc));
2550 H();
2551 }
2552# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
2553 char szTrunkName[INTNET_MAX_TRUNK_NAME];
2554 char *pszTrunkName = szTrunkName;
2555 wchar_t * pswzBindName;
2556 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
2557 Assert(hrc == S_OK);
2558 if (hrc == S_OK)
2559 {
2560 int cwBindName = (int)wcslen(pswzBindName) + 1;
2561 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
2562 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
2563 {
2564 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
2565 pszTrunkName += cbFullBindNamePrefix-1;
2566 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
2567 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
2568 {
2569 DWORD err = GetLastError();
2570 hrc = HRESULT_FROM_WIN32(err);
2571 AssertMsgFailed(("hrc=%Rhrc %#x\n", hrc, hrc));
2572 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
2573 hrc, hrc, err));
2574 }
2575 }
2576 else
2577 {
2578 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: insufficient szTrunkName buffer space\n"));
2579 /** @todo set appropriate error code */
2580 hrc = E_FAIL;
2581 }
2582
2583 if (hrc != S_OK)
2584 {
2585 AssertFailed();
2586 CoTaskMemFree(pswzBindName);
2587 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
2588 H();
2589 }
2590
2591 /* we're not freeing the bind name since we'll use it later for detecting wireless*/
2592 }
2593 else
2594 {
2595 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
2596 AssertLogRelMsgFailed(("NetworkAttachmentType_Bridged: VBoxNetCfgWinGetComponentByGuid failed, hrc (0x%x)",
2597 hrc));
2598 H();
2599 }
2600
2601 const char *pszTrunk = szTrunkName;
2602 /* we're not releasing the INetCfg stuff here since we use it later to figure out whether it is wireless */
2603
2604# elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
2605# if defined(RT_OS_FREEBSD)
2606 /*
2607 * If we bridge to a tap interface open it the `old' direct way.
2608 * This works and performs better than bridging a physical
2609 * interface via the current FreeBSD vboxnetflt implementation.
2610 */
2611 if (!strncmp(pszBridgedIfName, RT_STR_TUPLE("tap"))) {
2612 hrc = i_attachToTapInterface(aNetworkAdapter);
2613 if (FAILED(hrc))
2614 {
2615 switch (hrc)
2616 {
2617 case E_ACCESSDENIED:
2618 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
2619 "Failed to open '/dev/%s' for read/write access. Please check the "
2620 "permissions of that node, and that the net.link.tap.user_open "
2621 "sysctl is set. Either run 'chmod 0666 /dev/%s' or change the "
2622 "group of that node to vboxusers and make yourself a member of "
2623 "that group. Make sure that these changes are permanent."),
2624 pszBridgedIfName, pszBridgedIfName);
2625 default:
2626 AssertMsgFailed(("Could not attach to tap interface! Bad!\n"));
2627 return pVMM->pfnVMR3SetError(pUVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
2628 N_("Failed to initialize Host Interface Networking"));
2629 }
2630 }
2631
2632 Assert((intptr_t)maTapFD[uInstance] >= 0);
2633 if ((intptr_t)maTapFD[uInstance] >= 0)
2634 {
2635 InsertConfigString(pLunL0, "Driver", "HostInterface");
2636 InsertConfigNode(pLunL0, "Config", &pCfg);
2637 InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
2638 }
2639 break;
2640 }
2641# endif
2642 /** @todo Check for malformed names. */
2643 const char *pszTrunk = pszBridgedIfName;
2644
2645 /* Issue a warning if the interface is down */
2646 {
2647 int iSock = socket(AF_INET, SOCK_DGRAM, 0);
2648 if (iSock >= 0)
2649 {
2650 struct ifreq Req;
2651 RT_ZERO(Req);
2652 RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszBridgedIfName);
2653 if (ioctl(iSock, SIOCGIFFLAGS, &Req) >= 0)
2654 if ((Req.ifr_flags & IFF_UP) == 0)
2655 i_atVMRuntimeErrorCallbackF(0, "BridgedInterfaceDown",
2656 N_("Bridged interface %s is down. Guest will not be able to use this interface"),
2657 pszBridgedIfName);
2658
2659 close(iSock);
2660 }
2661 }
2662# ifdef VBOXNETFLT_LINUX_NAMESPACE_SUPPORT
2663 RTUUID IfaceUuid;
2664 Bstr IfId;
2665 hrc = hostInterface->COMGETTER(Id)(IfId.asOutParam()); H();
2666 vrc = RTUuidFromUtf16(&IfaceUuid, IfId.raw());
2667 AssertRCReturn(vrc, vrc);
2668 char szTrunkNameWithNamespace[INTNET_MAX_TRUNK_NAME];
2669 RTStrPrintf(szTrunkNameWithNamespace, sizeof(szTrunkNameWithNamespace), "%u/%s",
2670 IfaceUuid.au32[0], pszTrunk);
2671 pszTrunk = szTrunkNameWithNamespace;
2672# endif
2673
2674# else
2675# error "PORTME (VBOX_WITH_NETFLT)"
2676# endif
2677
2678# if defined(RT_OS_DARWIN) && defined(VBOX_WITH_VMNET)
2679 InsertConfigString(pLunL0, "Driver", "VMNet");
2680 InsertConfigNode(pLunL0, "Config", &pCfg);
2681 InsertConfigString(pCfg, "Trunk", pszTrunk);
2682 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
2683# else
2684 InsertConfigString(pLunL0, "Driver", "IntNet");
2685 InsertConfigNode(pLunL0, "Config", &pCfg);
2686 InsertConfigString(pCfg, "Trunk", pszTrunk);
2687 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
2688 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
2689 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
2690 char szNetwork[INTNET_MAX_NETWORK_NAME];
2691
2692# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
2693 /*
2694 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
2695 * interface name + optional description. We must not pass any description to the VM as it can differ
2696 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
2697 */
2698 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
2699# else
2700 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
2701# endif
2702 InsertConfigString(pCfg, "Network", szNetwork);
2703 networkName = Bstr(szNetwork);
2704 trunkName = Bstr(pszTrunk);
2705 trunkType = Bstr(TRUNKTYPE_NETFLT);
2706
2707 BOOL fSharedMacOnWire = false;
2708 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
2709 if (FAILED(hrc))
2710 {
2711 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
2712 H();
2713 }
2714 else if (fSharedMacOnWire)
2715 {
2716 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
2717 Log(("Set SharedMacOnWire\n"));
2718 }
2719
2720# if defined(RT_OS_SOLARIS)
2721# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
2722 /* Zone access restriction, don't allow snooping the global zone. */
2723 zoneid_t ZoneId = getzoneid();
2724 if (ZoneId != GLOBAL_ZONEID)
2725 {
2726 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
2727 }
2728# endif
2729# endif
2730# endif
2731
2732#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
2733 /* NOTHING TO DO HERE */
2734#elif defined(RT_OS_LINUX)
2735/// @todo aleksey: is there anything to be done here?
2736#elif defined(RT_OS_FREEBSD)
2737/** @todo FreeBSD: Check out this later (HIF networking). */
2738#else
2739# error "Port me"
2740#endif
2741 break;
2742 }
2743
2744 case NetworkAttachmentType_Internal:
2745 {
2746 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
2747 if (!bstr.isEmpty())
2748 {
2749 InsertConfigString(pLunL0, "Driver", "IntNet");
2750 InsertConfigNode(pLunL0, "Config", &pCfg);
2751 InsertConfigString(pCfg, "Network", bstr);
2752 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
2753 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
2754 networkName = bstr;
2755 trunkType = Bstr(TRUNKTYPE_WHATEVER);
2756 }
2757 break;
2758 }
2759
2760 case NetworkAttachmentType_HostOnly:
2761 {
2762 InsertConfigString(pLunL0, "Driver", "IntNet");
2763 InsertConfigNode(pLunL0, "Config", &pCfg);
2764
2765 Bstr HostOnlyName;
2766 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
2767 if (FAILED(hrc))
2768 {
2769 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
2770 H();
2771 }
2772
2773 Utf8Str HostOnlyNameUtf8(HostOnlyName);
2774 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
2775#ifdef VBOX_WITH_VMNET
2776 /* Check if the matching host-only network has already been created. */
2777 Bstr bstrLowerIP, bstrUpperIP, bstrNetworkMask;
2778 BstrFmt bstrNetworkName("Legacy %s Network", pszHostOnlyName);
2779 ComPtr<IHostOnlyNetwork> hostOnlyNetwork;
2780 hrc = virtualBox->FindHostOnlyNetworkByName(bstrNetworkName.raw(), hostOnlyNetwork.asOutParam());
2781 if (FAILED(hrc))
2782 {
2783 /*
2784 * With VMNET there is no VBoxNetAdp to create vboxnetX adapters,
2785 * which means that the Host object won't be able to re-create
2786 * them from extra data. Go through existing DHCP/adapter config
2787 * to derive the parameters for the new network.
2788 */
2789 BstrFmt bstrOldNetworkName("HostInterfaceNetworking-%s", pszHostOnlyName);
2790 ComPtr<IDHCPServer> dhcpServer;
2791 hrc = virtualBox->FindDHCPServerByNetworkName(bstrOldNetworkName.raw(),
2792 dhcpServer.asOutParam());
2793 if (SUCCEEDED(hrc))
2794 {
2795 /* There is a DHCP server available for this network. */
2796 hrc = dhcpServer->COMGETTER(LowerIP)(bstrLowerIP.asOutParam());
2797 if (FAILED(hrc))
2798 {
2799 LogRel(("Console::i_configNetwork: COMGETTER(LowerIP) failed, hrc (%Rhrc)\n", hrc));
2800 H();
2801 }
2802 hrc = dhcpServer->COMGETTER(UpperIP)(bstrUpperIP.asOutParam());
2803 if (FAILED(hrc))
2804 {
2805 LogRel(("Console::i_configNetwork: COMGETTER(UpperIP) failed, hrc (%Rhrc)\n", hrc));
2806 H();
2807 }
2808 hrc = dhcpServer->COMGETTER(NetworkMask)(bstrNetworkMask.asOutParam());
2809 if (FAILED(hrc))
2810 {
2811 LogRel(("Console::i_configNetwork: COMGETTER(NetworkMask) failed, hrc (%Rhrc)\n", hrc));
2812 H();
2813 }
2814 }
2815 else
2816 {
2817 /* No DHCP server for this hostonly interface, let's look at extra data */
2818 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
2819 pszHostOnlyName).raw(),
2820 bstrLowerIP.asOutParam());
2821 if (SUCCEEDED(hrc) && !bstrLowerIP.isEmpty())
2822 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
2823 pszHostOnlyName).raw(),
2824 bstrNetworkMask.asOutParam());
2825
2826 }
2827 RTNETADDRIPV4 ipAddr, ipMask;
2828 vrc = bstrLowerIP.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrLowerIP).c_str(), &ipAddr);
2829 if (RT_FAILURE(vrc))
2830 {
2831 /* We failed to locate any valid config of this vboxnetX interface, assume defaults. */
2832 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing lower IP '%ls', using '%ls' instead.\n",
2833 bstrLowerIP.raw(), getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw()));
2834 bstrLowerIP = getDefaultIPv4Address(Bstr(pszHostOnlyName));
2835 bstrNetworkMask.setNull();
2836 bstrUpperIP.setNull();
2837 vrc = RTNetStrToIPv4Addr(Utf8Str(bstrLowerIP).c_str(), &ipAddr);
2838 AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("RTNetStrToIPv4Addr(%ls) failed, vrc=%Rrc\n", bstrLowerIP.raw(), vrc),
2839 VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
2840 }
2841 vrc = bstrNetworkMask.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrNetworkMask).c_str(), &ipMask);
2842 if (RT_FAILURE(vrc))
2843 {
2844 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing network mask '%ls', using '%s' instead.\n",
2845 bstrNetworkMask.raw(), VBOXNET_IPV4MASK_DEFAULT));
2846 bstrNetworkMask = VBOXNET_IPV4MASK_DEFAULT;
2847 vrc = RTNetStrToIPv4Addr(Utf8Str(bstrNetworkMask).c_str(), &ipMask);
2848 AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("RTNetStrToIPv4Addr(%ls) failed, vrc=%Rrc\n", bstrNetworkMask.raw(), vrc),
2849 VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
2850 }
2851 vrc = bstrUpperIP.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrUpperIP).c_str(), &ipAddr);
2852 if (RT_FAILURE(vrc))
2853 {
2854 ipAddr.au32[0] = RT_H2N_U32((RT_N2H_U32(ipAddr.au32[0]) | ~RT_N2H_U32(ipMask.au32[0])) - 1); /* Do we need to exlude the last IP? */
2855 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing upper IP '%ls', using '%RTnaipv4' instead.\n",
2856 bstrUpperIP.raw(), ipAddr));
2857 bstrUpperIP = BstrFmt("%RTnaipv4", ipAddr);
2858 }
2859
2860 /* All parameters are set, create the new network. */
2861 hrc = virtualBox->CreateHostOnlyNetwork(bstrNetworkName.raw(), hostOnlyNetwork.asOutParam());
2862 if (FAILED(hrc))
2863 {
2864 LogRel(("NetworkAttachmentType_HostOnly: failed to create host-only network, hrc (0x%x)\n", hrc));
2865 H();
2866 }
2867 hrc = hostOnlyNetwork->COMSETTER(NetworkMask)(bstrNetworkMask.raw());
2868 if (FAILED(hrc))
2869 {
2870 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(NetworkMask) failed, hrc (0x%x)\n", hrc));
2871 H();
2872 }
2873 hrc = hostOnlyNetwork->COMSETTER(LowerIP)(bstrLowerIP.raw());
2874 if (FAILED(hrc))
2875 {
2876 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(LowerIP) failed, hrc (0x%x)\n", hrc));
2877 H();
2878 }
2879 hrc = hostOnlyNetwork->COMSETTER(UpperIP)(bstrUpperIP.raw());
2880 if (FAILED(hrc))
2881 {
2882 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(UpperIP) failed, hrc (0x%x)\n", hrc));
2883 H();
2884 }
2885 LogRel(("Console: created host-only network '%ls' with mask '%ls' and range '%ls'-'%ls'\n",
2886 bstrNetworkName.raw(), bstrNetworkMask.raw(), bstrLowerIP.raw(), bstrUpperIP.raw()));
2887 }
2888 else
2889 {
2890 /* The matching host-only network already exists. Tell the user to switch to it. */
2891 hrc = hostOnlyNetwork->COMGETTER(NetworkMask)(bstrNetworkMask.asOutParam());
2892 if (FAILED(hrc))
2893 {
2894 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(NetworkMask) failed, hrc (0x%x)\n", hrc));
2895 H();
2896 }
2897 hrc = hostOnlyNetwork->COMGETTER(LowerIP)(bstrLowerIP.asOutParam());
2898 if (FAILED(hrc))
2899 {
2900 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(LowerIP) failed, hrc (0x%x)\n", hrc));
2901 H();
2902 }
2903 hrc = hostOnlyNetwork->COMGETTER(UpperIP)(bstrUpperIP.asOutParam());
2904 if (FAILED(hrc))
2905 {
2906 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(UpperIP) failed, hrc (0x%x)\n", hrc));
2907 H();
2908 }
2909 }
2910 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2911 N_("Host-only adapters are no longer supported!\n"
2912 "For your convenience a host-only network named '%ls' has been "
2913 "created with network mask '%ls' and IP address range '%ls' - '%ls'.\n"
2914 "To fix this problem, switch to 'Host-only Network' "
2915 "attachment type in the VM settings.\n"),
2916 bstrNetworkName.raw(), bstrNetworkMask.raw(),
2917 bstrLowerIP.raw(), bstrUpperIP.raw());
2918#endif /* VBOX_WITH_VMNET */
2919 ComPtr<IHostNetworkInterface> hostInterface;
2920 hrc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
2921 hostInterface.asOutParam());
2922 if (!SUCCEEDED(hrc))
2923 {
2924 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, vrc=%Rrc\n", vrc));
2925 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
2926 N_("Nonexistent host networking interface, name '%ls'"), HostOnlyName.raw());
2927 }
2928
2929 char szNetwork[INTNET_MAX_NETWORK_NAME];
2930 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
2931
2932#if defined(RT_OS_WINDOWS)
2933# ifndef VBOX_WITH_NETFLT
2934 hrc = E_NOTIMPL;
2935 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
2936 H();
2937# else /* defined VBOX_WITH_NETFLT*/
2938 /** @todo r=bird: Put this in a function. */
2939
2940 HostNetworkInterfaceType_T eIfType;
2941 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
2942 if (FAILED(hrc))
2943 {
2944 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
2945 H();
2946 }
2947
2948 if (eIfType != HostNetworkInterfaceType_HostOnly)
2949 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
2950 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
2951 HostOnlyName.raw());
2952
2953 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
2954 if (FAILED(hrc))
2955 {
2956 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
2957 H();
2958 }
2959 Guid hostIFGuid(bstr);
2960
2961 INetCfg *pNc;
2962 ComPtr<INetCfgComponent> pAdaptorComponent;
2963 LPWSTR pszApp;
2964 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
2965 Assert(hrc == S_OK);
2966 if (hrc != S_OK)
2967 {
2968 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
2969 H();
2970 }
2971
2972 /* get the adapter's INetCfgComponent*/
2973 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
2974 pAdaptorComponent.asOutParam());
2975 if (hrc != S_OK)
2976 {
2977 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
2978 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
2979 H();
2980 }
2981# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
2982 char szTrunkName[INTNET_MAX_TRUNK_NAME];
2983 bool fNdis6 = false;
2984 wchar_t * pwszHelpText;
2985 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
2986 Assert(hrc == S_OK);
2987 if (hrc == S_OK)
2988 {
2989 Log(("help-text=%ls\n", pwszHelpText));
2990 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
2991 fNdis6 = true;
2992 CoTaskMemFree(pwszHelpText);
2993 }
2994 if (fNdis6)
2995 {
2996 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
2997 Log(("trunk=%s\n", szTrunkName));
2998 }
2999 else
3000 {
3001 char *pszTrunkName = szTrunkName;
3002 wchar_t * pswzBindName;
3003 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
3004 Assert(hrc == S_OK);
3005 if (hrc == S_OK)
3006 {
3007 int cwBindName = (int)wcslen(pswzBindName) + 1;
3008 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
3009 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
3010 {
3011 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
3012 pszTrunkName += cbFullBindNamePrefix-1;
3013 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
3014 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
3015 {
3016 DWORD err = GetLastError();
3017 hrc = HRESULT_FROM_WIN32(err);
3018 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
3019 hrc, hrc, err));
3020 }
3021 }
3022 else
3023 {
3024 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
3025 /** @todo set appropriate error code */
3026 hrc = E_FAIL;
3027 }
3028
3029 if (hrc != S_OK)
3030 {
3031 AssertFailed();
3032 CoTaskMemFree(pswzBindName);
3033 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3034 H();
3035 }
3036 }
3037 else
3038 {
3039 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3040 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
3041 hrc, hrc));
3042 H();
3043 }
3044
3045
3046 CoTaskMemFree(pswzBindName);
3047 }
3048
3049 trunkType = TRUNKTYPE_NETADP;
3050 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
3051
3052 pAdaptorComponent.setNull();
3053 /* release the pNc finally */
3054 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3055
3056 const char *pszTrunk = szTrunkName;
3057
3058 InsertConfigString(pCfg, "Trunk", pszTrunk);
3059 InsertConfigString(pCfg, "Network", szNetwork);
3060 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
3061 windows only?? */
3062 networkName = Bstr(szNetwork);
3063 trunkName = Bstr(pszTrunk);
3064# endif /* defined VBOX_WITH_NETFLT*/
3065#elif defined(RT_OS_DARWIN)
3066 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
3067 InsertConfigString(pCfg, "Network", szNetwork);
3068 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
3069 networkName = Bstr(szNetwork);
3070 trunkName = Bstr(pszHostOnlyName);
3071 trunkType = TRUNKTYPE_NETADP;
3072#else
3073 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
3074 InsertConfigString(pCfg, "Network", szNetwork);
3075 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
3076 networkName = Bstr(szNetwork);
3077 trunkName = Bstr(pszHostOnlyName);
3078 trunkType = TRUNKTYPE_NETFLT;
3079#endif
3080 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
3081
3082#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
3083
3084 Bstr tmpAddr, tmpMask;
3085
3086 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
3087 pszHostOnlyName).raw(),
3088 tmpAddr.asOutParam());
3089 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
3090 {
3091 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
3092 pszHostOnlyName).raw(),
3093 tmpMask.asOutParam());
3094 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
3095 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
3096 tmpMask.raw());
3097 else
3098 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
3099 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
3100 }
3101 else
3102 {
3103 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
3104 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
3105 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
3106 }
3107
3108 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
3109
3110 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
3111 pszHostOnlyName).raw(),
3112 tmpAddr.asOutParam());
3113 if (SUCCEEDED(hrc))
3114 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
3115 tmpMask.asOutParam());
3116 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
3117 {
3118 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
3119 Utf8Str(tmpMask).toUInt32());
3120 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
3121 }
3122#endif
3123 break;
3124 }
3125
3126 case NetworkAttachmentType_Generic:
3127 {
3128 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
3129 SafeArray<BSTR> names;
3130 SafeArray<BSTR> values;
3131 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
3132 ComSafeArrayAsOutParam(names),
3133 ComSafeArrayAsOutParam(values)); H();
3134
3135 InsertConfigString(pLunL0, "Driver", bstr);
3136 InsertConfigNode(pLunL0, "Config", &pCfg);
3137 for (size_t ii = 0; ii < names.size(); ++ii)
3138 {
3139 if (values[ii] && *values[ii])
3140 {
3141 Utf8Str const strName(names[ii]);
3142 Utf8Str const strValue(values[ii]);
3143 InsertConfigString(pCfg, strName.c_str(), strValue);
3144 }
3145 }
3146 break;
3147 }
3148
3149 case NetworkAttachmentType_NATNetwork:
3150 {
3151 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
3152 if (!bstr.isEmpty())
3153 {
3154 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
3155 InsertConfigString(pLunL0, "Driver", "IntNet");
3156 InsertConfigNode(pLunL0, "Config", &pCfg);
3157 InsertConfigString(pCfg, "Network", bstr);
3158 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
3159 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
3160 networkName = bstr;
3161 trunkType = Bstr(TRUNKTYPE_WHATEVER);
3162 }
3163 break;
3164 }
3165
3166#ifdef VBOX_WITH_CLOUD_NET
3167 case NetworkAttachmentType_Cloud:
3168 {
3169 static const char *s_pszCloudExtPackName = VBOX_PUEL_PRODUCT;
3170 /*
3171 * Cloud network attachments do not work wihout installed extpack.
3172 * Without extpack support they won't work either.
3173 */
3174# ifdef VBOX_WITH_EXTPACK
3175 if ( !mptrExtPackManager->i_isExtPackUsable(s_pszCloudExtPackName)
3176 && !mptrExtPackManager->i_isExtPackUsable("Oracle VM VirtualBox Extension Pack")) /* Legacy name -- see @bugref{10690}. */
3177# endif
3178 {
3179 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
3180 N_("Implementation of the cloud network attachment not found!\n"
3181 "To fix this problem, either install the '%s' or switch to "
3182 "another network attachment type in the VM settings."),
3183 s_pszCloudExtPackName);
3184 }
3185
3186 ComPtr<ICloudNetwork> network;
3187 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam()); H();
3188 hrc = pMachine->COMGETTER(Name)(mGateway.mTargetVM.asOutParam()); H();
3189 hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam()); H();
3190 hrc = generateKeys(mGateway);
3191 if (FAILED(hrc))
3192 {
3193 if (hrc == E_NOTIMPL)
3194 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
3195 N_("Failed to generate a key pair due to missing libssh\n"
3196 "To fix this problem, either build VirtualBox with libssh "
3197 "support or switch to another network attachment type in "
3198 "the VM settings."));
3199 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
3200 N_("Failed to generate a key pair due to libssh error!"));
3201 }
3202 hrc = startCloudGateway(virtualBox, network, mGateway);
3203 if (FAILED(hrc))
3204 {
3205 if (hrc == VBOX_E_OBJECT_NOT_FOUND)
3206 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3207 N_("Failed to start cloud gateway instance.\nCould not find suitable "
3208 "standard cloud images. Make sure you ran 'VBoxManage cloud network setup' "
3209 "with correct '--gateway-os-name' and '--gateway-os-version' parameters. "
3210 "Check VBoxSVC.log for actual values used to look up cloud images."));
3211 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3212 N_("Failed to start cloud gateway instance.\nMake sure you set up "
3213 "cloud networking properly with 'VBoxManage cloud network setup'. "
3214 "Check VBoxSVC.log for details."));
3215 }
3216 InsertConfigBytes(pDevCfg, "MAC", &mGateway.mCloudMacAddress, sizeof(mGateway.mCloudMacAddress));
3217 if (!bstr.isEmpty())
3218 {
3219 InsertConfigString(pLunL0, "Driver", "CloudTunnel");
3220 InsertConfigNode(pLunL0, "Config", &pCfg);
3221 InsertConfigPassword(pCfg, "SshKey", mGateway.mPrivateSshKey);
3222 InsertConfigString(pCfg, "PrimaryIP", mGateway.mCloudPublicIp);
3223 InsertConfigString(pCfg, "SecondaryIP", mGateway.mCloudSecondaryPublicIp);
3224 InsertConfigBytes(pCfg, "TargetMAC", &mGateway.mLocalMacAddress, sizeof(mGateway.mLocalMacAddress));
3225 hrc = i_configProxy(virtualBox, pCfg, "Primary", mGateway.mCloudPublicIp);
3226 if (FAILED(hrc))
3227 {
3228 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3229 N_("Failed to configure proxy for accessing cloud gateway instance via primary VNIC.\n"
3230 "Check VirtualBox.log for details."));
3231 }
3232 hrc = i_configProxy(virtualBox, pCfg, "Secondary", mGateway.mCloudSecondaryPublicIp);
3233 if (FAILED(hrc))
3234 {
3235 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3236 N_("Failed to configure proxy for accessing cloud gateway instance via secondary VNIC.\n"
3237 "Check VirtualBox.log for details."));
3238 }
3239 networkName = bstr;
3240 trunkType = Bstr(TRUNKTYPE_WHATEVER);
3241 }
3242 break;
3243 }
3244#endif /* VBOX_WITH_CLOUD_NET */
3245
3246#ifdef VBOX_WITH_VMNET
3247 case NetworkAttachmentType_HostOnlyNetwork:
3248 {
3249 Bstr bstrId, bstrNetMask, bstrLowerIP, bstrUpperIP;
3250 ComPtr<IHostOnlyNetwork> network;
3251 hrc = aNetworkAdapter->COMGETTER(HostOnlyNetwork)(bstr.asOutParam()); H();
3252 hrc = virtualBox->FindHostOnlyNetworkByName(bstr.raw(), network.asOutParam());
3253 if (FAILED(hrc))
3254 {
3255 LogRel(("NetworkAttachmentType_HostOnlyNetwork: FindByName failed, hrc (0x%x)\n", hrc));
3256 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
3257 N_("Nonexistent host-only network '%ls'"), bstr.raw());
3258 }
3259 hrc = network->COMGETTER(Id)(bstrId.asOutParam()); H();
3260 hrc = network->COMGETTER(NetworkMask)(bstrNetMask.asOutParam()); H();
3261 hrc = network->COMGETTER(LowerIP)(bstrLowerIP.asOutParam()); H();
3262 hrc = network->COMGETTER(UpperIP)(bstrUpperIP.asOutParam()); H();
3263 if (!bstr.isEmpty())
3264 {
3265 InsertConfigString(pLunL0, "Driver", "VMNet");
3266 InsertConfigNode(pLunL0, "Config", &pCfg);
3267 // InsertConfigString(pCfg, "Trunk", bstr);
3268 // InsertConfigStringF(pCfg, "Network", "HostOnlyNetworking-%ls", bstr.raw());
3269 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
3270 InsertConfigString(pCfg, "Id", bstrId);
3271 InsertConfigString(pCfg, "NetworkMask", bstrNetMask);
3272 InsertConfigString(pCfg, "LowerIP", bstrLowerIP);
3273 InsertConfigString(pCfg, "UpperIP", bstrUpperIP);
3274 // InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
3275 networkName.setNull(); // We do not want DHCP server on our network!
3276 // trunkType = Bstr(TRUNKTYPE_WHATEVER);
3277 }
3278 break;
3279 }
3280#endif /* VBOX_WITH_VMNET */
3281
3282 default:
3283 AssertMsgFailed(("should not get here!\n"));
3284 break;
3285 }
3286
3287 /*
3288 * Attempt to attach the driver.
3289 */
3290 switch (eAttachmentType)
3291 {
3292 case NetworkAttachmentType_Null:
3293 break;
3294
3295 case NetworkAttachmentType_Bridged:
3296 case NetworkAttachmentType_Internal:
3297 case NetworkAttachmentType_HostOnly:
3298#ifdef VBOX_WITH_VMNET
3299 case NetworkAttachmentType_HostOnlyNetwork:
3300#endif /* VBOX_WITH_VMNET */
3301 case NetworkAttachmentType_NAT:
3302 case NetworkAttachmentType_Generic:
3303 case NetworkAttachmentType_NATNetwork:
3304#ifdef VBOX_WITH_CLOUD_NET
3305 case NetworkAttachmentType_Cloud:
3306#endif /* VBOX_WITH_CLOUD_NET */
3307 {
3308 if (SUCCEEDED(hrc) && RT_SUCCESS(vrc))
3309 {
3310 if (fAttachDetach)
3311 {
3312 vrc = pVMM->pfnPDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
3313 //AssertRC(vrc);
3314 }
3315
3316 {
3317 /** @todo pritesh: get the dhcp server name from the
3318 * previous network configuration and then stop the server
3319 * else it may conflict with the dhcp server running with
3320 * the current attachment type
3321 */
3322 /* Stop the hostonly DHCP Server */
3323 }
3324
3325 /*
3326 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
3327 */
3328 if ( !networkName.isEmpty()
3329 && eAttachmentType != NetworkAttachmentType_NATNetwork)
3330 {
3331 /*
3332 * Until we implement service reference counters DHCP Server will be stopped
3333 * by DHCPServerRunner destructor.
3334 */
3335 ComPtr<IDHCPServer> dhcpServer;
3336 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(), dhcpServer.asOutParam());
3337 if (SUCCEEDED(hrc))
3338 {
3339 /* there is a DHCP server available for this network */
3340 BOOL fEnabledDhcp;
3341 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
3342 if (FAILED(hrc))
3343 {
3344 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
3345 H();
3346 }
3347
3348 if (fEnabledDhcp)
3349 hrc = dhcpServer->Start(trunkName.raw(), trunkType.raw());
3350 }
3351 else
3352 hrc = S_OK;
3353 }
3354 }
3355
3356 break;
3357 }
3358
3359 default:
3360 AssertMsgFailed(("should not get here!\n"));
3361 break;
3362 }
3363
3364 meAttachmentType[uInstance] = eAttachmentType;
3365 }
3366 catch (ConfigError &x)
3367 {
3368 // InsertConfig threw something:
3369 return x.m_vrc;
3370 }
3371
3372#undef H
3373
3374 return VINF_SUCCESS;
3375}
3376
3377
3378/**
3379 * Configures the serial port at the given CFGM node with the supplied parameters.
3380 *
3381 * @returns VBox status code.
3382 * @param pInst The instance CFGM node.
3383 * @param ePortMode The port mode to sue.
3384 * @param pszPath The serial port path.
3385 * @param fServer Flag whether the port should act as a server
3386 * for the pipe and TCP mode or connect as a client.
3387 */
3388int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
3389{
3390 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
3391 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
3392 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
3393
3394 try
3395 {
3396 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3397 if (ePortMode == PortMode_HostPipe)
3398 {
3399 InsertConfigString(pLunL0, "Driver", "Char");
3400 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3401 InsertConfigString(pLunL1, "Driver", "NamedPipe");
3402 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
3403 InsertConfigString(pLunL1Cfg, "Location", pszPath);
3404 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
3405 }
3406 else if (ePortMode == PortMode_HostDevice)
3407 {
3408 InsertConfigString(pLunL0, "Driver", "Host Serial");
3409 InsertConfigNode(pLunL0, "Config", &pLunL1);
3410 InsertConfigString(pLunL1, "DevicePath", pszPath);
3411 }
3412 else if (ePortMode == PortMode_TCP)
3413 {
3414 InsertConfigString(pLunL0, "Driver", "Char");
3415 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3416 InsertConfigString(pLunL1, "Driver", "TCP");
3417 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
3418 InsertConfigString(pLunL1Cfg, "Location", pszPath);
3419 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
3420 }
3421 else if (ePortMode == PortMode_RawFile)
3422 {
3423 InsertConfigString(pLunL0, "Driver", "Char");
3424 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3425 InsertConfigString(pLunL1, "Driver", "RawFile");
3426 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
3427 InsertConfigString(pLunL1Cfg, "Location", pszPath);
3428 }
3429 }
3430 catch (ConfigError &x)
3431 {
3432 /* InsertConfig threw something */
3433 return x.m_vrc;
3434 }
3435
3436 return VINF_SUCCESS;
3437}
3438
3439
3440#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3441#define VRC() AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("vrc=%Rrc\n", vrc), vrc)
3442
3443int Console::i_configPdm(ComPtr<IMachine> pMachine, PCVMMR3VTABLE pVMM, PUVM pUVM, PCFGMNODE pRoot)
3444{
3445 PCFGMNODE pPDM;
3446 PCFGMNODE pNode;
3447 PCFGMNODE pMod;
3448 InsertConfigNode(pRoot, "PDM", &pPDM);
3449 InsertConfigNode(pPDM, "Devices", &pNode);
3450 InsertConfigNode(pPDM, "Drivers", &pNode);
3451 InsertConfigNode(pNode, "VBoxC", &pMod);
3452#ifdef VBOX_WITH_XPCOM
3453 // VBoxC is located in the components subdirectory
3454 char szPathVBoxC[RTPATH_MAX];
3455 int vrc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX); VRC();
3456 vrc = RTPathAppend(szPathVBoxC, RTPATH_MAX, "/components/VBoxC"); VRC();
3457 InsertConfigString(pMod, "Path", szPathVBoxC);
3458#else
3459 InsertConfigString(pMod, "Path", "VBoxC");
3460#endif
3461
3462
3463 /*
3464 * Block cache settings.
3465 */
3466 PCFGMNODE pPDMBlkCache;
3467 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
3468
3469 /* I/O cache size */
3470 ULONG ioCacheSize = 5;
3471 HRESULT hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize); H();
3472 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
3473
3474 /*
3475 * Bandwidth groups.
3476 */
3477 ComPtr<IBandwidthControl> bwCtrl;
3478
3479 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();
3480
3481 com::SafeIfaceArray<IBandwidthGroup> bwGroups;
3482 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();
3483
3484 PCFGMNODE pAc;
3485 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
3486 PCFGMNODE pAcFile;
3487 InsertConfigNode(pAc, "File", &pAcFile);
3488 PCFGMNODE pAcFileBwGroups;
3489 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);
3490#ifdef VBOX_WITH_NETSHAPER
3491 PCFGMNODE pNetworkShaper;
3492 InsertConfigNode(pPDM, "NetworkShaper", &pNetworkShaper);
3493 PCFGMNODE pNetworkBwGroups;
3494 InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);
3495#endif /* VBOX_WITH_NETSHAPER */
3496
3497 for (size_t i = 0; i < bwGroups.size(); i++)
3498 {
3499 Bstr strName;
3500 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();
3501 if (strName.isEmpty())
3502 return pVMM->pfnVMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS, N_("No bandwidth group name specified"));
3503
3504 BandwidthGroupType_T enmType = BandwidthGroupType_Null;
3505 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();
3506 LONG64 cMaxBytesPerSec = 0;
3507 hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H();
3508
3509 if (enmType == BandwidthGroupType_Disk)
3510 {
3511 PCFGMNODE pBwGroup;
3512 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
3513 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
3514 InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);
3515 InsertConfigInteger(pBwGroup, "Step", 0);
3516 }
3517#ifdef VBOX_WITH_NETSHAPER
3518 else if (enmType == BandwidthGroupType_Network)
3519 {
3520 /* Network bandwidth groups. */
3521 PCFGMNODE pBwGroup;
3522 InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
3523 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
3524 }
3525#endif /* VBOX_WITH_NETSHAPER */
3526 }
3527
3528 /** @todo r=aeichner Looks like this setting is completely unused in VMM/PDM. */
3529 BOOL fAllowTracingToAccessVM;
3530 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3531 if (fAllowTracingToAccessVM)
3532 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3533
3534 return VINF_SUCCESS;
3535}
3536
3537
3538int Console::i_configAudioCtrl(ComPtr<IVirtualBox> pVBox, ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices,
3539 bool fOsXGuest, bool *pfAudioEnabled)
3540{
3541 Utf8Str strTmp;
3542 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
3543 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
3544 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
3545 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
3546
3547 /*
3548 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
3549 */
3550 ComPtr<IAudioSettings> audioSettings;
3551 HRESULT hrc = pMachine->COMGETTER(AudioSettings)(audioSettings.asOutParam()); H();
3552
3553 BOOL fAudioEnabled = FALSE;
3554 ComPtr<IAudioAdapter> audioAdapter;
3555 hrc = audioSettings->COMGETTER(Adapter)(audioAdapter.asOutParam()); H();
3556 if (audioAdapter)
3557 {
3558 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
3559 }
3560
3561 if (fAudioEnabled)
3562 {
3563 *pfAudioEnabled = true;
3564
3565 AudioControllerType_T enmAudioController;
3566 hrc = audioAdapter->COMGETTER(AudioController)(&enmAudioController); H();
3567 AudioCodecType_T enmAudioCodec;
3568 hrc = audioAdapter->COMGETTER(AudioCodec)(&enmAudioCodec); H();
3569
3570 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Device/TimerHz", &strTmp);
3571 const uint64_t uTimerHz = strTmp.toUInt64();
3572
3573 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeInMs", &strTmp);
3574 const uint64_t uBufSizeInMs = strTmp.toUInt64();
3575
3576 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeOutMs", &strTmp);
3577 const uint64_t uBufSizeOutMs = strTmp.toUInt64();
3578
3579 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3580 const bool fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3581
3582 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Debug/Level", &strTmp);
3583 const uint32_t uDebugLevel = strTmp.toUInt32();
3584
3585 Utf8Str strDebugPathOut;
3586 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3587
3588#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3589 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/VaKit/Enabled", &strTmp); /* Deprecated; do not use! */
3590 if (strTmp.isEmpty())
3591 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/ValKit/Enabled", &strTmp);
3592 /* Whether the Validation Kit audio backend runs as the primary backend.
3593 * Can also be used with VBox release builds. */
3594 const bool fValKitEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3595#endif
3596 /** @todo Implement an audio device class, similar to the audio backend class, to construct the common stuff
3597 * without duplicating (more) code. */
3598
3599 const char *pszAudioDevice;
3600 switch (enmAudioController)
3601 {
3602 case AudioControllerType_AC97:
3603 {
3604 /* ICH AC'97. */
3605 pszAudioDevice = "ichac97";
3606
3607 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3608 InsertConfigNode(pDev, "0", &pInst);
3609 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3610 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();
3611 InsertConfigNode(pInst, "Config", &pCfg);
3612 switch (enmAudioCodec)
3613 {
3614 case AudioCodecType_STAC9700:
3615 InsertConfigString(pCfg, "Codec", "STAC9700");
3616 break;
3617 case AudioCodecType_AD1980:
3618 InsertConfigString(pCfg, "Codec", "AD1980");
3619 break;
3620 default: AssertFailedBreak();
3621 }
3622 if (uTimerHz)
3623 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3624 if (uBufSizeInMs)
3625 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);
3626 if (uBufSizeOutMs)
3627 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);
3628 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3629 if (strDebugPathOut.isNotEmpty())
3630 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3631 break;
3632 }
3633 case AudioControllerType_SB16:
3634 {
3635 /* Legacy SoundBlaster16. */
3636 pszAudioDevice = "sb16";
3637
3638 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3639 InsertConfigNode(pDev, "0", &pInst);
3640 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3641 InsertConfigNode(pInst, "Config", &pCfg);
3642 InsertConfigInteger(pCfg, "IRQ", 5);
3643 InsertConfigInteger(pCfg, "DMA", 1);
3644 InsertConfigInteger(pCfg, "DMA16", 5);
3645 InsertConfigInteger(pCfg, "Port", 0x220);
3646 InsertConfigInteger(pCfg, "Version", 0x0405);
3647 if (uTimerHz)
3648 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3649 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3650 if (strDebugPathOut.isNotEmpty())
3651 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3652 break;
3653 }
3654 case AudioControllerType_HDA:
3655 {
3656 /* Intel HD Audio. */
3657 pszAudioDevice = "hda";
3658
3659 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3660 InsertConfigNode(pDev, "0", &pInst);
3661 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3662 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();
3663 InsertConfigNode(pInst, "Config", &pCfg);
3664 if (uBufSizeInMs)
3665 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);
3666 if (uBufSizeOutMs)
3667 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);
3668 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3669 if (strDebugPathOut.isNotEmpty())
3670 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3671
3672 /* macOS guests uses a different HDA variant to make 10.14+ (or maybe 10.13?) recognize the device. */
3673 if (fOsXGuest)
3674 InsertConfigString(pCfg, "DeviceName", "Intel Sunrise Point");
3675 break;
3676 }
3677 default:
3678 pszAudioDevice = "oops";
3679 AssertFailedBreak();
3680 }
3681
3682 PCFGMNODE pCfgAudioAdapter = NULL;
3683 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);
3684 SafeArray<BSTR> audioProps;
3685 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
3686
3687 std::list<Utf8Str> audioPropertyNamesList;
3688 for (size_t i = 0; i < audioProps.size(); ++i)
3689 {
3690 Bstr bstrValue;
3691 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
3692 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
3693 Utf8Str strKey(audioProps[i]);
3694 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);
3695 }
3696
3697 /*
3698 * The audio driver.
3699 */
3700 const char *pszAudioDriver = NULL;
3701#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3702 if (fValKitEnabled)
3703 {
3704 pszAudioDriver = "ValidationKitAudio";
3705 LogRel(("Audio: ValidationKit driver active\n"));
3706 }
3707#endif
3708 /* If nothing else was selected before, ask the API. */
3709 if (pszAudioDriver == NULL)
3710 {
3711 AudioDriverType_T enmAudioDriver;
3712 hrc = audioAdapter->COMGETTER(AudioDriver)(&enmAudioDriver); H();
3713
3714 /* The "Default" audio driver needs special treatment, as we need to figure out which driver to use
3715 * by default on the current platform. */
3716 bool const fUseDefaultDrv = enmAudioDriver == AudioDriverType_Default;
3717
3718 AudioDriverType_T const enmDefaultAudioDriver = settings::MachineConfigFile::getHostDefaultAudioDriver();
3719
3720 if (fUseDefaultDrv)
3721 {
3722 enmAudioDriver = enmDefaultAudioDriver;
3723 if (enmAudioDriver == AudioDriverType_Null)
3724 LogRel(("Audio: Warning: No default driver detected for current platform -- defaulting to Null audio backend\n"));
3725 }
3726
3727 switch (enmAudioDriver)
3728 {
3729 case AudioDriverType_Default: /* Can't happen, but handle it anyway. */
3730 RT_FALL_THROUGH();
3731 case AudioDriverType_Null:
3732 pszAudioDriver = "NullAudio";
3733 break;
3734#ifdef RT_OS_WINDOWS
3735# ifdef VBOX_WITH_WINMM
3736 case AudioDriverType_WinMM:
3737# error "Port WinMM audio backend!" /** @todo Still needed? */
3738 break;
3739# endif
3740 case AudioDriverType_DirectSound:
3741 /* Use the Windows Audio Session (WAS) API rather than Direct Sound on Windows
3742 versions we've tested it on (currently W7+). Since Vista, Direct Sound has
3743 been emulated on top of WAS according to the docs, so better use WAS directly.
3744
3745 Set extradata value "VBoxInternal2/Audio/WindowsDrv" "dsound" to no use WasAPI.
3746
3747 Keep this hack for backwards compatibility (introduced < 7.0).
3748 */
3749 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/WindowsDrv", &strTmp); H();
3750 if ( enmDefaultAudioDriver == AudioDriverType_WAS
3751 && ( strTmp.isEmpty()
3752 || strTmp.equalsIgnoreCase("was")
3753 || strTmp.equalsIgnoreCase("wasapi")) )
3754 {
3755 /* Nothing to do here, fall through to WAS driver. */
3756 }
3757 else
3758 {
3759 pszAudioDriver = "DSoundAudio";
3760 break;
3761 }
3762 RT_FALL_THROUGH();
3763 case AudioDriverType_WAS:
3764 if (enmDefaultAudioDriver == AudioDriverType_WAS) /* WAS supported? */
3765 pszAudioDriver = "HostAudioWas";
3766 else if (enmDefaultAudioDriver == AudioDriverType_DirectSound)
3767 {
3768 LogRel(("Audio: Warning: Windows Audio Session (WAS) not supported, defaulting to DirectSound backend\n"));
3769 pszAudioDriver = "DSoundAudio";
3770 }
3771 break;
3772#endif /* RT_OS_WINDOWS */
3773#ifdef RT_OS_SOLARIS
3774 case AudioDriverType_SolAudio:
3775 /* Should not happen, as the Solaris Audio backend is not around anymore.
3776 * Remove this sometime later. */
3777 LogRel(("Audio: Warning: Solaris Audio is deprecated, please switch to OSS!\n"));
3778 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
3779
3780 /* Manually set backend to OSS for now. */
3781 pszAudioDriver = "OSSAudio";
3782 break;
3783#endif
3784#ifdef VBOX_WITH_AUDIO_OSS
3785 case AudioDriverType_OSS:
3786 pszAudioDriver = "OSSAudio";
3787 break;
3788#endif
3789#ifdef VBOX_WITH_AUDIO_ALSA
3790 case AudioDriverType_ALSA:
3791 pszAudioDriver = "ALSAAudio";
3792 break;
3793#endif
3794#ifdef VBOX_WITH_AUDIO_PULSE
3795 case AudioDriverType_Pulse:
3796 pszAudioDriver = "PulseAudio";
3797 break;
3798#endif
3799#ifdef RT_OS_DARWIN
3800 case AudioDriverType_CoreAudio:
3801 pszAudioDriver = "CoreAudio";
3802 break;
3803#endif
3804 default:
3805 pszAudioDriver = "oops";
3806 AssertFailedBreak();
3807 }
3808
3809 if (fUseDefaultDrv)
3810 LogRel(("Audio: Detected default audio driver type is '%s'\n", pszAudioDriver));
3811 }
3812
3813 BOOL fAudioEnabledIn = FALSE;
3814 hrc = audioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();
3815 BOOL fAudioEnabledOut = FALSE;
3816 hrc = audioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut); H();
3817
3818 unsigned idxAudioLun = 0;
3819
3820 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3821 i_configAudioDriver(pVBox, pMachine, pLunL0, pszAudioDriver, !!fAudioEnabledIn, !!fAudioEnabledOut);
3822 idxAudioLun++;
3823
3824#ifdef VBOX_WITH_AUDIO_VRDE
3825 /* Insert dummy audio driver to have the LUN configured. */
3826 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3827 InsertConfigString(pLunL0, "Driver", "AUDIO");
3828 {
3829 AudioDriverCfg DrvCfgVRDE(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVRDE",
3830 !!fAudioEnabledIn, !!fAudioEnabledOut);
3831 int vrc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);
3832 AssertRCStmt(vrc, throw ConfigError(__FUNCTION__, vrc, "mAudioVRDE->InitializeConfig failed"));
3833 }
3834 idxAudioLun++;
3835#endif
3836
3837#ifdef VBOX_WITH_AUDIO_RECORDING
3838 /* Insert dummy audio driver to have the LUN configured. */
3839 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3840 InsertConfigString(pLunL0, "Driver", "AUDIO");
3841 {
3842 AudioDriverCfg DrvCfgVideoRec(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVideoRec",
3843 false /*a_fEnabledIn*/, true /*a_fEnabledOut*/);
3844 int vrc = mRecording.mAudioRec->InitializeConfig(&DrvCfgVideoRec);
3845 AssertRCStmt(vrc, throw ConfigError(__FUNCTION__, vrc, "Recording.mAudioRec->InitializeConfig failed"));
3846 }
3847 idxAudioLun++;
3848#endif
3849
3850 if (fDebugEnabled)
3851 {
3852#ifdef VBOX_WITH_AUDIO_DEBUG
3853# ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3854 /*
3855 * When both, ValidationKit and Debug mode (for audio) are enabled,
3856 * skip configuring the Debug audio driver, as both modes can
3857 * mess with the audio data and would lead to side effects.
3858 *
3859 * The ValidationKit audio driver has precedence over the Debug audio driver.
3860 *
3861 * This also can (and will) be used in VBox release builds.
3862 */
3863 if (fValKitEnabled)
3864 {
3865 LogRel(("Audio: Warning: ValidationKit running and Debug mode enabled -- disabling Debug driver\n"));
3866 }
3867 else /* Debug mode active -- run both (nice for catching errors / doing development). */
3868 {
3869 /*
3870 * The ValidationKit backend.
3871 */
3872 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3873 i_configAudioDriver(pVBox, pMachine, pLunL0, "ValidationKitAudio",
3874 !!fAudioEnabledIn, !!fAudioEnabledOut);
3875 idxAudioLun++;
3876# endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3877 /*
3878 * The Debug audio backend.
3879 */
3880 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3881 i_configAudioDriver(pVBox, pMachine, pLunL0, "DebugAudio",
3882 !!fAudioEnabledIn, !!fAudioEnabledOut);
3883 idxAudioLun++;
3884# ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3885 }
3886# endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3887#endif /* VBOX_WITH_AUDIO_DEBUG */
3888
3889 /*
3890 * Tweak the logging groups.
3891 */
3892 Utf8Str strGroups("drv_audio.e.l.l2.l3.f"
3893 " audio_mixer.e.l.l2.l3.f"
3894 " dev_hda_codec.e.l.l2.l3.f"
3895 " dev_hda.e.l.l2.l3.f"
3896 " dev_ac97.e.l.l2.l3.f"
3897 " dev_sb16.e.l.l2.l3.f");
3898
3899 LogRel(("Audio: Debug level set to %RU32\n", uDebugLevel));
3900
3901 switch (uDebugLevel)
3902 {
3903 case 0:
3904 strGroups += " drv_host_audio.e.l.l2.l3.f";
3905 break;
3906 case 1:
3907 RT_FALL_THROUGH();
3908 case 2:
3909 RT_FALL_THROUGH();
3910 case 3:
3911 strGroups += " drv_host_audio.e.l.l2.l3.f+audio_test.e.l.l2.l3.f";
3912 break;
3913 case 4:
3914 RT_FALL_THROUGH();
3915 default:
3916 strGroups += " drv_host_audio.e.l.l2.l3.l4.f+audio_test.e.l.l2.l3.l4.f";
3917 break;
3918 }
3919
3920 int vrc = RTLogGroupSettings(RTLogRelGetDefaultInstance(), strGroups.c_str());
3921 if (RT_FAILURE(vrc))
3922 LogRel(("Audio: Setting debug logging failed, vrc=%Rrc\n", vrc));
3923 }
3924 }
3925
3926 return VINF_SUCCESS;
3927}
3928
3929
3930int Console::i_configVmmDev(ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices, bool fMmioReq)
3931{
3932 VMMDev *pVMMDev = m_pVMMDev; Assert(pVMMDev);
3933
3934 int vrc = VINF_SUCCESS;
3935 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
3936 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
3937 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
3938 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
3939
3940 /*
3941 * VMM Device
3942 */
3943 InsertConfigNode(pDevices, "VMMDev", &pDev);
3944 InsertConfigNode(pDev, "0", &pInst);
3945 InsertConfigNode(pInst, "Config", &pCfg);
3946 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3947 HRESULT hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();
3948 if (fMmioReq)
3949 InsertConfigInteger(pCfg, "MmioReq", 1);
3950
3951 Bstr hwVersion;
3952 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
3953 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
3954 InsertConfigInteger(pCfg, "HeapEnabled", 0);
3955 Bstr snapshotFolder;
3956 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
3957 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
3958
3959 /* the VMM device's Main driver */
3960 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3961 InsertConfigString(pLunL0, "Driver", "HGCM");
3962 InsertConfigNode(pLunL0, "Config", &pCfg);
3963
3964 /*
3965 * Attach the status driver.
3966 */
3967 i_attachStatusDriver(pInst, DeviceType_SharedFolder);
3968
3969#ifdef VBOX_WITH_SHARED_CLIPBOARD
3970 /*
3971 * Shared Clipboard.
3972 */
3973 {
3974 ClipboardMode_T enmClipboardMode = ClipboardMode_Disabled;
3975 hrc = pMachine->COMGETTER(ClipboardMode)(&enmClipboardMode); H();
3976# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3977 BOOL fFileTransfersEnabled;
3978 hrc = pMachine->COMGETTER(ClipboardFileTransfersEnabled)(&fFileTransfersEnabled); H();
3979#endif
3980
3981 /* Load the service */
3982 vrc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3983 if (RT_SUCCESS(vrc))
3984 {
3985 LogRel(("Shared Clipboard: Service loaded\n"));
3986
3987 /* Set initial clipboard mode. */
3988 vrc = i_changeClipboardMode(enmClipboardMode);
3989 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial clipboard mode (%d): vrc=%Rrc\n",
3990 enmClipboardMode, vrc));
3991
3992 /* Setup the service. */
3993 VBOXHGCMSVCPARM parm;
3994 HGCMSvcSetU32(&parm, !i_useHostClipboard());
3995 vrc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, &parm);
3996 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial headless mode (%RTbool): vrc=%Rrc\n",
3997 !i_useHostClipboard(), vrc));
3998
3999# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
4000 vrc = i_changeClipboardFileTransferMode(RT_BOOL(fFileTransfersEnabled));
4001 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial file transfer mode (%u): vrc=%Rrc\n",
4002 fFileTransfersEnabled, vrc));
4003# endif
4004 GuestShCl::createInstance(this /* pConsole */);
4005 vrc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtShCl, "VBoxSharedClipboard",
4006 &GuestShCl::hgcmDispatcher,
4007 GuestShClInst());
4008 if (RT_FAILURE(vrc))
4009 Log(("Cannot register VBoxSharedClipboard extension, vrc=%Rrc\n", vrc));
4010 }
4011 else
4012 LogRel(("Shared Clipboard: Not available, vrc=%Rrc\n", vrc));
4013 vrc = VINF_SUCCESS; /* None of the potential failures above are fatal. */
4014 }
4015#endif /* VBOX_WITH_SHARED_CLIPBOARD */
4016
4017 /*
4018 * HGCM HostChannel.
4019 */
4020 {
4021 Bstr value;
4022 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
4023 value.asOutParam());
4024
4025 if ( hrc == S_OK
4026 && value == "1")
4027 {
4028 vrc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
4029 if (RT_FAILURE(vrc))
4030 {
4031 LogRel(("VBoxHostChannel is not available, vrc=%Rrc\n", vrc));
4032 /* That is not a fatal failure. */
4033 vrc = VINF_SUCCESS;
4034 }
4035 }
4036 }
4037
4038#ifdef VBOX_WITH_DRAG_AND_DROP
4039 /*
4040 * Drag and Drop.
4041 */
4042 {
4043 DnDMode_T enmMode = DnDMode_Disabled;
4044 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
4045
4046 /* Load the service */
4047 vrc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
4048 if (RT_FAILURE(vrc))
4049 {
4050 LogRel(("Drag and drop service is not available, vrc=%Rrc\n", vrc));
4051 /* That is not a fatal failure. */
4052 vrc = VINF_SUCCESS;
4053 }
4054 else
4055 {
4056 vrc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",
4057 &GuestDnD::notifyDnDDispatcher,
4058 GuestDnDInst());
4059 if (RT_FAILURE(vrc))
4060 Log(("Cannot register VBoxDragAndDropSvc extension, vrc=%Rrc\n", vrc));
4061 else
4062 {
4063 LogRel(("Drag and drop service loaded\n"));
4064 vrc = i_changeDnDMode(enmMode);
4065 }
4066 }
4067 }
4068#endif /* VBOX_WITH_DRAG_AND_DROP */
4069
4070 return vrc;
4071}
4072
4073
4074int Console::i_configUsb(ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCFGMNODE pRoot, PCFGMNODE pDevices,
4075 KeyboardHIDType_T enmKbdHid, PointingHIDType_T enmPointingHid, PCFGMNODE *ppUsbDevices)
4076{
4077 int vrc = VINF_SUCCESS;
4078 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
4079 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
4080 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
4081 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
4082 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
4083
4084 com::SafeIfaceArray<IUSBController> usbCtrls;
4085 HRESULT hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
4086 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
4087 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
4088
4089 if (SUCCEEDED(hrc))
4090 {
4091 for (size_t i = 0; i < usbCtrls.size(); ++i)
4092 {
4093 USBControllerType_T enmCtrlType;
4094 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
4095 if (enmCtrlType == USBControllerType_OHCI)
4096 {
4097 fOhciPresent = true;
4098 break;
4099 }
4100 else if (enmCtrlType == USBControllerType_XHCI)
4101 {
4102 fXhciPresent = true;
4103 break;
4104 }
4105 }
4106 }
4107 else if (hrc != E_NOTIMPL)
4108 {
4109 H();
4110 }
4111
4112 /*
4113 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
4114 */
4115 if (fOhciPresent || fXhciPresent)
4116 mfVMHasUsbController = true;
4117
4118 if (mfVMHasUsbController)
4119 {
4120 for (size_t i = 0; i < usbCtrls.size(); ++i)
4121 {
4122 USBControllerType_T enmCtrlType;
4123 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
4124
4125 if (enmCtrlType == USBControllerType_OHCI)
4126 {
4127 InsertConfigNode(pDevices, "usb-ohci", &pDev);
4128 InsertConfigNode(pDev, "0", &pInst);
4129 InsertConfigNode(pInst, "Config", &pCfg);
4130 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4131 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
4132 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4133 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
4134 InsertConfigNode(pLunL0, "Config", &pCfg);
4135
4136 /*
4137 * Attach the status driver.
4138 */
4139 i_attachStatusDriver(pInst, DeviceType_USB);
4140 }
4141#ifdef VBOX_WITH_EHCI
4142 else if (enmCtrlType == USBControllerType_EHCI)
4143 {
4144 InsertConfigNode(pDevices, "usb-ehci", &pDev);
4145 InsertConfigNode(pDev, "0", &pInst);
4146 InsertConfigNode(pInst, "Config", &pCfg);
4147 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4148 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
4149
4150 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4151 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
4152 InsertConfigNode(pLunL0, "Config", &pCfg);
4153
4154 /*
4155 * Attach the status driver.
4156 */
4157 i_attachStatusDriver(pInst, DeviceType_USB);
4158 }
4159#endif
4160 else if (enmCtrlType == USBControllerType_XHCI)
4161 {
4162 InsertConfigNode(pDevices, "usb-xhci", &pDev);
4163 InsertConfigNode(pDev, "0", &pInst);
4164 InsertConfigNode(pInst, "Config", &pCfg);
4165 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4166 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
4167
4168 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4169 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
4170 InsertConfigNode(pLunL0, "Config", &pCfg);
4171
4172 InsertConfigNode(pInst, "LUN#1", &pLunL1);
4173 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
4174 InsertConfigNode(pLunL1, "Config", &pCfg);
4175
4176 /*
4177 * Attach the status driver.
4178 */
4179 i_attachStatusDriver(pInst, DeviceType_USB, 2);
4180 }
4181 } /* for every USB controller. */
4182
4183
4184 /*
4185 * Virtual USB Devices.
4186 */
4187 PCFGMNODE pUsbDevices = NULL;
4188 InsertConfigNode(pRoot, "USB", &pUsbDevices);
4189 *ppUsbDevices = pUsbDevices;
4190
4191#ifdef VBOX_WITH_USB
4192 {
4193 /*
4194 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
4195 * on a per device level now.
4196 */
4197 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
4198 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
4199 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
4200 //InsertConfigInteger(pCfg, "Force11Device", true);
4201 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
4202 // that it's documented somewhere.) Users needing it can use:
4203 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
4204 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
4205 }
4206#endif
4207
4208#ifdef VBOX_WITH_USB_CARDREADER
4209 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
4210 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
4211 if (aEmulatedUSBCardReaderEnabled)
4212 {
4213 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
4214 InsertConfigNode(pDev, "0", &pInst);
4215 InsertConfigNode(pInst, "Config", &pCfg);
4216
4217 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4218# ifdef VBOX_WITH_USB_CARDREADER_TEST
4219 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
4220 InsertConfigNode(pLunL0, "Config", &pCfg);
4221# else
4222 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
4223 InsertConfigNode(pLunL0, "Config", &pCfg);
4224# endif
4225 }
4226#endif
4227
4228 /* Virtual USB Mouse/Tablet */
4229 if ( enmPointingHid == PointingHIDType_USBMouse
4230 || enmPointingHid == PointingHIDType_USBTablet
4231 || enmPointingHid == PointingHIDType_USBMultiTouch
4232 || enmPointingHid == PointingHIDType_USBMultiTouchScreenPlusPad)
4233 {
4234 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
4235 InsertConfigNode(pDev, "0", &pInst);
4236 InsertConfigNode(pInst, "Config", &pCfg);
4237
4238 if (enmPointingHid == PointingHIDType_USBMouse)
4239 InsertConfigString(pCfg, "Mode", "relative");
4240 else
4241 InsertConfigString(pCfg, "Mode", "absolute");
4242 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4243 InsertConfigString(pLunL0, "Driver", "MouseQueue");
4244 InsertConfigNode(pLunL0, "Config", &pCfg);
4245 InsertConfigInteger(pCfg, "QueueSize", 128);
4246
4247 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4248 InsertConfigString(pLunL1, "Driver", "MainMouse");
4249 }
4250 if ( enmPointingHid == PointingHIDType_USBMultiTouch
4251 || enmPointingHid == PointingHIDType_USBMultiTouchScreenPlusPad)
4252 {
4253 InsertConfigNode(pDev, "1", &pInst);
4254 InsertConfigNode(pInst, "Config", &pCfg);
4255
4256 InsertConfigString(pCfg, "Mode", "multitouch");
4257 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4258 InsertConfigString(pLunL0, "Driver", "MouseQueue");
4259 InsertConfigNode(pLunL0, "Config", &pCfg);
4260 InsertConfigInteger(pCfg, "QueueSize", 128);
4261
4262 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4263 InsertConfigString(pLunL1, "Driver", "MainMouse");
4264 }
4265 if (enmPointingHid == PointingHIDType_USBMultiTouchScreenPlusPad)
4266 {
4267 InsertConfigNode(pDev, "2", &pInst);
4268 InsertConfigNode(pInst, "Config", &pCfg);
4269
4270 InsertConfigString(pCfg, "Mode", "touchpad");
4271 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4272 InsertConfigString(pLunL0, "Driver", "MouseQueue");
4273 InsertConfigNode(pLunL0, "Config", &pCfg);
4274 InsertConfigInteger(pCfg, "QueueSize", 128);
4275
4276 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4277 InsertConfigString(pLunL1, "Driver", "MainMouse");
4278 }
4279
4280 /* Virtual USB Keyboard */
4281 if (enmKbdHid == KeyboardHIDType_USBKeyboard)
4282 {
4283 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
4284 InsertConfigNode(pDev, "0", &pInst);
4285 InsertConfigNode(pInst, "Config", &pCfg);
4286
4287 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4288 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
4289 InsertConfigNode(pLunL0, "Config", &pCfg);
4290 InsertConfigInteger(pCfg, "QueueSize", 64);
4291
4292 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4293 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
4294 }
4295 }
4296
4297 return VINF_SUCCESS;
4298}
4299
4300
4301/**
4302 * Translate IDE StorageControllerType_T to string representation.
4303 */
4304static const char* controllerString(StorageControllerType_T enmType)
4305{
4306 switch (enmType)
4307 {
4308 case StorageControllerType_PIIX3:
4309 return "PIIX3";
4310 case StorageControllerType_PIIX4:
4311 return "PIIX4";
4312 case StorageControllerType_ICH6:
4313 return "ICH6";
4314 default:
4315 return "Unknown";
4316 }
4317}
4318
4319
4320int Console::i_configStorageCtrls(ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCVMMR3VTABLE pVMM, PUVM pUVM,
4321 PCFGMNODE pDevices, PCFGMNODE pUsbDevices, PCFGMNODE pBiosCfg, bool *pfFdcEnabled)
4322{
4323 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
4324 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
4325
4326 com::SafeIfaceArray<IStorageController> ctrls;
4327 PCFGMNODE aCtrlNodes[StorageControllerType_VirtioSCSI + 1] = {};
4328 HRESULT hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
4329
4330 for (size_t i = 0; i < ctrls.size(); ++i)
4331 {
4332 DeviceType_T *paLedDevType = NULL;
4333
4334 StorageControllerType_T enmCtrlType;
4335 hrc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
4336 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)
4337 || enmCtrlType == StorageControllerType_USB);
4338
4339 StorageBus_T enmBus;
4340 hrc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
4341
4342 Bstr controllerName;
4343 hrc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
4344
4345 ULONG ulInstance = 999;
4346 hrc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
4347
4348 BOOL fUseHostIOCache;
4349 hrc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
4350
4351 BOOL fBootable;
4352 hrc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
4353
4354 PCFGMNODE pCtlInst = NULL;
4355 const char *pszCtrlDev = i_storageControllerTypeToStr(enmCtrlType);
4356 if (enmCtrlType != StorageControllerType_USB)
4357 {
4358 /* /Devices/<ctrldev>/ */
4359 pDev = aCtrlNodes[enmCtrlType];
4360 if (!pDev)
4361 {
4362 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
4363 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
4364 }
4365
4366 /* /Devices/<ctrldev>/<instance>/ */
4367 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
4368
4369 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
4370 InsertConfigInteger(pCtlInst, "Trusted", 1);
4371 InsertConfigNode(pCtlInst, "Config", &pCfg);
4372 }
4373
4374#define MAX_BIOS_LUN_COUNT 4
4375
4376 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
4377 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
4378
4379 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
4380 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
4381
4382#undef MAX_BIOS_LUN_COUNT
4383
4384 switch (enmCtrlType)
4385 {
4386 case StorageControllerType_LsiLogic:
4387 {
4388 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();
4389
4390 InsertConfigInteger(pCfg, "Bootable", fBootable);
4391
4392 /* BIOS configuration values, first SCSI controller only. */
4393 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)
4394 && !pBusMgr->hasPCIDevice("buslogic", 0)
4395 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
4396 && pBiosCfg)
4397 {
4398 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
4399 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
4400 }
4401
4402 /* Attach the status driver */
4403 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4404 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4405 break;
4406 }
4407
4408 case StorageControllerType_BusLogic:
4409 {
4410 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();
4411
4412 InsertConfigInteger(pCfg, "Bootable", fBootable);
4413
4414 /* BIOS configuration values, first SCSI controller only. */
4415 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
4416 && !pBusMgr->hasPCIDevice("buslogic", 1)
4417 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
4418 && pBiosCfg)
4419 {
4420 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
4421 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
4422 }
4423
4424 /* Attach the status driver */
4425 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4426 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4427 break;
4428 }
4429
4430 case StorageControllerType_IntelAhci:
4431 {
4432 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();
4433
4434 ULONG cPorts = 0;
4435 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4436 InsertConfigInteger(pCfg, "PortCount", cPorts);
4437 InsertConfigInteger(pCfg, "Bootable", fBootable);
4438
4439 com::SafeIfaceArray<IMediumAttachment> atts;
4440 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
4441 ComSafeArrayAsOutParam(atts)); H();
4442
4443 /* Configure the hotpluggable flag for the port. */
4444 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)
4445 {
4446 IMediumAttachment *pMediumAtt = atts[idxAtt];
4447
4448 LONG lPortNum = 0;
4449 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
4450
4451 BOOL fHotPluggable = FALSE;
4452 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
4453 if (SUCCEEDED(hrc))
4454 {
4455 PCFGMNODE pPortCfg;
4456 char szName[24];
4457 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
4458
4459 InsertConfigNode(pCfg, szName, &pPortCfg);
4460 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
4461 }
4462 }
4463
4464 /* BIOS configuration values, first AHCI controller only. */
4465 if ( !pBusMgr->hasPCIDevice("ahci", 1)
4466 && pBiosCfg)
4467 {
4468 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
4469 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();
4470 }
4471
4472 /* Attach the status driver */
4473 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4474 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4475 break;
4476 }
4477
4478 case StorageControllerType_PIIX3:
4479 case StorageControllerType_PIIX4:
4480 case StorageControllerType_ICH6:
4481 {
4482 /*
4483 * IDE (update this when the main interface changes)
4484 */
4485 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();
4486 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
4487
4488 /* Attach the status driver */
4489 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4490 4, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4491
4492 /* IDE flavors */
4493 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
4494 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
4495 aCtrlNodes[StorageControllerType_ICH6] = pDev;
4496 break;
4497 }
4498
4499 case StorageControllerType_I82078:
4500 {
4501 /*
4502 * i82078 Floppy drive controller
4503 */
4504 *pfFdcEnabled = true;
4505 InsertConfigInteger(pCfg, "IRQ", 6);
4506 InsertConfigInteger(pCfg, "DMA", 2);
4507 InsertConfigInteger(pCfg, "MemMapped", 0 );
4508 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
4509
4510 /* Attach the status driver */
4511 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_Floppy),
4512 2, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
4513 break;
4514 }
4515
4516 case StorageControllerType_LsiLogicSas:
4517 {
4518 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();
4519
4520 InsertConfigString(pCfg, "ControllerType", "SAS1068");
4521 InsertConfigInteger(pCfg, "Bootable", fBootable);
4522
4523 /* BIOS configuration values, first SCSI controller only. */
4524 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
4525 && !pBusMgr->hasPCIDevice("buslogic", 0)
4526 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)
4527 && pBiosCfg)
4528 {
4529 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
4530 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
4531 }
4532
4533 ULONG cPorts = 0;
4534 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4535 InsertConfigInteger(pCfg, "NumPorts", cPorts);
4536
4537 /* Attach the status driver */
4538 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
4539 8, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4540 break;
4541 }
4542
4543 case StorageControllerType_USB:
4544 {
4545 if (pUsbDevices)
4546 {
4547 /*
4548 * USB MSDs are handled a bit different as the device instance
4549 * doesn't match the storage controller instance but the port.
4550 */
4551 InsertConfigNode(pUsbDevices, "Msd", &pDev);
4552 pCtlInst = pDev;
4553 }
4554 else
4555 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
4556 N_("There is no USB controller enabled but there\n"
4557 "is at least one USB storage device configured for this VM.\n"
4558 "To fix this problem either enable the USB controller or remove\n"
4559 "the storage device from the VM"));
4560 break;
4561 }
4562
4563 case StorageControllerType_NVMe:
4564 {
4565 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();
4566
4567 ULONG cPorts = 0;
4568 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4569 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);
4570
4571 /* Attach the status driver */
4572 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),
4573 cPorts, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
4574 break;
4575 }
4576
4577 case StorageControllerType_VirtioSCSI:
4578 {
4579 hrc = pBusMgr->assignPCIDevice("virtio-scsi", pCtlInst); H();
4580
4581 ULONG cPorts = 0;
4582 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4583 InsertConfigInteger(pCfg, "NumTargets", cPorts);
4584 InsertConfigInteger(pCfg, "Bootable", fBootable);
4585
4586 /* Attach the status driver */
4587 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
4588 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4589 break;
4590 }
4591
4592 default:
4593 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
4594 }
4595
4596 /* Attach the media to the storage controllers. */
4597 com::SafeIfaceArray<IMediumAttachment> atts;
4598 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
4599 ComSafeArrayAsOutParam(atts)); H();
4600
4601 /* Builtin I/O cache - per device setting. */
4602 BOOL fBuiltinIOCache = true;
4603 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
4604
4605 bool fInsertDiskIntegrityDrv = false;
4606 Bstr strDiskIntegrityFlag;
4607 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
4608 strDiskIntegrityFlag.asOutParam());
4609 if ( hrc == S_OK
4610 && strDiskIntegrityFlag == "1")
4611 fInsertDiskIntegrityDrv = true;
4612
4613 for (size_t j = 0; j < atts.size(); ++j)
4614 {
4615 IMediumAttachment *pMediumAtt = atts[j];
4616 int vrc = i_configMediumAttachment(pszCtrlDev,
4617 ulInstance,
4618 enmBus,
4619 !!fUseHostIOCache,
4620 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
4621 fInsertDiskIntegrityDrv,
4622 false /* fSetupMerge */,
4623 0 /* uMergeSource */,
4624 0 /* uMergeTarget */,
4625 pMediumAtt,
4626 mMachineState,
4627 NULL /* phrc */,
4628 false /* fAttachDetach */,
4629 false /* fForceUnmount */,
4630 false /* fHotplug */,
4631 pUVM,
4632 pVMM,
4633 paLedDevType,
4634 NULL /* ppLunL0 */);
4635 if (RT_FAILURE(vrc))
4636 return vrc;
4637 }
4638 H();
4639 }
4640 H();
4641
4642 return VINF_SUCCESS;
4643}
4644
4645
4646int Console::i_configNetworkCtrls(ComPtr<IMachine> pMachine, ComPtr<IPlatformProperties> pPlatformProperties,
4647 ChipsetType_T enmChipset, BusAssignmentManager *pBusMgr, PCVMMR3VTABLE pVMM, PUVM pUVM,
4648 PCFGMNODE pDevices, std::list<BootNic> &llBootNics)
4649{
4650/* Comment out the following line to remove VMWare compatibility hack. */
4651#define VMWARE_NET_IN_SLOT_11
4652
4653 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
4654 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
4655 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
4656 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
4657
4658 ULONG maxNetworkAdapters;
4659 HRESULT hrc = pPlatformProperties->GetMaxNetworkAdapters(enmChipset, &maxNetworkAdapters); H();
4660
4661#ifdef VMWARE_NET_IN_SLOT_11
4662 bool fSwapSlots3and11 = false;
4663#endif
4664 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
4665 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
4666#ifdef VBOX_WITH_E1000
4667 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
4668 InsertConfigNode(pDevices, "e1000", &pDevE1000);
4669#endif
4670#ifdef VBOX_WITH_VIRTIO
4671 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
4672 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
4673#endif /* VBOX_WITH_VIRTIO */
4674 PCFGMNODE pDevDP8390 = NULL; /* DP8390-type devices */
4675 InsertConfigNode(pDevices, "dp8390", &pDevDP8390);
4676 PCFGMNODE pDev3C501 = NULL; /* EtherLink-type devices */
4677 InsertConfigNode(pDevices, "3c501", &pDev3C501);
4678
4679 for (ULONG uInstance = 0; uInstance < maxNetworkAdapters; ++uInstance)
4680 {
4681 ComPtr<INetworkAdapter> networkAdapter;
4682 hrc = pMachine->GetNetworkAdapter(uInstance, networkAdapter.asOutParam()); H();
4683 BOOL fEnabledNetAdapter = FALSE;
4684 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
4685 if (!fEnabledNetAdapter)
4686 continue;
4687
4688 /*
4689 * The virtual hardware type. Create appropriate device first.
4690 */
4691 const char *pszAdapterName = "pcnet";
4692 NetworkAdapterType_T adapterType;
4693 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
4694 switch (adapterType)
4695 {
4696 case NetworkAdapterType_Am79C970A:
4697 case NetworkAdapterType_Am79C973:
4698 case NetworkAdapterType_Am79C960:
4699 pDev = pDevPCNet;
4700 break;
4701#ifdef VBOX_WITH_E1000
4702 case NetworkAdapterType_I82540EM:
4703 case NetworkAdapterType_I82543GC:
4704 case NetworkAdapterType_I82545EM:
4705 pDev = pDevE1000;
4706 pszAdapterName = "e1000";
4707 break;
4708#endif
4709#ifdef VBOX_WITH_VIRTIO
4710 case NetworkAdapterType_Virtio:
4711 pDev = pDevVirtioNet;
4712 pszAdapterName = "virtio-net";
4713 break;
4714#endif /* VBOX_WITH_VIRTIO */
4715 case NetworkAdapterType_NE1000:
4716 case NetworkAdapterType_NE2000:
4717 case NetworkAdapterType_WD8003:
4718 case NetworkAdapterType_WD8013:
4719 case NetworkAdapterType_ELNK2:
4720 pDev = pDevDP8390;
4721 break;
4722 case NetworkAdapterType_ELNK1:
4723 pDev = pDev3C501;
4724 break;
4725 default:
4726 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'", adapterType, uInstance));
4727 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
4728 N_("Invalid network adapter type '%d' for slot '%d'"), adapterType, uInstance);
4729 }
4730
4731 InsertConfigNode(pDev, Utf8StrFmt("%u", uInstance).c_str(), &pInst);
4732 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4733
4734 int iPCIDeviceNo;
4735 if (enmChipset == ChipsetType_ICH9 || enmChipset == ChipsetType_PIIX3)
4736 {
4737 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
4738 * next 4 get 16..19. */
4739 switch (uInstance)
4740 {
4741 case 0:
4742 iPCIDeviceNo = 3;
4743 break;
4744 case 1: case 2: case 3:
4745 iPCIDeviceNo = uInstance - 1 + 8;
4746 break;
4747 case 4: case 5: case 6: case 7:
4748 iPCIDeviceNo = uInstance - 4 + 16;
4749 break;
4750 default:
4751 /* auto assignment */
4752 iPCIDeviceNo = -1;
4753 break;
4754 }
4755#ifdef VMWARE_NET_IN_SLOT_11
4756 /*
4757 * Dirty hack for PCI slot compatibility with VMWare,
4758 * it assigns slot 0x11 to the first network controller.
4759 */
4760 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
4761 {
4762 iPCIDeviceNo = 0x11;
4763 fSwapSlots3and11 = true;
4764 }
4765 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
4766 iPCIDeviceNo = 3;
4767#endif
4768 }
4769 else /* Platforms other than x86 just use the auto assignment, no slot swap hack there. */
4770 iPCIDeviceNo = -1;
4771
4772 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
4773 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
4774
4775 InsertConfigNode(pInst, "Config", &pCfg);
4776#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
4777 if (pDev == pDevPCNet)
4778 InsertConfigInteger(pCfg, "R0Enabled", false);
4779#endif
4780 /*
4781 * Collect information needed for network booting and add it to the list.
4782 */
4783 BootNic nic;
4784
4785 nic.mInstance = uInstance;
4786 /* Could be updated by reference, if auto assigned */
4787 nic.mPCIAddress = PCIAddr;
4788
4789 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
4790
4791 llBootNics.push_back(nic);
4792
4793 /*
4794 * The virtual hardware type. PCNet supports three types, E1000 three,
4795 * but VirtIO only one.
4796 */
4797 switch (adapterType)
4798 {
4799 case NetworkAdapterType_Am79C970A:
4800 InsertConfigString(pCfg, "ChipType", "Am79C970A");
4801 break;
4802 case NetworkAdapterType_Am79C973:
4803 InsertConfigString(pCfg, "ChipType", "Am79C973");
4804 break;
4805 case NetworkAdapterType_Am79C960:
4806 InsertConfigString(pCfg, "ChipType", "Am79C960");
4807 break;
4808 case NetworkAdapterType_I82540EM:
4809 InsertConfigInteger(pCfg, "AdapterType", 0);
4810 break;
4811 case NetworkAdapterType_I82543GC:
4812 InsertConfigInteger(pCfg, "AdapterType", 1);
4813 break;
4814 case NetworkAdapterType_I82545EM:
4815 InsertConfigInteger(pCfg, "AdapterType", 2);
4816 break;
4817 case NetworkAdapterType_Virtio:
4818 break;
4819 case NetworkAdapterType_NE1000:
4820 InsertConfigString(pCfg, "DeviceType", "NE1000");
4821 break;
4822 case NetworkAdapterType_NE2000:
4823 InsertConfigString(pCfg, "DeviceType", "NE2000");
4824 break;
4825 case NetworkAdapterType_WD8003:
4826 InsertConfigString(pCfg, "DeviceType", "WD8003");
4827 break;
4828 case NetworkAdapterType_WD8013:
4829 InsertConfigString(pCfg, "DeviceType", "WD8013");
4830 break;
4831 case NetworkAdapterType_ELNK2:
4832 InsertConfigString(pCfg, "DeviceType", "3C503");
4833 break;
4834 case NetworkAdapterType_ELNK1:
4835 break;
4836 case NetworkAdapterType_Null: AssertFailedBreak(); /* (compiler warnings) */
4837#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
4838 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
4839#endif
4840 }
4841
4842 /*
4843 * Get the MAC address and convert it to binary representation
4844 */
4845 Bstr macAddr;
4846 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
4847 Assert(!macAddr.isEmpty());
4848 Utf8Str macAddrUtf8 = macAddr;
4849#ifdef VBOX_WITH_CLOUD_NET
4850 NetworkAttachmentType_T eAttachmentType;
4851 hrc = networkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
4852 if (eAttachmentType == NetworkAttachmentType_Cloud)
4853 {
4854 mGateway.setLocalMacAddress(macAddrUtf8);
4855 /* We'll insert cloud MAC later, when it becomes known. */
4856 }
4857 else
4858 {
4859#endif
4860 char *macStr = (char*)macAddrUtf8.c_str();
4861 Assert(strlen(macStr) == 12);
4862 RTMAC Mac;
4863 RT_ZERO(Mac);
4864 char *pMac = (char*)&Mac;
4865 for (uint32_t i = 0; i < 6; ++i)
4866 {
4867 int c1 = *macStr++ - '0';
4868 if (c1 > 9)
4869 c1 -= 7;
4870 int c2 = *macStr++ - '0';
4871 if (c2 > 9)
4872 c2 -= 7;
4873 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
4874 }
4875 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
4876#ifdef VBOX_WITH_CLOUD_NET
4877 }
4878#endif
4879 /*
4880 * Check if the cable is supposed to be unplugged
4881 */
4882 BOOL fCableConnected;
4883 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
4884 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
4885
4886 /*
4887 * Line speed to report from custom drivers
4888 */
4889 ULONG ulLineSpeed;
4890 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
4891 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
4892
4893 /*
4894 * Attach the status driver.
4895 */
4896 i_attachStatusDriver(pInst, DeviceType_Network);
4897
4898 /*
4899 * Configure the network card now
4900 */
4901 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
4902 int vrc = i_configNetwork(pszAdapterName,
4903 uInstance,
4904 0,
4905 networkAdapter,
4906 pCfg,
4907 pLunL0,
4908 pInst,
4909 false /*fAttachDetach*/,
4910 fIgnoreConnectFailure,
4911 pUVM,
4912 pVMM);
4913 if (RT_FAILURE(vrc))
4914 return vrc;
4915 }
4916
4917 return VINF_SUCCESS;
4918}
4919
4920
4921int Console::i_configGuestDbg(ComPtr<IVirtualBox> pVBox, ComPtr<IMachine> pMachine, PCFGMNODE pRoot)
4922{
4923 PCFGMNODE pDbgf;
4924 InsertConfigNode(pRoot, "DBGF", &pDbgf);
4925
4926 /* Paths to search for debug info and such things. */
4927 Bstr bstr;
4928 HRESULT hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
4929 Utf8Str strSettingsPath(bstr);
4930 bstr.setNull();
4931 strSettingsPath.stripFilename();
4932 strSettingsPath.append("/");
4933
4934 char szHomeDir[RTPATH_MAX + 1];
4935 int vrc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
4936 if (RT_FAILURE(vrc2))
4937 szHomeDir[0] = '\0';
4938 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
4939
4940
4941 Utf8Str strPath;
4942 strPath.append(strSettingsPath).append("debug/;");
4943 strPath.append(strSettingsPath).append(";");
4944 strPath.append("cache*").append(strSettingsPath).append("dbgcache/;"); /* handy for symlinking to actual cache */
4945 strPath.append(szHomeDir);
4946
4947 InsertConfigString(pDbgf, "Path", strPath.c_str());
4948
4949 /* Tracing configuration. */
4950 BOOL fTracingEnabled;
4951 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
4952 if (fTracingEnabled)
4953 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
4954
4955 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
4956 if (fTracingEnabled)
4957 InsertConfigString(pDbgf, "TracingConfig", bstr);
4958
4959 /* Debugger console config. */
4960 PCFGMNODE pDbgc;
4961 InsertConfigNode(pRoot, "DBGC", &pDbgc);
4962
4963 hrc = pVBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
4964 Utf8Str strVBoxHome = bstr;
4965 bstr.setNull();
4966 if (strVBoxHome.isNotEmpty())
4967 strVBoxHome.append("/");
4968 else
4969 {
4970 strVBoxHome = szHomeDir;
4971 strVBoxHome.append("/.vbox");
4972 }
4973
4974 Utf8Str strFile(strVBoxHome);
4975 strFile.append("dbgc-history");
4976 InsertConfigString(pDbgc, "HistoryFile", strFile);
4977
4978 strFile = strSettingsPath;
4979 strFile.append("dbgc-init");
4980 InsertConfigString(pDbgc, "LocalInitScript", strFile);
4981
4982 strFile = strVBoxHome;
4983 strFile.append("dbgc-init");
4984 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
4985
4986 /*
4987 * Configure guest debug settings.
4988 */
4989 ComObjPtr<IGuestDebugControl> ptrGstDbgCtrl;
4990 GuestDebugProvider_T enmGstDbgProvider = GuestDebugProvider_None;
4991
4992 hrc = pMachine->COMGETTER(GuestDebugControl)(ptrGstDbgCtrl.asOutParam()); H();
4993 hrc = ptrGstDbgCtrl->COMGETTER(DebugProvider)(&enmGstDbgProvider); H();
4994 if (enmGstDbgProvider != GuestDebugProvider_None)
4995 {
4996 GuestDebugIoProvider_T enmGstDbgIoProvider = GuestDebugIoProvider_None;
4997 hrc = ptrGstDbgCtrl->COMGETTER(DebugIoProvider)(&enmGstDbgIoProvider); H();
4998 hrc = ptrGstDbgCtrl->COMGETTER(DebugAddress)(bstr.asOutParam()); H();
4999 Utf8Str strAddress = bstr;
5000 bstr.setNull();
5001
5002 ULONG ulPort = 0;
5003 hrc = ptrGstDbgCtrl->COMGETTER(DebugPort)(&ulPort); H();
5004
5005 PCFGMNODE pDbgSettings;
5006 InsertConfigNode(pDbgc, "Dbg", &pDbgSettings);
5007 InsertConfigString(pDbgSettings, "Address", strAddress);
5008 InsertConfigInteger(pDbgSettings, "Port", ulPort);
5009
5010 switch (enmGstDbgProvider)
5011 {
5012 case GuestDebugProvider_Native:
5013 InsertConfigString(pDbgSettings, "StubType", "Native");
5014 break;
5015 case GuestDebugProvider_GDB:
5016 InsertConfigString(pDbgSettings, "StubType", "Gdb");
5017 break;
5018 case GuestDebugProvider_KD:
5019 InsertConfigString(pDbgSettings, "StubType", "Kd");
5020 break;
5021 default:
5022 AssertFailed();
5023 break;
5024 }
5025
5026 switch (enmGstDbgIoProvider)
5027 {
5028 case GuestDebugIoProvider_TCP:
5029 InsertConfigString(pDbgSettings, "Provider", "tcp");
5030 break;
5031 case GuestDebugIoProvider_UDP:
5032 InsertConfigString(pDbgSettings, "Provider", "udp");
5033 break;
5034 case GuestDebugIoProvider_IPC:
5035 InsertConfigString(pDbgSettings, "Provider", "ipc");
5036 break;
5037 default:
5038 AssertFailed();
5039 break;
5040 }
5041 }
5042
5043 return VINF_SUCCESS;
5044}
5045
5046
5047int Console::i_configGraphicsController(PCFGMNODE pDevices,
5048 const GraphicsControllerType_T enmGraphicsController,
5049 BusAssignmentManager *pBusMgr,
5050 const ComPtr<IMachine> &ptrMachine,
5051 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
5052 const ComPtr<IFirmwareSettings> &ptrFirmwareSettings,
5053 bool fForceVmSvga3, bool fExposeLegacyVga)
5054{
5055 // InsertConfig* throws
5056 try
5057 {
5058 PCFGMNODE pDev, pInst, pCfg, pLunL0;
5059 HRESULT hrc;
5060 Bstr bstr;
5061 const char *pcszDevice = "vga";
5062
5063 InsertConfigNode(pDevices, pcszDevice, &pDev);
5064 InsertConfigNode(pDev, "0", &pInst);
5065 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
5066
5067 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
5068 InsertConfigNode(pInst, "Config", &pCfg);
5069 ULONG cVRamMBs;
5070 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
5071 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
5072 ULONG cMonitorCount;
5073 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
5074 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
5075
5076 BOOL f3DEnabled;
5077 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
5078 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
5079
5080 i_attachStatusDriver(pInst, DeviceType_Graphics3D);
5081
5082#ifdef VBOX_WITH_VMSVGA
5083 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
5084 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
5085 {
5086 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
5087 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
5088 {
5089 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
5090 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
5091 }
5092# ifdef VBOX_WITH_VMSVGA3D
5093 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
5094# else
5095 LogRel(("VMSVGA3d not available in this build!\n"));
5096# endif
5097
5098 InsertConfigInteger(pCfg, "VmSvga3", fForceVmSvga3);
5099 InsertConfigInteger(pCfg, "VmSvgaExposeLegacyVga", fExposeLegacyVga);
5100 }
5101#else
5102 RT_NOREF(enmGraphicsController, fForceVmSvga3, fExposeLegacyVga);
5103#endif /* !VBOX_WITH_VMSVGA */
5104
5105 /* Custom VESA mode list */
5106 unsigned cModes = 0;
5107 for (unsigned iMode = 1; iMode <= 16; ++iMode)
5108 {
5109 char szExtraDataKey[sizeof("CustomVideoModeXX")];
5110 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
5111 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
5112 if (bstr.isEmpty())
5113 break;
5114 InsertConfigString(pCfg, szExtraDataKey, bstr);
5115 ++cModes;
5116 }
5117 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
5118
5119 /* VESA height reduction */
5120 ULONG ulHeightReduction;
5121 IFramebuffer *pFramebuffer = NULL;
5122 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
5123 if (SUCCEEDED(hrc) && pFramebuffer)
5124 {
5125 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
5126 pFramebuffer->Release();
5127 pFramebuffer = NULL;
5128 }
5129 else
5130 {
5131 /* If framebuffer is not available, there is no height reduction. */
5132 ulHeightReduction = 0;
5133 }
5134 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
5135
5136 /*
5137 * BIOS logo
5138 */
5139 BOOL fFadeIn;
5140 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
5141 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
5142 BOOL fFadeOut;
5143 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
5144 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
5145 ULONG logoDisplayTime;
5146 hrc = ptrFirmwareSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
5147 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
5148 Bstr bstrLogoImagePath;
5149 hrc = ptrFirmwareSettings->COMGETTER(LogoImagePath)(bstrLogoImagePath.asOutParam()); H();
5150 InsertConfigString(pCfg, "LogoFile", bstrLogoImagePath);
5151
5152 /*
5153 * Boot menu
5154 */
5155 FirmwareBootMenuMode_T enmBootMenuMode;
5156 int iShowBootMenu;
5157 hrc = ptrFirmwareSettings->COMGETTER(BootMenuMode)(&enmBootMenuMode); H();
5158 switch (enmBootMenuMode)
5159 {
5160 case FirmwareBootMenuMode_Disabled: iShowBootMenu = 0; break;
5161 case FirmwareBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
5162 default: iShowBootMenu = 2; break;
5163 }
5164 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
5165
5166 /* Attach the display. */
5167 InsertConfigNode(pInst, "LUN#0", &pLunL0);
5168 InsertConfigString(pLunL0, "Driver", "MainDisplay");
5169 InsertConfigNode(pLunL0, "Config", &pCfg);
5170 }
5171 catch (ConfigError &x)
5172 {
5173 // InsertConfig threw something:
5174 return x.m_vrc;
5175 }
5176
5177 return VINF_SUCCESS;
5178}
5179
5180#undef H
5181#undef VRC
5182
5183#ifndef VBOX_WITH_EFI_IN_DD2
5184DECLHIDDEN(int) findEfiRom(IVirtualBox* vbox, PlatformArchitecture_T aPlatformArchitecture, FirmwareType_T aFirmwareType, Utf8Str *pEfiRomFile)
5185{
5186 Bstr aFilePath, empty;
5187 BOOL fPresent = FALSE;
5188 HRESULT hrc = vbox->CheckFirmwarePresent(aPlatformArchitecture, aFirmwareType, empty.raw(),
5189 empty.asOutParam(), aFilePath.asOutParam(), &fPresent);
5190 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
5191
5192 if (!fPresent)
5193 {
5194 LogRel(("Failed to find an EFI ROM file.\n"));
5195 return VERR_FILE_NOT_FOUND;
5196 }
5197
5198 *pEfiRomFile = Utf8Str(aFilePath);
5199
5200 return VINF_SUCCESS;
5201}
5202#endif
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