VirtualBox

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

Last change on this file since 104820 was 104779, checked in by vboxsync, 6 months ago

Main: Compile fix for using DevVGA.h if VBOX_WITH_VMSVGA is not defined. bugref:10693

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 220.0 KB
Line 
1/* $Id: ConsoleImplConfigCommon.cpp 104779 2024-05-24 13:42:47Z 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 AssertReturn(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
2663# else
2664# error "PORTME (VBOX_WITH_NETFLT)"
2665# endif
2666
2667# if defined(RT_OS_DARWIN) && defined(VBOX_WITH_VMNET)
2668 InsertConfigString(pLunL0, "Driver", "VMNet");
2669 InsertConfigNode(pLunL0, "Config", &pCfg);
2670 InsertConfigString(pCfg, "Trunk", pszTrunk);
2671 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
2672# else
2673 InsertConfigString(pLunL0, "Driver", "IntNet");
2674 InsertConfigNode(pLunL0, "Config", &pCfg);
2675 InsertConfigString(pCfg, "Trunk", pszTrunk);
2676 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
2677 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure);
2678 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
2679 char szNetwork[INTNET_MAX_NETWORK_NAME];
2680
2681# if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
2682 /*
2683 * 'pszTrunk' contains just the interface name required in ring-0, while 'pszBridgedIfName' contains
2684 * interface name + optional description. We must not pass any description to the VM as it can differ
2685 * for the same interface name, eg: "nge0 - ethernet" (GUI) vs "nge0" (VBoxManage).
2686 */
2687 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszTrunk);
2688# else
2689 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszBridgedIfName);
2690# endif
2691 InsertConfigString(pCfg, "Network", szNetwork);
2692 networkName = Bstr(szNetwork);
2693 trunkName = Bstr(pszTrunk);
2694 trunkType = Bstr(TRUNKTYPE_NETFLT);
2695
2696 BOOL fSharedMacOnWire = false;
2697 hrc = hostInterface->COMGETTER(Wireless)(&fSharedMacOnWire);
2698 if (FAILED(hrc))
2699 {
2700 LogRel(("NetworkAttachmentType_Bridged: COMGETTER(Wireless) failed, hrc (0x%x)\n", hrc));
2701 H();
2702 }
2703 else if (fSharedMacOnWire)
2704 {
2705 InsertConfigInteger(pCfg, "SharedMacOnWire", true);
2706 Log(("Set SharedMacOnWire\n"));
2707 }
2708
2709# if defined(RT_OS_SOLARIS)
2710# if 0 /* bird: this is a bit questionable and might cause more trouble than its worth. */
2711 /* Zone access restriction, don't allow snooping the global zone. */
2712 zoneid_t ZoneId = getzoneid();
2713 if (ZoneId != GLOBAL_ZONEID)
2714 {
2715 InsertConfigInteger(pCfg, "IgnoreAllPromisc", true);
2716 }
2717# endif
2718# endif
2719# endif
2720
2721#elif defined(RT_OS_WINDOWS) /* not defined NetFlt */
2722 /* NOTHING TO DO HERE */
2723#elif defined(RT_OS_LINUX)
2724/// @todo aleksey: is there anything to be done here?
2725#elif defined(RT_OS_FREEBSD)
2726/** @todo FreeBSD: Check out this later (HIF networking). */
2727#else
2728# error "Port me"
2729#endif
2730 break;
2731 }
2732
2733 case NetworkAttachmentType_Internal:
2734 {
2735 hrc = aNetworkAdapter->COMGETTER(InternalNetwork)(bstr.asOutParam()); H();
2736 if (!bstr.isEmpty())
2737 {
2738 InsertConfigString(pLunL0, "Driver", "IntNet");
2739 InsertConfigNode(pLunL0, "Config", &pCfg);
2740 InsertConfigString(pCfg, "Network", bstr);
2741 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
2742 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
2743 networkName = bstr;
2744 trunkType = Bstr(TRUNKTYPE_WHATEVER);
2745 }
2746 break;
2747 }
2748
2749 case NetworkAttachmentType_HostOnly:
2750 {
2751 InsertConfigString(pLunL0, "Driver", "IntNet");
2752 InsertConfigNode(pLunL0, "Config", &pCfg);
2753
2754 Bstr HostOnlyName;
2755 hrc = aNetworkAdapter->COMGETTER(HostOnlyInterface)(HostOnlyName.asOutParam());
2756 if (FAILED(hrc))
2757 {
2758 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(HostOnlyInterface) failed, hrc (0x%x)\n", hrc));
2759 H();
2760 }
2761
2762 Utf8Str HostOnlyNameUtf8(HostOnlyName);
2763 const char *pszHostOnlyName = HostOnlyNameUtf8.c_str();
2764#ifdef VBOX_WITH_VMNET
2765 /* Check if the matching host-only network has already been created. */
2766 Bstr bstrLowerIP, bstrUpperIP, bstrNetworkMask;
2767 BstrFmt bstrNetworkName("Legacy %s Network", pszHostOnlyName);
2768 ComPtr<IHostOnlyNetwork> hostOnlyNetwork;
2769 hrc = virtualBox->FindHostOnlyNetworkByName(bstrNetworkName.raw(), hostOnlyNetwork.asOutParam());
2770 if (FAILED(hrc))
2771 {
2772 /*
2773 * With VMNET there is no VBoxNetAdp to create vboxnetX adapters,
2774 * which means that the Host object won't be able to re-create
2775 * them from extra data. Go through existing DHCP/adapter config
2776 * to derive the parameters for the new network.
2777 */
2778 BstrFmt bstrOldNetworkName("HostInterfaceNetworking-%s", pszHostOnlyName);
2779 ComPtr<IDHCPServer> dhcpServer;
2780 hrc = virtualBox->FindDHCPServerByNetworkName(bstrOldNetworkName.raw(),
2781 dhcpServer.asOutParam());
2782 if (SUCCEEDED(hrc))
2783 {
2784 /* There is a DHCP server available for this network. */
2785 hrc = dhcpServer->COMGETTER(LowerIP)(bstrLowerIP.asOutParam());
2786 if (FAILED(hrc))
2787 {
2788 LogRel(("Console::i_configNetwork: COMGETTER(LowerIP) failed, hrc (%Rhrc)\n", hrc));
2789 H();
2790 }
2791 hrc = dhcpServer->COMGETTER(UpperIP)(bstrUpperIP.asOutParam());
2792 if (FAILED(hrc))
2793 {
2794 LogRel(("Console::i_configNetwork: COMGETTER(UpperIP) failed, hrc (%Rhrc)\n", hrc));
2795 H();
2796 }
2797 hrc = dhcpServer->COMGETTER(NetworkMask)(bstrNetworkMask.asOutParam());
2798 if (FAILED(hrc))
2799 {
2800 LogRel(("Console::i_configNetwork: COMGETTER(NetworkMask) failed, hrc (%Rhrc)\n", hrc));
2801 H();
2802 }
2803 }
2804 else
2805 {
2806 /* No DHCP server for this hostonly interface, let's look at extra data */
2807 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
2808 pszHostOnlyName).raw(),
2809 bstrLowerIP.asOutParam());
2810 if (SUCCEEDED(hrc) && !bstrLowerIP.isEmpty())
2811 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
2812 pszHostOnlyName).raw(),
2813 bstrNetworkMask.asOutParam());
2814
2815 }
2816 RTNETADDRIPV4 ipAddr, ipMask;
2817 vrc = bstrLowerIP.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrLowerIP).c_str(), &ipAddr);
2818 if (RT_FAILURE(vrc))
2819 {
2820 /* We failed to locate any valid config of this vboxnetX interface, assume defaults. */
2821 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing lower IP '%ls', using '%ls' instead.\n",
2822 bstrLowerIP.raw(), getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw()));
2823 bstrLowerIP = getDefaultIPv4Address(Bstr(pszHostOnlyName));
2824 bstrNetworkMask.setNull();
2825 bstrUpperIP.setNull();
2826 vrc = RTNetStrToIPv4Addr(Utf8Str(bstrLowerIP).c_str(), &ipAddr);
2827 AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("RTNetStrToIPv4Addr(%ls) failed, vrc=%Rrc\n", bstrLowerIP.raw(), vrc),
2828 VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
2829 }
2830 vrc = bstrNetworkMask.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrNetworkMask).c_str(), &ipMask);
2831 if (RT_FAILURE(vrc))
2832 {
2833 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing network mask '%ls', using '%s' instead.\n",
2834 bstrNetworkMask.raw(), VBOXNET_IPV4MASK_DEFAULT));
2835 bstrNetworkMask = VBOXNET_IPV4MASK_DEFAULT;
2836 vrc = RTNetStrToIPv4Addr(Utf8Str(bstrNetworkMask).c_str(), &ipMask);
2837 AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("RTNetStrToIPv4Addr(%ls) failed, vrc=%Rrc\n", bstrNetworkMask.raw(), vrc),
2838 VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
2839 }
2840 vrc = bstrUpperIP.isEmpty() ? VERR_MISSING : RTNetStrToIPv4Addr(Utf8Str(bstrUpperIP).c_str(), &ipAddr);
2841 if (RT_FAILURE(vrc))
2842 {
2843 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? */
2844 LogRel(("NetworkAttachmentType_HostOnly: Invalid or missing upper IP '%ls', using '%RTnaipv4' instead.\n",
2845 bstrUpperIP.raw(), ipAddr));
2846 bstrUpperIP = BstrFmt("%RTnaipv4", ipAddr);
2847 }
2848
2849 /* All parameters are set, create the new network. */
2850 hrc = virtualBox->CreateHostOnlyNetwork(bstrNetworkName.raw(), hostOnlyNetwork.asOutParam());
2851 if (FAILED(hrc))
2852 {
2853 LogRel(("NetworkAttachmentType_HostOnly: failed to create host-only network, hrc (0x%x)\n", hrc));
2854 H();
2855 }
2856 hrc = hostOnlyNetwork->COMSETTER(NetworkMask)(bstrNetworkMask.raw());
2857 if (FAILED(hrc))
2858 {
2859 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(NetworkMask) failed, hrc (0x%x)\n", hrc));
2860 H();
2861 }
2862 hrc = hostOnlyNetwork->COMSETTER(LowerIP)(bstrLowerIP.raw());
2863 if (FAILED(hrc))
2864 {
2865 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(LowerIP) failed, hrc (0x%x)\n", hrc));
2866 H();
2867 }
2868 hrc = hostOnlyNetwork->COMSETTER(UpperIP)(bstrUpperIP.raw());
2869 if (FAILED(hrc))
2870 {
2871 LogRel(("NetworkAttachmentType_HostOnly: COMSETTER(UpperIP) failed, hrc (0x%x)\n", hrc));
2872 H();
2873 }
2874 LogRel(("Console: created host-only network '%ls' with mask '%ls' and range '%ls'-'%ls'\n",
2875 bstrNetworkName.raw(), bstrNetworkMask.raw(), bstrLowerIP.raw(), bstrUpperIP.raw()));
2876 }
2877 else
2878 {
2879 /* The matching host-only network already exists. Tell the user to switch to it. */
2880 hrc = hostOnlyNetwork->COMGETTER(NetworkMask)(bstrNetworkMask.asOutParam());
2881 if (FAILED(hrc))
2882 {
2883 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(NetworkMask) failed, hrc (0x%x)\n", hrc));
2884 H();
2885 }
2886 hrc = hostOnlyNetwork->COMGETTER(LowerIP)(bstrLowerIP.asOutParam());
2887 if (FAILED(hrc))
2888 {
2889 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(LowerIP) failed, hrc (0x%x)\n", hrc));
2890 H();
2891 }
2892 hrc = hostOnlyNetwork->COMGETTER(UpperIP)(bstrUpperIP.asOutParam());
2893 if (FAILED(hrc))
2894 {
2895 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(UpperIP) failed, hrc (0x%x)\n", hrc));
2896 H();
2897 }
2898 }
2899 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
2900 N_("Host-only adapters are no longer supported!\n"
2901 "For your convenience a host-only network named '%ls' has been "
2902 "created with network mask '%ls' and IP address range '%ls' - '%ls'.\n"
2903 "To fix this problem, switch to 'Host-only Network' "
2904 "attachment type in the VM settings.\n"),
2905 bstrNetworkName.raw(), bstrNetworkMask.raw(),
2906 bstrLowerIP.raw(), bstrUpperIP.raw());
2907#endif /* VBOX_WITH_VMNET */
2908 ComPtr<IHostNetworkInterface> hostInterface;
2909 hrc = host->FindHostNetworkInterfaceByName(HostOnlyName.raw(),
2910 hostInterface.asOutParam());
2911 if (!SUCCEEDED(hrc))
2912 {
2913 LogRel(("NetworkAttachmentType_HostOnly: FindByName failed, vrc=%Rrc\n", vrc));
2914 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
2915 N_("Nonexistent host networking interface, name '%ls'"), HostOnlyName.raw());
2916 }
2917
2918 char szNetwork[INTNET_MAX_NETWORK_NAME];
2919 RTStrPrintf(szNetwork, sizeof(szNetwork), "HostInterfaceNetworking-%s", pszHostOnlyName);
2920
2921#if defined(RT_OS_WINDOWS)
2922# ifndef VBOX_WITH_NETFLT
2923 hrc = E_NOTIMPL;
2924 LogRel(("NetworkAttachmentType_HostOnly: Not Implemented\n"));
2925 H();
2926# else /* defined VBOX_WITH_NETFLT*/
2927 /** @todo r=bird: Put this in a function. */
2928
2929 HostNetworkInterfaceType_T eIfType;
2930 hrc = hostInterface->COMGETTER(InterfaceType)(&eIfType);
2931 if (FAILED(hrc))
2932 {
2933 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(InterfaceType) failed, hrc (0x%x)\n", hrc));
2934 H();
2935 }
2936
2937 if (eIfType != HostNetworkInterfaceType_HostOnly)
2938 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
2939 N_("Interface ('%ls') is not a Host-Only Adapter interface"),
2940 HostOnlyName.raw());
2941
2942 hrc = hostInterface->COMGETTER(Id)(bstr.asOutParam());
2943 if (FAILED(hrc))
2944 {
2945 LogRel(("NetworkAttachmentType_HostOnly: COMGETTER(Id) failed, hrc (0x%x)\n", hrc));
2946 H();
2947 }
2948 Guid hostIFGuid(bstr);
2949
2950 INetCfg *pNc;
2951 ComPtr<INetCfgComponent> pAdaptorComponent;
2952 LPWSTR pszApp;
2953 hrc = VBoxNetCfgWinQueryINetCfg(&pNc, FALSE, L"VirtualBox", 10, &pszApp);
2954 Assert(hrc == S_OK);
2955 if (hrc != S_OK)
2956 {
2957 LogRel(("NetworkAttachmentType_HostOnly: Failed to get NetCfg, hrc=%Rhrc (0x%x)\n", hrc, hrc));
2958 H();
2959 }
2960
2961 /* get the adapter's INetCfgComponent*/
2962 hrc = VBoxNetCfgWinGetComponentByGuid(pNc, &GUID_DEVCLASS_NET, (GUID*)hostIFGuid.raw(),
2963 pAdaptorComponent.asOutParam());
2964 if (hrc != S_OK)
2965 {
2966 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
2967 LogRel(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n", hrc, hrc));
2968 H();
2969 }
2970# define VBOX_WIN_BINDNAME_PREFIX "\\DEVICE\\"
2971 char szTrunkName[INTNET_MAX_TRUNK_NAME];
2972 bool fNdis6 = false;
2973 wchar_t * pwszHelpText;
2974 hrc = pAdaptorComponent->GetHelpText(&pwszHelpText);
2975 Assert(hrc == S_OK);
2976 if (hrc == S_OK)
2977 {
2978 Log(("help-text=%ls\n", pwszHelpText));
2979 if (!wcscmp(pwszHelpText, L"VirtualBox NDIS 6.0 Miniport Driver"))
2980 fNdis6 = true;
2981 CoTaskMemFree(pwszHelpText);
2982 }
2983 if (fNdis6)
2984 {
2985 strncpy(szTrunkName, pszHostOnlyName, sizeof(szTrunkName) - 1);
2986 Log(("trunk=%s\n", szTrunkName));
2987 }
2988 else
2989 {
2990 char *pszTrunkName = szTrunkName;
2991 wchar_t * pswzBindName;
2992 hrc = pAdaptorComponent->GetBindName(&pswzBindName);
2993 Assert(hrc == S_OK);
2994 if (hrc == S_OK)
2995 {
2996 int cwBindName = (int)wcslen(pswzBindName) + 1;
2997 int cbFullBindNamePrefix = sizeof(VBOX_WIN_BINDNAME_PREFIX);
2998 if (sizeof(szTrunkName) > cbFullBindNamePrefix + cwBindName)
2999 {
3000 strcpy(szTrunkName, VBOX_WIN_BINDNAME_PREFIX);
3001 pszTrunkName += cbFullBindNamePrefix-1;
3002 if (!WideCharToMultiByte(CP_ACP, 0, pswzBindName, cwBindName, pszTrunkName,
3003 sizeof(szTrunkName) - cbFullBindNamePrefix + 1, NULL, NULL))
3004 {
3005 DWORD err = GetLastError();
3006 hrc = HRESULT_FROM_WIN32(err);
3007 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: WideCharToMultiByte failed, hr=%Rhrc (0x%x) err=%u\n",
3008 hrc, hrc, err));
3009 }
3010 }
3011 else
3012 {
3013 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: insufficient szTrunkName buffer space\n"));
3014 /** @todo set appropriate error code */
3015 hrc = E_FAIL;
3016 }
3017
3018 if (hrc != S_OK)
3019 {
3020 AssertFailed();
3021 CoTaskMemFree(pswzBindName);
3022 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3023 H();
3024 }
3025 }
3026 else
3027 {
3028 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3029 AssertLogRelMsgFailed(("NetworkAttachmentType_HostOnly: VBoxNetCfgWinGetComponentByGuid failed, hrc=%Rhrc (0x%x)\n",
3030 hrc, hrc));
3031 H();
3032 }
3033
3034
3035 CoTaskMemFree(pswzBindName);
3036 }
3037
3038 trunkType = TRUNKTYPE_NETADP;
3039 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
3040
3041 pAdaptorComponent.setNull();
3042 /* release the pNc finally */
3043 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE /*fHasWriteLock*/);
3044
3045 const char *pszTrunk = szTrunkName;
3046
3047 InsertConfigString(pCfg, "Trunk", pszTrunk);
3048 InsertConfigString(pCfg, "Network", szNetwork);
3049 InsertConfigInteger(pCfg, "IgnoreConnectFailure", (uint64_t)fIgnoreConnectFailure); /** @todo why is this
3050 windows only?? */
3051 networkName = Bstr(szNetwork);
3052 trunkName = Bstr(pszTrunk);
3053# endif /* defined VBOX_WITH_NETFLT*/
3054#elif defined(RT_OS_DARWIN)
3055 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
3056 InsertConfigString(pCfg, "Network", szNetwork);
3057 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
3058 networkName = Bstr(szNetwork);
3059 trunkName = Bstr(pszHostOnlyName);
3060 trunkType = TRUNKTYPE_NETADP;
3061#else
3062 InsertConfigString(pCfg, "Trunk", pszHostOnlyName);
3063 InsertConfigString(pCfg, "Network", szNetwork);
3064 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetFlt);
3065 networkName = Bstr(szNetwork);
3066 trunkName = Bstr(pszHostOnlyName);
3067 trunkType = TRUNKTYPE_NETFLT;
3068#endif
3069 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
3070
3071#if !defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
3072
3073 Bstr tmpAddr, tmpMask;
3074
3075 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
3076 pszHostOnlyName).raw(),
3077 tmpAddr.asOutParam());
3078 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty())
3079 {
3080 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
3081 pszHostOnlyName).raw(),
3082 tmpMask.asOutParam());
3083 if (SUCCEEDED(hrc) && !tmpMask.isEmpty())
3084 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
3085 tmpMask.raw());
3086 else
3087 hrc = hostInterface->EnableStaticIPConfig(tmpAddr.raw(),
3088 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
3089 }
3090 else
3091 {
3092 /* Grab the IP number from the 'vboxnetX' instance number (see netif.h) */
3093 hrc = hostInterface->EnableStaticIPConfig(getDefaultIPv4Address(Bstr(pszHostOnlyName)).raw(),
3094 Bstr(VBOXNET_IPV4MASK_DEFAULT).raw());
3095 }
3096
3097 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
3098
3099 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
3100 pszHostOnlyName).raw(),
3101 tmpAddr.asOutParam());
3102 if (SUCCEEDED(hrc))
3103 hrc = virtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6NetMask", pszHostOnlyName).raw(),
3104 tmpMask.asOutParam());
3105 if (SUCCEEDED(hrc) && !tmpAddr.isEmpty() && !tmpMask.isEmpty())
3106 {
3107 hrc = hostInterface->EnableStaticIPConfigV6(tmpAddr.raw(),
3108 Utf8Str(tmpMask).toUInt32());
3109 ComAssertComRC(hrc); /** @todo r=bird: Why this isn't fatal? (H()) */
3110 }
3111#endif
3112 break;
3113 }
3114
3115 case NetworkAttachmentType_Generic:
3116 {
3117 hrc = aNetworkAdapter->COMGETTER(GenericDriver)(bstr.asOutParam()); H();
3118 SafeArray<BSTR> names;
3119 SafeArray<BSTR> values;
3120 hrc = aNetworkAdapter->GetProperties(Bstr().raw(),
3121 ComSafeArrayAsOutParam(names),
3122 ComSafeArrayAsOutParam(values)); H();
3123
3124 InsertConfigString(pLunL0, "Driver", bstr);
3125 InsertConfigNode(pLunL0, "Config", &pCfg);
3126 for (size_t ii = 0; ii < names.size(); ++ii)
3127 {
3128 if (values[ii] && *values[ii])
3129 {
3130 Utf8Str const strName(names[ii]);
3131 Utf8Str const strValue(values[ii]);
3132 InsertConfigString(pCfg, strName.c_str(), strValue);
3133 }
3134 }
3135 break;
3136 }
3137
3138 case NetworkAttachmentType_NATNetwork:
3139 {
3140 hrc = aNetworkAdapter->COMGETTER(NATNetwork)(bstr.asOutParam()); H();
3141 if (!bstr.isEmpty())
3142 {
3143 /** @todo add intnet prefix to separate namespaces, and add trunk if dealing with vboxnatX */
3144 InsertConfigString(pLunL0, "Driver", "IntNet");
3145 InsertConfigNode(pLunL0, "Config", &pCfg);
3146 InsertConfigString(pCfg, "Network", bstr);
3147 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone);
3148 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
3149 networkName = bstr;
3150 trunkType = Bstr(TRUNKTYPE_WHATEVER);
3151 }
3152 break;
3153 }
3154
3155#ifdef VBOX_WITH_CLOUD_NET
3156 case NetworkAttachmentType_Cloud:
3157 {
3158 static const char *s_pszCloudExtPackName = VBOX_PUEL_PRODUCT;
3159 /*
3160 * Cloud network attachments do not work wihout installed extpack.
3161 * Without extpack support they won't work either.
3162 */
3163# ifdef VBOX_WITH_EXTPACK
3164 if ( !mptrExtPackManager->i_isExtPackUsable(s_pszCloudExtPackName)
3165 && !mptrExtPackManager->i_isExtPackUsable("Oracle VM VirtualBox Extension Pack")) /* Legacy name -- see @bugref{10690}. */
3166# endif
3167 {
3168 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
3169 N_("Implementation of the cloud network attachment not found!\n"
3170 "To fix this problem, either install the '%s' or switch to "
3171 "another network attachment type in the VM settings."),
3172 s_pszCloudExtPackName);
3173 }
3174
3175 ComPtr<ICloudNetwork> network;
3176 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam()); H();
3177 hrc = pMachine->COMGETTER(Name)(mGateway.mTargetVM.asOutParam()); H();
3178 hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam()); H();
3179 hrc = generateKeys(mGateway);
3180 if (FAILED(hrc))
3181 {
3182 if (hrc == E_NOTIMPL)
3183 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
3184 N_("Failed to generate a key pair due to missing libssh\n"
3185 "To fix this problem, either build VirtualBox with libssh "
3186 "support or switch to another network attachment type in "
3187 "the VM settings."));
3188 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
3189 N_("Failed to generate a key pair due to libssh error!"));
3190 }
3191 hrc = startCloudGateway(virtualBox, network, mGateway);
3192 if (FAILED(hrc))
3193 {
3194 if (hrc == VBOX_E_OBJECT_NOT_FOUND)
3195 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3196 N_("Failed to start cloud gateway instance.\nCould not find suitable "
3197 "standard cloud images. Make sure you ran 'VBoxManage cloud network setup' "
3198 "with correct '--gateway-os-name' and '--gateway-os-version' parameters. "
3199 "Check VBoxSVC.log for actual values used to look up cloud images."));
3200 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3201 N_("Failed to start cloud gateway instance.\nMake sure you set up "
3202 "cloud networking properly with 'VBoxManage cloud network setup'. "
3203 "Check VBoxSVC.log for details."));
3204 }
3205 InsertConfigBytes(pDevCfg, "MAC", &mGateway.mCloudMacAddress, sizeof(mGateway.mCloudMacAddress));
3206 if (!bstr.isEmpty())
3207 {
3208 InsertConfigString(pLunL0, "Driver", "CloudTunnel");
3209 InsertConfigNode(pLunL0, "Config", &pCfg);
3210 InsertConfigPassword(pCfg, "SshKey", mGateway.mPrivateSshKey);
3211 InsertConfigString(pCfg, "PrimaryIP", mGateway.mCloudPublicIp);
3212 InsertConfigString(pCfg, "SecondaryIP", mGateway.mCloudSecondaryPublicIp);
3213 InsertConfigBytes(pCfg, "TargetMAC", &mGateway.mLocalMacAddress, sizeof(mGateway.mLocalMacAddress));
3214 hrc = i_configProxy(virtualBox, pCfg, "Primary", mGateway.mCloudPublicIp);
3215 if (FAILED(hrc))
3216 {
3217 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3218 N_("Failed to configure proxy for accessing cloud gateway instance via primary VNIC.\n"
3219 "Check VirtualBox.log for details."));
3220 }
3221 hrc = i_configProxy(virtualBox, pCfg, "Secondary", mGateway.mCloudSecondaryPublicIp);
3222 if (FAILED(hrc))
3223 {
3224 return pVMM->pfnVMR3SetError(pUVM, hrc, RT_SRC_POS,
3225 N_("Failed to configure proxy for accessing cloud gateway instance via secondary VNIC.\n"
3226 "Check VirtualBox.log for details."));
3227 }
3228 networkName = bstr;
3229 trunkType = Bstr(TRUNKTYPE_WHATEVER);
3230 }
3231 break;
3232 }
3233#endif /* VBOX_WITH_CLOUD_NET */
3234
3235#ifdef VBOX_WITH_VMNET
3236 case NetworkAttachmentType_HostOnlyNetwork:
3237 {
3238 Bstr bstrId, bstrNetMask, bstrLowerIP, bstrUpperIP;
3239 ComPtr<IHostOnlyNetwork> network;
3240 hrc = aNetworkAdapter->COMGETTER(HostOnlyNetwork)(bstr.asOutParam()); H();
3241 hrc = virtualBox->FindHostOnlyNetworkByName(bstr.raw(), network.asOutParam());
3242 if (FAILED(hrc))
3243 {
3244 LogRel(("NetworkAttachmentType_HostOnlyNetwork: FindByName failed, hrc (0x%x)\n", hrc));
3245 return pVMM->pfnVMR3SetError(pUVM, VERR_INTERNAL_ERROR, RT_SRC_POS,
3246 N_("Nonexistent host-only network '%ls'"), bstr.raw());
3247 }
3248 hrc = network->COMGETTER(Id)(bstrId.asOutParam()); H();
3249 hrc = network->COMGETTER(NetworkMask)(bstrNetMask.asOutParam()); H();
3250 hrc = network->COMGETTER(LowerIP)(bstrLowerIP.asOutParam()); H();
3251 hrc = network->COMGETTER(UpperIP)(bstrUpperIP.asOutParam()); H();
3252 if (!bstr.isEmpty())
3253 {
3254 InsertConfigString(pLunL0, "Driver", "VMNet");
3255 InsertConfigNode(pLunL0, "Config", &pCfg);
3256 // InsertConfigString(pCfg, "Trunk", bstr);
3257 // InsertConfigStringF(pCfg, "Network", "HostOnlyNetworking-%ls", bstr.raw());
3258 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_NetAdp);
3259 InsertConfigString(pCfg, "Id", bstrId);
3260 InsertConfigString(pCfg, "NetworkMask", bstrNetMask);
3261 InsertConfigString(pCfg, "LowerIP", bstrLowerIP);
3262 InsertConfigString(pCfg, "UpperIP", bstrUpperIP);
3263 // InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy);
3264 networkName.setNull(); // We do not want DHCP server on our network!
3265 // trunkType = Bstr(TRUNKTYPE_WHATEVER);
3266 }
3267 break;
3268 }
3269#endif /* VBOX_WITH_VMNET */
3270
3271 default:
3272 AssertMsgFailed(("should not get here!\n"));
3273 break;
3274 }
3275
3276 /*
3277 * Attempt to attach the driver.
3278 */
3279 switch (eAttachmentType)
3280 {
3281 case NetworkAttachmentType_Null:
3282 break;
3283
3284 case NetworkAttachmentType_Bridged:
3285 case NetworkAttachmentType_Internal:
3286 case NetworkAttachmentType_HostOnly:
3287#ifdef VBOX_WITH_VMNET
3288 case NetworkAttachmentType_HostOnlyNetwork:
3289#endif /* VBOX_WITH_VMNET */
3290 case NetworkAttachmentType_NAT:
3291 case NetworkAttachmentType_Generic:
3292 case NetworkAttachmentType_NATNetwork:
3293#ifdef VBOX_WITH_CLOUD_NET
3294 case NetworkAttachmentType_Cloud:
3295#endif /* VBOX_WITH_CLOUD_NET */
3296 {
3297 if (SUCCEEDED(hrc) && RT_SUCCESS(vrc))
3298 {
3299 if (fAttachDetach)
3300 {
3301 vrc = pVMM->pfnPDMR3DriverAttach(mpUVM, pszDevice, uInstance, uLun, 0 /*fFlags*/, NULL /* ppBase */);
3302 //AssertRC(vrc);
3303 }
3304
3305 {
3306 /** @todo pritesh: get the dhcp server name from the
3307 * previous network configuration and then stop the server
3308 * else it may conflict with the dhcp server running with
3309 * the current attachment type
3310 */
3311 /* Stop the hostonly DHCP Server */
3312 }
3313
3314 /*
3315 * NAT networks start their DHCP server theirself, see NATNetwork::Start()
3316 */
3317 if ( !networkName.isEmpty()
3318 && eAttachmentType != NetworkAttachmentType_NATNetwork)
3319 {
3320 /*
3321 * Until we implement service reference counters DHCP Server will be stopped
3322 * by DHCPServerRunner destructor.
3323 */
3324 ComPtr<IDHCPServer> dhcpServer;
3325 hrc = virtualBox->FindDHCPServerByNetworkName(networkName.raw(), dhcpServer.asOutParam());
3326 if (SUCCEEDED(hrc))
3327 {
3328 /* there is a DHCP server available for this network */
3329 BOOL fEnabledDhcp;
3330 hrc = dhcpServer->COMGETTER(Enabled)(&fEnabledDhcp);
3331 if (FAILED(hrc))
3332 {
3333 LogRel(("DHCP svr: COMGETTER(Enabled) failed, hrc (%Rhrc)\n", hrc));
3334 H();
3335 }
3336
3337 if (fEnabledDhcp)
3338 hrc = dhcpServer->Start(trunkName.raw(), trunkType.raw());
3339 }
3340 else
3341 hrc = S_OK;
3342 }
3343 }
3344
3345 break;
3346 }
3347
3348 default:
3349 AssertMsgFailed(("should not get here!\n"));
3350 break;
3351 }
3352
3353 meAttachmentType[uInstance] = eAttachmentType;
3354 }
3355 catch (ConfigError &x)
3356 {
3357 // InsertConfig threw something:
3358 return x.m_vrc;
3359 }
3360
3361#undef H
3362
3363 return VINF_SUCCESS;
3364}
3365
3366
3367/**
3368 * Configures the serial port at the given CFGM node with the supplied parameters.
3369 *
3370 * @returns VBox status code.
3371 * @param pInst The instance CFGM node.
3372 * @param ePortMode The port mode to sue.
3373 * @param pszPath The serial port path.
3374 * @param fServer Flag whether the port should act as a server
3375 * for the pipe and TCP mode or connect as a client.
3376 */
3377int Console::i_configSerialPort(PCFGMNODE pInst, PortMode_T ePortMode, const char *pszPath, bool fServer)
3378{
3379 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
3380 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
3381 PCFGMNODE pLunL1Cfg = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/Config */
3382
3383 try
3384 {
3385 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3386 if (ePortMode == PortMode_HostPipe)
3387 {
3388 InsertConfigString(pLunL0, "Driver", "Char");
3389 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3390 InsertConfigString(pLunL1, "Driver", "NamedPipe");
3391 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
3392 InsertConfigString(pLunL1Cfg, "Location", pszPath);
3393 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
3394 }
3395 else if (ePortMode == PortMode_HostDevice)
3396 {
3397 InsertConfigString(pLunL0, "Driver", "Host Serial");
3398 InsertConfigNode(pLunL0, "Config", &pLunL1);
3399 InsertConfigString(pLunL1, "DevicePath", pszPath);
3400 }
3401 else if (ePortMode == PortMode_TCP)
3402 {
3403 InsertConfigString(pLunL0, "Driver", "Char");
3404 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3405 InsertConfigString(pLunL1, "Driver", "TCP");
3406 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
3407 InsertConfigString(pLunL1Cfg, "Location", pszPath);
3408 InsertConfigInteger(pLunL1Cfg, "IsServer", fServer);
3409 }
3410 else if (ePortMode == PortMode_RawFile)
3411 {
3412 InsertConfigString(pLunL0, "Driver", "Char");
3413 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
3414 InsertConfigString(pLunL1, "Driver", "RawFile");
3415 InsertConfigNode(pLunL1, "Config", &pLunL1Cfg);
3416 InsertConfigString(pLunL1Cfg, "Location", pszPath);
3417 }
3418 }
3419 catch (ConfigError &x)
3420 {
3421 /* InsertConfig threw something */
3422 return x.m_vrc;
3423 }
3424
3425 return VINF_SUCCESS;
3426}
3427
3428
3429#define H() AssertLogRelMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR)
3430#define VRC() AssertLogRelMsgReturn(RT_SUCCESS(vrc), ("vrc=%Rrc\n", vrc), vrc)
3431
3432int Console::i_configPdm(ComPtr<IMachine> pMachine, PCVMMR3VTABLE pVMM, PUVM pUVM, PCFGMNODE pRoot)
3433{
3434 PCFGMNODE pPDM;
3435 PCFGMNODE pNode;
3436 PCFGMNODE pMod;
3437 InsertConfigNode(pRoot, "PDM", &pPDM);
3438 InsertConfigNode(pPDM, "Devices", &pNode);
3439 InsertConfigNode(pPDM, "Drivers", &pNode);
3440 InsertConfigNode(pNode, "VBoxC", &pMod);
3441#ifdef VBOX_WITH_XPCOM
3442 // VBoxC is located in the components subdirectory
3443 char szPathVBoxC[RTPATH_MAX];
3444 int vrc = RTPathAppPrivateArch(szPathVBoxC, RTPATH_MAX); VRC();
3445 vrc = RTPathAppend(szPathVBoxC, RTPATH_MAX, "/components/VBoxC"); VRC();
3446 InsertConfigString(pMod, "Path", szPathVBoxC);
3447#else
3448 InsertConfigString(pMod, "Path", "VBoxC");
3449#endif
3450
3451
3452 /*
3453 * Block cache settings.
3454 */
3455 PCFGMNODE pPDMBlkCache;
3456 InsertConfigNode(pPDM, "BlkCache", &pPDMBlkCache);
3457
3458 /* I/O cache size */
3459 ULONG ioCacheSize = 5;
3460 HRESULT hrc = pMachine->COMGETTER(IOCacheSize)(&ioCacheSize); H();
3461 InsertConfigInteger(pPDMBlkCache, "CacheSize", ioCacheSize * _1M);
3462
3463 /*
3464 * Bandwidth groups.
3465 */
3466 ComPtr<IBandwidthControl> bwCtrl;
3467
3468 hrc = pMachine->COMGETTER(BandwidthControl)(bwCtrl.asOutParam()); H();
3469
3470 com::SafeIfaceArray<IBandwidthGroup> bwGroups;
3471 hrc = bwCtrl->GetAllBandwidthGroups(ComSafeArrayAsOutParam(bwGroups)); H();
3472
3473 PCFGMNODE pAc;
3474 InsertConfigNode(pPDM, "AsyncCompletion", &pAc);
3475 PCFGMNODE pAcFile;
3476 InsertConfigNode(pAc, "File", &pAcFile);
3477 PCFGMNODE pAcFileBwGroups;
3478 InsertConfigNode(pAcFile, "BwGroups", &pAcFileBwGroups);
3479#ifdef VBOX_WITH_NETSHAPER
3480 PCFGMNODE pNetworkShaper;
3481 InsertConfigNode(pPDM, "NetworkShaper", &pNetworkShaper);
3482 PCFGMNODE pNetworkBwGroups;
3483 InsertConfigNode(pNetworkShaper, "BwGroups", &pNetworkBwGroups);
3484#endif /* VBOX_WITH_NETSHAPER */
3485
3486 for (size_t i = 0; i < bwGroups.size(); i++)
3487 {
3488 Bstr strName;
3489 hrc = bwGroups[i]->COMGETTER(Name)(strName.asOutParam()); H();
3490 if (strName.isEmpty())
3491 return pVMM->pfnVMR3SetError(pUVM, VERR_CFGM_NO_NODE, RT_SRC_POS, N_("No bandwidth group name specified"));
3492
3493 BandwidthGroupType_T enmType = BandwidthGroupType_Null;
3494 hrc = bwGroups[i]->COMGETTER(Type)(&enmType); H();
3495 LONG64 cMaxBytesPerSec = 0;
3496 hrc = bwGroups[i]->COMGETTER(MaxBytesPerSec)(&cMaxBytesPerSec); H();
3497
3498 if (enmType == BandwidthGroupType_Disk)
3499 {
3500 PCFGMNODE pBwGroup;
3501 InsertConfigNode(pAcFileBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
3502 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
3503 InsertConfigInteger(pBwGroup, "Start", cMaxBytesPerSec);
3504 InsertConfigInteger(pBwGroup, "Step", 0);
3505 }
3506#ifdef VBOX_WITH_NETSHAPER
3507 else if (enmType == BandwidthGroupType_Network)
3508 {
3509 /* Network bandwidth groups. */
3510 PCFGMNODE pBwGroup;
3511 InsertConfigNode(pNetworkBwGroups, Utf8Str(strName).c_str(), &pBwGroup);
3512 InsertConfigInteger(pBwGroup, "Max", cMaxBytesPerSec);
3513 }
3514#endif /* VBOX_WITH_NETSHAPER */
3515 }
3516
3517 /** @todo r=aeichner Looks like this setting is completely unused in VMM/PDM. */
3518 BOOL fAllowTracingToAccessVM;
3519 hrc = pMachine->COMGETTER(AllowTracingToAccessVM)(&fAllowTracingToAccessVM); H();
3520 if (fAllowTracingToAccessVM)
3521 InsertConfigInteger(pPDM, "AllowTracingToAccessVM", 1);
3522
3523 return VINF_SUCCESS;
3524}
3525
3526
3527int Console::i_configAudioCtrl(ComPtr<IVirtualBox> pVBox, ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices,
3528 bool fOsXGuest, bool *pfAudioEnabled)
3529{
3530 Utf8Str strTmp;
3531 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
3532 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
3533 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
3534 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
3535
3536 /*
3537 * AC'97 ICH / SoundBlaster16 audio / Intel HD Audio.
3538 */
3539 ComPtr<IAudioSettings> audioSettings;
3540 HRESULT hrc = pMachine->COMGETTER(AudioSettings)(audioSettings.asOutParam()); H();
3541
3542 BOOL fAudioEnabled = FALSE;
3543 ComPtr<IAudioAdapter> audioAdapter;
3544 hrc = audioSettings->COMGETTER(Adapter)(audioAdapter.asOutParam()); H();
3545 if (audioAdapter)
3546 {
3547 hrc = audioAdapter->COMGETTER(Enabled)(&fAudioEnabled); H();
3548 }
3549
3550 if (fAudioEnabled)
3551 {
3552 *pfAudioEnabled = true;
3553
3554 AudioControllerType_T enmAudioController;
3555 hrc = audioAdapter->COMGETTER(AudioController)(&enmAudioController); H();
3556 AudioCodecType_T enmAudioCodec;
3557 hrc = audioAdapter->COMGETTER(AudioCodec)(&enmAudioCodec); H();
3558
3559 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Device/TimerHz", &strTmp);
3560 const uint64_t uTimerHz = strTmp.toUInt64();
3561
3562 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeInMs", &strTmp);
3563 const uint64_t uBufSizeInMs = strTmp.toUInt64();
3564
3565 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Device/BufSizeOutMs", &strTmp);
3566 const uint64_t uBufSizeOutMs = strTmp.toUInt64();
3567
3568 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Debug/Enabled", &strTmp);
3569 const bool fDebugEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3570
3571 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Debug/Level", &strTmp);
3572 const uint32_t uDebugLevel = strTmp.toUInt32();
3573
3574 Utf8Str strDebugPathOut;
3575 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/Debug/PathOut", &strDebugPathOut);
3576
3577#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3578 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/VaKit/Enabled", &strTmp); /* Deprecated; do not use! */
3579 if (strTmp.isEmpty())
3580 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/ValKit/Enabled", &strTmp);
3581 /* Whether the Validation Kit audio backend runs as the primary backend.
3582 * Can also be used with VBox release builds. */
3583 const bool fValKitEnabled = strTmp.equalsIgnoreCase("true") || strTmp.equalsIgnoreCase("1");
3584#endif
3585 /** @todo Implement an audio device class, similar to the audio backend class, to construct the common stuff
3586 * without duplicating (more) code. */
3587
3588 const char *pszAudioDevice;
3589 switch (enmAudioController)
3590 {
3591 case AudioControllerType_AC97:
3592 {
3593 /* ICH AC'97. */
3594 pszAudioDevice = "ichac97";
3595
3596 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3597 InsertConfigNode(pDev, "0", &pInst);
3598 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3599 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();
3600 InsertConfigNode(pInst, "Config", &pCfg);
3601 switch (enmAudioCodec)
3602 {
3603 case AudioCodecType_STAC9700:
3604 InsertConfigString(pCfg, "Codec", "STAC9700");
3605 break;
3606 case AudioCodecType_AD1980:
3607 InsertConfigString(pCfg, "Codec", "AD1980");
3608 break;
3609 default: AssertFailedBreak();
3610 }
3611 if (uTimerHz)
3612 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3613 if (uBufSizeInMs)
3614 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);
3615 if (uBufSizeOutMs)
3616 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);
3617 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3618 if (strDebugPathOut.isNotEmpty())
3619 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3620 break;
3621 }
3622 case AudioControllerType_SB16:
3623 {
3624 /* Legacy SoundBlaster16. */
3625 pszAudioDevice = "sb16";
3626
3627 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3628 InsertConfigNode(pDev, "0", &pInst);
3629 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3630 InsertConfigNode(pInst, "Config", &pCfg);
3631 InsertConfigInteger(pCfg, "IRQ", 5);
3632 InsertConfigInteger(pCfg, "DMA", 1);
3633 InsertConfigInteger(pCfg, "DMA16", 5);
3634 InsertConfigInteger(pCfg, "Port", 0x220);
3635 InsertConfigInteger(pCfg, "Version", 0x0405);
3636 if (uTimerHz)
3637 InsertConfigInteger(pCfg, "TimerHz", uTimerHz);
3638 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3639 if (strDebugPathOut.isNotEmpty())
3640 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3641 break;
3642 }
3643 case AudioControllerType_HDA:
3644 {
3645 /* Intel HD Audio. */
3646 pszAudioDevice = "hda";
3647
3648 InsertConfigNode(pDevices, pszAudioDevice, &pDev);
3649 InsertConfigNode(pDev, "0", &pInst);
3650 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3651 hrc = pBusMgr->assignPCIDevice(pszAudioDevice, pInst); H();
3652 InsertConfigNode(pInst, "Config", &pCfg);
3653 if (uBufSizeInMs)
3654 InsertConfigInteger(pCfg, "BufSizeInMs", uBufSizeInMs);
3655 if (uBufSizeOutMs)
3656 InsertConfigInteger(pCfg, "BufSizeOutMs", uBufSizeOutMs);
3657 InsertConfigInteger(pCfg, "DebugEnabled", fDebugEnabled);
3658 if (strDebugPathOut.isNotEmpty())
3659 InsertConfigString(pCfg, "DebugPathOut", strDebugPathOut);
3660
3661 /* macOS guests uses a different HDA variant to make 10.14+ (or maybe 10.13?) recognize the device. */
3662 if (fOsXGuest)
3663 InsertConfigString(pCfg, "DeviceName", "Intel Sunrise Point");
3664 break;
3665 }
3666 default:
3667 pszAudioDevice = "oops";
3668 AssertFailedBreak();
3669 }
3670
3671 PCFGMNODE pCfgAudioAdapter = NULL;
3672 InsertConfigNode(pInst, "AudioConfig", &pCfgAudioAdapter);
3673 SafeArray<BSTR> audioProps;
3674 hrc = audioAdapter->COMGETTER(PropertiesList)(ComSafeArrayAsOutParam(audioProps)); H();
3675
3676 std::list<Utf8Str> audioPropertyNamesList;
3677 for (size_t i = 0; i < audioProps.size(); ++i)
3678 {
3679 Bstr bstrValue;
3680 audioPropertyNamesList.push_back(Utf8Str(audioProps[i]));
3681 hrc = audioAdapter->GetProperty(audioProps[i], bstrValue.asOutParam());
3682 Utf8Str strKey(audioProps[i]);
3683 InsertConfigString(pCfgAudioAdapter, strKey.c_str(), bstrValue);
3684 }
3685
3686 /*
3687 * The audio driver.
3688 */
3689 const char *pszAudioDriver = NULL;
3690#ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3691 if (fValKitEnabled)
3692 {
3693 pszAudioDriver = "ValidationKitAudio";
3694 LogRel(("Audio: ValidationKit driver active\n"));
3695 }
3696#endif
3697 /* If nothing else was selected before, ask the API. */
3698 if (pszAudioDriver == NULL)
3699 {
3700 AudioDriverType_T enmAudioDriver;
3701 hrc = audioAdapter->COMGETTER(AudioDriver)(&enmAudioDriver); H();
3702
3703 /* The "Default" audio driver needs special treatment, as we need to figure out which driver to use
3704 * by default on the current platform. */
3705 bool const fUseDefaultDrv = enmAudioDriver == AudioDriverType_Default;
3706
3707 AudioDriverType_T const enmDefaultAudioDriver = settings::MachineConfigFile::getHostDefaultAudioDriver();
3708
3709 if (fUseDefaultDrv)
3710 {
3711 enmAudioDriver = enmDefaultAudioDriver;
3712 if (enmAudioDriver == AudioDriverType_Null)
3713 LogRel(("Audio: Warning: No default driver detected for current platform -- defaulting to Null audio backend\n"));
3714 }
3715
3716 switch (enmAudioDriver)
3717 {
3718 case AudioDriverType_Default: /* Can't happen, but handle it anyway. */
3719 RT_FALL_THROUGH();
3720 case AudioDriverType_Null:
3721 pszAudioDriver = "NullAudio";
3722 break;
3723#ifdef RT_OS_WINDOWS
3724# ifdef VBOX_WITH_WINMM
3725 case AudioDriverType_WinMM:
3726# error "Port WinMM audio backend!" /** @todo Still needed? */
3727 break;
3728# endif
3729 case AudioDriverType_DirectSound:
3730 /* Use the Windows Audio Session (WAS) API rather than Direct Sound on Windows
3731 versions we've tested it on (currently W7+). Since Vista, Direct Sound has
3732 been emulated on top of WAS according to the docs, so better use WAS directly.
3733
3734 Set extradata value "VBoxInternal2/Audio/WindowsDrv" "dsound" to no use WasAPI.
3735
3736 Keep this hack for backwards compatibility (introduced < 7.0).
3737 */
3738 GetExtraDataBoth(pVBox, pMachine, "VBoxInternal2/Audio/WindowsDrv", &strTmp); H();
3739 if ( enmDefaultAudioDriver == AudioDriverType_WAS
3740 && ( strTmp.isEmpty()
3741 || strTmp.equalsIgnoreCase("was")
3742 || strTmp.equalsIgnoreCase("wasapi")) )
3743 {
3744 /* Nothing to do here, fall through to WAS driver. */
3745 }
3746 else
3747 {
3748 pszAudioDriver = "DSoundAudio";
3749 break;
3750 }
3751 RT_FALL_THROUGH();
3752 case AudioDriverType_WAS:
3753 if (enmDefaultAudioDriver == AudioDriverType_WAS) /* WAS supported? */
3754 pszAudioDriver = "HostAudioWas";
3755 else if (enmDefaultAudioDriver == AudioDriverType_DirectSound)
3756 {
3757 LogRel(("Audio: Warning: Windows Audio Session (WAS) not supported, defaulting to DirectSound backend\n"));
3758 pszAudioDriver = "DSoundAudio";
3759 }
3760 break;
3761#endif /* RT_OS_WINDOWS */
3762#ifdef RT_OS_SOLARIS
3763 case AudioDriverType_SolAudio:
3764 /* Should not happen, as the Solaris Audio backend is not around anymore.
3765 * Remove this sometime later. */
3766 LogRel(("Audio: Warning: Solaris Audio is deprecated, please switch to OSS!\n"));
3767 LogRel(("Audio: Automatically setting host audio backend to OSS\n"));
3768
3769 /* Manually set backend to OSS for now. */
3770 pszAudioDriver = "OSSAudio";
3771 break;
3772#endif
3773#ifdef VBOX_WITH_AUDIO_OSS
3774 case AudioDriverType_OSS:
3775 pszAudioDriver = "OSSAudio";
3776 break;
3777#endif
3778#ifdef VBOX_WITH_AUDIO_ALSA
3779 case AudioDriverType_ALSA:
3780 pszAudioDriver = "ALSAAudio";
3781 break;
3782#endif
3783#ifdef VBOX_WITH_AUDIO_PULSE
3784 case AudioDriverType_Pulse:
3785 pszAudioDriver = "PulseAudio";
3786 break;
3787#endif
3788#ifdef RT_OS_DARWIN
3789 case AudioDriverType_CoreAudio:
3790 pszAudioDriver = "CoreAudio";
3791 break;
3792#endif
3793 default:
3794 pszAudioDriver = "oops";
3795 AssertFailedBreak();
3796 }
3797
3798 if (fUseDefaultDrv)
3799 LogRel(("Audio: Detected default audio driver type is '%s'\n", pszAudioDriver));
3800 }
3801
3802 BOOL fAudioEnabledIn = FALSE;
3803 hrc = audioAdapter->COMGETTER(EnabledIn)(&fAudioEnabledIn); H();
3804 BOOL fAudioEnabledOut = FALSE;
3805 hrc = audioAdapter->COMGETTER(EnabledOut)(&fAudioEnabledOut); H();
3806
3807 unsigned idxAudioLun = 0;
3808
3809 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3810 i_configAudioDriver(pVBox, pMachine, pLunL0, pszAudioDriver, !!fAudioEnabledIn, !!fAudioEnabledOut);
3811 idxAudioLun++;
3812
3813#ifdef VBOX_WITH_AUDIO_VRDE
3814 /* Insert dummy audio driver to have the LUN configured. */
3815 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3816 InsertConfigString(pLunL0, "Driver", "AUDIO");
3817 {
3818 AudioDriverCfg DrvCfgVRDE(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVRDE",
3819 !!fAudioEnabledIn, !!fAudioEnabledOut);
3820 int vrc = mAudioVRDE->InitializeConfig(&DrvCfgVRDE);
3821 AssertRCStmt(vrc, throw ConfigError(__FUNCTION__, vrc, "mAudioVRDE->InitializeConfig failed"));
3822 }
3823 idxAudioLun++;
3824#endif
3825
3826#ifdef VBOX_WITH_AUDIO_RECORDING
3827 /* Insert dummy audio driver to have the LUN configured. */
3828 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3829 InsertConfigString(pLunL0, "Driver", "AUDIO");
3830 {
3831 AudioDriverCfg DrvCfgVideoRec(pszAudioDevice, 0 /* Instance */, idxAudioLun, "AudioVideoRec",
3832 false /*a_fEnabledIn*/, true /*a_fEnabledOut*/);
3833 int vrc = mRecording.mAudioRec->InitializeConfig(&DrvCfgVideoRec);
3834 AssertRCStmt(vrc, throw ConfigError(__FUNCTION__, vrc, "Recording.mAudioRec->InitializeConfig failed"));
3835 }
3836 idxAudioLun++;
3837#endif
3838
3839 if (fDebugEnabled)
3840 {
3841#ifdef VBOX_WITH_AUDIO_DEBUG
3842# ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3843 /*
3844 * When both, ValidationKit and Debug mode (for audio) are enabled,
3845 * skip configuring the Debug audio driver, as both modes can
3846 * mess with the audio data and would lead to side effects.
3847 *
3848 * The ValidationKit audio driver has precedence over the Debug audio driver.
3849 *
3850 * This also can (and will) be used in VBox release builds.
3851 */
3852 if (fValKitEnabled)
3853 {
3854 LogRel(("Audio: Warning: ValidationKit running and Debug mode enabled -- disabling Debug driver\n"));
3855 }
3856 else /* Debug mode active -- run both (nice for catching errors / doing development). */
3857 {
3858 /*
3859 * The ValidationKit backend.
3860 */
3861 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3862 i_configAudioDriver(pVBox, pMachine, pLunL0, "ValidationKitAudio",
3863 !!fAudioEnabledIn, !!fAudioEnabledOut);
3864 idxAudioLun++;
3865# endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3866 /*
3867 * The Debug audio backend.
3868 */
3869 InsertConfigNodeF(pInst, &pLunL0, "LUN#%u", idxAudioLun);
3870 i_configAudioDriver(pVBox, pMachine, pLunL0, "DebugAudio",
3871 !!fAudioEnabledIn, !!fAudioEnabledOut);
3872 idxAudioLun++;
3873# ifdef VBOX_WITH_AUDIO_VALIDATIONKIT
3874 }
3875# endif /* VBOX_WITH_AUDIO_VALIDATIONKIT */
3876#endif /* VBOX_WITH_AUDIO_DEBUG */
3877
3878 /*
3879 * Tweak the logging groups.
3880 */
3881 Utf8Str strGroups("drv_audio.e.l.l2.l3.f"
3882 " audio_mixer.e.l.l2.l3.f"
3883 " dev_hda_codec.e.l.l2.l3.f"
3884 " dev_hda.e.l.l2.l3.f"
3885 " dev_ac97.e.l.l2.l3.f"
3886 " dev_sb16.e.l.l2.l3.f");
3887
3888 LogRel(("Audio: Debug level set to %RU32\n", uDebugLevel));
3889
3890 switch (uDebugLevel)
3891 {
3892 case 0:
3893 strGroups += " drv_host_audio.e.l.l2.l3.f";
3894 break;
3895 case 1:
3896 RT_FALL_THROUGH();
3897 case 2:
3898 RT_FALL_THROUGH();
3899 case 3:
3900 strGroups += " drv_host_audio.e.l.l2.l3.f+audio_test.e.l.l2.l3.f";
3901 break;
3902 case 4:
3903 RT_FALL_THROUGH();
3904 default:
3905 strGroups += " drv_host_audio.e.l.l2.l3.l4.f+audio_test.e.l.l2.l3.l4.f";
3906 break;
3907 }
3908
3909 int vrc = RTLogGroupSettings(RTLogRelGetDefaultInstance(), strGroups.c_str());
3910 if (RT_FAILURE(vrc))
3911 LogRel(("Audio: Setting debug logging failed, vrc=%Rrc\n", vrc));
3912 }
3913 }
3914
3915 return VINF_SUCCESS;
3916}
3917
3918
3919int Console::i_configVmmDev(ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCFGMNODE pDevices, bool fMmioReq)
3920{
3921 VMMDev *pVMMDev = m_pVMMDev; Assert(pVMMDev);
3922
3923 int vrc = VINF_SUCCESS;
3924 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
3925 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
3926 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
3927 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
3928
3929 /*
3930 * VMM Device
3931 */
3932 InsertConfigNode(pDevices, "VMMDev", &pDev);
3933 InsertConfigNode(pDev, "0", &pInst);
3934 InsertConfigNode(pInst, "Config", &pCfg);
3935 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
3936 HRESULT hrc = pBusMgr->assignPCIDevice("VMMDev", pInst); H();
3937 if (fMmioReq)
3938 InsertConfigInteger(pCfg, "MmioReq", 1);
3939
3940 Bstr hwVersion;
3941 hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
3942 if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
3943 InsertConfigInteger(pCfg, "HeapEnabled", 0);
3944 Bstr snapshotFolder;
3945 hrc = pMachine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam()); H();
3946 InsertConfigString(pCfg, "GuestCoreDumpDir", snapshotFolder);
3947
3948 /* the VMM device's Main driver */
3949 InsertConfigNode(pInst, "LUN#0", &pLunL0);
3950 InsertConfigString(pLunL0, "Driver", "HGCM");
3951 InsertConfigNode(pLunL0, "Config", &pCfg);
3952
3953 /*
3954 * Attach the status driver.
3955 */
3956 i_attachStatusDriver(pInst, DeviceType_SharedFolder);
3957
3958#ifdef VBOX_WITH_SHARED_CLIPBOARD
3959 /*
3960 * Shared Clipboard.
3961 */
3962 {
3963 ClipboardMode_T enmClipboardMode = ClipboardMode_Disabled;
3964 hrc = pMachine->COMGETTER(ClipboardMode)(&enmClipboardMode); H();
3965# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3966 BOOL fFileTransfersEnabled;
3967 hrc = pMachine->COMGETTER(ClipboardFileTransfersEnabled)(&fFileTransfersEnabled); H();
3968#endif
3969
3970 /* Load the service */
3971 vrc = pVMMDev->hgcmLoadService("VBoxSharedClipboard", "VBoxSharedClipboard");
3972 if (RT_SUCCESS(vrc))
3973 {
3974 LogRel(("Shared Clipboard: Service loaded\n"));
3975
3976 /* Set initial clipboard mode. */
3977 vrc = i_changeClipboardMode(enmClipboardMode);
3978 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial clipboard mode (%d): vrc=%Rrc\n",
3979 enmClipboardMode, vrc));
3980
3981 /* Setup the service. */
3982 VBOXHGCMSVCPARM parm;
3983 HGCMSvcSetU32(&parm, !i_useHostClipboard());
3984 vrc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_HEADLESS, 1, &parm);
3985 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial headless mode (%RTbool): vrc=%Rrc\n",
3986 !i_useHostClipboard(), vrc));
3987
3988# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
3989 vrc = i_changeClipboardFileTransferMode(RT_BOOL(fFileTransfersEnabled));
3990 AssertLogRelMsg(RT_SUCCESS(vrc), ("Shared Clipboard: Failed to set initial file transfer mode (%u): vrc=%Rrc\n",
3991 fFileTransfersEnabled, vrc));
3992# endif
3993 GuestShCl::createInstance(this /* pConsole */);
3994 vrc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtShCl, "VBoxSharedClipboard",
3995 &GuestShCl::hgcmDispatcher,
3996 GuestShClInst());
3997 if (RT_FAILURE(vrc))
3998 Log(("Cannot register VBoxSharedClipboard extension, vrc=%Rrc\n", vrc));
3999 }
4000 else
4001 LogRel(("Shared Clipboard: Not available, vrc=%Rrc\n", vrc));
4002 vrc = VINF_SUCCESS; /* None of the potential failures above are fatal. */
4003 }
4004#endif /* VBOX_WITH_SHARED_CLIPBOARD */
4005
4006 /*
4007 * HGCM HostChannel.
4008 */
4009 {
4010 Bstr value;
4011 hrc = pMachine->GetExtraData(Bstr("HGCM/HostChannel").raw(),
4012 value.asOutParam());
4013
4014 if ( hrc == S_OK
4015 && value == "1")
4016 {
4017 vrc = pVMMDev->hgcmLoadService("VBoxHostChannel", "VBoxHostChannel");
4018 if (RT_FAILURE(vrc))
4019 {
4020 LogRel(("VBoxHostChannel is not available, vrc=%Rrc\n", vrc));
4021 /* That is not a fatal failure. */
4022 vrc = VINF_SUCCESS;
4023 }
4024 }
4025 }
4026
4027#ifdef VBOX_WITH_DRAG_AND_DROP
4028 /*
4029 * Drag and Drop.
4030 */
4031 {
4032 DnDMode_T enmMode = DnDMode_Disabled;
4033 hrc = pMachine->COMGETTER(DnDMode)(&enmMode); H();
4034
4035 /* Load the service */
4036 vrc = pVMMDev->hgcmLoadService("VBoxDragAndDropSvc", "VBoxDragAndDropSvc");
4037 if (RT_FAILURE(vrc))
4038 {
4039 LogRel(("Drag and drop service is not available, vrc=%Rrc\n", vrc));
4040 /* That is not a fatal failure. */
4041 vrc = VINF_SUCCESS;
4042 }
4043 else
4044 {
4045 vrc = HGCMHostRegisterServiceExtension(&m_hHgcmSvcExtDragAndDrop, "VBoxDragAndDropSvc",
4046 &GuestDnD::notifyDnDDispatcher,
4047 GuestDnDInst());
4048 if (RT_FAILURE(vrc))
4049 Log(("Cannot register VBoxDragAndDropSvc extension, vrc=%Rrc\n", vrc));
4050 else
4051 {
4052 LogRel(("Drag and drop service loaded\n"));
4053 vrc = i_changeDnDMode(enmMode);
4054 }
4055 }
4056 }
4057#endif /* VBOX_WITH_DRAG_AND_DROP */
4058
4059 return vrc;
4060}
4061
4062
4063int Console::i_configUsb(ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCFGMNODE pRoot, PCFGMNODE pDevices,
4064 KeyboardHIDType_T enmKbdHid, PointingHIDType_T enmPointingHid, PCFGMNODE *ppUsbDevices)
4065{
4066 int vrc = VINF_SUCCESS;
4067 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
4068 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
4069 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
4070 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
4071 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
4072
4073 com::SafeIfaceArray<IUSBController> usbCtrls;
4074 HRESULT hrc = pMachine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(usbCtrls));
4075 bool fOhciPresent = false; /**< Flag whether at least one OHCI controller is present. */
4076 bool fXhciPresent = false; /**< Flag whether at least one XHCI controller is present. */
4077
4078 if (SUCCEEDED(hrc))
4079 {
4080 for (size_t i = 0; i < usbCtrls.size(); ++i)
4081 {
4082 USBControllerType_T enmCtrlType;
4083 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
4084 if (enmCtrlType == USBControllerType_OHCI)
4085 {
4086 fOhciPresent = true;
4087 break;
4088 }
4089 else if (enmCtrlType == USBControllerType_XHCI)
4090 {
4091 fXhciPresent = true;
4092 break;
4093 }
4094 }
4095 }
4096 else if (hrc != E_NOTIMPL)
4097 {
4098 H();
4099 }
4100
4101 /*
4102 * Currently EHCI is only enabled when an OHCI or XHCI controller is present as well.
4103 */
4104 if (fOhciPresent || fXhciPresent)
4105 mfVMHasUsbController = true;
4106
4107 if (mfVMHasUsbController)
4108 {
4109 for (size_t i = 0; i < usbCtrls.size(); ++i)
4110 {
4111 USBControllerType_T enmCtrlType;
4112 vrc = usbCtrls[i]->COMGETTER(Type)(&enmCtrlType); H();
4113
4114 if (enmCtrlType == USBControllerType_OHCI)
4115 {
4116 InsertConfigNode(pDevices, "usb-ohci", &pDev);
4117 InsertConfigNode(pDev, "0", &pInst);
4118 InsertConfigNode(pInst, "Config", &pCfg);
4119 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4120 hrc = pBusMgr->assignPCIDevice("usb-ohci", pInst); H();
4121 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4122 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
4123 InsertConfigNode(pLunL0, "Config", &pCfg);
4124
4125 /*
4126 * Attach the status driver.
4127 */
4128 i_attachStatusDriver(pInst, DeviceType_USB);
4129 }
4130#ifdef VBOX_WITH_EHCI
4131 else if (enmCtrlType == USBControllerType_EHCI)
4132 {
4133 InsertConfigNode(pDevices, "usb-ehci", &pDev);
4134 InsertConfigNode(pDev, "0", &pInst);
4135 InsertConfigNode(pInst, "Config", &pCfg);
4136 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4137 hrc = pBusMgr->assignPCIDevice("usb-ehci", pInst); H();
4138
4139 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4140 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
4141 InsertConfigNode(pLunL0, "Config", &pCfg);
4142
4143 /*
4144 * Attach the status driver.
4145 */
4146 i_attachStatusDriver(pInst, DeviceType_USB);
4147 }
4148#endif
4149 else if (enmCtrlType == USBControllerType_XHCI)
4150 {
4151 InsertConfigNode(pDevices, "usb-xhci", &pDev);
4152 InsertConfigNode(pDev, "0", &pInst);
4153 InsertConfigNode(pInst, "Config", &pCfg);
4154 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4155 hrc = pBusMgr->assignPCIDevice("usb-xhci", pInst); H();
4156
4157 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4158 InsertConfigString(pLunL0, "Driver", "VUSBRootHub");
4159 InsertConfigNode(pLunL0, "Config", &pCfg);
4160
4161 InsertConfigNode(pInst, "LUN#1", &pLunL1);
4162 InsertConfigString(pLunL1, "Driver", "VUSBRootHub");
4163 InsertConfigNode(pLunL1, "Config", &pCfg);
4164
4165 /*
4166 * Attach the status driver.
4167 */
4168 i_attachStatusDriver(pInst, DeviceType_USB, 2);
4169 }
4170 } /* for every USB controller. */
4171
4172
4173 /*
4174 * Virtual USB Devices.
4175 */
4176 PCFGMNODE pUsbDevices = NULL;
4177 InsertConfigNode(pRoot, "USB", &pUsbDevices);
4178 *ppUsbDevices = pUsbDevices;
4179
4180#ifdef VBOX_WITH_USB
4181 {
4182 /*
4183 * Global USB options, currently unused as we'll apply the 2.0 -> 1.1 morphing
4184 * on a per device level now.
4185 */
4186 InsertConfigNode(pUsbDevices, "USBProxy", &pCfg);
4187 InsertConfigNode(pCfg, "GlobalConfig", &pCfg);
4188 // This globally enables the 2.0 -> 1.1 device morphing of proxied devices to keep windows quiet.
4189 //InsertConfigInteger(pCfg, "Force11Device", true);
4190 // The following breaks stuff, but it makes MSDs work in vista. (I include it here so
4191 // that it's documented somewhere.) Users needing it can use:
4192 // VBoxManage setextradata "myvm" "VBoxInternal/USB/USBProxy/GlobalConfig/Force11PacketSize" 1
4193 //InsertConfigInteger(pCfg, "Force11PacketSize", true);
4194 }
4195#endif
4196
4197#ifdef VBOX_WITH_USB_CARDREADER
4198 BOOL aEmulatedUSBCardReaderEnabled = FALSE;
4199 hrc = pMachine->COMGETTER(EmulatedUSBCardReaderEnabled)(&aEmulatedUSBCardReaderEnabled); H();
4200 if (aEmulatedUSBCardReaderEnabled)
4201 {
4202 InsertConfigNode(pUsbDevices, "CardReader", &pDev);
4203 InsertConfigNode(pDev, "0", &pInst);
4204 InsertConfigNode(pInst, "Config", &pCfg);
4205
4206 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4207# ifdef VBOX_WITH_USB_CARDREADER_TEST
4208 InsertConfigString(pLunL0, "Driver", "DrvDirectCardReader");
4209 InsertConfigNode(pLunL0, "Config", &pCfg);
4210# else
4211 InsertConfigString(pLunL0, "Driver", "UsbCardReader");
4212 InsertConfigNode(pLunL0, "Config", &pCfg);
4213# endif
4214 }
4215#endif
4216
4217 /* Virtual USB Mouse/Tablet */
4218 if ( enmPointingHid == PointingHIDType_USBMouse
4219 || enmPointingHid == PointingHIDType_USBTablet
4220 || enmPointingHid == PointingHIDType_USBMultiTouch
4221 || enmPointingHid == PointingHIDType_USBMultiTouchScreenPlusPad)
4222 {
4223 InsertConfigNode(pUsbDevices, "HidMouse", &pDev);
4224 InsertConfigNode(pDev, "0", &pInst);
4225 InsertConfigNode(pInst, "Config", &pCfg);
4226
4227 if (enmPointingHid == PointingHIDType_USBMouse)
4228 InsertConfigString(pCfg, "Mode", "relative");
4229 else
4230 InsertConfigString(pCfg, "Mode", "absolute");
4231 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4232 InsertConfigString(pLunL0, "Driver", "MouseQueue");
4233 InsertConfigNode(pLunL0, "Config", &pCfg);
4234 InsertConfigInteger(pCfg, "QueueSize", 128);
4235
4236 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4237 InsertConfigString(pLunL1, "Driver", "MainMouse");
4238 }
4239 if ( enmPointingHid == PointingHIDType_USBMultiTouch
4240 || enmPointingHid == PointingHIDType_USBMultiTouchScreenPlusPad)
4241 {
4242 InsertConfigNode(pDev, "1", &pInst);
4243 InsertConfigNode(pInst, "Config", &pCfg);
4244
4245 InsertConfigString(pCfg, "Mode", "multitouch");
4246 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4247 InsertConfigString(pLunL0, "Driver", "MouseQueue");
4248 InsertConfigNode(pLunL0, "Config", &pCfg);
4249 InsertConfigInteger(pCfg, "QueueSize", 128);
4250
4251 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4252 InsertConfigString(pLunL1, "Driver", "MainMouse");
4253 }
4254 if (enmPointingHid == PointingHIDType_USBMultiTouchScreenPlusPad)
4255 {
4256 InsertConfigNode(pDev, "2", &pInst);
4257 InsertConfigNode(pInst, "Config", &pCfg);
4258
4259 InsertConfigString(pCfg, "Mode", "touchpad");
4260 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4261 InsertConfigString(pLunL0, "Driver", "MouseQueue");
4262 InsertConfigNode(pLunL0, "Config", &pCfg);
4263 InsertConfigInteger(pCfg, "QueueSize", 128);
4264
4265 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4266 InsertConfigString(pLunL1, "Driver", "MainMouse");
4267 }
4268
4269 /* Virtual USB Keyboard */
4270 if (enmKbdHid == KeyboardHIDType_USBKeyboard)
4271 {
4272 InsertConfigNode(pUsbDevices, "HidKeyboard", &pDev);
4273 InsertConfigNode(pDev, "0", &pInst);
4274 InsertConfigNode(pInst, "Config", &pCfg);
4275
4276 InsertConfigNode(pInst, "LUN#0", &pLunL0);
4277 InsertConfigString(pLunL0, "Driver", "KeyboardQueue");
4278 InsertConfigNode(pLunL0, "Config", &pCfg);
4279 InsertConfigInteger(pCfg, "QueueSize", 64);
4280
4281 InsertConfigNode(pLunL0, "AttachedDriver", &pLunL1);
4282 InsertConfigString(pLunL1, "Driver", "MainKeyboard");
4283 }
4284 }
4285
4286 return VINF_SUCCESS;
4287}
4288
4289
4290/**
4291 * Translate IDE StorageControllerType_T to string representation.
4292 */
4293static const char* controllerString(StorageControllerType_T enmType)
4294{
4295 switch (enmType)
4296 {
4297 case StorageControllerType_PIIX3:
4298 return "PIIX3";
4299 case StorageControllerType_PIIX4:
4300 return "PIIX4";
4301 case StorageControllerType_ICH6:
4302 return "ICH6";
4303 default:
4304 return "Unknown";
4305 }
4306}
4307
4308
4309int Console::i_configStorageCtrls(ComPtr<IMachine> pMachine, BusAssignmentManager *pBusMgr, PCVMMR3VTABLE pVMM, PUVM pUVM,
4310 PCFGMNODE pDevices, PCFGMNODE pUsbDevices, PCFGMNODE pBiosCfg, bool *pfFdcEnabled)
4311{
4312 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
4313 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
4314
4315 com::SafeIfaceArray<IStorageController> ctrls;
4316 PCFGMNODE aCtrlNodes[StorageControllerType_VirtioSCSI + 1] = {};
4317 HRESULT hrc = pMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls)); H();
4318
4319 for (size_t i = 0; i < ctrls.size(); ++i)
4320 {
4321 DeviceType_T *paLedDevType = NULL;
4322
4323 StorageControllerType_T enmCtrlType;
4324 hrc = ctrls[i]->COMGETTER(ControllerType)(&enmCtrlType); H();
4325 AssertRelease((unsigned)enmCtrlType < RT_ELEMENTS(aCtrlNodes)
4326 || enmCtrlType == StorageControllerType_USB);
4327
4328 StorageBus_T enmBus;
4329 hrc = ctrls[i]->COMGETTER(Bus)(&enmBus); H();
4330
4331 Bstr controllerName;
4332 hrc = ctrls[i]->COMGETTER(Name)(controllerName.asOutParam()); H();
4333
4334 ULONG ulInstance = 999;
4335 hrc = ctrls[i]->COMGETTER(Instance)(&ulInstance); H();
4336
4337 BOOL fUseHostIOCache;
4338 hrc = ctrls[i]->COMGETTER(UseHostIOCache)(&fUseHostIOCache); H();
4339
4340 BOOL fBootable;
4341 hrc = ctrls[i]->COMGETTER(Bootable)(&fBootable); H();
4342
4343 PCFGMNODE pCtlInst = NULL;
4344 const char *pszCtrlDev = i_storageControllerTypeToStr(enmCtrlType);
4345 if (enmCtrlType != StorageControllerType_USB)
4346 {
4347 /* /Devices/<ctrldev>/ */
4348 pDev = aCtrlNodes[enmCtrlType];
4349 if (!pDev)
4350 {
4351 InsertConfigNode(pDevices, pszCtrlDev, &pDev);
4352 aCtrlNodes[enmCtrlType] = pDev; /* IDE variants are handled in the switch */
4353 }
4354
4355 /* /Devices/<ctrldev>/<instance>/ */
4356 InsertConfigNode(pDev, Utf8StrFmt("%u", ulInstance).c_str(), &pCtlInst);
4357
4358 /* Device config: /Devices/<ctrldev>/<instance>/<values> & /ditto/Config/<values> */
4359 InsertConfigInteger(pCtlInst, "Trusted", 1);
4360 InsertConfigNode(pCtlInst, "Config", &pCfg);
4361 }
4362
4363#define MAX_BIOS_LUN_COUNT 4
4364
4365 static const char * const apszBiosConfigScsi[MAX_BIOS_LUN_COUNT] =
4366 { "ScsiLUN1", "ScsiLUN2", "ScsiLUN3", "ScsiLUN4" };
4367
4368 static const char * const apszBiosConfigSata[MAX_BIOS_LUN_COUNT] =
4369 { "SataLUN1", "SataLUN2", "SataLUN3", "SataLUN4" };
4370
4371#undef MAX_BIOS_LUN_COUNT
4372
4373 switch (enmCtrlType)
4374 {
4375 case StorageControllerType_LsiLogic:
4376 {
4377 hrc = pBusMgr->assignPCIDevice("lsilogic", pCtlInst); H();
4378
4379 InsertConfigInteger(pCfg, "Bootable", fBootable);
4380
4381 /* BIOS configuration values, first SCSI controller only. */
4382 if ( !pBusMgr->hasPCIDevice("lsilogic", 1)
4383 && !pBusMgr->hasPCIDevice("buslogic", 0)
4384 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
4385 && pBiosCfg)
4386 {
4387 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicscsi");
4388 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
4389 }
4390
4391 /* Attach the status driver */
4392 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4393 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4394 break;
4395 }
4396
4397 case StorageControllerType_BusLogic:
4398 {
4399 hrc = pBusMgr->assignPCIDevice("buslogic", pCtlInst); H();
4400
4401 InsertConfigInteger(pCfg, "Bootable", fBootable);
4402
4403 /* BIOS configuration values, first SCSI controller only. */
4404 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
4405 && !pBusMgr->hasPCIDevice("buslogic", 1)
4406 && !pBusMgr->hasPCIDevice("lsilogicsas", 0)
4407 && pBiosCfg)
4408 {
4409 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "buslogic");
4410 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
4411 }
4412
4413 /* Attach the status driver */
4414 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4415 16, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4416 break;
4417 }
4418
4419 case StorageControllerType_IntelAhci:
4420 {
4421 hrc = pBusMgr->assignPCIDevice("ahci", pCtlInst); H();
4422
4423 ULONG cPorts = 0;
4424 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4425 InsertConfigInteger(pCfg, "PortCount", cPorts);
4426 InsertConfigInteger(pCfg, "Bootable", fBootable);
4427
4428 com::SafeIfaceArray<IMediumAttachment> atts;
4429 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
4430 ComSafeArrayAsOutParam(atts)); H();
4431
4432 /* Configure the hotpluggable flag for the port. */
4433 for (unsigned idxAtt = 0; idxAtt < atts.size(); ++idxAtt)
4434 {
4435 IMediumAttachment *pMediumAtt = atts[idxAtt];
4436
4437 LONG lPortNum = 0;
4438 hrc = pMediumAtt->COMGETTER(Port)(&lPortNum); H();
4439
4440 BOOL fHotPluggable = FALSE;
4441 hrc = pMediumAtt->COMGETTER(HotPluggable)(&fHotPluggable); H();
4442 if (SUCCEEDED(hrc))
4443 {
4444 PCFGMNODE pPortCfg;
4445 char szName[24];
4446 RTStrPrintf(szName, sizeof(szName), "Port%d", lPortNum);
4447
4448 InsertConfigNode(pCfg, szName, &pPortCfg);
4449 InsertConfigInteger(pPortCfg, "Hotpluggable", fHotPluggable ? 1 : 0);
4450 }
4451 }
4452
4453 /* BIOS configuration values, first AHCI controller only. */
4454 if ( !pBusMgr->hasPCIDevice("ahci", 1)
4455 && pBiosCfg)
4456 {
4457 InsertConfigString(pBiosCfg, "SataHardDiskDevice", "ahci");
4458 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigSata); H();
4459 }
4460
4461 /* Attach the status driver */
4462 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4463 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4464 break;
4465 }
4466
4467 case StorageControllerType_PIIX3:
4468 case StorageControllerType_PIIX4:
4469 case StorageControllerType_ICH6:
4470 {
4471 /*
4472 * IDE (update this when the main interface changes)
4473 */
4474 hrc = pBusMgr->assignPCIDevice("piix3ide", pCtlInst); H();
4475 InsertConfigString(pCfg, "Type", controllerString(enmCtrlType));
4476
4477 /* Attach the status driver */
4478 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD),
4479 4, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4480
4481 /* IDE flavors */
4482 aCtrlNodes[StorageControllerType_PIIX3] = pDev;
4483 aCtrlNodes[StorageControllerType_PIIX4] = pDev;
4484 aCtrlNodes[StorageControllerType_ICH6] = pDev;
4485 break;
4486 }
4487
4488 case StorageControllerType_I82078:
4489 {
4490 /*
4491 * i82078 Floppy drive controller
4492 */
4493 *pfFdcEnabled = true;
4494 InsertConfigInteger(pCfg, "IRQ", 6);
4495 InsertConfigInteger(pCfg, "DMA", 2);
4496 InsertConfigInteger(pCfg, "MemMapped", 0 );
4497 InsertConfigInteger(pCfg, "IOBase", 0x3f0);
4498
4499 /* Attach the status driver */
4500 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_Floppy),
4501 2, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
4502 break;
4503 }
4504
4505 case StorageControllerType_LsiLogicSas:
4506 {
4507 hrc = pBusMgr->assignPCIDevice("lsilogicsas", pCtlInst); H();
4508
4509 InsertConfigString(pCfg, "ControllerType", "SAS1068");
4510 InsertConfigInteger(pCfg, "Bootable", fBootable);
4511
4512 /* BIOS configuration values, first SCSI controller only. */
4513 if ( !pBusMgr->hasPCIDevice("lsilogic", 0)
4514 && !pBusMgr->hasPCIDevice("buslogic", 0)
4515 && !pBusMgr->hasPCIDevice("lsilogicsas", 1)
4516 && pBiosCfg)
4517 {
4518 InsertConfigString(pBiosCfg, "ScsiHardDiskDevice", "lsilogicsas");
4519 hrc = SetBiosDiskInfo(pMachine, pCfg, pBiosCfg, controllerName, apszBiosConfigScsi); H();
4520 }
4521
4522 ULONG cPorts = 0;
4523 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4524 InsertConfigInteger(pCfg, "NumPorts", cPorts);
4525
4526 /* Attach the status driver */
4527 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
4528 8, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4529 break;
4530 }
4531
4532 case StorageControllerType_USB:
4533 {
4534 if (pUsbDevices)
4535 {
4536 /*
4537 * USB MSDs are handled a bit different as the device instance
4538 * doesn't match the storage controller instance but the port.
4539 */
4540 InsertConfigNode(pUsbDevices, "Msd", &pDev);
4541 pCtlInst = pDev;
4542 }
4543 else
4544 return pVMM->pfnVMR3SetError(pUVM, VERR_NOT_FOUND, RT_SRC_POS,
4545 N_("There is no USB controller enabled but there\n"
4546 "is at least one USB storage device configured for this VM.\n"
4547 "To fix this problem either enable the USB controller or remove\n"
4548 "the storage device from the VM"));
4549 break;
4550 }
4551
4552 case StorageControllerType_NVMe:
4553 {
4554 hrc = pBusMgr->assignPCIDevice("nvme", pCtlInst); H();
4555
4556 ULONG cPorts = 0;
4557 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4558 InsertConfigInteger(pCfg, "NamespacesMax", cPorts);
4559
4560 /* Attach the status driver */
4561 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk),
4562 cPorts, NULL, &mapMediumAttachments, pszCtrlDev, ulInstance);
4563 break;
4564 }
4565
4566 case StorageControllerType_VirtioSCSI:
4567 {
4568 hrc = pBusMgr->assignPCIDevice("virtio-scsi", pCtlInst); H();
4569
4570 ULONG cPorts = 0;
4571 hrc = ctrls[i]->COMGETTER(PortCount)(&cPorts); H();
4572 InsertConfigInteger(pCfg, "NumTargets", cPorts);
4573 InsertConfigInteger(pCfg, "Bootable", fBootable);
4574
4575 /* Attach the status driver */
4576 i_attachStatusDriver(pCtlInst, RT_BIT_32(DeviceType_HardDisk) | RT_BIT_32(DeviceType_DVD) /*?*/,
4577 cPorts, &paLedDevType, &mapMediumAttachments, pszCtrlDev, ulInstance);
4578 break;
4579 }
4580
4581 default:
4582 AssertLogRelMsgFailedReturn(("invalid storage controller type: %d\n", enmCtrlType), VERR_MAIN_CONFIG_CONSTRUCTOR_IPE);
4583 }
4584
4585 /* Attach the media to the storage controllers. */
4586 com::SafeIfaceArray<IMediumAttachment> atts;
4587 hrc = pMachine->GetMediumAttachmentsOfController(controllerName.raw(),
4588 ComSafeArrayAsOutParam(atts)); H();
4589
4590 /* Builtin I/O cache - per device setting. */
4591 BOOL fBuiltinIOCache = true;
4592 hrc = pMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache); H();
4593
4594 bool fInsertDiskIntegrityDrv = false;
4595 Bstr strDiskIntegrityFlag;
4596 hrc = pMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
4597 strDiskIntegrityFlag.asOutParam());
4598 if ( hrc == S_OK
4599 && strDiskIntegrityFlag == "1")
4600 fInsertDiskIntegrityDrv = true;
4601
4602 for (size_t j = 0; j < atts.size(); ++j)
4603 {
4604 IMediumAttachment *pMediumAtt = atts[j];
4605 int vrc = i_configMediumAttachment(pszCtrlDev,
4606 ulInstance,
4607 enmBus,
4608 !!fUseHostIOCache,
4609 enmCtrlType == StorageControllerType_NVMe ? false : !!fBuiltinIOCache,
4610 fInsertDiskIntegrityDrv,
4611 false /* fSetupMerge */,
4612 0 /* uMergeSource */,
4613 0 /* uMergeTarget */,
4614 pMediumAtt,
4615 mMachineState,
4616 NULL /* phrc */,
4617 false /* fAttachDetach */,
4618 false /* fForceUnmount */,
4619 false /* fHotplug */,
4620 pUVM,
4621 pVMM,
4622 paLedDevType,
4623 NULL /* ppLunL0 */);
4624 if (RT_FAILURE(vrc))
4625 return vrc;
4626 }
4627 H();
4628 }
4629 H();
4630
4631 return VINF_SUCCESS;
4632}
4633
4634
4635int Console::i_configNetworkCtrls(ComPtr<IMachine> pMachine, ComPtr<IPlatformProperties> pPlatformProperties,
4636 ChipsetType_T enmChipset, BusAssignmentManager *pBusMgr, PCVMMR3VTABLE pVMM, PUVM pUVM,
4637 PCFGMNODE pDevices, std::list<BootNic> &llBootNics)
4638{
4639/* Comment out the following line to remove VMWare compatibility hack. */
4640#define VMWARE_NET_IN_SLOT_11
4641
4642 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
4643 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
4644 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
4645 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
4646
4647 ULONG maxNetworkAdapters;
4648 HRESULT hrc = pPlatformProperties->GetMaxNetworkAdapters(enmChipset, &maxNetworkAdapters); H();
4649
4650#ifdef VMWARE_NET_IN_SLOT_11
4651 bool fSwapSlots3and11 = false;
4652#endif
4653 PCFGMNODE pDevPCNet = NULL; /* PCNet-type devices */
4654 InsertConfigNode(pDevices, "pcnet", &pDevPCNet);
4655#ifdef VBOX_WITH_E1000
4656 PCFGMNODE pDevE1000 = NULL; /* E1000-type devices */
4657 InsertConfigNode(pDevices, "e1000", &pDevE1000);
4658#endif
4659#ifdef VBOX_WITH_VIRTIO
4660 PCFGMNODE pDevVirtioNet = NULL; /* Virtio network devices */
4661 InsertConfigNode(pDevices, "virtio-net", &pDevVirtioNet);
4662#endif /* VBOX_WITH_VIRTIO */
4663 PCFGMNODE pDevDP8390 = NULL; /* DP8390-type devices */
4664 InsertConfigNode(pDevices, "dp8390", &pDevDP8390);
4665 PCFGMNODE pDev3C501 = NULL; /* EtherLink-type devices */
4666 InsertConfigNode(pDevices, "3c501", &pDev3C501);
4667
4668 for (ULONG uInstance = 0; uInstance < maxNetworkAdapters; ++uInstance)
4669 {
4670 ComPtr<INetworkAdapter> networkAdapter;
4671 hrc = pMachine->GetNetworkAdapter(uInstance, networkAdapter.asOutParam()); H();
4672 BOOL fEnabledNetAdapter = FALSE;
4673 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabledNetAdapter); H();
4674 if (!fEnabledNetAdapter)
4675 continue;
4676
4677 /*
4678 * The virtual hardware type. Create appropriate device first.
4679 */
4680 const char *pszAdapterName = "pcnet";
4681 NetworkAdapterType_T adapterType;
4682 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
4683 switch (adapterType)
4684 {
4685 case NetworkAdapterType_Am79C970A:
4686 case NetworkAdapterType_Am79C973:
4687 case NetworkAdapterType_Am79C960:
4688 pDev = pDevPCNet;
4689 break;
4690#ifdef VBOX_WITH_E1000
4691 case NetworkAdapterType_I82540EM:
4692 case NetworkAdapterType_I82543GC:
4693 case NetworkAdapterType_I82545EM:
4694 pDev = pDevE1000;
4695 pszAdapterName = "e1000";
4696 break;
4697#endif
4698#ifdef VBOX_WITH_VIRTIO
4699 case NetworkAdapterType_Virtio:
4700 pDev = pDevVirtioNet;
4701 pszAdapterName = "virtio-net";
4702 break;
4703#endif /* VBOX_WITH_VIRTIO */
4704 case NetworkAdapterType_NE1000:
4705 case NetworkAdapterType_NE2000:
4706 case NetworkAdapterType_WD8003:
4707 case NetworkAdapterType_WD8013:
4708 case NetworkAdapterType_ELNK2:
4709 pDev = pDevDP8390;
4710 break;
4711 case NetworkAdapterType_ELNK1:
4712 pDev = pDev3C501;
4713 break;
4714 default:
4715 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'", adapterType, uInstance));
4716 return pVMM->pfnVMR3SetError(pUVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
4717 N_("Invalid network adapter type '%d' for slot '%d'"), adapterType, uInstance);
4718 }
4719
4720 InsertConfigNode(pDev, Utf8StrFmt("%u", uInstance).c_str(), &pInst);
4721 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
4722
4723 int iPCIDeviceNo;
4724 if (enmChipset == ChipsetType_ICH9 || enmChipset == ChipsetType_PIIX3)
4725 {
4726 /* the first network card gets the PCI ID 3, the next 3 gets 8..10,
4727 * next 4 get 16..19. */
4728 switch (uInstance)
4729 {
4730 case 0:
4731 iPCIDeviceNo = 3;
4732 break;
4733 case 1: case 2: case 3:
4734 iPCIDeviceNo = uInstance - 1 + 8;
4735 break;
4736 case 4: case 5: case 6: case 7:
4737 iPCIDeviceNo = uInstance - 4 + 16;
4738 break;
4739 default:
4740 /* auto assignment */
4741 iPCIDeviceNo = -1;
4742 break;
4743 }
4744#ifdef VMWARE_NET_IN_SLOT_11
4745 /*
4746 * Dirty hack for PCI slot compatibility with VMWare,
4747 * it assigns slot 0x11 to the first network controller.
4748 */
4749 if (iPCIDeviceNo == 3 && adapterType == NetworkAdapterType_I82545EM)
4750 {
4751 iPCIDeviceNo = 0x11;
4752 fSwapSlots3and11 = true;
4753 }
4754 else if (iPCIDeviceNo == 0x11 && fSwapSlots3and11)
4755 iPCIDeviceNo = 3;
4756#endif
4757 }
4758 else /* Platforms other than x86 just use the auto assignment, no slot swap hack there. */
4759 iPCIDeviceNo = -1;
4760
4761 PCIBusAddress PCIAddr = PCIBusAddress(0, iPCIDeviceNo, 0);
4762 hrc = pBusMgr->assignPCIDevice(pszAdapterName, pInst, PCIAddr); H();
4763
4764 InsertConfigNode(pInst, "Config", &pCfg);
4765#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE /* not safe here yet. */ /** @todo Make PCNet ring-0 safe on 32-bit mac kernels! */
4766 if (pDev == pDevPCNet)
4767 InsertConfigInteger(pCfg, "R0Enabled", false);
4768#endif
4769 /*
4770 * Collect information needed for network booting and add it to the list.
4771 */
4772 BootNic nic;
4773
4774 nic.mInstance = uInstance;
4775 /* Could be updated by reference, if auto assigned */
4776 nic.mPCIAddress = PCIAddr;
4777
4778 hrc = networkAdapter->COMGETTER(BootPriority)(&nic.mBootPrio); H();
4779
4780 llBootNics.push_back(nic);
4781
4782 /*
4783 * The virtual hardware type. PCNet supports three types, E1000 three,
4784 * but VirtIO only one.
4785 */
4786 switch (adapterType)
4787 {
4788 case NetworkAdapterType_Am79C970A:
4789 InsertConfigString(pCfg, "ChipType", "Am79C970A");
4790 break;
4791 case NetworkAdapterType_Am79C973:
4792 InsertConfigString(pCfg, "ChipType", "Am79C973");
4793 break;
4794 case NetworkAdapterType_Am79C960:
4795 InsertConfigString(pCfg, "ChipType", "Am79C960");
4796 break;
4797 case NetworkAdapterType_I82540EM:
4798 InsertConfigInteger(pCfg, "AdapterType", 0);
4799 break;
4800 case NetworkAdapterType_I82543GC:
4801 InsertConfigInteger(pCfg, "AdapterType", 1);
4802 break;
4803 case NetworkAdapterType_I82545EM:
4804 InsertConfigInteger(pCfg, "AdapterType", 2);
4805 break;
4806 case NetworkAdapterType_Virtio:
4807 break;
4808 case NetworkAdapterType_NE1000:
4809 InsertConfigString(pCfg, "DeviceType", "NE1000");
4810 break;
4811 case NetworkAdapterType_NE2000:
4812 InsertConfigString(pCfg, "DeviceType", "NE2000");
4813 break;
4814 case NetworkAdapterType_WD8003:
4815 InsertConfigString(pCfg, "DeviceType", "WD8003");
4816 break;
4817 case NetworkAdapterType_WD8013:
4818 InsertConfigString(pCfg, "DeviceType", "WD8013");
4819 break;
4820 case NetworkAdapterType_ELNK2:
4821 InsertConfigString(pCfg, "DeviceType", "3C503");
4822 break;
4823 case NetworkAdapterType_ELNK1:
4824 break;
4825 case NetworkAdapterType_Null: AssertFailedBreak(); /* (compiler warnings) */
4826#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
4827 case NetworkAdapterType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
4828#endif
4829 }
4830
4831 /*
4832 * Get the MAC address and convert it to binary representation
4833 */
4834 Bstr macAddr;
4835 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
4836 Assert(!macAddr.isEmpty());
4837 Utf8Str macAddrUtf8 = macAddr;
4838#ifdef VBOX_WITH_CLOUD_NET
4839 NetworkAttachmentType_T eAttachmentType;
4840 hrc = networkAdapter->COMGETTER(AttachmentType)(&eAttachmentType); H();
4841 if (eAttachmentType == NetworkAttachmentType_Cloud)
4842 {
4843 mGateway.setLocalMacAddress(macAddrUtf8);
4844 /* We'll insert cloud MAC later, when it becomes known. */
4845 }
4846 else
4847 {
4848#endif
4849 char *macStr = (char*)macAddrUtf8.c_str();
4850 Assert(strlen(macStr) == 12);
4851 RTMAC Mac;
4852 RT_ZERO(Mac);
4853 char *pMac = (char*)&Mac;
4854 for (uint32_t i = 0; i < 6; ++i)
4855 {
4856 int c1 = *macStr++ - '0';
4857 if (c1 > 9)
4858 c1 -= 7;
4859 int c2 = *macStr++ - '0';
4860 if (c2 > 9)
4861 c2 -= 7;
4862 *pMac++ = (char)(((c1 & 0x0f) << 4) | (c2 & 0x0f));
4863 }
4864 InsertConfigBytes(pCfg, "MAC", &Mac, sizeof(Mac));
4865#ifdef VBOX_WITH_CLOUD_NET
4866 }
4867#endif
4868 /*
4869 * Check if the cable is supposed to be unplugged
4870 */
4871 BOOL fCableConnected;
4872 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
4873 InsertConfigInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0);
4874
4875 /*
4876 * Line speed to report from custom drivers
4877 */
4878 ULONG ulLineSpeed;
4879 hrc = networkAdapter->COMGETTER(LineSpeed)(&ulLineSpeed); H();
4880 InsertConfigInteger(pCfg, "LineSpeed", ulLineSpeed);
4881
4882 /*
4883 * Attach the status driver.
4884 */
4885 i_attachStatusDriver(pInst, DeviceType_Network);
4886
4887 /*
4888 * Configure the network card now
4889 */
4890 bool fIgnoreConnectFailure = mMachineState == MachineState_Restoring;
4891 int vrc = i_configNetwork(pszAdapterName,
4892 uInstance,
4893 0,
4894 networkAdapter,
4895 pCfg,
4896 pLunL0,
4897 pInst,
4898 false /*fAttachDetach*/,
4899 fIgnoreConnectFailure,
4900 pUVM,
4901 pVMM);
4902 if (RT_FAILURE(vrc))
4903 return vrc;
4904 }
4905
4906 return VINF_SUCCESS;
4907}
4908
4909
4910int Console::i_configGuestDbg(ComPtr<IVirtualBox> pVBox, ComPtr<IMachine> pMachine, PCFGMNODE pRoot)
4911{
4912 PCFGMNODE pDbgf;
4913 InsertConfigNode(pRoot, "DBGF", &pDbgf);
4914
4915 /* Paths to search for debug info and such things. */
4916 Bstr bstr;
4917 HRESULT hrc = pMachine->COMGETTER(SettingsFilePath)(bstr.asOutParam()); H();
4918 Utf8Str strSettingsPath(bstr);
4919 bstr.setNull();
4920 strSettingsPath.stripFilename();
4921 strSettingsPath.append("/");
4922
4923 char szHomeDir[RTPATH_MAX + 1];
4924 int vrc2 = RTPathUserHome(szHomeDir, sizeof(szHomeDir) - 1);
4925 if (RT_FAILURE(vrc2))
4926 szHomeDir[0] = '\0';
4927 RTPathEnsureTrailingSeparator(szHomeDir, sizeof(szHomeDir));
4928
4929
4930 Utf8Str strPath;
4931 strPath.append(strSettingsPath).append("debug/;");
4932 strPath.append(strSettingsPath).append(";");
4933 strPath.append("cache*").append(strSettingsPath).append("dbgcache/;"); /* handy for symlinking to actual cache */
4934 strPath.append(szHomeDir);
4935
4936 InsertConfigString(pDbgf, "Path", strPath.c_str());
4937
4938 /* Tracing configuration. */
4939 BOOL fTracingEnabled;
4940 hrc = pMachine->COMGETTER(TracingEnabled)(&fTracingEnabled); H();
4941 if (fTracingEnabled)
4942 InsertConfigInteger(pDbgf, "TracingEnabled", 1);
4943
4944 hrc = pMachine->COMGETTER(TracingConfig)(bstr.asOutParam()); H();
4945 if (fTracingEnabled)
4946 InsertConfigString(pDbgf, "TracingConfig", bstr);
4947
4948 /* Debugger console config. */
4949 PCFGMNODE pDbgc;
4950 InsertConfigNode(pRoot, "DBGC", &pDbgc);
4951
4952 hrc = pVBox->COMGETTER(HomeFolder)(bstr.asOutParam()); H();
4953 Utf8Str strVBoxHome = bstr;
4954 bstr.setNull();
4955 if (strVBoxHome.isNotEmpty())
4956 strVBoxHome.append("/");
4957 else
4958 {
4959 strVBoxHome = szHomeDir;
4960 strVBoxHome.append("/.vbox");
4961 }
4962
4963 Utf8Str strFile(strVBoxHome);
4964 strFile.append("dbgc-history");
4965 InsertConfigString(pDbgc, "HistoryFile", strFile);
4966
4967 strFile = strSettingsPath;
4968 strFile.append("dbgc-init");
4969 InsertConfigString(pDbgc, "LocalInitScript", strFile);
4970
4971 strFile = strVBoxHome;
4972 strFile.append("dbgc-init");
4973 InsertConfigString(pDbgc, "GlobalInitScript", strFile);
4974
4975 /*
4976 * Configure guest debug settings.
4977 */
4978 ComObjPtr<IGuestDebugControl> ptrGstDbgCtrl;
4979 GuestDebugProvider_T enmGstDbgProvider = GuestDebugProvider_None;
4980
4981 hrc = pMachine->COMGETTER(GuestDebugControl)(ptrGstDbgCtrl.asOutParam()); H();
4982 hrc = ptrGstDbgCtrl->COMGETTER(DebugProvider)(&enmGstDbgProvider); H();
4983 if (enmGstDbgProvider != GuestDebugProvider_None)
4984 {
4985 GuestDebugIoProvider_T enmGstDbgIoProvider = GuestDebugIoProvider_None;
4986 hrc = ptrGstDbgCtrl->COMGETTER(DebugIoProvider)(&enmGstDbgIoProvider); H();
4987 hrc = ptrGstDbgCtrl->COMGETTER(DebugAddress)(bstr.asOutParam()); H();
4988 Utf8Str strAddress = bstr;
4989 bstr.setNull();
4990
4991 ULONG ulPort = 0;
4992 hrc = ptrGstDbgCtrl->COMGETTER(DebugPort)(&ulPort); H();
4993
4994 PCFGMNODE pDbgSettings;
4995 InsertConfigNode(pDbgc, "Dbg", &pDbgSettings);
4996 InsertConfigString(pDbgSettings, "Address", strAddress);
4997 InsertConfigInteger(pDbgSettings, "Port", ulPort);
4998
4999 switch (enmGstDbgProvider)
5000 {
5001 case GuestDebugProvider_Native:
5002 InsertConfigString(pDbgSettings, "StubType", "Native");
5003 break;
5004 case GuestDebugProvider_GDB:
5005 InsertConfigString(pDbgSettings, "StubType", "Gdb");
5006 break;
5007 case GuestDebugProvider_KD:
5008 InsertConfigString(pDbgSettings, "StubType", "Kd");
5009 break;
5010 default:
5011 AssertFailed();
5012 break;
5013 }
5014
5015 switch (enmGstDbgIoProvider)
5016 {
5017 case GuestDebugIoProvider_TCP:
5018 InsertConfigString(pDbgSettings, "Provider", "tcp");
5019 break;
5020 case GuestDebugIoProvider_UDP:
5021 InsertConfigString(pDbgSettings, "Provider", "udp");
5022 break;
5023 case GuestDebugIoProvider_IPC:
5024 InsertConfigString(pDbgSettings, "Provider", "ipc");
5025 break;
5026 default:
5027 AssertFailed();
5028 break;
5029 }
5030 }
5031
5032 return VINF_SUCCESS;
5033}
5034
5035
5036int Console::i_configGraphicsController(PCFGMNODE pDevices,
5037 const GraphicsControllerType_T enmGraphicsController,
5038 BusAssignmentManager *pBusMgr,
5039 const ComPtr<IMachine> &ptrMachine,
5040 const ComPtr<IGraphicsAdapter> &ptrGraphicsAdapter,
5041 const ComPtr<IFirmwareSettings> &ptrFirmwareSettings,
5042 bool fForceVmSvga3, bool fExposeLegacyVga)
5043{
5044 // InsertConfig* throws
5045 try
5046 {
5047 PCFGMNODE pDev, pInst, pCfg, pLunL0;
5048 HRESULT hrc;
5049 Bstr bstr;
5050 const char *pcszDevice = "vga";
5051
5052 InsertConfigNode(pDevices, pcszDevice, &pDev);
5053 InsertConfigNode(pDev, "0", &pInst);
5054 InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
5055
5056 hrc = pBusMgr->assignPCIDevice(pcszDevice, pInst); H();
5057 InsertConfigNode(pInst, "Config", &pCfg);
5058 ULONG cVRamMBs;
5059 hrc = ptrGraphicsAdapter->COMGETTER(VRAMSize)(&cVRamMBs); H();
5060 InsertConfigInteger(pCfg, "VRamSize", cVRamMBs * _1M);
5061 ULONG cMonitorCount;
5062 hrc = ptrGraphicsAdapter->COMGETTER(MonitorCount)(&cMonitorCount); H();
5063 InsertConfigInteger(pCfg, "MonitorCount", cMonitorCount);
5064
5065 BOOL f3DEnabled;
5066 hrc = ptrGraphicsAdapter->COMGETTER(Accelerate3DEnabled)(&f3DEnabled); H();
5067 InsertConfigInteger(pCfg, "3DEnabled", f3DEnabled);
5068
5069 i_attachStatusDriver(pInst, DeviceType_Graphics3D);
5070
5071#ifdef VBOX_WITH_VMSVGA
5072 if ( enmGraphicsController == GraphicsControllerType_VMSVGA
5073 || enmGraphicsController == GraphicsControllerType_VBoxSVGA)
5074 {
5075 InsertConfigInteger(pCfg, "VMSVGAEnabled", true);
5076 if (enmGraphicsController == GraphicsControllerType_VMSVGA)
5077 {
5078 InsertConfigInteger(pCfg, "VMSVGAPciBarLayout", true);
5079 InsertConfigInteger(pCfg, "VMSVGAPciId", true);
5080 }
5081# ifdef VBOX_WITH_VMSVGA3D
5082 InsertConfigInteger(pCfg, "VMSVGA3dEnabled", f3DEnabled);
5083# else
5084 LogRel(("VMSVGA3d not available in this build!\n"));
5085# endif /* VBOX_WITH_VMSVGA3D */
5086
5087 InsertConfigInteger(pCfg, "VmSvga3", fForceVmSvga3);
5088 InsertConfigInteger(pCfg, "VmSvgaExposeLegacyVga", fExposeLegacyVga);
5089 }
5090#else
5091 RT_NOREF(enmGraphicsController, fForceVmSvga3, fExposeLegacyVga);
5092#endif /* VBOX_WITH_VMSVGA */
5093
5094 /* Custom VESA mode list */
5095 unsigned cModes = 0;
5096 for (unsigned iMode = 1; iMode <= 16; ++iMode)
5097 {
5098 char szExtraDataKey[sizeof("CustomVideoModeXX")];
5099 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%u", iMode);
5100 hrc = ptrMachine->GetExtraData(Bstr(szExtraDataKey).raw(), bstr.asOutParam()); H();
5101 if (bstr.isEmpty())
5102 break;
5103 InsertConfigString(pCfg, szExtraDataKey, bstr);
5104 ++cModes;
5105 }
5106 InsertConfigInteger(pCfg, "CustomVideoModes", cModes);
5107
5108 /* VESA height reduction */
5109 ULONG ulHeightReduction;
5110 IFramebuffer *pFramebuffer = NULL;
5111 hrc = i_getDisplay()->QueryFramebuffer(0, &pFramebuffer);
5112 if (SUCCEEDED(hrc) && pFramebuffer)
5113 {
5114 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
5115 pFramebuffer->Release();
5116 pFramebuffer = NULL;
5117 }
5118 else
5119 {
5120 /* If framebuffer is not available, there is no height reduction. */
5121 ulHeightReduction = 0;
5122 }
5123 InsertConfigInteger(pCfg, "HeightReduction", ulHeightReduction);
5124
5125 /*
5126 * BIOS logo
5127 */
5128 BOOL fFadeIn;
5129 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
5130 InsertConfigInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0);
5131 BOOL fFadeOut;
5132 hrc = ptrFirmwareSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
5133 InsertConfigInteger(pCfg, "FadeOut", fFadeOut ? 1: 0);
5134 ULONG logoDisplayTime;
5135 hrc = ptrFirmwareSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
5136 InsertConfigInteger(pCfg, "LogoTime", logoDisplayTime);
5137 Bstr bstrLogoImagePath;
5138 hrc = ptrFirmwareSettings->COMGETTER(LogoImagePath)(bstrLogoImagePath.asOutParam()); H();
5139 InsertConfigString(pCfg, "LogoFile", bstrLogoImagePath);
5140
5141 /*
5142 * Boot menu
5143 */
5144 FirmwareBootMenuMode_T enmBootMenuMode;
5145 int iShowBootMenu;
5146 hrc = ptrFirmwareSettings->COMGETTER(BootMenuMode)(&enmBootMenuMode); H();
5147 switch (enmBootMenuMode)
5148 {
5149 case FirmwareBootMenuMode_Disabled: iShowBootMenu = 0; break;
5150 case FirmwareBootMenuMode_MenuOnly: iShowBootMenu = 1; break;
5151 default: iShowBootMenu = 2; break;
5152 }
5153 InsertConfigInteger(pCfg, "ShowBootMenu", iShowBootMenu);
5154
5155 /* Attach the display. */
5156 InsertConfigNode(pInst, "LUN#0", &pLunL0);
5157 InsertConfigString(pLunL0, "Driver", "MainDisplay");
5158 InsertConfigNode(pLunL0, "Config", &pCfg);
5159 }
5160 catch (ConfigError &x)
5161 {
5162 // InsertConfig threw something:
5163 return x.m_vrc;
5164 }
5165
5166 return VINF_SUCCESS;
5167}
5168
5169#undef H
5170#undef VRC
5171
5172#ifndef VBOX_WITH_EFI_IN_DD2
5173DECLHIDDEN(int) findEfiRom(IVirtualBox* vbox, PlatformArchitecture_T aPlatformArchitecture, FirmwareType_T aFirmwareType, Utf8Str *pEfiRomFile)
5174{
5175 Bstr aFilePath, empty;
5176 BOOL fPresent = FALSE;
5177 HRESULT hrc = vbox->CheckFirmwarePresent(aPlatformArchitecture, aFirmwareType, empty.raw(),
5178 empty.asOutParam(), aFilePath.asOutParam(), &fPresent);
5179 AssertComRCReturn(hrc, Global::vboxStatusCodeFromCOM(hrc));
5180
5181 if (!fPresent)
5182 {
5183 LogRel(("Failed to find an EFI ROM file.\n"));
5184 return VERR_FILE_NOT_FOUND;
5185 }
5186
5187 *pEfiRomFile = Utf8Str(aFilePath);
5188
5189 return VINF_SUCCESS;
5190}
5191#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