VirtualBox

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

Last change on this file was 107930, checked in by vboxsync, 4 weeks ago

Audio/Windows: Purged the WinMM backend wherever possible; default to WAS backend if applicable. Also fixed the XML samples which had WinMM set for many many years. bugref:10845

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