VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/NetworkAdapterImpl.cpp

Last change on this file was 101035, checked in by vboxsync, 8 months ago

Initial commit (based draft v2 / on patch v5) for implementing platform architecture support for x86 and ARM. bugref:10384

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.9 KB
Line 
1/* $Id: NetworkAdapterImpl.cpp 101035 2023-09-07 08:59:15Z vboxsync $ */
2/** @file
3 * Implementation of INetworkAdapter in VBoxSVC.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_NETWORKADAPTER
29#include "NetworkAdapterImpl.h"
30#include "NATEngineImpl.h"
31#include "AutoCaller.h"
32#include "LoggingNew.h"
33#include "MachineImpl.h"
34#include "GuestOSTypeImpl.h"
35#include "HostImpl.h"
36#include "SystemPropertiesImpl.h"
37#include "VirtualBoxImpl.h"
38
39#include <iprt/ctype.h>
40#include <iprt/string.h>
41#include <iprt/cpp/utils.h>
42
43#include <iprt/errcore.h>
44#include <VBox/settings.h>
45
46#include "AutoStateDep.h"
47
48// constructor / destructor
49////////////////////////////////////////////////////////////////////////////////
50
51NetworkAdapter::NetworkAdapter()
52 : mParent(NULL)
53{
54}
55
56NetworkAdapter::~NetworkAdapter()
57{
58}
59
60HRESULT NetworkAdapter::FinalConstruct()
61{
62 return BaseFinalConstruct();
63}
64
65void NetworkAdapter::FinalRelease()
66{
67 uninit();
68 BaseFinalRelease();
69}
70
71// public initializer/uninitializer for internal purposes only
72////////////////////////////////////////////////////////////////////////////////
73
74/**
75 * Initializes the network adapter object.
76 *
77 * @param aParent Handle of the parent object.
78 * @param uSlot Slot number this network adapter is plugged into.
79 */
80HRESULT NetworkAdapter::init(Machine *aParent, ULONG uSlot)
81{
82 ComAssertRet(aParent, E_INVALIDARG);
83
84 LogFlowThisFunc(("aParent=%p, uSlot=%d\n", aParent, uSlot));
85
86 ChipsetType_T enmChipsetType;
87 HRESULT hrc = aParent->i_getPlatform()->getChipsetType(&enmChipsetType);
88 if (FAILED(hrc))
89 return hrc;
90
91 uint32_t const maxNetworkAdapters = PlatformProperties::s_getMaxNetworkAdapters(enmChipsetType);
92 ComAssertRet(uSlot < maxNetworkAdapters, E_INVALIDARG);
93
94 /* Enclose the state transition NotReady->InInit->Ready */
95 AutoInitSpan autoInitSpan(this);
96 AssertReturn(autoInitSpan.isOk(), E_FAIL);
97
98 unconst(mParent) = aParent;
99 unconst(mNATEngine).createObject();
100 mNATEngine->init(aParent, this);
101 /* mPeer is left null */
102
103 mData.allocate();
104
105 /* initialize data */
106 mData->ulSlot = uSlot;
107
108 /* default to Am79C973 */
109 mData->type = NetworkAdapterType_Am79C973;
110
111 /* Confirm a successful initialization */
112 autoInitSpan.setSucceeded();
113
114 return S_OK;
115}
116
117/**
118 * Initializes the network adapter object given another network adapter object
119 * (a kind of copy constructor). This object shares data with
120 * the object passed as an argument.
121 *
122 * @param aParent Parent object.
123 * @param aThat
124 * @param aReshare
125 * When false, the original object will remain a data owner.
126 * Otherwise, data ownership will be transferred from the original
127 * object to this one.
128 *
129 * @note This object must be destroyed before the original object
130 * it shares data with is destroyed.
131 *
132 * @note Locks @a aThat object for reading.
133 */
134HRESULT NetworkAdapter::init(Machine *aParent, NetworkAdapter *aThat, bool aReshare /* = false */)
135{
136 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n", aParent, aThat, aReshare));
137
138 ComAssertRet(aParent && aThat, E_INVALIDARG);
139
140 /* Enclose the state transition NotReady->InInit->Ready */
141 AutoInitSpan autoInitSpan(this);
142 AssertReturn(autoInitSpan.isOk(), E_FAIL);
143
144 unconst(mParent) = aParent;
145 /* mPeer is left null */
146
147 unconst(mNATEngine).createObject();
148 mNATEngine->init(aParent, this, aThat->mNATEngine);
149
150 /* sanity */
151 AutoCaller thatCaller(aThat);
152 AssertComRCReturnRC(thatCaller.hrc());
153
154 if (aReshare)
155 {
156 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
157
158 unconst(aThat->mPeer) = this;
159 mData.attach(aThat->mData);
160 }
161 else
162 {
163 unconst(mPeer) = aThat;
164
165 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
166 mData.share(aThat->mData);
167 }
168
169 /* Confirm a successful initialization */
170 autoInitSpan.setSucceeded();
171
172 return S_OK;
173}
174
175/**
176 * Initializes the guest object given another guest object
177 * (a kind of copy constructor). This object makes a private copy of data
178 * of the original object passed as an argument.
179 *
180 * @note Locks @a aThat object for reading.
181 */
182HRESULT NetworkAdapter::initCopy(Machine *aParent, NetworkAdapter *aThat)
183{
184 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
185
186 ComAssertRet(aParent && aThat, E_INVALIDARG);
187
188 /* Enclose the state transition NotReady->InInit->Ready */
189 AutoInitSpan autoInitSpan(this);
190 AssertReturn(autoInitSpan.isOk(), E_FAIL);
191
192 unconst(mParent) = aParent;
193 /* mPeer is left null */
194
195 unconst(mNATEngine).createObject();
196 mNATEngine->initCopy(aParent, this, aThat->mNATEngine);
197
198 /* sanity */
199 AutoCaller thatCaller(aThat);
200 AssertComRCReturnRC(thatCaller.hrc());
201
202 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
203 mData.attachCopy(aThat->mData);
204
205 /* Confirm a successful initialization */
206 autoInitSpan.setSucceeded();
207
208 return S_OK;
209}
210
211/**
212 * Uninitializes the instance and sets the ready flag to FALSE.
213 * Called either from FinalRelease() or by the parent when it gets destroyed.
214 */
215void NetworkAdapter::uninit()
216{
217 LogFlowThisFunc(("\n"));
218
219 /* Enclose the state transition Ready->InUninit->NotReady */
220 AutoUninitSpan autoUninitSpan(this);
221 if (autoUninitSpan.uninitDone())
222 return;
223
224 mData.free();
225
226 unconst(mNATEngine).setNull();
227 unconst(mPeer) = NULL;
228 unconst(mParent) = NULL;
229}
230
231// wrapped INetworkAdapter properties
232////////////////////////////////////////////////////////////////////////////////
233HRESULT NetworkAdapter::getAdapterType(NetworkAdapterType_T *aAdapterType)
234{
235 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
236
237 *aAdapterType = mData->type;
238
239 return S_OK;
240}
241
242HRESULT NetworkAdapter::setAdapterType(NetworkAdapterType_T aAdapterType)
243{
244 /* the machine needs to be mutable */
245 AutoMutableStateDependency adep(mParent);
246 if (FAILED(adep.hrc())) return adep.hrc();
247
248 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
249
250 /* make sure the value is allowed */
251 switch (aAdapterType)
252 {
253 case NetworkAdapterType_Am79C970A:
254 case NetworkAdapterType_Am79C973:
255 case NetworkAdapterType_Am79C960:
256#ifdef VBOX_WITH_E1000
257 case NetworkAdapterType_I82540EM:
258 case NetworkAdapterType_I82543GC:
259 case NetworkAdapterType_I82545EM:
260#endif
261#ifdef VBOX_WITH_VIRTIO
262 case NetworkAdapterType_Virtio:
263#endif
264 case NetworkAdapterType_NE1000:
265 case NetworkAdapterType_NE2000:
266 case NetworkAdapterType_WD8003:
267 case NetworkAdapterType_WD8013:
268 case NetworkAdapterType_ELNK2:
269 case NetworkAdapterType_ELNK1:
270 break;
271 default:
272 return setError(E_FAIL,
273 tr("Invalid network adapter type '%d'"),
274 aAdapterType);
275 }
276
277 if (mData->type != aAdapterType)
278 {
279 mData.backup();
280 mData->type = aAdapterType;
281
282 // leave the lock before informing callbacks
283 alock.release();
284
285 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
286 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
287 mlock.release();
288
289 /* Changing the network adapter type during runtime is not allowed,
290 * therefore no immediate change in CFGM logic => changeAdapter=FALSE. */
291 mParent->i_onNetworkAdapterChange(this, FALSE);
292 }
293
294 return S_OK;
295}
296
297
298HRESULT NetworkAdapter::getSlot(ULONG *uSlot)
299{
300 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
301
302 *uSlot = mData->ulSlot;
303
304 return S_OK;
305}
306
307HRESULT NetworkAdapter::getEnabled(BOOL *aEnabled)
308{
309 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
310
311 *aEnabled = mData->fEnabled;
312
313 return S_OK;
314}
315
316HRESULT NetworkAdapter::setEnabled(BOOL aEnabled)
317{
318 /* the machine needs to be mutable */
319 AutoMutableStateDependency adep(mParent);
320 if (FAILED(adep.hrc())) return adep.hrc();
321
322 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
323
324 if (mData->fEnabled != RT_BOOL(aEnabled))
325 {
326 mData.backup();
327 mData->fEnabled = RT_BOOL(aEnabled);
328 if (RT_BOOL(aEnabled) && mData->strMACAddress.isEmpty())
329 i_generateMACAddress();
330
331 // leave the lock before informing callbacks
332 alock.release();
333
334 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
335 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
336 mlock.release();
337
338 /* Disabling the network adapter during runtime is not allowed
339 * therefore no immediate change in CFGM logic => changeAdapter=FALSE. */
340 mParent->i_onNetworkAdapterChange(this, FALSE);
341 }
342
343 return S_OK;
344}
345
346HRESULT NetworkAdapter::getMACAddress(com::Utf8Str &aMACAddress)
347{
348 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
349
350 ComAssertRet(!mData->fEnabled || !mData->strMACAddress.isEmpty(), E_FAIL);
351
352 aMACAddress = mData->strMACAddress;
353
354 return S_OK;
355}
356
357HRESULT NetworkAdapter::i_updateMacAddress(Utf8Str aMACAddress)
358{
359 HRESULT hrc = S_OK;
360
361 /*
362 * Are we supposed to generate a MAC?
363 */
364 if (mData->fEnabled && aMACAddress.isEmpty())
365 i_generateMACAddress();
366 else
367 {
368 if (mData->strMACAddress != aMACAddress)
369 {
370 if (mData->fEnabled || !aMACAddress.isEmpty())
371 {
372 /*
373 * Verify given MAC address
374 */
375 char *macAddressStr = aMACAddress.mutableRaw();
376 int i = 0;
377 while ((i < 13) && macAddressStr && *macAddressStr && hrc == S_OK)
378 {
379 char c = *macAddressStr;
380 /* canonicalize hex digits to capital letters */
381 if (c >= 'a' && c <= 'f')
382 {
383 c = (char)RTLocCToUpper(c);
384 *macAddressStr = c;
385 }
386 /* we only accept capital letters */
387 if ( (c < '0' || c > '9')
388 && (c < 'A' || c > 'F'))
389 hrc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
390 /* the second digit must have even value for unicast addresses */
391 if ( (i == 1)
392 && (!!(c & 1) == (c >= '0' && c <= '9')))
393 hrc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
394
395 macAddressStr++;
396 i++;
397 }
398 /* we must have parsed exactly 12 characters */
399 if (i != 12)
400 hrc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
401 }
402
403 if (SUCCEEDED(hrc))
404 mData->strMACAddress = aMACAddress;
405 }
406 }
407
408 return hrc;
409}
410
411HRESULT NetworkAdapter::setMACAddress(const com::Utf8Str &aMACAddress)
412{
413 /* the machine needs to be mutable */
414 AutoMutableStateDependency adep(mParent);
415 if (FAILED(adep.hrc())) return adep.hrc();
416
417 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
418 mData.backup();
419
420 HRESULT hrc = i_updateMacAddress(aMACAddress);
421 if (SUCCEEDED(hrc))
422 {
423 // leave the lock before informing callbacks
424 alock.release();
425
426 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
427 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
428 mlock.release();
429
430 /* Changing the MAC via the Main API during runtime is not allowed,
431 * therefore no immediate change in CFGM logic => changeAdapter=FALSE. */
432 mParent->i_onNetworkAdapterChange(this, FALSE);
433 }
434
435 return hrc;
436}
437
438HRESULT NetworkAdapter::getAttachmentType(NetworkAttachmentType_T *aAttachmentType)
439{
440 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
441
442 *aAttachmentType = mData->mode;
443
444 return S_OK;
445}
446
447HRESULT NetworkAdapter::setAttachmentType(NetworkAttachmentType_T aAttachmentType)
448{
449 /* the machine needs to be mutable */
450 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
451 if (FAILED(adep.hrc())) return adep.hrc();
452
453 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
454
455 if (mData->mode != aAttachmentType)
456 {
457 mData.backup();
458
459 /* there must an internal network name */
460 if (mData->strInternalNetworkName.isEmpty())
461 {
462 Log(("Internal network name not defined, setting to default \"intnet\"\n"));
463 mData->strInternalNetworkName = "intnet";
464 }
465
466 /* there must a NAT network name */
467 if (mData->strNATNetworkName.isEmpty())
468 {
469 Log(("NAT network name not defined, setting to default \"NatNetwork\"\n"));
470 mData->strNATNetworkName = "NatNetwork";
471 }
472
473 NetworkAttachmentType_T oldAttachmentType = mData->mode;
474 mData->mode = aAttachmentType;
475
476 // leave the lock before informing callbacks
477 alock.release();
478
479 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
480 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
481 mlock.release();
482
483 if (oldAttachmentType == NetworkAttachmentType_NATNetwork)
484 i_switchFromNatNetworking(mData->strNATNetworkName);
485
486 if (aAttachmentType == NetworkAttachmentType_NATNetwork)
487 i_switchToNatNetworking(mData->strNATNetworkName);
488
489 /* Adapt the CFGM logic and notify the guest => changeAdapter=TRUE. */
490 mParent->i_onNetworkAdapterChange(this, TRUE);
491 }
492
493 return S_OK;
494}
495
496HRESULT NetworkAdapter::getBridgedInterface(com::Utf8Str &aBridgedInterface)
497{
498 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
499
500 aBridgedInterface = mData->strBridgedName;
501
502 return S_OK;
503}
504
505HRESULT NetworkAdapter::setBridgedInterface(const com::Utf8Str &aBridgedInterface)
506{
507 /* the machine needs to be mutable */
508 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
509 if (FAILED(adep.hrc())) return adep.hrc();
510
511 Bstr canonicalName = aBridgedInterface;
512#ifdef RT_OS_DARWIN
513 com::SafeIfaceArray<IHostNetworkInterface> hostNetworkInterfaces;
514 ComPtr<IHost> host;
515 HRESULT hrc = mParent->i_getVirtualBox()->COMGETTER(Host)(host.asOutParam());
516 if (SUCCEEDED(hrc))
517 {
518 host->FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_Bridged,
519 ComSafeArrayAsOutParam(hostNetworkInterfaces));
520 for (size_t i = 0; i < hostNetworkInterfaces.size(); ++i)
521 {
522 Bstr shortName;
523 ComPtr<IHostNetworkInterface> ni = hostNetworkInterfaces[i];
524 ni->COMGETTER(ShortName)(shortName.asOutParam());
525 if (shortName == aBridgedInterface)
526 {
527 ni->COMGETTER(Name)(canonicalName.asOutParam());
528 break;
529 }
530 }
531 }
532#endif /* RT_OS_DARWIN */
533 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
534
535 if (Bstr(mData->strBridgedName) != canonicalName)
536 {
537 /* if an empty/null string is to be set, bridged interface must be
538 * turned off */
539 if ( canonicalName.isEmpty()
540 && mData->fEnabled
541 && mData->mode == NetworkAttachmentType_Bridged)
542 {
543 return setError(E_FAIL,
544 tr("Empty or null bridged interface name is not valid"));
545 }
546
547 mData.backup();
548 mData->strBridgedName = canonicalName;
549
550 // leave the lock before informing callbacks
551 alock.release();
552
553 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
554 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
555 mlock.release();
556
557 /* When changing the host adapter, adapt the CFGM logic to make this
558 * change immediately effect and to notify the guest that the network
559 * might have changed, therefore changeAdapter=TRUE. */
560 mParent->i_onNetworkAdapterChange(this, TRUE);
561 }
562
563 return S_OK;
564}
565
566HRESULT NetworkAdapter::getHostOnlyInterface(com::Utf8Str &aHostOnlyInterface)
567{
568 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
569
570 aHostOnlyInterface = mData->strHostOnlyName;
571
572 return S_OK;
573}
574
575HRESULT NetworkAdapter::setHostOnlyInterface(const com::Utf8Str &aHostOnlyInterface)
576{
577 /* the machine needs to be mutable */
578 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
579 if (FAILED(adep.hrc())) return adep.hrc();
580
581 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
582
583 if (mData->strHostOnlyName != aHostOnlyInterface)
584 {
585 /* if an empty/null string is to be set, host only interface must be
586 * turned off */
587 if ( aHostOnlyInterface.isEmpty()
588 && mData->fEnabled
589 && mData->mode == NetworkAttachmentType_HostOnly)
590 {
591 return setError(E_FAIL,
592 tr("Empty or null host only interface name is not valid"));
593 }
594
595 mData.backup();
596 mData->strHostOnlyName = aHostOnlyInterface;
597
598 // leave the lock before informing callbacks
599 alock.release();
600
601 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
602 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
603 mlock.release();
604
605 /* When changing the host adapter, adapt the CFGM logic to make this
606 * change immediately effect and to notify the guest that the network
607 * might have changed, therefore changeAdapter=TRUE. */
608 mParent->i_onNetworkAdapterChange(this, TRUE);
609 }
610
611 return S_OK;
612}
613
614
615HRESULT NetworkAdapter::getHostOnlyNetwork(com::Utf8Str &aHostOnlyNetwork)
616{
617#ifdef VBOX_WITH_VMNET
618 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
619
620 aHostOnlyNetwork = mData->strHostOnlyNetworkName;
621
622 return S_OK;
623#else /* !VBOX_WITH_VMNET */
624 NOREF(aHostOnlyNetwork);
625 return E_NOTIMPL;
626#endif /* !VBOX_WITH_VMNET */
627}
628
629HRESULT NetworkAdapter::setHostOnlyNetwork(const com::Utf8Str &aHostOnlyNetwork)
630{
631#ifdef VBOX_WITH_VMNET
632 /* the machine needs to be mutable */
633 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
634 if (FAILED(adep.hrc())) return adep.hrc();
635
636 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
637
638 if (mData->strHostOnlyNetworkName != aHostOnlyNetwork)
639 {
640 /* if an empty/null string is to be set, host only Network must be
641 * turned off */
642 if ( aHostOnlyNetwork.isEmpty()
643 && mData->fEnabled
644 && mData->mode == NetworkAttachmentType_HostOnly)
645 {
646 return setError(E_FAIL,
647 tr("Empty or null host only Network name is not valid"));
648 }
649
650 mData.backup();
651 mData->strHostOnlyNetworkName = aHostOnlyNetwork;
652
653 // leave the lock before informing callbacks
654 alock.release();
655
656 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
657 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
658 mlock.release();
659
660 /* When changing the host adapter, adapt the CFGM logic to make this
661 * change immediately effect and to notify the guest that the network
662 * might have changed, therefore changeAdapter=TRUE. */
663 mParent->i_onNetworkAdapterChange(this, TRUE);
664 }
665
666 return S_OK;
667#else /* !VBOX_WITH_VMNET */
668 NOREF(aHostOnlyNetwork);
669 return E_NOTIMPL;
670#endif /* !VBOX_WITH_VMNET */
671}
672
673
674HRESULT NetworkAdapter::getInternalNetwork(com::Utf8Str &aInternalNetwork)
675{
676 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
677
678 aInternalNetwork = mData->strInternalNetworkName;
679
680 return S_OK;
681}
682
683HRESULT NetworkAdapter::setInternalNetwork(const com::Utf8Str &aInternalNetwork)
684{
685 /* the machine needs to be mutable */
686 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
687 if (FAILED(adep.hrc())) return adep.hrc();
688
689 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
690
691 if (mData->strInternalNetworkName != aInternalNetwork)
692 {
693 /* if an empty/null string is to be set, internal networking must be
694 * turned off */
695 if ( aInternalNetwork.isEmpty()
696 && mData->fEnabled
697 && mData->mode == NetworkAttachmentType_Internal)
698 {
699 return setError(E_FAIL,
700 tr("Empty or null internal network name is not valid"));
701 }
702 mData.backup();
703 mData->strInternalNetworkName = aInternalNetwork;
704
705 // leave the lock before informing callbacks
706 alock.release();
707
708 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
709 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
710 mlock.release();
711
712 /* When changing the internal network, adapt the CFGM logic to make this
713 * change immediately effect and to notify the guest that the network
714 * might have changed, therefore changeAdapter=TRUE. */
715 mParent->i_onNetworkAdapterChange(this, TRUE);
716 }
717
718 return S_OK;
719}
720
721HRESULT NetworkAdapter::getNATNetwork(com::Utf8Str &aNATNetwork)
722{
723 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
724
725 aNATNetwork = mData->strNATNetworkName;
726
727 return S_OK;
728}
729
730
731HRESULT NetworkAdapter::setNATNetwork(const com::Utf8Str &aNATNetwork)
732{
733 /* the machine needs to be mutable */
734 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
735 if (FAILED(adep.hrc())) return adep.hrc();
736
737 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
738
739 if (mData->strNATNetworkName != aNATNetwork)
740 {
741 /* if an empty/null string is to be set, host only interface must be
742 * turned off */
743 if ( aNATNetwork.isEmpty()
744 && mData->fEnabled
745 && mData->mode == NetworkAttachmentType_NATNetwork)
746 return setError(E_FAIL,
747 tr("Empty or null NAT network name is not valid"));
748
749 mData.backup();
750
751 Bstr oldNatNetworkName = mData->strNATNetworkName;
752 mData->strNATNetworkName = aNATNetwork;
753
754 // leave the lock before informing callbacks
755 alock.release();
756
757 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
758 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
759 mlock.release();
760
761 if (mData->mode == NetworkAttachmentType_NATNetwork)
762 {
763 i_switchFromNatNetworking(oldNatNetworkName.raw());
764 i_switchToNatNetworking(aNATNetwork);
765 }
766
767 /* When changing the host adapter, adapt the CFGM logic to make this
768 * change immediately effect and to notify the guest that the network
769 * might have changed, therefore changeAdapter=TRUE. */
770 mParent->i_onNetworkAdapterChange(this, TRUE);
771 }
772
773 return S_OK;
774}
775
776HRESULT NetworkAdapter::getGenericDriver(com::Utf8Str &aGenericDriver)
777{
778 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
779
780 aGenericDriver = mData->strGenericDriver;
781
782 return S_OK;
783}
784
785HRESULT NetworkAdapter::setGenericDriver(const com::Utf8Str &aGenericDriver)
786{
787 /* the machine needs to be mutable */
788 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
789 if (FAILED(adep.hrc())) return adep.hrc();
790
791 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
792
793 if (mData->strGenericDriver != aGenericDriver)
794 {
795 mData.backup();
796 mData->strGenericDriver = aGenericDriver;
797
798 /* leave the lock before informing callbacks */
799 alock.release();
800
801 mParent->i_onNetworkAdapterChange(this, FALSE);
802 }
803
804 return S_OK;
805}
806
807
808HRESULT NetworkAdapter::getCloudNetwork(com::Utf8Str &aCloudNetwork)
809{
810#ifdef VBOX_WITH_CLOUD_NET
811 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
812
813 aCloudNetwork = mData->strCloudNetworkName;
814
815 return S_OK;
816#else /* !VBOX_WITH_CLOUD_NET */
817 NOREF(aCloudNetwork);
818 return E_NOTIMPL;
819#endif /* !VBOX_WITH_CLOUD_NET */
820}
821
822HRESULT NetworkAdapter::setCloudNetwork(const com::Utf8Str &aCloudNetwork)
823{
824#ifdef VBOX_WITH_CLOUD_NET
825 /* the machine needs to be mutable */
826 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
827 if (FAILED(adep.hrc())) return adep.hrc();
828
829 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
830
831 if (mData->strCloudNetworkName != aCloudNetwork)
832 {
833 /* if an empty/null string is to be set, Cloud networking must be
834 * turned off */
835 if ( aCloudNetwork.isEmpty()
836 && mData->fEnabled
837 && mData->mode == NetworkAttachmentType_Cloud)
838 {
839 return setError(E_FAIL,
840 tr("Empty or null Cloud network name is not valid"));
841 }
842 mData.backup();
843 mData->strCloudNetworkName = aCloudNetwork;
844
845 // leave the lock before informing callbacks
846 alock.release();
847
848#if 0
849 /// @todo Implement dynamic re-attachment of cloud network
850 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
851 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
852 mlock.release();
853
854 /* When changing the internal network, adapt the CFGM logic to make this
855 * change immediately effect and to notify the guest that the network
856 * might have changed, therefore changeAdapter=TRUE. */
857 mParent->i_onNetworkAdapterChange(this, TRUE);
858#else
859 mParent->i_onNetworkAdapterChange(this, FALSE);
860#endif
861 }
862 return S_OK;
863#else /* !VBOX_WITH_CLOUD_NET */
864 NOREF(aCloudNetwork);
865 return E_NOTIMPL;
866#endif /* !VBOX_WITH_CLOUD_NET */
867}
868
869
870HRESULT NetworkAdapter::getCableConnected(BOOL *aConnected)
871{
872 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
873
874 *aConnected = mData->fCableConnected;
875
876 return S_OK;
877}
878
879
880HRESULT NetworkAdapter::setCableConnected(BOOL aConnected)
881{
882 /* the machine needs to be mutable */
883 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
884 if (FAILED(adep.hrc())) return adep.hrc();
885
886 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
887
888 if (RT_BOOL(aConnected) != mData->fCableConnected)
889 {
890 mData.backup();
891 mData->fCableConnected = RT_BOOL(aConnected);
892
893 // leave the lock before informing callbacks
894 alock.release();
895
896 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
897 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
898 mlock.release();
899
900 /* No change in CFGM logic => changeAdapter=FALSE. */
901 mParent->i_onNetworkAdapterChange(this, FALSE);
902 }
903
904 return S_OK;
905}
906
907
908HRESULT NetworkAdapter::getLineSpeed(ULONG *aSpeed)
909{
910 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
911
912 *aSpeed = mData->ulLineSpeed;
913
914 return S_OK;
915}
916
917HRESULT NetworkAdapter::setLineSpeed(ULONG aSpeed)
918{
919 /* the machine needs to be mutable */
920 AutoMutableStateDependency adep(mParent);
921 if (FAILED(adep.hrc())) return adep.hrc();
922
923 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
924
925 if (aSpeed != mData->ulLineSpeed)
926 {
927 mData.backup();
928 mData->ulLineSpeed = aSpeed;
929
930 // leave the lock before informing callbacks
931 alock.release();
932
933 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
934 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
935 mlock.release();
936
937 /* No change in CFGM logic => changeAdapter=FALSE. */
938 mParent->i_onNetworkAdapterChange(this, FALSE);
939 }
940
941 return S_OK;
942}
943
944HRESULT NetworkAdapter::getPromiscModePolicy(NetworkAdapterPromiscModePolicy_T *aPromiscModePolicy)
945{
946 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
947
948 *aPromiscModePolicy = mData->enmPromiscModePolicy;
949
950 return S_OK;
951}
952
953HRESULT NetworkAdapter::setPromiscModePolicy(NetworkAdapterPromiscModePolicy_T aPromiscModePolicy)
954{
955 /* the machine needs to be mutable */
956 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
957 if (FAILED(adep.hrc())) return adep.hrc();
958
959 switch (aPromiscModePolicy)
960 {
961 case NetworkAdapterPromiscModePolicy_Deny:
962 case NetworkAdapterPromiscModePolicy_AllowNetwork:
963 case NetworkAdapterPromiscModePolicy_AllowAll:
964 break;
965 default:
966 return setError(E_INVALIDARG, tr("Invalid promiscuous mode policy (%d)"), aPromiscModePolicy);
967 }
968
969 AutoCaller autoCaller(this);
970 HRESULT hrc = autoCaller.hrc();
971
972 if (SUCCEEDED(hrc))
973 {
974 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
975 if (aPromiscModePolicy != mData->enmPromiscModePolicy)
976 {
977 mData.backup();
978 mData->enmPromiscModePolicy = aPromiscModePolicy;
979
980 alock.release();
981 mParent->i_setModifiedLock(Machine::IsModified_NetworkAdapters);
982 mParent->i_onNetworkAdapterChange(this, TRUE);
983 }
984 }
985
986 return hrc;
987}
988
989
990HRESULT NetworkAdapter::getTraceEnabled(BOOL *aEnabled)
991{
992
993 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
994
995 *aEnabled = mData->fTraceEnabled;
996
997 return S_OK;
998}
999
1000HRESULT NetworkAdapter::setTraceEnabled(BOOL aEnabled)
1001{
1002 /* the machine needs to be mutable */
1003 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
1004 if (FAILED(adep.hrc())) return adep.hrc();
1005
1006 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1007
1008 if (RT_BOOL(aEnabled) != mData->fTraceEnabled)
1009 {
1010 mData.backup();
1011 mData->fTraceEnabled = RT_BOOL(aEnabled);
1012
1013 // leave the lock before informing callbacks
1014 alock.release();
1015
1016 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
1017 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
1018 mlock.release();
1019
1020 /* Adapt the CFGM logic changeAdapter=TRUE */
1021 mParent->i_onNetworkAdapterChange(this, TRUE);
1022 }
1023
1024 return S_OK;
1025}
1026
1027HRESULT NetworkAdapter::getTraceFile(com::Utf8Str &aTraceFile)
1028{
1029 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1030
1031 aTraceFile = mData->strTraceFile;
1032
1033 return S_OK;
1034}
1035
1036
1037HRESULT NetworkAdapter::setTraceFile(const com::Utf8Str &aTraceFile)
1038{
1039 /* the machine needs to be mutable */
1040 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
1041 if (FAILED(adep.hrc())) return adep.hrc();
1042
1043 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1044
1045 if (mData->strTraceFile != aTraceFile)
1046 {
1047 mData.backup();
1048 mData->strTraceFile = aTraceFile;
1049
1050 // leave the lock before informing callbacks
1051 alock.release();
1052
1053 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
1054 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
1055 mlock.release();
1056
1057 /* We change the 'File' => changeAdapter=TRUE. */
1058 mParent->i_onNetworkAdapterChange(this, TRUE);
1059 }
1060
1061 return S_OK;
1062}
1063
1064HRESULT NetworkAdapter::getNATEngine(ComPtr<INATEngine> &aNATEngine)
1065{
1066 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1067
1068 aNATEngine = mNATEngine;
1069
1070 return S_OK;
1071}
1072
1073HRESULT NetworkAdapter::getBootPriority(ULONG *aBootPriority)
1074{
1075 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1076
1077 *aBootPriority = mData->ulBootPriority;
1078
1079 return S_OK;
1080}
1081
1082HRESULT NetworkAdapter::setBootPriority(ULONG aBootPriority)
1083{
1084 /* the machine needs to be mutable */
1085 AutoMutableStateDependency adep(mParent);
1086 if (FAILED(adep.hrc())) return adep.hrc();
1087
1088 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1089
1090 if (aBootPriority != mData->ulBootPriority)
1091 {
1092 mData.backup();
1093 mData->ulBootPriority = aBootPriority;
1094
1095 // leave the lock before informing callbacks
1096 alock.release();
1097
1098 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
1099 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
1100 mlock.release();
1101
1102 /* No change in CFGM logic => changeAdapter=FALSE. */
1103 mParent->i_onNetworkAdapterChange(this, FALSE);
1104 }
1105
1106 return S_OK;
1107}
1108
1109// wrapped INetworkAdapter methods
1110////////////////////////////////////////////////////////////////////////////////
1111
1112HRESULT NetworkAdapter::getProperty(const com::Utf8Str &aKey, com::Utf8Str &aValue)
1113{
1114 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1115 aValue = "";
1116 settings::StringsMap::const_iterator it = mData->genericProperties.find(aKey);
1117 if (it != mData->genericProperties.end())
1118 aValue = it->second; // source is a Utf8Str
1119
1120 return S_OK;
1121}
1122
1123HRESULT NetworkAdapter::setProperty(const com::Utf8Str &aKey, const com::Utf8Str &aValue)
1124{
1125 LogFlowThisFunc(("\n"));
1126 /* The machine needs to be mutable. */
1127 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
1128 if (FAILED(adep.hrc())) return adep.hrc();
1129 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1130 bool fGenericChange = (mData->mode == NetworkAttachmentType_Generic);
1131 /* Generic properties processing.
1132 * Look up the old value first; if nothing's changed then do nothing.
1133 */
1134 Utf8Str strOldValue;
1135 settings::StringsMap::const_iterator it = mData->genericProperties.find(aKey);
1136 if (it != mData->genericProperties.end())
1137 strOldValue = it->second;
1138
1139 if (strOldValue != aValue)
1140 {
1141 if (aValue.isEmpty())
1142 mData->genericProperties.erase(aKey);
1143 else
1144 mData->genericProperties[aKey] = aValue;
1145
1146 /* leave the lock before informing callbacks */
1147 alock.release();
1148
1149 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
1150 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
1151 mlock.release();
1152
1153 /* Avoid deadlock when the event triggers a call to a method of this
1154 * interface. */
1155 adep.release();
1156
1157 mParent->i_onNetworkAdapterChange(this, fGenericChange);
1158 }
1159
1160 return S_OK;
1161}
1162
1163HRESULT NetworkAdapter::getProperties(const com::Utf8Str &aNames,
1164 std::vector<com::Utf8Str> &aReturnNames,
1165 std::vector<com::Utf8Str> &aReturnValues)
1166{
1167 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1168
1169 /// @todo make use of aNames according to the documentation
1170 NOREF(aNames);
1171 aReturnNames.resize(mData->genericProperties.size());
1172 aReturnValues.resize(mData->genericProperties.size());
1173
1174 size_t i = 0;
1175
1176 for (settings::StringsMap::const_iterator it = mData->genericProperties.begin();
1177 it != mData->genericProperties.end();
1178 ++it, ++i)
1179 {
1180 aReturnNames[i] = it->first;
1181 aReturnValues[i] = it->second;
1182 }
1183
1184 return S_OK;
1185}
1186
1187
1188
1189// public methods only for internal purposes
1190////////////////////////////////////////////////////////////////////////////////
1191
1192/**
1193 * Loads settings from the given adapter node.
1194 * May be called once right after this object creation.
1195 *
1196 * @param bwctl bandwidth control object.
1197 * @param data Configuration settings.
1198 *
1199 * @note Locks this object for writing.
1200 */
1201HRESULT NetworkAdapter::i_loadSettings(BandwidthControl *bwctl,
1202 const settings::NetworkAdapter &data)
1203{
1204 AutoCaller autoCaller(this);
1205 AssertComRCReturnRC(autoCaller.hrc());
1206
1207 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1208
1209 /* Note: we assume that the default values for attributes of optional
1210 * nodes are assigned in the Data::Data() constructor and don't do it
1211 * here. It implies that this method may only be called after constructing
1212 * a new FirmwareSettings object while all its data fields are in the default
1213 * values. Exceptions are fields whose creation time defaults don't match
1214 * values that should be applied when these fields are not explicitly set
1215 * in the settings file (for backwards compatibility reasons). This takes
1216 * place when a setting of a newly created object must default to A while
1217 * the same setting of an object loaded from the old settings file must
1218 * default to B. */
1219
1220 /* MAC address (can be null) */
1221 HRESULT hrc = i_updateMacAddress(data.strMACAddress);
1222 if (FAILED(hrc)) return hrc;
1223
1224 mData.assignCopy(&data);
1225
1226 if (mData->strBandwidthGroup.isNotEmpty())
1227 {
1228 ComObjPtr<BandwidthGroup> group;
1229 hrc = bwctl->i_getBandwidthGroupByName(data.strBandwidthGroup, group, true);
1230 if (FAILED(hrc)) return hrc;
1231 group->i_reference();
1232 }
1233
1234 // Load NAT engine settings.
1235 mNATEngine->i_loadSettings(data.nat);
1236
1237 // leave the lock before setting attachment type
1238 alock.release();
1239
1240 hrc = COMSETTER(AttachmentType)(data.mode);
1241 if (FAILED(hrc)) return hrc;
1242
1243 return S_OK;
1244}
1245
1246/**
1247 * Saves settings to the given adapter node.
1248 *
1249 * Note that the given Adapter node is completely empty on input.
1250 *
1251 * @param data Configuration settings.
1252 *
1253 * @note Locks this object for reading.
1254 */
1255HRESULT NetworkAdapter::i_saveSettings(settings::NetworkAdapter &data)
1256{
1257 AutoCaller autoCaller(this);
1258 AssertComRCReturnRC(autoCaller.hrc());
1259
1260 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1261
1262 data = *mData.data();
1263
1264 mNATEngine->i_saveSettings(data.nat);
1265
1266 return S_OK;
1267}
1268
1269/**
1270 * Returns true if any setter method has modified settings of this instance.
1271 * @return
1272 */
1273bool NetworkAdapter::i_isModified()
1274{
1275 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1276
1277 bool fChanged = mData.isBackedUp();
1278 fChanged |= mNATEngine->i_isModified();
1279 return fChanged;
1280}
1281
1282/**
1283 * @note Locks this object for writing.
1284 */
1285void NetworkAdapter::i_rollback()
1286{
1287 /* sanity */
1288 AutoCaller autoCaller(this);
1289 AssertComRCReturnVoid(autoCaller.hrc());
1290
1291 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1292
1293 mNATEngine->i_rollback();
1294
1295 mData.rollback();
1296}
1297
1298/**
1299 * @note Locks this object for writing, together with the peer object (also
1300 * for writing) if there is one.
1301 */
1302void NetworkAdapter::i_commit()
1303{
1304 /* sanity */
1305 AutoCaller autoCaller(this);
1306 AssertComRCReturnVoid(autoCaller.hrc());
1307
1308 /* sanity too */
1309 AutoCaller peerCaller(mPeer);
1310 AssertComRCReturnVoid(peerCaller.hrc());
1311
1312 /* lock both for writing since we modify both (mPeer is "master" so locked
1313 * first) */
1314 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
1315
1316 mNATEngine->i_commit();
1317
1318 if (mData.isBackedUp())
1319 {
1320 mData.commit();
1321 if (mPeer)
1322 {
1323 /* attach new data to the peer and reshare it */
1324 mPeer->mData.attach(mData);
1325 }
1326 }
1327}
1328
1329/**
1330 * @note Locks this object for writing, together with the peer object
1331 * represented by @a aThat (locked for reading).
1332 */
1333void NetworkAdapter::i_copyFrom(NetworkAdapter *aThat)
1334{
1335 AssertReturnVoid(aThat != NULL);
1336
1337 /* sanity */
1338 AutoCaller autoCaller(this);
1339 AssertComRCReturnVoid(autoCaller.hrc());
1340
1341 /* sanity too */
1342 AutoCaller thatCaller(aThat);
1343 AssertComRCReturnVoid(thatCaller.hrc());
1344
1345 mNATEngine->i_copyFrom(aThat->mNATEngine);
1346
1347 /* peer is not modified, lock it for reading (aThat is "master" so locked
1348 * first) */
1349 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1350 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1351
1352 /* this will back up current data */
1353 mData.assignCopy(aThat->mData);
1354
1355}
1356
1357/**
1358 * Applies the defaults for this network adapter.
1359 *
1360 * @note This method currently assumes that the object is in the state after
1361 * calling init(), it does not set defaults from an arbitrary state.
1362 */
1363void NetworkAdapter::i_applyDefaults(GuestOSType *aOsType)
1364{
1365 /* sanity */
1366 AutoCaller autoCaller(this);
1367 AssertComRCReturnVoid(autoCaller.hrc());
1368
1369 mNATEngine->i_applyDefaults();
1370
1371 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1372
1373 bool e1000enabled = false;
1374#ifdef VBOX_WITH_E1000
1375 e1000enabled = true;
1376#endif // VBOX_WITH_E1000
1377
1378 NetworkAdapterType_T defaultType;
1379 if (aOsType)
1380 defaultType = aOsType->i_networkAdapterType();
1381 else
1382 {
1383#ifdef VBOX_WITH_E1000
1384 defaultType = NetworkAdapterType_I82540EM;
1385#else
1386 defaultType = NetworkAdapterType_Am79C973A;
1387#endif
1388 }
1389
1390
1391 /* Set default network adapter for this OS type */
1392 if (defaultType == NetworkAdapterType_I82540EM ||
1393 defaultType == NetworkAdapterType_I82543GC ||
1394 defaultType == NetworkAdapterType_I82545EM)
1395 {
1396 if (e1000enabled)
1397 mData->type = defaultType;
1398 }
1399 else
1400 mData->type = defaultType;
1401
1402 /* Enable the first one adapter and set it to NAT */
1403 /** @todo r=klaus remove this long term, since a newly created VM should
1404 * have no additional hardware components unless configured either
1405 * explicitly or through Machine::applyDefaults. */
1406 if (aOsType && mData->ulSlot == 0)
1407 {
1408 mData->fEnabled = true;
1409 if (mData->strMACAddress.isEmpty())
1410 i_generateMACAddress();
1411 mData->mode = NetworkAttachmentType_NAT;
1412 }
1413 mData->fCableConnected = true;
1414}
1415
1416bool NetworkAdapter::i_hasDefaults()
1417{
1418 /* sanity */
1419 AutoCaller autoCaller(this);
1420 AssertComRCReturn(autoCaller.hrc(), true);
1421
1422 ComObjPtr<GuestOSType> pGuestOSType;
1423 HRESULT hrc = mParent->i_getVirtualBox()->i_findGuestOSType(mParent->i_getOSTypeId(), pGuestOSType);
1424 if (FAILED(hrc))
1425 return false;
1426
1427 NetworkAdapterType_T defaultType = pGuestOSType->i_networkAdapterType();
1428
1429 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1430
1431 if ( !mData->fEnabled
1432 && mData->strMACAddress.isEmpty()
1433 && mData->type == defaultType
1434 && mData->fCableConnected
1435 && mData->ulLineSpeed == 0
1436 && mData->enmPromiscModePolicy == NetworkAdapterPromiscModePolicy_Deny
1437 && mData->mode == NetworkAttachmentType_Null
1438 && mData->strBridgedName.isEmpty()
1439 && mData->strInternalNetworkName.isEmpty()
1440 && mData->strHostOnlyName.isEmpty()
1441 && mData->strNATNetworkName.isEmpty()
1442 && mData->strGenericDriver.isEmpty()
1443 && mData->genericProperties.size() == 0)
1444 {
1445 /* Could be default, check NAT defaults. */
1446 return mNATEngine->i_hasDefaults();
1447 }
1448
1449 return false;
1450}
1451
1452ComObjPtr<NetworkAdapter> NetworkAdapter::i_getPeer()
1453{
1454 return mPeer;
1455}
1456
1457
1458// private methods
1459////////////////////////////////////////////////////////////////////////////////
1460
1461/**
1462 * Generates a new unique MAC address based on our vendor ID and
1463 * parts of a GUID.
1464 *
1465 * @note Must be called from under the object's write lock or within the init
1466 * span.
1467 */
1468void NetworkAdapter::i_generateMACAddress()
1469{
1470 Utf8Str mac;
1471 Host::i_generateMACAddress(mac);
1472 LogFlowThisFunc(("generated MAC: '%s'\n", mac.c_str()));
1473 mData->strMACAddress = mac;
1474}
1475
1476HRESULT NetworkAdapter::getBandwidthGroup(ComPtr<IBandwidthGroup> &aBandwidthGroup)
1477{
1478 LogFlowThisFuncEnter();
1479
1480 HRESULT hrc = S_OK;
1481
1482 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1483
1484 if (mData->strBandwidthGroup.isNotEmpty())
1485 {
1486 ComObjPtr<BandwidthGroup> pBwGroup;
1487 hrc = mParent->i_getBandwidthGroup(mData->strBandwidthGroup, pBwGroup, true /* fSetError */);
1488
1489 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence
1490 * of the group was checked when it was attached. */
1491 if (SUCCEEDED(hrc))
1492 pBwGroup.queryInterfaceTo(aBandwidthGroup.asOutParam());
1493 }
1494
1495 LogFlowThisFuncLeave();
1496 return hrc;
1497}
1498
1499HRESULT NetworkAdapter::setBandwidthGroup(const ComPtr<IBandwidthGroup> &aBandwidthGroup)
1500{
1501 LogFlowThisFuncEnter();
1502
1503 /* the machine needs to be mutable */
1504 AutoMutableOrSavedStateDependency adep(mParent);
1505 if (FAILED(adep.hrc())) return adep.hrc();
1506
1507 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1508
1509 IBandwidthGroup *iBw = aBandwidthGroup;
1510 Utf8Str strBwGroup;
1511 if (aBandwidthGroup)
1512 strBwGroup = static_cast<BandwidthGroup *>(iBw)->i_getName();
1513
1514 if (mData->strBandwidthGroup != strBwGroup)
1515 {
1516 ComObjPtr<BandwidthGroup> pBwGroup;
1517 if (!strBwGroup.isEmpty())
1518 {
1519 HRESULT hrc = mParent->i_getBandwidthGroup(strBwGroup, pBwGroup, false /* fSetError */);
1520 NOREF(hrc);
1521 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence
1522 of the group was checked when it was attached. */
1523 }
1524
1525 i_updateBandwidthGroup(pBwGroup);
1526
1527 // leave the lock before informing callbacks
1528 alock.release();
1529
1530 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
1531 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
1532 mlock.release();
1533
1534 /** @todo changeAdapter=???. */
1535 mParent->i_onNetworkAdapterChange(this, FALSE);
1536 }
1537
1538 LogFlowThisFuncLeave();
1539 return S_OK;
1540}
1541
1542void NetworkAdapter::i_updateBandwidthGroup(BandwidthGroup *aBwGroup)
1543{
1544 LogFlowThisFuncEnter();
1545 Assert(isWriteLockOnCurrentThread());
1546
1547 ComObjPtr<BandwidthGroup> pOldBwGroup;
1548 if (!mData->strBandwidthGroup.isEmpty())
1549 {
1550 HRESULT hrc = mParent->i_getBandwidthGroup(mData->strBandwidthGroup, pOldBwGroup, false /* fSetError */);
1551 NOREF(hrc);
1552 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of
1553 the group was checked when it was attached. */
1554 }
1555
1556 mData.backup();
1557 if (!pOldBwGroup.isNull())
1558 {
1559 pOldBwGroup->i_release();
1560 mData->strBandwidthGroup = Utf8Str::Empty;
1561 }
1562
1563 if (aBwGroup)
1564 {
1565 mData->strBandwidthGroup = aBwGroup->i_getName();
1566 aBwGroup->i_reference();
1567 }
1568
1569 LogFlowThisFuncLeave();
1570}
1571
1572
1573HRESULT NetworkAdapter::i_switchFromNatNetworking(const com::Utf8Str &networkName)
1574{
1575 HRESULT hrc;
1576 MachineState_T state;
1577
1578 hrc = mParent->COMGETTER(State)(&state);
1579 if (FAILED(hrc))
1580 return hrc;
1581
1582 if ( state == MachineState_Running
1583 || state == MachineState_Paused)
1584 {
1585 Bstr bstrName;
1586 hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
1587 LogRel(("VM '%ls' stops using NAT network '%s'\n", bstrName.raw(), networkName.c_str()));
1588 int natCount = mParent->i_getVirtualBox()->i_natNetworkRefDec(Bstr(networkName).raw());
1589 if (natCount == -1)
1590 return E_INVALIDARG; /* no such network */
1591 }
1592
1593 return S_OK;
1594}
1595
1596
1597HRESULT NetworkAdapter::i_switchToNatNetworking(const com::Utf8Str &aNatNetworkName)
1598{
1599 HRESULT hrc;
1600 MachineState_T state;
1601
1602 hrc = mParent->COMGETTER(State)(&state);
1603 if (FAILED(hrc))
1604 return hrc;
1605
1606 if ( state == MachineState_Running
1607 || state == MachineState_Paused)
1608 {
1609 Bstr bstrName;
1610 hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
1611 LogRel(("VM '%ls' starts using NAT network '%s'\n", bstrName.raw(), aNatNetworkName.c_str()));
1612 int natCount = mParent->i_getVirtualBox()->i_natNetworkRefInc(Bstr(aNatNetworkName).raw());
1613 if (natCount == -1)
1614 return E_INVALIDARG; /* not found */
1615 }
1616
1617 return S_OK;
1618}
1619/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use