VirtualBox

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

Last change on this file since 107644 was 107579, checked in by vboxsync, 3 months ago

src/VBox/Main/src-client/ConsoleImplConfigCommon.cpp: Fixed warnings found by Parfait (assignment unused). jiraref:VBP-1424

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette