VirtualBox

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

Last change on this file since 48973 was 48973, checked in by vboxsync, 12 years ago

Main/NetworkAdapter: disable for now as the locking order is wrong

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

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