VirtualBox

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

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

NatNetworking/Main: do reference couting on network attachment switch.

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