summaryrefslogtreecommitdiffstats
path: root/src/VBox/Main/src-server/NetworkAdapterImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-server/NetworkAdapterImpl.cpp')
-rw-r--r--src/VBox/Main/src-server/NetworkAdapterImpl.cpp1616
1 files changed, 1616 insertions, 0 deletions
diff --git a/src/VBox/Main/src-server/NetworkAdapterImpl.cpp b/src/VBox/Main/src-server/NetworkAdapterImpl.cpp
new file mode 100644
index 00000000..28ef3b1a
--- /dev/null
+++ b/src/VBox/Main/src-server/NetworkAdapterImpl.cpp
@@ -0,0 +1,1616 @@
+/* $Id: NetworkAdapterImpl.cpp $ */
+/** @file
+ * Implementation of INetworkAdapter in VBoxSVC.
+ */
+
+/*
+ * Copyright (C) 2006-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#define LOG_GROUP LOG_GROUP_MAIN_NETWORKADAPTER
+#include "NetworkAdapterImpl.h"
+#include "NATEngineImpl.h"
+#include "AutoCaller.h"
+#include "LoggingNew.h"
+#include "MachineImpl.h"
+#include "GuestOSTypeImpl.h"
+#include "HostImpl.h"
+#include "SystemPropertiesImpl.h"
+#include "VirtualBoxImpl.h"
+
+#include <iprt/ctype.h>
+#include <iprt/string.h>
+#include <iprt/cpp/utils.h>
+
+#include <iprt/errcore.h>
+#include <VBox/settings.h>
+
+#include "AutoStateDep.h"
+
+// constructor / destructor
+////////////////////////////////////////////////////////////////////////////////
+
+NetworkAdapter::NetworkAdapter()
+ : mParent(NULL)
+{
+}
+
+NetworkAdapter::~NetworkAdapter()
+{
+}
+
+HRESULT NetworkAdapter::FinalConstruct()
+{
+ return BaseFinalConstruct();
+}
+
+void NetworkAdapter::FinalRelease()
+{
+ uninit();
+ BaseFinalRelease();
+}
+
+// public initializer/uninitializer for internal purposes only
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Initializes the network adapter object.
+ *
+ * @param aParent Handle of the parent object.
+ * @param uSlot Slot number this network adapter is plugged into.
+ */
+HRESULT NetworkAdapter::init(Machine *aParent, ULONG uSlot)
+{
+ LogFlowThisFunc(("aParent=%p, uSlot=%d\n", aParent, uSlot));
+
+ ComAssertRet(aParent, E_INVALIDARG);
+ uint32_t maxNetworkAdapters = Global::getMaxNetworkAdapters(aParent->i_getChipsetType());
+ ComAssertRet(uSlot < maxNetworkAdapters, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ unconst(mParent) = aParent;
+ unconst(mNATEngine).createObject();
+ mNATEngine->init(aParent, this);
+ /* mPeer is left null */
+
+ mData.allocate();
+
+ /* initialize data */
+ mData->ulSlot = uSlot;
+
+ /* default to Am79C973 */
+ mData->type = NetworkAdapterType_Am79C973;
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Initializes the network adapter object given another network adapter object
+ * (a kind of copy constructor). This object shares data with
+ * the object passed as an argument.
+ *
+ * @param aParent Parent object.
+ * @param aThat
+ * @param aReshare
+ * When false, the original object will remain a data owner.
+ * Otherwise, data ownership will be transferred from the original
+ * object to this one.
+ *
+ * @note This object must be destroyed before the original object
+ * it shares data with is destroyed.
+ *
+ * @note Locks @a aThat object for reading.
+ */
+HRESULT NetworkAdapter::init(Machine *aParent, NetworkAdapter *aThat, bool aReshare /* = false */)
+{
+ LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n", aParent, aThat, aReshare));
+
+ ComAssertRet(aParent && aThat, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ unconst(mParent) = aParent;
+ /* mPeer is left null */
+
+ unconst(mNATEngine).createObject();
+ mNATEngine->init(aParent, this, aThat->mNATEngine);
+
+ /* sanity */
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnRC(thatCaller.rc());
+
+ if (aReshare)
+ {
+ AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
+
+ unconst(aThat->mPeer) = this;
+ mData.attach(aThat->mData);
+ }
+ else
+ {
+ unconst(mPeer) = aThat;
+
+ AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
+ mData.share(aThat->mData);
+ }
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Initializes the guest object given another guest object
+ * (a kind of copy constructor). This object makes a private copy of data
+ * of the original object passed as an argument.
+ *
+ * @note Locks @a aThat object for reading.
+ */
+HRESULT NetworkAdapter::initCopy(Machine *aParent, NetworkAdapter *aThat)
+{
+ LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
+
+ ComAssertRet(aParent && aThat, E_INVALIDARG);
+
+ /* Enclose the state transition NotReady->InInit->Ready */
+ AutoInitSpan autoInitSpan(this);
+ AssertReturn(autoInitSpan.isOk(), E_FAIL);
+
+ unconst(mParent) = aParent;
+ /* mPeer is left null */
+
+ unconst(mNATEngine).createObject();
+ mNATEngine->initCopy(aParent, this, aThat->mNATEngine);
+
+ /* sanity */
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnRC(thatCaller.rc());
+
+ AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
+ mData.attachCopy(aThat->mData);
+
+ /* Confirm a successful initialization */
+ autoInitSpan.setSucceeded();
+
+ return S_OK;
+}
+
+/**
+ * Uninitializes the instance and sets the ready flag to FALSE.
+ * Called either from FinalRelease() or by the parent when it gets destroyed.
+ */
+void NetworkAdapter::uninit()
+{
+ LogFlowThisFunc(("\n"));
+
+ /* Enclose the state transition Ready->InUninit->NotReady */
+ AutoUninitSpan autoUninitSpan(this);
+ if (autoUninitSpan.uninitDone())
+ return;
+
+ mData.free();
+
+ unconst(mNATEngine).setNull();
+ unconst(mPeer) = NULL;
+ unconst(mParent) = NULL;
+}
+
+// wrapped INetworkAdapter properties
+////////////////////////////////////////////////////////////////////////////////
+HRESULT NetworkAdapter::getAdapterType(NetworkAdapterType_T *aAdapterType)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aAdapterType = mData->type;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setAdapterType(NetworkAdapterType_T aAdapterType)
+{
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ /* make sure the value is allowed */
+ switch (aAdapterType)
+ {
+ case NetworkAdapterType_Am79C970A:
+ case NetworkAdapterType_Am79C973:
+ case NetworkAdapterType_Am79C960:
+#ifdef VBOX_WITH_E1000
+ case NetworkAdapterType_I82540EM:
+ case NetworkAdapterType_I82543GC:
+ case NetworkAdapterType_I82545EM:
+#endif
+#ifdef VBOX_WITH_VIRTIO
+ case NetworkAdapterType_Virtio:
+#endif
+ case NetworkAdapterType_NE1000:
+ case NetworkAdapterType_NE2000:
+ case NetworkAdapterType_WD8003:
+ case NetworkAdapterType_WD8013:
+ case NetworkAdapterType_ELNK2:
+ case NetworkAdapterType_ELNK1:
+ break;
+ default:
+ return setError(E_FAIL,
+ tr("Invalid network adapter type '%d'"),
+ aAdapterType);
+ }
+
+ if (mData->type != aAdapterType)
+ {
+ mData.backup();
+ mData->type = aAdapterType;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* Changing the network adapter type during runtime is not allowed,
+ * therefore no immediate change in CFGM logic => changeAdapter=FALSE. */
+ mParent->i_onNetworkAdapterChange(this, FALSE);
+ }
+
+ return S_OK;
+}
+
+
+HRESULT NetworkAdapter::getSlot(ULONG *uSlot)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *uSlot = mData->ulSlot;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getEnabled(BOOL *aEnabled)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aEnabled = mData->fEnabled;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setEnabled(BOOL aEnabled)
+{
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mData->fEnabled != RT_BOOL(aEnabled))
+ {
+ mData.backup();
+ mData->fEnabled = RT_BOOL(aEnabled);
+ if (RT_BOOL(aEnabled) && mData->strMACAddress.isEmpty())
+ i_generateMACAddress();
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* Disabling the network adapter during runtime is not allowed
+ * therefore no immediate change in CFGM logic => changeAdapter=FALSE. */
+ mParent->i_onNetworkAdapterChange(this, FALSE);
+ }
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getMACAddress(com::Utf8Str &aMACAddress)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ ComAssertRet(!mData->fEnabled || !mData->strMACAddress.isEmpty(), E_FAIL);
+
+ aMACAddress = mData->strMACAddress;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::i_updateMacAddress(Utf8Str aMACAddress)
+{
+ HRESULT rc = S_OK;
+
+ /*
+ * Are we supposed to generate a MAC?
+ */
+ if (mData->fEnabled && aMACAddress.isEmpty())
+ i_generateMACAddress();
+ else
+ {
+ if (mData->strMACAddress != aMACAddress)
+ {
+ if (mData->fEnabled || !aMACAddress.isEmpty())
+ {
+ /*
+ * Verify given MAC address
+ */
+ char *macAddressStr = aMACAddress.mutableRaw();
+ int i = 0;
+ while ((i < 13) && macAddressStr && *macAddressStr && (rc == S_OK))
+ {
+ char c = *macAddressStr;
+ /* canonicalize hex digits to capital letters */
+ if (c >= 'a' && c <= 'f')
+ {
+ c = (char)RTLocCToUpper(c);
+ *macAddressStr = c;
+ }
+ /* we only accept capital letters */
+ if ( (c < '0' || c > '9')
+ && (c < 'A' || c > 'F'))
+ rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
+ /* the second digit must have even value for unicast addresses */
+ if ( (i == 1)
+ && (!!(c & 1) == (c >= '0' && c <= '9')))
+ rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
+
+ macAddressStr++;
+ i++;
+ }
+ /* we must have parsed exactly 12 characters */
+ if (i != 12)
+ rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
+ }
+
+ if (SUCCEEDED(rc))
+ mData->strMACAddress = aMACAddress;
+ }
+ }
+
+ return rc;
+}
+
+HRESULT NetworkAdapter::setMACAddress(const com::Utf8Str &aMACAddress)
+{
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ mData.backup();
+
+ HRESULT rc = i_updateMacAddress(aMACAddress);
+ if (SUCCEEDED(rc))
+ {
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* Changing the MAC via the Main API during runtime is not allowed,
+ * therefore no immediate change in CFGM logic => changeAdapter=FALSE. */
+ mParent->i_onNetworkAdapterChange(this, FALSE);
+ }
+
+ return rc;
+}
+
+HRESULT NetworkAdapter::getAttachmentType(NetworkAttachmentType_T *aAttachmentType)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aAttachmentType = mData->mode;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setAttachmentType(NetworkAttachmentType_T aAttachmentType)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mData->mode != aAttachmentType)
+ {
+ mData.backup();
+
+ /* there must an internal network name */
+ if (mData->strInternalNetworkName.isEmpty())
+ {
+ Log(("Internal network name not defined, setting to default \"intnet\"\n"));
+ mData->strInternalNetworkName = "intnet";
+ }
+
+ /* there must a NAT network name */
+ if (mData->strNATNetworkName.isEmpty())
+ {
+ Log(("NAT network name not defined, setting to default \"NatNetwork\"\n"));
+ mData->strNATNetworkName = "NatNetwork";
+ }
+
+ NetworkAttachmentType_T oldAttachmentType = mData->mode;
+ mData->mode = aAttachmentType;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ if (oldAttachmentType == NetworkAttachmentType_NATNetwork)
+ i_switchFromNatNetworking(mData->strNATNetworkName);
+
+ if (aAttachmentType == NetworkAttachmentType_NATNetwork)
+ i_switchToNatNetworking(mData->strNATNetworkName);
+
+ /* Adapt the CFGM logic and notify the guest => changeAdapter=TRUE. */
+ mParent->i_onNetworkAdapterChange(this, TRUE);
+ }
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getBridgedInterface(com::Utf8Str &aBridgedInterface)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aBridgedInterface = mData->strBridgedName;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setBridgedInterface(const com::Utf8Str &aBridgedInterface)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ Bstr canonicalName = aBridgedInterface;
+#ifdef RT_OS_DARWIN
+ com::SafeIfaceArray<IHostNetworkInterface> hostNetworkInterfaces;
+ ComPtr<IHost> host;
+ HRESULT rc = mParent->i_getVirtualBox()->COMGETTER(Host)(host.asOutParam());
+ if (SUCCEEDED(rc))
+ {
+ host->FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_Bridged,
+ ComSafeArrayAsOutParam(hostNetworkInterfaces));
+ for (size_t i = 0; i < hostNetworkInterfaces.size(); ++i)
+ {
+ Bstr shortName;
+ ComPtr<IHostNetworkInterface> ni = hostNetworkInterfaces[i];
+ ni->COMGETTER(ShortName)(shortName.asOutParam());
+ if (shortName == aBridgedInterface)
+ {
+ ni->COMGETTER(Name)(canonicalName.asOutParam());
+ break;
+ }
+ }
+ }
+#endif /* RT_OS_DARWIN */
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (Bstr(mData->strBridgedName) != canonicalName)
+ {
+ /* if an empty/null string is to be set, bridged interface must be
+ * turned off */
+ if ( canonicalName.isEmpty()
+ && mData->fEnabled
+ && mData->mode == NetworkAttachmentType_Bridged)
+ {
+ return setError(E_FAIL,
+ tr("Empty or null bridged interface name is not valid"));
+ }
+
+ mData.backup();
+ mData->strBridgedName = canonicalName;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* When changing the host adapter, adapt the CFGM logic to make this
+ * change immediately effect and to notify the guest that the network
+ * might have changed, therefore changeAdapter=TRUE. */
+ mParent->i_onNetworkAdapterChange(this, TRUE);
+ }
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getHostOnlyInterface(com::Utf8Str &aHostOnlyInterface)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aHostOnlyInterface = mData->strHostOnlyName;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setHostOnlyInterface(const com::Utf8Str &aHostOnlyInterface)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mData->strHostOnlyName != aHostOnlyInterface)
+ {
+ /* if an empty/null string is to be set, host only interface must be
+ * turned off */
+ if ( aHostOnlyInterface.isEmpty()
+ && mData->fEnabled
+ && mData->mode == NetworkAttachmentType_HostOnly)
+ {
+ return setError(E_FAIL,
+ tr("Empty or null host only interface name is not valid"));
+ }
+
+ mData.backup();
+ mData->strHostOnlyName = aHostOnlyInterface;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* When changing the host adapter, adapt the CFGM logic to make this
+ * change immediately effect and to notify the guest that the network
+ * might have changed, therefore changeAdapter=TRUE. */
+ mParent->i_onNetworkAdapterChange(this, TRUE);
+ }
+
+ return S_OK;
+}
+
+
+HRESULT NetworkAdapter::getHostOnlyNetwork(com::Utf8Str &aHostOnlyNetwork)
+{
+#ifdef VBOX_WITH_VMNET
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aHostOnlyNetwork = mData->strHostOnlyNetworkName;
+
+ return S_OK;
+#else /* !VBOX_WITH_VMNET */
+ NOREF(aHostOnlyNetwork);
+ return E_NOTIMPL;
+#endif /* !VBOX_WITH_VMNET */
+}
+
+HRESULT NetworkAdapter::setHostOnlyNetwork(const com::Utf8Str &aHostOnlyNetwork)
+{
+#ifdef VBOX_WITH_VMNET
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mData->strHostOnlyNetworkName != aHostOnlyNetwork)
+ {
+ /* if an empty/null string is to be set, host only Network must be
+ * turned off */
+ if ( aHostOnlyNetwork.isEmpty()
+ && mData->fEnabled
+ && mData->mode == NetworkAttachmentType_HostOnly)
+ {
+ return setError(E_FAIL,
+ tr("Empty or null host only Network name is not valid"));
+ }
+
+ mData.backup();
+ mData->strHostOnlyNetworkName = aHostOnlyNetwork;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* When changing the host adapter, adapt the CFGM logic to make this
+ * change immediately effect and to notify the guest that the network
+ * might have changed, therefore changeAdapter=TRUE. */
+ mParent->i_onNetworkAdapterChange(this, TRUE);
+ }
+
+ return S_OK;
+#else /* !VBOX_WITH_VMNET */
+ NOREF(aHostOnlyNetwork);
+ return E_NOTIMPL;
+#endif /* !VBOX_WITH_VMNET */
+}
+
+
+HRESULT NetworkAdapter::getInternalNetwork(com::Utf8Str &aInternalNetwork)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aInternalNetwork = mData->strInternalNetworkName;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setInternalNetwork(const com::Utf8Str &aInternalNetwork)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mData->strInternalNetworkName != aInternalNetwork)
+ {
+ /* if an empty/null string is to be set, internal networking must be
+ * turned off */
+ if ( aInternalNetwork.isEmpty()
+ && mData->fEnabled
+ && mData->mode == NetworkAttachmentType_Internal)
+ {
+ return setError(E_FAIL,
+ tr("Empty or null internal network name is not valid"));
+ }
+ mData.backup();
+ mData->strInternalNetworkName = aInternalNetwork;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* When changing the internal network, adapt the CFGM logic to make this
+ * change immediately effect and to notify the guest that the network
+ * might have changed, therefore changeAdapter=TRUE. */
+ mParent->i_onNetworkAdapterChange(this, TRUE);
+ }
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getNATNetwork(com::Utf8Str &aNATNetwork)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aNATNetwork = mData->strNATNetworkName;
+
+ return S_OK;
+}
+
+
+HRESULT NetworkAdapter::setNATNetwork(const com::Utf8Str &aNATNetwork)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mData->strNATNetworkName != aNATNetwork)
+ {
+ /* if an empty/null string is to be set, host only interface must be
+ * turned off */
+ if ( aNATNetwork.isEmpty()
+ && mData->fEnabled
+ && mData->mode == NetworkAttachmentType_NATNetwork)
+ return setError(E_FAIL,
+ tr("Empty or null NAT network name is not valid"));
+
+ mData.backup();
+
+ Bstr oldNatNetworkName = mData->strNATNetworkName;
+ mData->strNATNetworkName = aNATNetwork;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ if (mData->mode == NetworkAttachmentType_NATNetwork)
+ {
+ i_switchFromNatNetworking(oldNatNetworkName.raw());
+ i_switchToNatNetworking(aNATNetwork);
+ }
+
+ /* When changing the host adapter, adapt the CFGM logic to make this
+ * change immediately effect and to notify the guest that the network
+ * might have changed, therefore changeAdapter=TRUE. */
+ mParent->i_onNetworkAdapterChange(this, TRUE);
+ }
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getGenericDriver(com::Utf8Str &aGenericDriver)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aGenericDriver = mData->strGenericDriver;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setGenericDriver(const com::Utf8Str &aGenericDriver)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mData->strGenericDriver != aGenericDriver)
+ {
+ mData.backup();
+ mData->strGenericDriver = aGenericDriver;
+
+ /* leave the lock before informing callbacks */
+ alock.release();
+
+ mParent->i_onNetworkAdapterChange(this, FALSE);
+ }
+
+ return S_OK;
+}
+
+
+HRESULT NetworkAdapter::getCloudNetwork(com::Utf8Str &aCloudNetwork)
+{
+#ifdef VBOX_WITH_CLOUD_NET
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aCloudNetwork = mData->strCloudNetworkName;
+
+ return S_OK;
+#else /* !VBOX_WITH_CLOUD_NET */
+ NOREF(aCloudNetwork);
+ return E_NOTIMPL;
+#endif /* !VBOX_WITH_CLOUD_NET */
+}
+
+HRESULT NetworkAdapter::setCloudNetwork(const com::Utf8Str &aCloudNetwork)
+{
+#ifdef VBOX_WITH_CLOUD_NET
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mData->strCloudNetworkName != aCloudNetwork)
+ {
+ /* if an empty/null string is to be set, Cloud networking must be
+ * turned off */
+ if ( aCloudNetwork.isEmpty()
+ && mData->fEnabled
+ && mData->mode == NetworkAttachmentType_Cloud)
+ {
+ return setError(E_FAIL,
+ tr("Empty or null Cloud network name is not valid"));
+ }
+ mData.backup();
+ mData->strCloudNetworkName = aCloudNetwork;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+#if 0
+ /// @todo Implement dynamic re-attachment of cloud network
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* When changing the internal network, adapt the CFGM logic to make this
+ * change immediately effect and to notify the guest that the network
+ * might have changed, therefore changeAdapter=TRUE. */
+ mParent->i_onNetworkAdapterChange(this, TRUE);
+#else
+ mParent->i_onNetworkAdapterChange(this, FALSE);
+#endif
+ }
+ return S_OK;
+#else /* !VBOX_WITH_CLOUD_NET */
+ NOREF(aCloudNetwork);
+ return E_NOTIMPL;
+#endif /* !VBOX_WITH_CLOUD_NET */
+}
+
+
+HRESULT NetworkAdapter::getCableConnected(BOOL *aConnected)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aConnected = mData->fCableConnected;
+
+ return S_OK;
+}
+
+
+HRESULT NetworkAdapter::setCableConnected(BOOL aConnected)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (RT_BOOL(aConnected) != mData->fCableConnected)
+ {
+ mData.backup();
+ mData->fCableConnected = RT_BOOL(aConnected);
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* No change in CFGM logic => changeAdapter=FALSE. */
+ mParent->i_onNetworkAdapterChange(this, FALSE);
+ }
+
+ return S_OK;
+}
+
+
+HRESULT NetworkAdapter::getLineSpeed(ULONG *aSpeed)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aSpeed = mData->ulLineSpeed;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setLineSpeed(ULONG aSpeed)
+{
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aSpeed != mData->ulLineSpeed)
+ {
+ mData.backup();
+ mData->ulLineSpeed = aSpeed;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* No change in CFGM logic => changeAdapter=FALSE. */
+ mParent->i_onNetworkAdapterChange(this, FALSE);
+ }
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getPromiscModePolicy(NetworkAdapterPromiscModePolicy_T *aPromiscModePolicy)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aPromiscModePolicy = mData->enmPromiscModePolicy;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setPromiscModePolicy(NetworkAdapterPromiscModePolicy_T aPromiscModePolicy)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ switch (aPromiscModePolicy)
+ {
+ case NetworkAdapterPromiscModePolicy_Deny:
+ case NetworkAdapterPromiscModePolicy_AllowNetwork:
+ case NetworkAdapterPromiscModePolicy_AllowAll:
+ break;
+ default:
+ return setError(E_INVALIDARG, tr("Invalid promiscuous mode policy (%d)"), aPromiscModePolicy);
+ }
+
+ AutoCaller autoCaller(this);
+ HRESULT hrc = autoCaller.rc();
+
+ if (SUCCEEDED(hrc))
+ {
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ if (aPromiscModePolicy != mData->enmPromiscModePolicy)
+ {
+ mData.backup();
+ mData->enmPromiscModePolicy = aPromiscModePolicy;
+
+ alock.release();
+ mParent->i_setModifiedLock(Machine::IsModified_NetworkAdapters);
+ mParent->i_onNetworkAdapterChange(this, TRUE);
+ }
+ }
+
+ return hrc;
+}
+
+
+HRESULT NetworkAdapter::getTraceEnabled(BOOL *aEnabled)
+{
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aEnabled = mData->fTraceEnabled;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setTraceEnabled(BOOL aEnabled)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (RT_BOOL(aEnabled) != mData->fTraceEnabled)
+ {
+ mData.backup();
+ mData->fTraceEnabled = RT_BOOL(aEnabled);
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* Adapt the CFGM logic changeAdapter=TRUE */
+ mParent->i_onNetworkAdapterChange(this, TRUE);
+ }
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getTraceFile(com::Utf8Str &aTraceFile)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aTraceFile = mData->strTraceFile;
+
+ return S_OK;
+}
+
+
+HRESULT NetworkAdapter::setTraceFile(const com::Utf8Str &aTraceFile)
+{
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mData->strTraceFile != aTraceFile)
+ {
+ mData.backup();
+ mData->strTraceFile = aTraceFile;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* We change the 'File' => changeAdapter=TRUE. */
+ mParent->i_onNetworkAdapterChange(this, TRUE);
+ }
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getNATEngine(ComPtr<INATEngine> &aNATEngine)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ aNATEngine = mNATEngine;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getBootPriority(ULONG *aBootPriority)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aBootPriority = mData->ulBootPriority;
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setBootPriority(ULONG aBootPriority)
+{
+ /* the machine needs to be mutable */
+ AutoMutableStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (aBootPriority != mData->ulBootPriority)
+ {
+ mData.backup();
+ mData->ulBootPriority = aBootPriority;
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* No change in CFGM logic => changeAdapter=FALSE. */
+ mParent->i_onNetworkAdapterChange(this, FALSE);
+ }
+
+ return S_OK;
+}
+
+// wrapped INetworkAdapter methods
+////////////////////////////////////////////////////////////////////////////////
+
+HRESULT NetworkAdapter::getProperty(const com::Utf8Str &aKey, com::Utf8Str &aValue)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+ aValue = "";
+ settings::StringsMap::const_iterator it = mData->genericProperties.find(aKey);
+ if (it != mData->genericProperties.end())
+ aValue = it->second; // source is a Utf8Str
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::setProperty(const com::Utf8Str &aKey, const com::Utf8Str &aValue)
+{
+ LogFlowThisFunc(("\n"));
+ /* The machine needs to be mutable. */
+ AutoMutableOrSavedOrRunningStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+ bool fGenericChange = (mData->mode == NetworkAttachmentType_Generic);
+ /* Generic properties processing.
+ * Look up the old value first; if nothing's changed then do nothing.
+ */
+ Utf8Str strOldValue;
+ settings::StringsMap::const_iterator it = mData->genericProperties.find(aKey);
+ if (it != mData->genericProperties.end())
+ strOldValue = it->second;
+
+ if (strOldValue != aValue)
+ {
+ if (aValue.isEmpty())
+ mData->genericProperties.erase(aKey);
+ else
+ mData->genericProperties[aKey] = aValue;
+
+ /* leave the lock before informing callbacks */
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /* Avoid deadlock when the event triggers a call to a method of this
+ * interface. */
+ adep.release();
+
+ mParent->i_onNetworkAdapterChange(this, fGenericChange);
+ }
+
+ return S_OK;
+}
+
+HRESULT NetworkAdapter::getProperties(const com::Utf8Str &aNames,
+ std::vector<com::Utf8Str> &aReturnNames,
+ std::vector<com::Utf8Str> &aReturnValues)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ /// @todo make use of aNames according to the documentation
+ NOREF(aNames);
+ aReturnNames.resize(mData->genericProperties.size());
+ aReturnValues.resize(mData->genericProperties.size());
+
+ size_t i = 0;
+
+ for (settings::StringsMap::const_iterator it = mData->genericProperties.begin();
+ it != mData->genericProperties.end();
+ ++it, ++i)
+ {
+ aReturnNames[i] = it->first;
+ aReturnValues[i] = it->second;
+ }
+
+ return S_OK;
+}
+
+
+
+// public methods only for internal purposes
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Loads settings from the given adapter node.
+ * May be called once right after this object creation.
+ *
+ * @param bwctl bandwidth control object.
+ * @param data Configuration settings.
+ *
+ * @note Locks this object for writing.
+ */
+HRESULT NetworkAdapter::i_loadSettings(BandwidthControl *bwctl,
+ const settings::NetworkAdapter &data)
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ /* Note: we assume that the default values for attributes of optional
+ * nodes are assigned in the Data::Data() constructor and don't do it
+ * here. It implies that this method may only be called after constructing
+ * a new BIOSSettings object while all its data fields are in the default
+ * values. Exceptions are fields whose creation time defaults don't match
+ * values that should be applied when these fields are not explicitly set
+ * in the settings file (for backwards compatibility reasons). This takes
+ * place when a setting of a newly created object must default to A while
+ * the same setting of an object loaded from the old settings file must
+ * default to B. */
+
+ HRESULT rc = S_OK;
+
+ /* MAC address (can be null) */
+ rc = i_updateMacAddress(data.strMACAddress);
+ if (FAILED(rc)) return rc;
+
+ mData.assignCopy(&data);
+
+ if (mData->strBandwidthGroup.isNotEmpty())
+ {
+ ComObjPtr<BandwidthGroup> group;
+ rc = bwctl->i_getBandwidthGroupByName(data.strBandwidthGroup, group, true);
+ if (FAILED(rc)) return rc;
+ group->i_reference();
+ }
+
+ // Load NAT engine settings.
+ mNATEngine->i_loadSettings(data.nat);
+
+ // leave the lock before setting attachment type
+ alock.release();
+
+ rc = COMSETTER(AttachmentType)(data.mode);
+ if (FAILED(rc)) return rc;
+
+ return S_OK;
+}
+
+/**
+ * Saves settings to the given adapter node.
+ *
+ * Note that the given Adapter node is completely empty on input.
+ *
+ * @param data Configuration settings.
+ *
+ * @note Locks this object for reading.
+ */
+HRESULT NetworkAdapter::i_saveSettings(settings::NetworkAdapter &data)
+{
+ AutoCaller autoCaller(this);
+ AssertComRCReturnRC(autoCaller.rc());
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ data = *mData.data();
+
+ mNATEngine->i_saveSettings(data.nat);
+
+ return S_OK;
+}
+
+/**
+ * Returns true if any setter method has modified settings of this instance.
+ * @return
+ */
+bool NetworkAdapter::i_isModified()
+{
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ bool fChanged = mData.isBackedUp();
+ fChanged |= mNATEngine->i_isModified();
+ return fChanged;
+}
+
+/**
+ * @note Locks this object for writing.
+ */
+void NetworkAdapter::i_rollback()
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ mNATEngine->i_rollback();
+
+ mData.rollback();
+}
+
+/**
+ * @note Locks this object for writing, together with the peer object (also
+ * for writing) if there is one.
+ */
+void NetworkAdapter::i_commit()
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ /* sanity too */
+ AutoCaller peerCaller(mPeer);
+ AssertComRCReturnVoid(peerCaller.rc());
+
+ /* lock both for writing since we modify both (mPeer is "master" so locked
+ * first) */
+ AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
+
+ mNATEngine->i_commit();
+
+ if (mData.isBackedUp())
+ {
+ mData.commit();
+ if (mPeer)
+ {
+ /* attach new data to the peer and reshare it */
+ mPeer->mData.attach(mData);
+ }
+ }
+}
+
+/**
+ * @note Locks this object for writing, together with the peer object
+ * represented by @a aThat (locked for reading).
+ */
+void NetworkAdapter::i_copyFrom(NetworkAdapter *aThat)
+{
+ AssertReturnVoid(aThat != NULL);
+
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ /* sanity too */
+ AutoCaller thatCaller(aThat);
+ AssertComRCReturnVoid(thatCaller.rc());
+
+ mNATEngine->i_copyFrom(aThat->mNATEngine);
+
+ /* peer is not modified, lock it for reading (aThat is "master" so locked
+ * first) */
+ AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
+ AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
+
+ /* this will back up current data */
+ mData.assignCopy(aThat->mData);
+
+}
+
+/**
+ * Applies the defaults for this network adapter.
+ *
+ * @note This method currently assumes that the object is in the state after
+ * calling init(), it does not set defaults from an arbitrary state.
+ */
+void NetworkAdapter::i_applyDefaults(GuestOSType *aOsType)
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturnVoid(autoCaller.rc());
+
+ mNATEngine->i_applyDefaults();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ bool e1000enabled = false;
+#ifdef VBOX_WITH_E1000
+ e1000enabled = true;
+#endif // VBOX_WITH_E1000
+
+ NetworkAdapterType_T defaultType;
+ if (aOsType)
+ defaultType = aOsType->i_networkAdapterType();
+ else
+ {
+#ifdef VBOX_WITH_E1000
+ defaultType = NetworkAdapterType_I82540EM;
+#else
+ defaultType = NetworkAdapterType_Am79C973A;
+#endif
+ }
+
+
+ /* Set default network adapter for this OS type */
+ if (defaultType == NetworkAdapterType_I82540EM ||
+ defaultType == NetworkAdapterType_I82543GC ||
+ defaultType == NetworkAdapterType_I82545EM)
+ {
+ if (e1000enabled)
+ mData->type = defaultType;
+ }
+ else
+ mData->type = defaultType;
+
+ /* Enable the first one adapter and set it to NAT */
+ /** @todo r=klaus remove this long term, since a newly created VM should
+ * have no additional hardware components unless configured either
+ * explicitly or through Machine::applyDefaults. */
+ if (aOsType && mData->ulSlot == 0)
+ {
+ mData->fEnabled = true;
+ if (mData->strMACAddress.isEmpty())
+ i_generateMACAddress();
+ mData->mode = NetworkAttachmentType_NAT;
+ }
+ mData->fCableConnected = true;
+}
+
+bool NetworkAdapter::i_hasDefaults()
+{
+ /* sanity */
+ AutoCaller autoCaller(this);
+ AssertComRCReturn(autoCaller.rc(), true);
+
+ ComObjPtr<GuestOSType> pGuestOSType;
+ HRESULT rc = mParent->i_getVirtualBox()->i_findGuestOSType(mParent->i_getOSTypeId(),
+ pGuestOSType);
+ if (FAILED(rc))
+ return false;
+
+ NetworkAdapterType_T defaultType = pGuestOSType->i_networkAdapterType();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if ( !mData->fEnabled
+ && mData->strMACAddress.isEmpty()
+ && mData->type == defaultType
+ && mData->fCableConnected
+ && mData->ulLineSpeed == 0
+ && mData->enmPromiscModePolicy == NetworkAdapterPromiscModePolicy_Deny
+ && mData->mode == NetworkAttachmentType_Null
+ && mData->strBridgedName.isEmpty()
+ && mData->strInternalNetworkName.isEmpty()
+ && mData->strHostOnlyName.isEmpty()
+ && mData->strNATNetworkName.isEmpty()
+ && mData->strGenericDriver.isEmpty()
+ && mData->genericProperties.size() == 0)
+ {
+ /* Could be default, check NAT defaults. */
+ return mNATEngine->i_hasDefaults();
+ }
+
+ return false;
+}
+
+ComObjPtr<NetworkAdapter> NetworkAdapter::i_getPeer()
+{
+ return mPeer;
+}
+
+
+// private methods
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Generates a new unique MAC address based on our vendor ID and
+ * parts of a GUID.
+ *
+ * @note Must be called from under the object's write lock or within the init
+ * span.
+ */
+void NetworkAdapter::i_generateMACAddress()
+{
+ Utf8Str mac;
+ Host::i_generateMACAddress(mac);
+ LogFlowThisFunc(("generated MAC: '%s'\n", mac.c_str()));
+ mData->strMACAddress = mac;
+}
+
+HRESULT NetworkAdapter::getBandwidthGroup(ComPtr<IBandwidthGroup> &aBandwidthGroup)
+{
+ LogFlowThisFuncEnter();
+
+ HRESULT hrc = S_OK;
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ if (mData->strBandwidthGroup.isNotEmpty())
+ {
+ ComObjPtr<BandwidthGroup> pBwGroup;
+ hrc = mParent->i_getBandwidthGroup(mData->strBandwidthGroup, pBwGroup, true /* fSetError */);
+
+ Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence
+ * of the group was checked when it was attached. */
+ if (SUCCEEDED(hrc))
+ pBwGroup.queryInterfaceTo(aBandwidthGroup.asOutParam());
+ }
+
+ LogFlowThisFuncLeave();
+ return hrc;
+}
+
+HRESULT NetworkAdapter::setBandwidthGroup(const ComPtr<IBandwidthGroup> &aBandwidthGroup)
+{
+ LogFlowThisFuncEnter();
+
+ /* the machine needs to be mutable */
+ AutoMutableOrSavedStateDependency adep(mParent);
+ if (FAILED(adep.rc())) return adep.rc();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ IBandwidthGroup *iBw = aBandwidthGroup;
+ Utf8Str strBwGroup;
+ if (aBandwidthGroup)
+ strBwGroup = static_cast<BandwidthGroup *>(iBw)->i_getName();
+
+ if (mData->strBandwidthGroup != strBwGroup)
+ {
+ ComObjPtr<BandwidthGroup> pBwGroup;
+ if (!strBwGroup.isEmpty())
+ {
+ HRESULT hrc = mParent->i_getBandwidthGroup(strBwGroup, pBwGroup, false /* fSetError */);
+ NOREF(hrc);
+ Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence
+ of the group was checked when it was attached. */
+ }
+
+ i_updateBandwidthGroup(pBwGroup);
+
+ // leave the lock before informing callbacks
+ alock.release();
+
+ AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
+ mParent->i_setModified(Machine::IsModified_NetworkAdapters);
+ mlock.release();
+
+ /** @todo changeAdapter=???. */
+ mParent->i_onNetworkAdapterChange(this, FALSE);
+ }
+
+ LogFlowThisFuncLeave();
+ return S_OK;
+}
+
+void NetworkAdapter::i_updateBandwidthGroup(BandwidthGroup *aBwGroup)
+{
+ LogFlowThisFuncEnter();
+ Assert(isWriteLockOnCurrentThread());
+
+ ComObjPtr<BandwidthGroup> pOldBwGroup;
+ if (!mData->strBandwidthGroup.isEmpty())
+ {
+ HRESULT hrc = mParent->i_getBandwidthGroup(mData->strBandwidthGroup, pOldBwGroup, false /* fSetError */);
+ NOREF(hrc);
+ Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of
+ the group was checked when it was attached. */
+ }
+
+ mData.backup();
+ if (!pOldBwGroup.isNull())
+ {
+ pOldBwGroup->i_release();
+ mData->strBandwidthGroup = Utf8Str::Empty;
+ }
+
+ if (aBwGroup)
+ {
+ mData->strBandwidthGroup = aBwGroup->i_getName();
+ aBwGroup->i_reference();
+ }
+
+ LogFlowThisFuncLeave();
+}
+
+
+HRESULT NetworkAdapter::i_switchFromNatNetworking(const com::Utf8Str &networkName)
+{
+ HRESULT hrc;
+ MachineState_T state;
+
+ hrc = mParent->COMGETTER(State)(&state);
+ if (FAILED(hrc))
+ return hrc;
+
+ if ( state == MachineState_Running
+ || state == MachineState_Paused)
+ {
+ Bstr bstrName;
+ hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
+ LogRel(("VM '%ls' stops using NAT network '%s'\n", bstrName.raw(), networkName.c_str()));
+ int natCount = mParent->i_getVirtualBox()->i_natNetworkRefDec(Bstr(networkName).raw());
+ if (natCount == -1)
+ return E_INVALIDARG; /* no such network */
+ }
+
+ return S_OK;
+}
+
+
+HRESULT NetworkAdapter::i_switchToNatNetworking(const com::Utf8Str &aNatNetworkName)
+{
+ HRESULT hrc;
+ MachineState_T state;
+
+ hrc = mParent->COMGETTER(State)(&state);
+ if (FAILED(hrc))
+ return hrc;
+
+ if ( state == MachineState_Running
+ || state == MachineState_Paused)
+ {
+ Bstr bstrName;
+ hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
+ LogRel(("VM '%ls' starts using NAT network '%s'\n", bstrName.raw(), aNatNetworkName.c_str()));
+ int natCount = mParent->i_getVirtualBox()->i_natNetworkRefInc(Bstr(aNatNetworkName).raw());
+ if (natCount == -1)
+ return E_INVALIDARG; /* not found */
+ }
+
+ return S_OK;
+}
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */