VirtualBox

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

Last change on this file since 107834 was 107820, checked in by vboxsync, 4 months ago

libslirp/udp.c,Main: Spaces. bugref:10268

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