VirtualBox

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

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

Main/NetworkAdapter: notify NAT network changes also if we switch the attachment type

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.4 KB
Line 
1/* $Id: NetworkAdapterImpl.cpp 48970 2013-10-08 11:08:17Z 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.215389.xyz. 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 checkAndSwitchFromNatNetworking();
487
488 mData->mAttachmentType = aAttachmentType;
489
490 if (aAttachmentType == NetworkAttachmentType_NATNetwork)
491 {
492 HRESULT hrc = switchToNatNetworking(mData->mNATNetwork.raw());
493 if (FAILED(hrc))
494 return hrc;
495 }
496
497 m_fModified = true;
498 // leave the lock before informing callbacks
499 alock.release();
500
501 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
502 mParent->setModified(Machine::IsModified_NetworkAdapters);
503 mlock.release();
504
505 /* Adapt the CFGM logic and notify the guest => changeAdapter=TRUE. */
506 mParent->onNetworkAdapterChange(this, TRUE);
507 }
508
509 return S_OK;
510}
511
512STDMETHODIMP NetworkAdapter::COMGETTER(BridgedInterface)(BSTR *aBridgedInterface)
513{
514 CheckComArgOutPointerValid(aBridgedInterface);
515
516 AutoCaller autoCaller(this);
517 if (FAILED(autoCaller.rc())) return autoCaller.rc();
518
519 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
520
521 mData->mBridgedInterface.cloneTo(aBridgedInterface);
522
523 return S_OK;
524}
525
526STDMETHODIMP NetworkAdapter::COMSETTER(BridgedInterface)(IN_BSTR aBridgedInterface)
527{
528 Bstr bstrEmpty("");
529 if (!aBridgedInterface)
530 aBridgedInterface = bstrEmpty.raw();
531
532 AutoCaller autoCaller(this);
533 if (FAILED(autoCaller.rc())) return autoCaller.rc();
534
535 /* the machine needs to be mutable */
536 AutoMutableStateDependency adep(mParent);
537 if (FAILED(adep.rc())) return adep.rc();
538
539 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
540
541 if (mData->mBridgedInterface != aBridgedInterface)
542 {
543 /* if an empty/null string is to be set, bridged interface must be
544 * turned off */
545 if ( (aBridgedInterface == NULL || *aBridgedInterface == '\0')
546 && mData->mAttachmentType == NetworkAttachmentType_Bridged)
547 {
548 return setError(E_FAIL,
549 tr("Empty or null bridged interface name is not valid"));
550 }
551
552 alock.release();
553
554 HRESULT hrc = checkAndSwitchFromNatNetworking();
555 if (FAILED(hrc))
556 return hrc;
557
558 alock.acquire();
559
560 mData.backup();
561 mData->mBridgedInterface = aBridgedInterface;
562
563 m_fModified = true;
564 // leave the lock before informing callbacks
565 alock.release();
566
567 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
568 mParent->setModified(Machine::IsModified_NetworkAdapters);
569 mlock.release();
570
571 /* When changing the host adapter, adapt the CFGM logic to make this
572 * change immediately effect and to notify the guest that the network
573 * might have changed, therefore changeAdapter=TRUE. */
574 mParent->onNetworkAdapterChange(this, TRUE);
575 }
576
577 return S_OK;
578}
579
580STDMETHODIMP NetworkAdapter::COMGETTER(HostOnlyInterface)(BSTR *aHostOnlyInterface)
581{
582 CheckComArgOutPointerValid(aHostOnlyInterface);
583
584 AutoCaller autoCaller(this);
585 if (FAILED(autoCaller.rc())) return autoCaller.rc();
586
587 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
588
589 mData->mHostOnlyInterface.cloneTo(aHostOnlyInterface);
590
591 return S_OK;
592}
593
594STDMETHODIMP NetworkAdapter::COMSETTER(HostOnlyInterface)(IN_BSTR aHostOnlyInterface)
595{
596 Bstr bstrEmpty("");
597 if (!aHostOnlyInterface)
598 aHostOnlyInterface = bstrEmpty.raw();
599
600 AutoCaller autoCaller(this);
601 if (FAILED(autoCaller.rc())) return autoCaller.rc();
602
603 /* the machine needs to be mutable */
604 AutoMutableStateDependency adep(mParent);
605 if (FAILED(adep.rc())) return adep.rc();
606
607 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
608
609 if (mData->mHostOnlyInterface != aHostOnlyInterface)
610 {
611 /* if an empty/null string is to be set, host only interface must be
612 * turned off */
613 if ( (aHostOnlyInterface == NULL || *aHostOnlyInterface == '\0')
614 && mData->mAttachmentType == NetworkAttachmentType_HostOnly)
615 {
616 return setError(E_FAIL,
617 tr("Empty or null host only interface name is not valid"));
618 }
619
620 alock.release();
621
622 HRESULT hrc = checkAndSwitchFromNatNetworking();
623 if (FAILED(hrc))
624 return hrc;
625
626 alock.acquire();
627
628 mData.backup();
629 mData->mHostOnlyInterface = aHostOnlyInterface;
630
631 m_fModified = true;
632 // leave the lock before informing callbacks
633 alock.release();
634
635 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
636 mParent->setModified(Machine::IsModified_NetworkAdapters);
637 mlock.release();
638
639 /* When changing the host adapter, adapt the CFGM logic to make this
640 * change immediately effect and to notify the guest that the network
641 * might have changed, therefore changeAdapter=TRUE. */
642 mParent->onNetworkAdapterChange(this, TRUE);
643 }
644
645 return S_OK;
646}
647
648STDMETHODIMP NetworkAdapter::COMGETTER(InternalNetwork)(BSTR *aInternalNetwork)
649{
650 CheckComArgOutPointerValid(aInternalNetwork);
651
652 AutoCaller autoCaller(this);
653 if (FAILED(autoCaller.rc())) return autoCaller.rc();
654
655 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
656
657 mData->mInternalNetwork.cloneTo(aInternalNetwork);
658
659 return S_OK;
660}
661
662STDMETHODIMP NetworkAdapter::COMSETTER(InternalNetwork)(IN_BSTR aInternalNetwork)
663{
664 AutoCaller autoCaller(this);
665 if (FAILED(autoCaller.rc())) return autoCaller.rc();
666
667 /* the machine needs to be mutable */
668 AutoMutableStateDependency adep(mParent);
669 if (FAILED(adep.rc())) return adep.rc();
670
671 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
672
673 if (mData->mInternalNetwork != aInternalNetwork)
674 {
675 /* if an empty/null string is to be set, internal networking must be
676 * turned off */
677 if ( (aInternalNetwork == NULL || *aInternalNetwork == '\0')
678 && mData->mAttachmentType == NetworkAttachmentType_Internal)
679 {
680 return setError(E_FAIL,
681 tr("Empty or null internal network name is not valid"));
682 }
683
684 alock.release();
685
686 HRESULT hrc = checkAndSwitchFromNatNetworking();
687 if (FAILED(hrc))
688 return hrc;
689
690 alock.acquire();
691
692 mData.backup();
693 mData->mInternalNetwork = aInternalNetwork;
694
695 m_fModified = true;
696 // leave the lock before informing callbacks
697 alock.release();
698
699 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
700 mParent->setModified(Machine::IsModified_NetworkAdapters);
701 mlock.release();
702
703 /* When changing the internal network, adapt the CFGM logic to make this
704 * change immediately effect and to notify the guest that the network
705 * might have changed, therefore changeAdapter=TRUE. */
706 mParent->onNetworkAdapterChange(this, TRUE);
707 }
708
709 return S_OK;
710}
711
712STDMETHODIMP NetworkAdapter::COMGETTER(NATNetwork)(BSTR *aNATNetwork)
713{
714 CheckComArgOutPointerValid(aNATNetwork);
715
716 AutoCaller autoCaller(this);
717 if (FAILED(autoCaller.rc())) return autoCaller.rc();
718
719 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
720
721 mData->mNATNetwork.cloneTo(aNATNetwork);
722
723 return S_OK;
724}
725
726STDMETHODIMP NetworkAdapter::COMSETTER(NATNetwork)(IN_BSTR aNATNetwork)
727{
728 Bstr bstrEmpty("");
729 if (!aNATNetwork)
730 aNATNetwork = bstrEmpty.raw();
731
732 AutoCaller autoCaller(this);
733 if (FAILED(autoCaller.rc())) return autoCaller.rc();
734
735 /* the machine needs to be mutable */
736 AutoMutableStateDependency adep(mParent);
737 if (FAILED(adep.rc())) return adep.rc();
738
739 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
740
741 if (mData->mNATNetwork != aNATNetwork)
742 {
743
744 HRESULT hrc;
745 /* if an empty/null string is to be set, host only interface must be
746 * turned off */
747 if ( (aNATNetwork == NULL || *aNATNetwork == '\0')
748 && mData->mAttachmentType == NetworkAttachmentType_NATNetwork)
749 {
750 return setError(E_FAIL,
751 tr("Empty or null NAT network name is not valid"));
752 }
753
754 mData.backup();
755
756 alock.release();
757
758 hrc = checkAndSwitchFromNatNetworking();
759 if (FAILED(hrc))
760 return hrc;
761
762 hrc = switchToNatNetworking(aNATNetwork);
763 if (FAILED(hrc))
764 return hrc;
765
766 alock.acquire();
767
768 mData->mNATNetwork = aNATNetwork;
769
770 m_fModified = true;
771 // leave the lock before informing callbacks
772 alock.release();
773
774 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
775 mParent->setModified(Machine::IsModified_NetworkAdapters);
776 mlock.release();
777
778 /* When changing the host adapter, adapt the CFGM logic to make this
779 * change immediately effect and to notify the guest that the network
780 * might have changed, therefore changeAdapter=TRUE. */
781 mParent->onNetworkAdapterChange(this, TRUE);
782 }
783
784 return S_OK;
785}
786
787STDMETHODIMP NetworkAdapter::COMGETTER(GenericDriver)(BSTR *aGenericDriver)
788{
789 CheckComArgOutPointerValid(aGenericDriver);
790
791 AutoCaller autoCaller(this);
792 if (FAILED(autoCaller.rc())) return autoCaller.rc();
793
794 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
795
796 mData->mGenericDriver.cloneTo(aGenericDriver);
797
798 return S_OK;
799}
800
801STDMETHODIMP NetworkAdapter::COMSETTER(GenericDriver)(IN_BSTR aGenericDriver)
802{
803 Bstr bstrEmpty("");
804 if (!aGenericDriver)
805 aGenericDriver = bstrEmpty.raw();
806
807 AutoCaller autoCaller(this);
808 if (FAILED(autoCaller.rc())) return autoCaller.rc();
809
810 /* the machine needs to be mutable */
811 AutoMutableStateDependency adep(mParent);
812 if (FAILED(adep.rc())) return adep.rc();
813
814 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
815
816 if (mData->mGenericDriver != aGenericDriver)
817 {
818 mData.backup();
819 mData->mGenericDriver = aGenericDriver;
820
821 /* leave the lock before informing callbacks */
822 alock.release();
823
824 mParent->onNetworkAdapterChange(this, FALSE);
825 }
826
827 return S_OK;
828}
829
830STDMETHODIMP NetworkAdapter::COMGETTER(CableConnected)(BOOL *aConnected)
831{
832 CheckComArgOutPointerValid(aConnected);
833
834 AutoCaller autoCaller(this);
835 if (FAILED(autoCaller.rc())) return autoCaller.rc();
836
837 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
838
839 *aConnected = mData->mCableConnected;
840
841 return S_OK;
842}
843
844STDMETHODIMP NetworkAdapter::COMSETTER(CableConnected)(BOOL aConnected)
845{
846 AutoCaller autoCaller(this);
847 if (FAILED(autoCaller.rc())) return autoCaller.rc();
848
849 /* the machine needs to be mutable */
850 AutoMutableStateDependency adep(mParent);
851 if (FAILED(adep.rc())) return adep.rc();
852
853 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
854
855 if (aConnected != mData->mCableConnected)
856 {
857 mData.backup();
858 mData->mCableConnected = aConnected;
859
860 m_fModified = true;
861 // leave the lock before informing callbacks
862 alock.release();
863
864 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
865 mParent->setModified(Machine::IsModified_NetworkAdapters);
866 mlock.release();
867
868 /* No change in CFGM logic => changeAdapter=FALSE. */
869 mParent->onNetworkAdapterChange(this, FALSE);
870 }
871
872 return S_OK;
873}
874
875STDMETHODIMP NetworkAdapter::COMGETTER(LineSpeed)(ULONG *aSpeed)
876{
877 CheckComArgOutPointerValid(aSpeed);
878
879 AutoCaller autoCaller(this);
880 if (FAILED(autoCaller.rc())) return autoCaller.rc();
881
882 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
883
884 *aSpeed = mData->mLineSpeed;
885
886 return S_OK;
887}
888
889STDMETHODIMP NetworkAdapter::COMSETTER(LineSpeed)(ULONG aSpeed)
890{
891 AutoCaller autoCaller(this);
892 if (FAILED(autoCaller.rc())) return autoCaller.rc();
893
894 /* the machine needs to be mutable */
895 AutoMutableStateDependency adep(mParent);
896 if (FAILED(adep.rc())) return adep.rc();
897
898 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
899
900 if (aSpeed != mData->mLineSpeed)
901 {
902 mData.backup();
903 mData->mLineSpeed = aSpeed;
904
905 m_fModified = true;
906 // leave the lock before informing callbacks
907 alock.release();
908
909 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
910 mParent->setModified(Machine::IsModified_NetworkAdapters);
911 mlock.release();
912
913 /* No change in CFGM logic => changeAdapter=FALSE. */
914 mParent->onNetworkAdapterChange(this, FALSE);
915 }
916
917 return S_OK;
918}
919
920
921STDMETHODIMP NetworkAdapter::COMGETTER(PromiscModePolicy)(NetworkAdapterPromiscModePolicy_T *aPromiscModePolicy)
922{
923 CheckComArgOutPointerValid(aPromiscModePolicy);
924
925 AutoCaller autoCaller(this);
926 HRESULT hrc = autoCaller.rc();
927 if (SUCCEEDED(hrc))
928 {
929 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
930 *aPromiscModePolicy = mData->mPromiscModePolicy;
931 }
932 return hrc;
933}
934
935STDMETHODIMP NetworkAdapter::COMSETTER(PromiscModePolicy)(NetworkAdapterPromiscModePolicy_T aPromiscModePolicy)
936{
937 switch (aPromiscModePolicy)
938 {
939 case NetworkAdapterPromiscModePolicy_Deny:
940 case NetworkAdapterPromiscModePolicy_AllowNetwork:
941 case NetworkAdapterPromiscModePolicy_AllowAll:
942 break;
943 default:
944 return setError(E_INVALIDARG, tr("Invalid promiscuous mode policy (%d)"), aPromiscModePolicy);
945 }
946
947 AutoCaller autoCaller(this);
948 HRESULT hrc = autoCaller.rc();
949
950 if (SUCCEEDED(hrc))
951 {
952 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
953 if (aPromiscModePolicy != mData->mPromiscModePolicy)
954 {
955 mData.backup();
956 mData->mPromiscModePolicy = aPromiscModePolicy;
957 m_fModified = true;
958
959 alock.release();
960 mParent->setModifiedLock(Machine::IsModified_NetworkAdapters);
961 mParent->onNetworkAdapterChange(this, TRUE);
962 }
963 }
964
965 return hrc;
966}
967
968STDMETHODIMP NetworkAdapter::COMGETTER(TraceEnabled)(BOOL *aEnabled)
969{
970 CheckComArgOutPointerValid(aEnabled);
971
972 AutoCaller autoCaller(this);
973 if (FAILED(autoCaller.rc())) return autoCaller.rc();
974
975 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
976
977 *aEnabled = mData->mTraceEnabled;
978 return S_OK;
979}
980
981STDMETHODIMP NetworkAdapter::COMSETTER(TraceEnabled)(BOOL aEnabled)
982{
983 AutoCaller autoCaller(this);
984 if (FAILED(autoCaller.rc())) return autoCaller.rc();
985
986 /* the machine needs to be mutable */
987 AutoMutableStateDependency adep(mParent);
988 if (FAILED(adep.rc())) return adep.rc();
989
990 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
991
992 if (aEnabled != mData->mTraceEnabled)
993 {
994 mData.backup();
995 mData->mTraceEnabled = aEnabled;
996
997 m_fModified = true;
998 // leave the lock before informing callbacks
999 alock.release();
1000
1001 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
1002 mParent->setModified(Machine::IsModified_NetworkAdapters);
1003 mlock.release();
1004
1005 /* Adapt the CFGM logic changeAdapter=TRUE */
1006 mParent->onNetworkAdapterChange(this, TRUE);
1007 }
1008
1009 return S_OK;
1010}
1011
1012STDMETHODIMP NetworkAdapter::COMGETTER(TraceFile)(BSTR *aTraceFile)
1013{
1014 CheckComArgOutPointerValid(aTraceFile);
1015
1016 AutoCaller autoCaller(this);
1017 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1018
1019 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1020
1021 mData->mTraceFile.cloneTo(aTraceFile);
1022
1023 return S_OK;
1024}
1025
1026STDMETHODIMP NetworkAdapter::COMSETTER(TraceFile)(IN_BSTR aTraceFile)
1027{
1028 AutoCaller autoCaller(this);
1029 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1030
1031 /* the machine needs to be mutable */
1032 AutoMutableStateDependency adep(mParent);
1033 if (FAILED(adep.rc())) return adep.rc();
1034
1035 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1036
1037 if (mData->mTraceFile != aTraceFile)
1038 {
1039 mData.backup();
1040 mData->mTraceFile = aTraceFile;
1041
1042 m_fModified = true;
1043 // leave the lock before informing callbacks
1044 alock.release();
1045
1046 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
1047 mParent->setModified(Machine::IsModified_NetworkAdapters);
1048 mlock.release();
1049
1050 /* No change in CFGM logic => changeAdapter=FALSE. */
1051 mParent->onNetworkAdapterChange(this, FALSE);
1052 }
1053
1054 return S_OK;
1055}
1056
1057STDMETHODIMP NetworkAdapter::COMGETTER(NATEngine)(INATEngine **aNATEngine)
1058{
1059 CheckComArgOutPointerValid(aNATEngine);
1060
1061 AutoCaller autoCaller(this);
1062 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1063
1064 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1065
1066 mNATEngine.queryInterfaceTo(aNATEngine);
1067
1068 return S_OK;
1069}
1070
1071STDMETHODIMP NetworkAdapter::COMGETTER(BootPriority)(ULONG *aBootPriority)
1072{
1073 CheckComArgOutPointerValid(aBootPriority);
1074
1075 AutoCaller autoCaller(this);
1076 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1077
1078 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1079
1080 *aBootPriority = mData->mBootPriority;
1081
1082 return S_OK;
1083}
1084
1085STDMETHODIMP NetworkAdapter::COMSETTER(BootPriority)(ULONG aBootPriority)
1086{
1087 AutoCaller autoCaller(this);
1088 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1089
1090 /* the machine needs to be mutable */
1091 AutoMutableStateDependency adep(mParent);
1092 if (FAILED(adep.rc())) return adep.rc();
1093
1094 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1095
1096 if (aBootPriority != mData->mBootPriority)
1097 {
1098 mData.backup();
1099 mData->mBootPriority = aBootPriority;
1100
1101 m_fModified = true;
1102 // leave the lock before informing callbacks
1103 alock.release();
1104
1105 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
1106 mParent->setModified(Machine::IsModified_NetworkAdapters);
1107 mlock.release();
1108
1109 /* No change in CFGM logic => changeAdapter=FALSE. */
1110 mParent->onNetworkAdapterChange(this, FALSE);
1111 }
1112
1113 return S_OK;
1114}
1115
1116// INetworkAdapter methods
1117////////////////////////////////////////////////////////////////////////////////
1118
1119STDMETHODIMP NetworkAdapter::GetProperty(IN_BSTR aKey, BSTR *aValue)
1120{
1121 CheckComArgOutPointerValid(aValue);
1122
1123 AutoCaller autoCaller(this);
1124 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1125
1126 Bstr key = aKey;
1127 Bstr value;
1128
1129 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1130
1131 Utf8Str strKey(key);
1132 settings::StringsMap::const_iterator it = mData->mGenericProperties.find(strKey);
1133 if (it != mData->mGenericProperties.end())
1134 {
1135 value = it->second; // source is a Utf8Str
1136 value.cloneTo(aValue);
1137 }
1138
1139 return S_OK;
1140}
1141
1142STDMETHODIMP NetworkAdapter::SetProperty(IN_BSTR aKey, IN_BSTR aValue)
1143{
1144 LogFlowThisFunc(("\n"));
1145
1146 AutoCaller autoCaller(this);
1147 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1148
1149 /* The machine needs to be mutable. */
1150 AutoMutableStateDependency adep(mParent);
1151 if (FAILED(adep.rc())) return adep.rc();
1152
1153 Bstr key = aKey;
1154
1155 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1156
1157 bool fGenericChange = (mData->mAttachmentType == NetworkAttachmentType_Generic);
1158
1159 /* Generic properties processing.
1160 * Look up the old value first; if nothing's changed then do nothing.
1161 */
1162 Utf8Str strValue(aValue);
1163 Utf8Str strKey(aKey);
1164 Utf8Str strOldValue;
1165
1166 settings::StringsMap::const_iterator it = mData->mGenericProperties.find(strKey);
1167 if (it != mData->mGenericProperties.end())
1168 strOldValue = it->second;
1169
1170 if (strOldValue != strValue)
1171 {
1172 if (strValue.isEmpty())
1173 mData->mGenericProperties.erase(strKey);
1174 else
1175 mData->mGenericProperties[strKey] = strValue;
1176
1177 /* leave the lock before informing callbacks */
1178 alock.release();
1179
1180 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
1181 mParent->setModified(Machine::IsModified_NetworkAdapters);
1182 mlock.release();
1183
1184 /* Avoid deadlock when the event triggers a call to a method of this
1185 * interface. */
1186 adep.release();
1187
1188 mParent->onNetworkAdapterChange(this, fGenericChange);
1189 }
1190
1191 return S_OK;
1192}
1193
1194STDMETHODIMP NetworkAdapter::GetProperties(IN_BSTR aNames,
1195 ComSafeArrayOut(BSTR, aReturnNames),
1196 ComSafeArrayOut(BSTR, aReturnValues))
1197{
1198 CheckComArgOutSafeArrayPointerValid(aReturnNames);
1199 CheckComArgOutSafeArrayPointerValid(aReturnValues);
1200
1201 AutoCaller autoCaller(this);
1202 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1203
1204 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1205
1206 /// @todo make use of aNames according to the documentation
1207 NOREF(aNames);
1208
1209 com::SafeArray<BSTR> names(mData->mGenericProperties.size());
1210 com::SafeArray<BSTR> values(mData->mGenericProperties.size());
1211 size_t i = 0;
1212
1213 for (settings::StringsMap::const_iterator it = mData->mGenericProperties.begin();
1214 it != mData->mGenericProperties.end();
1215 ++it)
1216 {
1217 it->first.cloneTo(&names[i]);
1218 it->second.cloneTo(&values[i]);
1219 ++i;
1220 }
1221
1222 names.detachTo(ComSafeArrayOutArg(aReturnNames));
1223 values.detachTo(ComSafeArrayOutArg(aReturnValues));
1224
1225 return S_OK;
1226}
1227
1228
1229
1230// public methods only for internal purposes
1231////////////////////////////////////////////////////////////////////////////////
1232
1233/**
1234 * Loads settings from the given adapter node.
1235 * May be called once right after this object creation.
1236 *
1237 * @param aAdapterNode <Adapter> node.
1238 *
1239 * @note Locks this object for writing.
1240 */
1241HRESULT NetworkAdapter::loadSettings(BandwidthControl *bwctl,
1242 const settings::NetworkAdapter &data)
1243{
1244 AutoCaller autoCaller(this);
1245 AssertComRCReturnRC(autoCaller.rc());
1246
1247 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1248
1249 /* Note: we assume that the default values for attributes of optional
1250 * nodes are assigned in the Data::Data() constructor and don't do it
1251 * here. It implies that this method may only be called after constructing
1252 * a new BIOSSettings object while all its data fields are in the default
1253 * values. Exceptions are fields whose creation time defaults don't match
1254 * values that should be applied when these fields are not explicitly set
1255 * in the settings file (for backwards compatibility reasons). This takes
1256 * place when a setting of a newly created object must default to A while
1257 * the same setting of an object loaded from the old settings file must
1258 * default to B. */
1259
1260 HRESULT rc = S_OK;
1261
1262 mData->mAdapterType = data.type;
1263 mData->mEnabled = data.fEnabled;
1264 /* MAC address (can be null) */
1265 rc = updateMacAddress(data.strMACAddress);
1266 if (FAILED(rc)) return rc;
1267 /* cable (required) */
1268 mData->mCableConnected = data.fCableConnected;
1269 /* line speed (defaults to 100 Mbps) */
1270 mData->mLineSpeed = data.ulLineSpeed;
1271 mData->mPromiscModePolicy = data.enmPromiscModePolicy;
1272 /* tracing (defaults to false) */
1273 mData->mTraceEnabled = data.fTraceEnabled;
1274 mData->mTraceFile = data.strTraceFile;
1275 /* boot priority (defaults to 0, i.e. lowest) */
1276 mData->mBootPriority = data.ulBootPriority;
1277 /* bandwidth group */
1278 mData->mBandwidthGroup = data.strBandwidthGroup;
1279 if (mData->mBandwidthGroup.isNotEmpty())
1280 {
1281 ComObjPtr<BandwidthGroup> group;
1282 rc = bwctl->getBandwidthGroupByName(data.strBandwidthGroup, group, true);
1283 if (FAILED(rc)) return rc;
1284 group->reference();
1285 }
1286
1287 mNATEngine->loadSettings(data.nat);
1288 mData->mBridgedInterface = data.strBridgedName;
1289 mData->mInternalNetwork = data.strInternalNetworkName;
1290 mData->mHostOnlyInterface = data.strHostOnlyName;
1291 mData->mGenericDriver = data.strGenericDriver;
1292 mData->mGenericProperties = data.genericProperties;
1293 mData->mNATNetwork = data.strNATNetworkName;
1294
1295 // leave the lock before setting attachment type
1296 alock.release();
1297
1298 rc = COMSETTER(AttachmentType)(data.mode);
1299 if (FAILED(rc)) return rc;
1300
1301 // after loading settings, we are no longer different from the XML on disk
1302 m_fModified = false;
1303
1304 return S_OK;
1305}
1306
1307/**
1308 * Saves settings to the given adapter node.
1309 *
1310 * Note that the given Adapter node is completely empty on input.
1311 *
1312 * @param aAdapterNode <Adapter> node.
1313 *
1314 * @note Locks this object for reading.
1315 */
1316HRESULT NetworkAdapter::saveSettings(settings::NetworkAdapter &data)
1317{
1318 AutoCaller autoCaller(this);
1319 AssertComRCReturnRC(autoCaller.rc());
1320
1321 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1322
1323 data.fEnabled = !!mData->mEnabled;
1324 data.strMACAddress = mData->mMACAddress;
1325 data.fCableConnected = !!mData->mCableConnected;
1326
1327 data.enmPromiscModePolicy = mData->mPromiscModePolicy;
1328 data.ulLineSpeed = mData->mLineSpeed;
1329
1330 data.fTraceEnabled = !!mData->mTraceEnabled;
1331
1332 data.strTraceFile = mData->mTraceFile;
1333
1334 data.ulBootPriority = mData->mBootPriority;
1335
1336 data.strBandwidthGroup = mData->mBandwidthGroup;
1337
1338 data.type = mData->mAdapterType;
1339
1340 data.mode = mData->mAttachmentType;
1341
1342 mNATEngine->commit();
1343 mNATEngine->saveSettings(data.nat);
1344
1345 data.strBridgedName = mData->mBridgedInterface;
1346
1347 data.strHostOnlyName = mData->mHostOnlyInterface;
1348
1349 data.strInternalNetworkName = mData->mInternalNetwork;
1350
1351 data.strGenericDriver = mData->mGenericDriver;
1352 data.genericProperties = mData->mGenericProperties;
1353
1354 data.strNATNetworkName = mData->mNATNetwork;
1355
1356 // after saving settings, we are no longer different from the XML on disk
1357 m_fModified = false;
1358
1359 return S_OK;
1360}
1361
1362/**
1363 * Returns true if any setter method has modified settings of this instance.
1364 * @return
1365 */
1366bool NetworkAdapter::isModified() {
1367 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1368 bool fChanged = m_fModified;
1369 fChanged |= (mData->mAdapterType == NetworkAttachmentType_NAT? mNATEngine->isModified() : false);
1370 return fChanged;
1371}
1372
1373/**
1374 * @note Locks this object for writing.
1375 */
1376void NetworkAdapter::rollback()
1377{
1378 /* sanity */
1379 AutoCaller autoCaller(this);
1380 AssertComRCReturnVoid(autoCaller.rc());
1381
1382 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1383
1384 mData.rollback();
1385}
1386
1387/**
1388 * @note Locks this object for writing, together with the peer object (also
1389 * for writing) if there is one.
1390 */
1391void NetworkAdapter::commit()
1392{
1393 /* sanity */
1394 AutoCaller autoCaller(this);
1395 AssertComRCReturnVoid(autoCaller.rc());
1396
1397 /* sanity too */
1398 AutoCaller peerCaller(mPeer);
1399 AssertComRCReturnVoid(peerCaller.rc());
1400
1401 /* lock both for writing since we modify both (mPeer is "master" so locked
1402 * first) */
1403 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
1404
1405 if (mData.isBackedUp())
1406 {
1407 mData.commit();
1408 if (mPeer)
1409 {
1410 /* attach new data to the peer and reshare it */
1411 mPeer->mData.attach(mData);
1412 }
1413 }
1414}
1415
1416/**
1417 * @note Locks this object for writing, together with the peer object
1418 * represented by @a aThat (locked for reading).
1419 */
1420void NetworkAdapter::copyFrom(NetworkAdapter *aThat)
1421{
1422 AssertReturnVoid(aThat != NULL);
1423
1424 /* sanity */
1425 AutoCaller autoCaller(this);
1426 AssertComRCReturnVoid(autoCaller.rc());
1427
1428 /* sanity too */
1429 AutoCaller thatCaller(aThat);
1430 AssertComRCReturnVoid(thatCaller.rc());
1431
1432 /* peer is not modified, lock it for reading (aThat is "master" so locked
1433 * first) */
1434 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1435 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1436
1437 /* this will back up current data */
1438 mData.assignCopy(aThat->mData);
1439}
1440
1441void NetworkAdapter::applyDefaults(GuestOSType *aOsType)
1442{
1443 AssertReturnVoid(aOsType != NULL);
1444
1445 /* sanity */
1446 AutoCaller autoCaller(this);
1447 AssertComRCReturnVoid(autoCaller.rc());
1448
1449 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1450
1451 bool e1000enabled = false;
1452#ifdef VBOX_WITH_E1000
1453 e1000enabled = true;
1454#endif // VBOX_WITH_E1000
1455
1456 NetworkAdapterType_T defaultType = aOsType->networkAdapterType();
1457
1458 /* Set default network adapter for this OS type */
1459 if (defaultType == NetworkAdapterType_I82540EM ||
1460 defaultType == NetworkAdapterType_I82543GC ||
1461 defaultType == NetworkAdapterType_I82545EM)
1462 {
1463 if (e1000enabled) mData->mAdapterType = defaultType;
1464 }
1465 else mData->mAdapterType = defaultType;
1466
1467 /* Enable and connect the first one adapter to the NAT */
1468 if (mData->mSlot == 0)
1469 {
1470 mData->mEnabled = true;
1471 mData->mAttachmentType = NetworkAttachmentType_NAT;
1472 mData->mCableConnected = true;
1473 }
1474}
1475
1476ComObjPtr<NetworkAdapter> NetworkAdapter::getPeer()
1477{
1478 return mPeer;
1479}
1480
1481
1482// private methods
1483////////////////////////////////////////////////////////////////////////////////
1484
1485/**
1486 * Generates a new unique MAC address based on our vendor ID and
1487 * parts of a GUID.
1488 *
1489 * @note Must be called from under the object's write lock or within the init
1490 * span.
1491 */
1492void NetworkAdapter::generateMACAddress()
1493{
1494 Utf8Str mac;
1495 Host::generateMACAddress(mac);
1496 LogFlowThisFunc(("generated MAC: '%s'\n", mac.c_str()));
1497 mData->mMACAddress = mac;
1498}
1499
1500STDMETHODIMP NetworkAdapter::COMGETTER(BandwidthGroup)(IBandwidthGroup **aBwGroup)
1501{
1502 LogFlowThisFuncEnter();
1503 CheckComArgOutPointerValid(aBwGroup);
1504
1505 HRESULT hrc = S_OK;
1506
1507 AutoCaller autoCaller(this);
1508 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1509
1510 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1511
1512 if (mData->mBandwidthGroup.isNotEmpty())
1513 {
1514 ComObjPtr<BandwidthGroup> pBwGroup;
1515 hrc = mParent->getBandwidthGroup(mData->mBandwidthGroup, pBwGroup, true /* fSetError */);
1516
1517 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of the group was checked when it was attached. */
1518
1519 if (SUCCEEDED(hrc))
1520 pBwGroup.queryInterfaceTo(aBwGroup);
1521 }
1522
1523 LogFlowThisFuncLeave();
1524 return hrc;
1525}
1526
1527STDMETHODIMP NetworkAdapter::COMSETTER(BandwidthGroup)(IBandwidthGroup *aBwGroup)
1528{
1529 LogFlowThisFuncEnter();
1530
1531 AutoCaller autoCaller(this);
1532 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1533
1534 /* the machine needs to be mutable */
1535 AutoMutableStateDependency adep(mParent);
1536 if (FAILED(adep.rc())) return adep.rc();
1537
1538 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1539
1540 Utf8Str strBwGroup;
1541 if (aBwGroup)
1542 strBwGroup = static_cast<BandwidthGroup*>(aBwGroup)->getName();
1543 if (mData->mBandwidthGroup != strBwGroup)
1544 {
1545 ComObjPtr<BandwidthGroup> pBwGroup;
1546 if (!strBwGroup.isEmpty())
1547 {
1548 HRESULT hrc = mParent->getBandwidthGroup(strBwGroup, pBwGroup, false /* fSetError */);
1549 NOREF(hrc);
1550 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of the group was checked when it was attached. */
1551 }
1552
1553 updateBandwidthGroup(pBwGroup);
1554
1555 m_fModified = true;
1556 // leave the lock before informing callbacks
1557 alock.release();
1558
1559 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
1560 mParent->setModified(Machine::IsModified_NetworkAdapters);
1561 mlock.release();
1562
1563 /* TODO: changeAdapter=???. */
1564 mParent->onNetworkAdapterChange(this, FALSE);
1565 }
1566
1567 LogFlowThisFuncLeave();
1568 return S_OK;
1569}
1570
1571void NetworkAdapter::updateBandwidthGroup(BandwidthGroup *aBwGroup)
1572{
1573 LogFlowThisFuncEnter();
1574 Assert(isWriteLockOnCurrentThread());
1575
1576 ComObjPtr<BandwidthGroup> pOldBwGroup;
1577 if (!mData->mBandwidthGroup.isEmpty())
1578 {
1579 HRESULT hrc = mParent->getBandwidthGroup(mData->mBandwidthGroup, pOldBwGroup, false /* fSetError */);
1580 NOREF(hrc);
1581 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of the group was checked when it was attached. */
1582 }
1583
1584 mData.backup();
1585 if (!pOldBwGroup.isNull())
1586 {
1587 pOldBwGroup->release();
1588 mData->mBandwidthGroup = Utf8Str::Empty;
1589 }
1590
1591 if (aBwGroup)
1592 {
1593 mData->mBandwidthGroup = aBwGroup->getName();
1594 aBwGroup->reference();
1595 }
1596
1597 LogFlowThisFuncLeave();
1598}
1599
1600
1601HRESULT NetworkAdapter::checkAndSwitchFromNatNetworking()
1602{
1603 HRESULT hrc;
1604 MachineState_T state;
1605
1606 hrc = mParent->COMGETTER(State)(&state);
1607 if (FAILED(hrc))
1608 return hrc;
1609
1610 if ( mData->mAttachmentType == NetworkAttachmentType_NATNetwork
1611 && state == MachineState_Running)
1612 {
1613 Bstr bstrName;
1614 hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
1615 LogRel(("VM '%ls' stops using NAT network '%ls'\n", bstrName.raw(), mData->mNATNetwork.raw()));
1616 int natCount = mParent->getVirtualBox()->natNetworkRefDec(mData->mNATNetwork.raw());
1617 if (natCount == -1)
1618 return E_INVALIDARG; /* no such network */
1619 }
1620
1621 return S_OK;
1622}
1623
1624
1625HRESULT NetworkAdapter::switchToNatNetworking(IN_BSTR aNatNetworkName)
1626{
1627 HRESULT hrc;
1628 MachineState_T state;
1629
1630 hrc = mParent->COMGETTER(State)(&state);
1631 if (FAILED(hrc))
1632 return hrc;
1633
1634 if (state == MachineState_Running)
1635 {
1636 Bstr bstrName;
1637 hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
1638 LogRel(("VM '%ls' starts using NAT network '%ls'\n", bstrName.raw(), aNatNetworkName));
1639 int natCount = mParent->getVirtualBox()->natNetworkRefInc(aNatNetworkName);
1640 if (natCount == -1)
1641 return E_INVALIDARG; /* not found */
1642 }
1643
1644 return S_OK;
1645}
1646/* 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