VirtualBox

source: vbox/trunk/src/VBox/Main/NetworkAdapterImpl.cpp@ 16596

Last change on this file since 16596 was 16560, checked in by vboxsync, 16 years ago

Main: do not include include/VBox/settings.h from other header files but only from implementations that need it (save compile time)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.0 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "NetworkAdapterImpl.h"
23#include "Logging.h"
24#include "MachineImpl.h"
25#include "GuestOSTypeImpl.h"
26
27#include <iprt/string.h>
28#include <iprt/cpputils.h>
29
30#include <VBox/err.h>
31#include <VBox/settings.h>
32
33// constructor / destructor
34////////////////////////////////////////////////////////////////////////////////
35
36DEFINE_EMPTY_CTOR_DTOR (NetworkAdapter)
37
38HRESULT NetworkAdapter::FinalConstruct()
39{
40 return S_OK;
41}
42
43void NetworkAdapter::FinalRelease()
44{
45 uninit ();
46}
47
48// public initializer/uninitializer for internal purposes only
49////////////////////////////////////////////////////////////////////////////////
50
51/**
52 * Initializes the network adapter object.
53 *
54 * @param aParent Handle of the parent object.
55 */
56HRESULT NetworkAdapter::init (Machine *aParent, ULONG aSlot)
57{
58 LogFlowThisFunc (("aParent=%p, aSlot=%d\n", aParent, aSlot));
59
60 ComAssertRet (aParent, E_INVALIDARG);
61 ComAssertRet (aSlot < SchemaDefs::NetworkAdapterCount, E_INVALIDARG);
62
63 /* Enclose the state transition NotReady->InInit->Ready */
64 AutoInitSpan autoInitSpan (this);
65 AssertReturn (autoInitSpan.isOk(), E_FAIL);
66
67 unconst (mParent) = aParent;
68 /* mPeer is left null */
69
70 mData.allocate();
71
72 /* initialize data */
73 mData->mSlot = aSlot;
74
75 /* default to Am79C973 */
76 mData->mAdapterType = NetworkAdapterType_Am79C973;
77
78 /* generate the MAC address early to guarantee it is the same both after
79 * changing some other property (i.e. after mData.backup()) and after the
80 * subsequent mData.rollback(). */
81 generateMACAddress();
82
83 /* Confirm a successful initialization */
84 autoInitSpan.setSucceeded();
85
86 return S_OK;
87}
88
89/**
90 * Initializes the network adapter object given another network adapter object
91 * (a kind of copy constructor). This object shares data with
92 * the object passed as an argument.
93 *
94 * @note This object must be destroyed before the original object
95 * it shares data with is destroyed.
96 *
97 * @note Locks @a aThat object for reading.
98 */
99HRESULT NetworkAdapter::init (Machine *aParent, NetworkAdapter *aThat)
100{
101 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
102
103 ComAssertRet (aParent && aThat, E_INVALIDARG);
104
105 /* Enclose the state transition NotReady->InInit->Ready */
106 AutoInitSpan autoInitSpan (this);
107 AssertReturn (autoInitSpan.isOk(), E_FAIL);
108
109 unconst (mParent) = aParent;
110 unconst (mPeer) = aThat;
111
112 AutoCaller thatCaller (aThat);
113 AssertComRCReturnRC (thatCaller.rc());
114
115 AutoReadLock thatLock (aThat);
116 mData.share (aThat->mData);
117
118 /* Confirm a successful initialization */
119 autoInitSpan.setSucceeded();
120
121 return S_OK;
122}
123
124/**
125 * Initializes the guest object given another guest object
126 * (a kind of copy constructor). This object makes a private copy of data
127 * of the original object passed as an argument.
128 *
129 * @note Locks @a aThat object for reading.
130 */
131HRESULT NetworkAdapter::initCopy (Machine *aParent, NetworkAdapter *aThat)
132{
133 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
134
135 ComAssertRet (aParent && aThat, E_INVALIDARG);
136
137 /* Enclose the state transition NotReady->InInit->Ready */
138 AutoInitSpan autoInitSpan (this);
139 AssertReturn (autoInitSpan.isOk(), E_FAIL);
140
141 unconst (mParent) = aParent;
142 /* mPeer is left null */
143
144 AutoCaller thatCaller (aThat);
145 AssertComRCReturnRC (thatCaller.rc());
146
147 AutoReadLock thatLock (aThat);
148 mData.attachCopy (aThat->mData);
149
150 /* Confirm a successful initialization */
151 autoInitSpan.setSucceeded();
152
153 return S_OK;
154}
155
156/**
157 * Uninitializes the instance and sets the ready flag to FALSE.
158 * Called either from FinalRelease() or by the parent when it gets destroyed.
159 */
160void NetworkAdapter::uninit()
161{
162 LogFlowThisFunc (("\n"));
163
164 /* Enclose the state transition Ready->InUninit->NotReady */
165 AutoUninitSpan autoUninitSpan (this);
166 if (autoUninitSpan.uninitDone())
167 return;
168
169 mData.free();
170
171 unconst (mPeer).setNull();
172 unconst (mParent).setNull();
173}
174
175// INetworkAdapter properties
176////////////////////////////////////////////////////////////////////////////////
177
178STDMETHODIMP NetworkAdapter::COMGETTER(AdapterType) (NetworkAdapterType_T *aAdapterType)
179{
180 CheckComArgOutPointerValid(aAdapterType);
181
182 AutoCaller autoCaller (this);
183 CheckComRCReturnRC (autoCaller.rc());
184
185 AutoReadLock alock (this);
186
187 *aAdapterType = mData->mAdapterType;
188
189 return S_OK;
190}
191
192STDMETHODIMP NetworkAdapter::COMSETTER(AdapterType) (NetworkAdapterType_T aAdapterType)
193{
194 AutoCaller autoCaller (this);
195 CheckComRCReturnRC (autoCaller.rc());
196
197 /* the machine needs to be mutable */
198 Machine::AutoMutableStateDependency adep (mParent);
199 CheckComRCReturnRC (adep.rc());
200
201 AutoWriteLock alock (this);
202
203 /* make sure the value is allowed */
204 switch (aAdapterType)
205 {
206 case NetworkAdapterType_Am79C970A:
207 case NetworkAdapterType_Am79C973:
208#ifdef VBOX_WITH_E1000
209 case NetworkAdapterType_I82540EM:
210 case NetworkAdapterType_I82543GC:
211#endif
212 break;
213 default:
214 return setError (E_FAIL,
215 tr("Invalid network adapter type '%d'"),
216 aAdapterType);
217 }
218
219 if (mData->mAdapterType != aAdapterType)
220 {
221 mData.backup();
222 mData->mAdapterType = aAdapterType;
223
224 /* leave the lock before informing callbacks */
225 alock.unlock();
226
227 mParent->onNetworkAdapterChange (this);
228 }
229
230 return S_OK;
231}
232
233STDMETHODIMP NetworkAdapter::COMGETTER(Slot) (ULONG *aSlot)
234{
235 CheckComArgOutPointerValid(aSlot);
236
237 AutoCaller autoCaller (this);
238 CheckComRCReturnRC (autoCaller.rc());
239
240 AutoReadLock alock (this);
241
242 *aSlot = mData->mSlot;
243
244 return S_OK;
245}
246
247STDMETHODIMP NetworkAdapter::COMGETTER(Enabled) (BOOL *aEnabled)
248{
249 CheckComArgOutPointerValid(aEnabled);
250
251 AutoCaller autoCaller (this);
252 CheckComRCReturnRC (autoCaller.rc());
253
254 AutoReadLock alock (this);
255
256 *aEnabled = mData->mEnabled;
257
258 return S_OK;
259}
260
261STDMETHODIMP NetworkAdapter::COMSETTER(Enabled) (BOOL aEnabled)
262{
263 AutoCaller autoCaller (this);
264 CheckComRCReturnRC (autoCaller.rc());
265
266 /* the machine needs to be mutable */
267 Machine::AutoMutableStateDependency adep (mParent);
268 CheckComRCReturnRC (adep.rc());
269
270 AutoWriteLock alock (this);
271
272 if (mData->mEnabled != aEnabled)
273 {
274 mData.backup();
275 mData->mEnabled = aEnabled;
276
277 /* leave the lock before informing callbacks */
278 alock.unlock();
279
280 mParent->onNetworkAdapterChange (this);
281 }
282
283 return S_OK;
284}
285
286STDMETHODIMP NetworkAdapter::COMGETTER(MACAddress)(BSTR *aMACAddress)
287{
288 CheckComArgOutPointerValid(aMACAddress);
289
290 AutoCaller autoCaller (this);
291 CheckComRCReturnRC (autoCaller.rc());
292
293 AutoReadLock alock (this);
294
295 ComAssertRet (!!mData->mMACAddress, E_FAIL);
296
297 mData->mMACAddress.cloneTo (aMACAddress);
298
299 return S_OK;
300}
301
302STDMETHODIMP NetworkAdapter::COMSETTER(MACAddress)(IN_BSTR aMACAddress)
303{
304 AutoCaller autoCaller (this);
305 CheckComRCReturnRC (autoCaller.rc());
306
307 /* the machine needs to be mutable */
308 Machine::AutoMutableStateDependency adep (mParent);
309 CheckComRCReturnRC (adep.rc());
310
311 AutoWriteLock alock (this);
312
313 HRESULT rc = S_OK;
314 bool emitChangeEvent = false;
315
316 /*
317 * Are we supposed to generate a MAC?
318 */
319 if (!aMACAddress)
320 {
321 mData.backup();
322
323 generateMACAddress();
324 emitChangeEvent = true;
325 }
326 else
327 {
328 if (mData->mMACAddress != aMACAddress)
329 {
330 /*
331 * Verify given MAC address
332 */
333 Utf8Str macAddressUtf = aMACAddress;
334 char *macAddressStr = macAddressUtf.mutableRaw();
335 int i = 0;
336 while ((i < 13) && macAddressStr && *macAddressStr && (rc == S_OK))
337 {
338 char c = *macAddressStr;
339 /* canonicalize hex digits to capital letters */
340 if (c >= 'a' && c <= 'f')
341 {
342 /** @todo the runtime lacks an ascii lower/upper conv */
343 c &= 0xdf;
344 *macAddressStr = c;
345 }
346 /* we only accept capital letters */
347 if (((c < '0') || (c > '9')) &&
348 ((c < 'A') || (c > 'F')))
349 rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
350 /* the second digit must have even value for unicast addresses */
351 if ((i == 1) && (!!(c & 1) == (c >= '0' && c <= '9')))
352 rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
353
354 macAddressStr++;
355 i++;
356 }
357 /* we must have parsed exactly 12 characters */
358 if (i != 12)
359 rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
360
361 if (SUCCEEDED (rc))
362 {
363 mData.backup();
364
365 mData->mMACAddress = macAddressUtf;
366 emitChangeEvent = true;
367 }
368 }
369 }
370
371 if (emitChangeEvent)
372 {
373 /* leave the lock before informing callbacks */
374 alock.unlock();
375
376 mParent->onNetworkAdapterChange (this);
377 }
378
379 return rc;
380}
381
382STDMETHODIMP NetworkAdapter::COMGETTER(AttachmentType)(
383 NetworkAttachmentType_T *aAttachmentType)
384{
385 CheckComArgOutPointerValid(aAttachmentType);
386
387 AutoCaller autoCaller (this);
388 CheckComRCReturnRC (autoCaller.rc());
389
390 AutoReadLock alock (this);
391
392 *aAttachmentType = mData->mAttachmentType;
393
394 return S_OK;
395}
396
397STDMETHODIMP NetworkAdapter::COMGETTER(HostInterface)(BSTR *aHostInterface)
398{
399 CheckComArgOutPointerValid(aHostInterface);
400
401 AutoCaller autoCaller (this);
402 CheckComRCReturnRC (autoCaller.rc());
403
404 AutoReadLock alock (this);
405
406 mData->mHostInterface.cloneTo (aHostInterface);
407
408 return S_OK;
409}
410
411STDMETHODIMP NetworkAdapter::COMSETTER(HostInterface)(IN_BSTR aHostInterface)
412{
413 /** @todo Validate input string length. r=dmik: do it in XML schema?*/
414
415 /* we don't allow null strings for the host interface (because the @name
416 * attribute of <HostInterface> must be always present but can be empty). */
417 CheckComArgNotNull (aHostInterface);
418
419 AutoCaller autoCaller (this);
420 CheckComRCReturnRC (autoCaller.rc());
421
422 /* the machine needs to be mutable */
423 Machine::AutoMutableStateDependency adep (mParent);
424 CheckComRCReturnRC (adep.rc());
425
426 AutoWriteLock alock (this);
427
428 if (mData->mHostInterface != aHostInterface)
429 {
430 mData.backup();
431 mData->mHostInterface = aHostInterface;
432
433 /* leave the lock before informing callbacks */
434 alock.unlock();
435
436 mParent->onNetworkAdapterChange (this);
437 }
438
439 return S_OK;
440}
441
442STDMETHODIMP NetworkAdapter::COMGETTER(InternalNetwork) (BSTR *aInternalNetwork)
443{
444 CheckComArgOutPointerValid(aInternalNetwork);
445
446 AutoCaller autoCaller (this);
447 CheckComRCReturnRC (autoCaller.rc());
448
449 AutoReadLock alock (this);
450
451 mData->mInternalNetwork.cloneTo (aInternalNetwork);
452
453 return S_OK;
454}
455
456STDMETHODIMP NetworkAdapter::COMSETTER(InternalNetwork) (IN_BSTR aInternalNetwork)
457{
458 AutoCaller autoCaller (this);
459 CheckComRCReturnRC (autoCaller.rc());
460
461 /* the machine needs to be mutable */
462 Machine::AutoMutableStateDependency adep (mParent);
463 CheckComRCReturnRC (adep.rc());
464
465 AutoWriteLock alock (this);
466
467 if (mData->mInternalNetwork != aInternalNetwork)
468 {
469 /* if an empty/null string is to be set, internal networking must be
470 * turned off */
471 if ( (aInternalNetwork == NULL || *aInternalNetwork == '\0')
472 && mData->mAttachmentType == NetworkAttachmentType_Internal)
473 {
474 return setError (E_FAIL,
475 tr ("Empty or null internal network name is not valid"));
476 }
477
478 mData.backup();
479 mData->mInternalNetwork = aInternalNetwork;
480
481 /* leave the lock before informing callbacks */
482 alock.unlock();
483
484 mParent->onNetworkAdapterChange (this);
485 }
486
487 return S_OK;
488}
489
490STDMETHODIMP NetworkAdapter::COMGETTER(NATNetwork) (BSTR *aNATNetwork)
491{
492 CheckComArgOutPointerValid(aNATNetwork);
493
494 AutoCaller autoCaller (this);
495 CheckComRCReturnRC (autoCaller.rc());
496
497 AutoReadLock alock (this);
498
499 mData->mNATNetwork.cloneTo (aNATNetwork);
500
501 return S_OK;
502}
503
504STDMETHODIMP NetworkAdapter::COMSETTER(NATNetwork) (IN_BSTR aNATNetwork)
505{
506 AutoCaller autoCaller (this);
507 CheckComRCReturnRC (autoCaller.rc());
508
509 /* the machine needs to be mutable */
510 Machine::AutoMutableStateDependency adep (mParent);
511 CheckComRCReturnRC (adep.rc());
512
513 AutoWriteLock alock (this);
514
515 if (mData->mNATNetwork != aNATNetwork)
516 {
517 mData.backup();
518 mData->mNATNetwork = aNATNetwork;
519
520 /* leave the lock before informing callbacks */
521 alock.unlock();
522
523 mParent->onNetworkAdapterChange (this);
524 }
525
526 return S_OK;
527}
528
529STDMETHODIMP NetworkAdapter::COMGETTER(CableConnected) (BOOL *aConnected)
530{
531 CheckComArgOutPointerValid(aConnected);
532
533 AutoCaller autoCaller (this);
534 CheckComRCReturnRC (autoCaller.rc());
535
536 AutoReadLock alock (this);
537
538 *aConnected = mData->mCableConnected;
539
540 return S_OK;
541}
542
543STDMETHODIMP NetworkAdapter::COMSETTER(CableConnected) (BOOL aConnected)
544{
545 AutoCaller autoCaller (this);
546 CheckComRCReturnRC (autoCaller.rc());
547
548 /* the machine needs to be mutable */
549 Machine::AutoMutableStateDependency adep (mParent);
550 CheckComRCReturnRC (adep.rc());
551
552 AutoWriteLock alock (this);
553
554 if (aConnected != mData->mCableConnected)
555 {
556 mData.backup();
557 mData->mCableConnected = aConnected;
558
559 /* leave the lock before informing callbacks */
560 alock.unlock();
561
562 mParent->onNetworkAdapterChange (this);
563 }
564
565 return S_OK;
566}
567
568STDMETHODIMP NetworkAdapter::COMGETTER(LineSpeed) (ULONG *aSpeed)
569{
570 CheckComArgOutPointerValid(aSpeed);
571
572 AutoCaller autoCaller (this);
573 CheckComRCReturnRC (autoCaller.rc());
574
575 AutoReadLock alock (this);
576
577 *aSpeed = mData->mLineSpeed;
578
579 return S_OK;
580}
581
582STDMETHODIMP NetworkAdapter::COMSETTER(LineSpeed) (ULONG aSpeed)
583{
584 AutoCaller autoCaller (this);
585 CheckComRCReturnRC (autoCaller.rc());
586
587 /* the machine needs to be mutable */
588 Machine::AutoMutableStateDependency adep (mParent);
589 CheckComRCReturnRC (adep.rc());
590
591 AutoWriteLock alock (this);
592
593 if (aSpeed != mData->mLineSpeed)
594 {
595 mData.backup();
596 mData->mLineSpeed = aSpeed;
597
598 /* leave the lock before informing callbacks */
599 alock.unlock();
600
601 mParent->onNetworkAdapterChange (this);
602 }
603
604 return S_OK;
605}
606
607STDMETHODIMP NetworkAdapter::COMGETTER(TraceEnabled) (BOOL *aEnabled)
608{
609 CheckComArgOutPointerValid(aEnabled);
610
611 AutoCaller autoCaller (this);
612 CheckComRCReturnRC (autoCaller.rc());
613
614 AutoReadLock alock (this);
615
616 *aEnabled = mData->mTraceEnabled;
617 return S_OK;
618}
619
620STDMETHODIMP NetworkAdapter::COMSETTER(TraceEnabled) (BOOL aEnabled)
621{
622 AutoCaller autoCaller (this);
623 CheckComRCReturnRC (autoCaller.rc());
624
625 /* the machine needs to be mutable */
626 Machine::AutoMutableStateDependency adep (mParent);
627 CheckComRCReturnRC (adep.rc());
628
629 AutoWriteLock alock (this);
630
631 if (aEnabled != mData->mTraceEnabled)
632 {
633 mData.backup();
634 mData->mTraceEnabled = aEnabled;
635
636 /* leave the lock before informing callbacks */
637 alock.unlock();
638
639 mParent->onNetworkAdapterChange (this);
640 }
641
642 return S_OK;
643}
644
645STDMETHODIMP NetworkAdapter::COMGETTER(TraceFile) (BSTR *aTraceFile)
646{
647 CheckComArgOutPointerValid(aTraceFile);
648
649 AutoCaller autoCaller (this);
650 CheckComRCReturnRC (autoCaller.rc());
651
652 AutoReadLock alock (this);
653
654 mData->mTraceFile.cloneTo (aTraceFile);
655
656 return S_OK;
657}
658
659STDMETHODIMP NetworkAdapter::COMSETTER(TraceFile) (IN_BSTR aTraceFile)
660{
661 AutoCaller autoCaller (this);
662 CheckComRCReturnRC (autoCaller.rc());
663
664 /* the machine needs to be mutable */
665 Machine::AutoMutableStateDependency adep (mParent);
666 CheckComRCReturnRC (adep.rc());
667
668 AutoWriteLock alock (this);
669
670 if (mData->mTraceFile != aTraceFile)
671 {
672 mData.backup();
673 mData->mTraceFile = aTraceFile;
674
675 /* leave the lock before informing callbacks */
676 alock.unlock();
677
678 mParent->onNetworkAdapterChange (this);
679 }
680
681 return S_OK;
682}
683
684// INetworkAdapter methods
685////////////////////////////////////////////////////////////////////////////////
686
687STDMETHODIMP NetworkAdapter::AttachToNAT()
688{
689 AutoCaller autoCaller (this);
690 CheckComRCReturnRC (autoCaller.rc());
691
692 /* the machine needs to be mutable */
693 Machine::AutoMutableStateDependency adep (mParent);
694 CheckComRCReturnRC (adep.rc());
695
696 AutoWriteLock alock (this);
697
698 if (mData->mAttachmentType != NetworkAttachmentType_NAT)
699 {
700 mData.backup();
701
702 detach();
703
704 mData->mAttachmentType = NetworkAttachmentType_NAT;
705
706 /* leave the lock before informing callbacks */
707 alock.unlock();
708
709 mParent->onNetworkAdapterChange (this);
710 }
711
712 return S_OK;
713}
714
715STDMETHODIMP NetworkAdapter::AttachToHostInterface()
716{
717 AutoCaller autoCaller (this);
718 CheckComRCReturnRC (autoCaller.rc());
719
720 /* the machine needs to be mutable */
721 Machine::AutoMutableStateDependency adep (mParent);
722 CheckComRCReturnRC (adep.rc());
723
724 AutoWriteLock alock (this);
725
726 /* don't do anything if we're already host interface attached */
727 if (mData->mAttachmentType != NetworkAttachmentType_HostInterface)
728 {
729 mData.backup();
730
731 /* first detach the current attachment */
732 detach();
733
734 mData->mAttachmentType = NetworkAttachmentType_HostInterface;
735
736 /* leave the lock before informing callbacks */
737 alock.unlock();
738
739 mParent->onNetworkAdapterChange (this);
740 }
741
742 return S_OK;
743}
744
745STDMETHODIMP NetworkAdapter::AttachToInternalNetwork()
746{
747 AutoCaller autoCaller (this);
748 CheckComRCReturnRC (autoCaller.rc());
749
750 /* the machine needs to be mutable */
751 Machine::AutoMutableStateDependency adep (mParent);
752 CheckComRCReturnRC (adep.rc());
753
754 AutoWriteLock alock (this);
755
756 /* don't do anything if we're already internal network attached */
757 if (mData->mAttachmentType != NetworkAttachmentType_Internal)
758 {
759 mData.backup();
760
761 /* first detach the current attachment */
762 detach();
763
764 /* there must an internal network name */
765 if (mData->mInternalNetwork.isEmpty())
766 {
767 LogRel (("Internal network name not defined, "
768 "setting to default \"intnet\"\n"));
769 mData->mInternalNetwork = "intnet";
770 }
771
772 mData->mAttachmentType = NetworkAttachmentType_Internal;
773
774 /* leave the lock before informing callbacks */
775 alock.unlock();
776
777 mParent->onNetworkAdapterChange (this);
778 }
779
780 return S_OK;
781}
782
783STDMETHODIMP NetworkAdapter::AttachToHostOnlyNetwork()
784{
785 AutoCaller autoCaller (this);
786 CheckComRCReturnRC (autoCaller.rc());
787
788 /* the machine needs to be mutable */
789 Machine::AutoMutableStateDependency adep (mParent);
790 CheckComRCReturnRC (adep.rc());
791
792 AutoWriteLock alock (this);
793
794 /* don't do anything if we're already host interface attached */
795 if (mData->mAttachmentType != NetworkAttachmentType_HostOnly)
796 {
797 mData.backup();
798
799 /* first detach the current attachment */
800 detach();
801
802 mData->mAttachmentType = NetworkAttachmentType_HostOnly;
803
804 /* leave the lock before informing callbacks */
805 alock.unlock();
806
807 mParent->onNetworkAdapterChange (this);
808 }
809
810 return S_OK;
811}
812
813STDMETHODIMP NetworkAdapter::Detach()
814{
815 AutoCaller autoCaller (this);
816 CheckComRCReturnRC (autoCaller.rc());
817
818 /* the machine needs to be mutable */
819 Machine::AutoMutableStateDependency adep (mParent);
820 CheckComRCReturnRC (adep.rc());
821
822 AutoWriteLock alock (this);
823
824 if (mData->mAttachmentType != NetworkAttachmentType_Null)
825 {
826 mData.backup();
827
828 detach();
829
830 /* leave the lock before informing callbacks */
831 alock.unlock();
832
833 mParent->onNetworkAdapterChange (this);
834 }
835
836 return S_OK;
837}
838
839// public methods only for internal purposes
840////////////////////////////////////////////////////////////////////////////////
841
842/**
843 * Loads settings from the given adapter node.
844 * May be called once right after this object creation.
845 *
846 * @param aAdapterNode <Adapter> node.
847 *
848 * @note Locks this object for writing.
849 */
850HRESULT NetworkAdapter::loadSettings (const settings::Key &aAdapterNode)
851{
852 using namespace settings;
853
854 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
855
856 AutoCaller autoCaller (this);
857 AssertComRCReturnRC (autoCaller.rc());
858
859 AutoWriteLock alock (this);
860
861 /* Note: we assume that the default values for attributes of optional
862 * nodes are assigned in the Data::Data() constructor and don't do it
863 * here. It implies that this method may only be called after constructing
864 * a new BIOSSettings object while all its data fields are in the default
865 * values. Exceptions are fields whose creation time defaults don't match
866 * values that should be applied when these fields are not explicitly set
867 * in the settings file (for backwards compatibility reasons). This takes
868 * place when a setting of a newly created object must default to A while
869 * the same setting of an object loaded from the old settings file must
870 * default to B. */
871
872 HRESULT rc = S_OK;
873
874 /* type (optional, defaults to Am79C970A) */
875 const char *adapterType = aAdapterNode.stringValue ("type");
876
877 if (strcmp (adapterType, "Am79C970A") == 0)
878 mData->mAdapterType = NetworkAdapterType_Am79C970A;
879 else if (strcmp (adapterType, "Am79C973") == 0)
880 mData->mAdapterType = NetworkAdapterType_Am79C973;
881 else if (strcmp (adapterType, "82540EM") == 0)
882 mData->mAdapterType = NetworkAdapterType_I82540EM;
883 else if (strcmp (adapterType, "82543GC") == 0)
884 mData->mAdapterType = NetworkAdapterType_I82543GC;
885 else
886 ComAssertMsgFailedRet (("Invalid adapter type '%s'", adapterType),
887 E_FAIL);
888
889 /* enabled (required) */
890 mData->mEnabled = aAdapterNode.value <bool> ("enabled");
891 /* MAC address (can be null) */
892 rc = COMSETTER(MACAddress) (Bstr (aAdapterNode.stringValue ("MACAddress")));
893 CheckComRCReturnRC (rc);
894 /* cable (required) */
895 mData->mCableConnected = aAdapterNode.value <bool> ("cable");
896 /* line speed (defaults to 100 Mbps) */
897 mData->mLineSpeed = aAdapterNode.value <ULONG> ("speed");
898 /* tracing (defaults to false) */
899 mData->mTraceEnabled = aAdapterNode.value <bool> ("trace");
900 mData->mTraceFile = aAdapterNode.stringValue ("tracefile");
901
902 /* One of NAT, HostInerface, Internal or nothing */
903 Key attachmentNode;
904
905 if (!(attachmentNode = aAdapterNode.findKey ("NAT")).isNull())
906 {
907 /* NAT */
908
909 /* optional */
910 mData->mNATNetwork = attachmentNode.stringValue ("network");
911
912 rc = AttachToNAT();
913 CheckComRCReturnRC (rc);
914 }
915 else
916 if (!(attachmentNode = aAdapterNode.findKey ("HostInterface")).isNull())
917 {
918 /* Host Interface Networking */
919
920 Bstr name = attachmentNode.stringValue ("name");
921 /* name can be empty, but not null */
922 ComAssertRet (!name.isNull(), E_FAIL);
923
924 rc = COMSETTER(HostInterface) (name);
925 CheckComRCReturnRC (rc);
926
927 rc = AttachToHostInterface();
928 CheckComRCReturnRC (rc);
929 }
930 else
931 if (!(attachmentNode = aAdapterNode.findKey ("InternalNetwork")).isNull())
932 {
933 /* Internal Networking */
934
935 /* required */
936 mData->mInternalNetwork = attachmentNode.stringValue ("name");
937 Assert (!mData->mInternalNetwork.isNull());
938
939 rc = AttachToInternalNetwork();
940 CheckComRCReturnRC (rc);
941 }
942 else
943 if (!(attachmentNode = aAdapterNode.findKey ("HostOnlyNetwork")).isNull())
944 {
945 /* Host Interface Networking */
946 rc = AttachToHostOnlyNetwork();
947 CheckComRCReturnRC (rc);
948 }
949 else
950 {
951 /* Adapter has no children */
952 rc = Detach();
953 CheckComRCReturnRC (rc);
954 }
955
956 return S_OK;
957}
958
959/**
960 * Saves settings to the given adapter node.
961 *
962 * Note that the given Adapter node is comletely empty on input.
963 *
964 * @param aAdapterNode <Adapter> node.
965 *
966 * @note Locks this object for reading.
967 */
968HRESULT NetworkAdapter::saveSettings (settings::Key &aAdapterNode)
969{
970 using namespace settings;
971
972 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
973
974 AutoCaller autoCaller (this);
975 AssertComRCReturnRC (autoCaller.rc());
976
977 AutoReadLock alock (this);
978
979 aAdapterNode.setValue <bool> ("enabled", !!mData->mEnabled);
980 aAdapterNode.setValue <Bstr> ("MACAddress", mData->mMACAddress);
981 aAdapterNode.setValue <bool> ("cable", !!mData->mCableConnected);
982
983 aAdapterNode.setValue <ULONG> ("speed", mData->mLineSpeed);
984
985 if (mData->mTraceEnabled)
986 aAdapterNode.setValue <bool> ("trace", true);
987
988 aAdapterNode.setValueOr <Bstr> ("tracefile", mData->mTraceFile, Bstr::Null);
989
990 const char *typeStr = NULL;
991 switch (mData->mAdapterType)
992 {
993 case NetworkAdapterType_Am79C970A:
994 typeStr = "Am79C970A";
995 break;
996 case NetworkAdapterType_Am79C973:
997 typeStr = "Am79C973";
998 break;
999 case NetworkAdapterType_I82540EM:
1000 typeStr = "82540EM";
1001 break;
1002 case NetworkAdapterType_I82543GC:
1003 typeStr = "82543GC";
1004 break;
1005 default:
1006 ComAssertMsgFailedRet (("Invalid network adapter type: %d",
1007 mData->mAdapterType),
1008 E_FAIL);
1009 }
1010 aAdapterNode.setStringValue ("type", typeStr);
1011
1012 switch (mData->mAttachmentType)
1013 {
1014 case NetworkAttachmentType_Null:
1015 {
1016 /* do nothing -- empty content */
1017 break;
1018 }
1019 case NetworkAttachmentType_NAT:
1020 {
1021 Key attachmentNode = aAdapterNode.createKey ("NAT");
1022 if (!mData->mNATNetwork.isEmpty())
1023 attachmentNode.setValue <Bstr> ("network",
1024 mData->mNATNetwork);
1025 break;
1026 }
1027 case NetworkAttachmentType_HostInterface:
1028 {
1029 Key attachmentNode = aAdapterNode.createKey ("HostInterface");
1030 Assert (!mData->mHostInterface.isNull());
1031 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1032 break;
1033 }
1034 case NetworkAttachmentType_Internal:
1035 {
1036 Key attachmentNode = aAdapterNode.createKey ("InternalNetwork");
1037 Assert (!mData->mInternalNetwork.isEmpty());
1038 attachmentNode.setValue <Bstr> ("name", mData->mInternalNetwork);
1039 break;
1040 }
1041 case NetworkAttachmentType_HostOnly:
1042 {
1043 Key attachmentNode = aAdapterNode.createKey ("HostOnlyNetwork");
1044 break;
1045 }
1046 default:
1047 {
1048 ComAssertFailedRet (E_FAIL);
1049 }
1050 }
1051
1052 return S_OK;
1053}
1054
1055/**
1056 * @note Locks this object for writing.
1057 */
1058bool NetworkAdapter::rollback()
1059{
1060 /* sanity */
1061 AutoCaller autoCaller (this);
1062 AssertComRCReturn (autoCaller.rc(), false);
1063
1064 AutoWriteLock alock (this);
1065
1066 bool changed = false;
1067
1068 if (mData.isBackedUp())
1069 {
1070 /* we need to check all data to see whether anything will be changed
1071 * after rollback */
1072 changed = mData.hasActualChanges();
1073 mData.rollback();
1074 }
1075
1076 return changed;
1077}
1078
1079/**
1080 * @note Locks this object for writing, together with the peer object (also
1081 * for writing) if there is one.
1082 */
1083void NetworkAdapter::commit()
1084{
1085 /* sanity */
1086 AutoCaller autoCaller (this);
1087 AssertComRCReturnVoid (autoCaller.rc());
1088
1089 /* sanity too */
1090 AutoCaller peerCaller (mPeer);
1091 AssertComRCReturnVoid (peerCaller.rc());
1092
1093 /* lock both for writing since we modify both (mPeer is "master" so locked
1094 * first) */
1095 AutoMultiWriteLock2 alock (mPeer, this);
1096
1097 if (mData.isBackedUp())
1098 {
1099 mData.commit();
1100 if (mPeer)
1101 {
1102 /* attach new data to the peer and reshare it */
1103 mPeer->mData.attach (mData);
1104 }
1105 }
1106}
1107
1108/**
1109 * @note Locks this object for writing, together with the peer object
1110 * represented by @a aThat (locked for reading).
1111 */
1112void NetworkAdapter::copyFrom (NetworkAdapter *aThat)
1113{
1114 AssertReturnVoid (aThat != NULL);
1115
1116 /* sanity */
1117 AutoCaller autoCaller (this);
1118 AssertComRCReturnVoid (autoCaller.rc());
1119
1120 /* sanity too */
1121 AutoCaller thatCaller (aThat);
1122 AssertComRCReturnVoid (thatCaller.rc());
1123
1124 /* peer is not modified, lock it for reading (aThat is "master" so locked
1125 * first) */
1126 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
1127
1128 /* this will back up current data */
1129 mData.assignCopy (aThat->mData);
1130}
1131
1132void NetworkAdapter::applyDefaults (GuestOSType *aOsType)
1133{
1134 AssertReturnVoid (aOsType != NULL);
1135
1136 /* sanity */
1137 AutoCaller autoCaller (this);
1138 AssertComRCReturnVoid (autoCaller.rc());
1139
1140 AutoWriteLock alock (this);
1141
1142 bool e1000enabled = false;
1143#ifdef VBOX_WITH_E1000
1144 e1000enabled = true;
1145#endif // VBOX_WITH_E1000
1146
1147 NetworkAdapterType_T defaultType = aOsType->networkAdapterType();
1148
1149 /* Set default network adapter for this OS type */
1150 if (defaultType == NetworkAdapterType_I82540EM ||
1151 defaultType == NetworkAdapterType_I82543GC)
1152 {
1153 if (e1000enabled) mData->mAdapterType = defaultType;
1154 }
1155 else mData->mAdapterType = defaultType;
1156
1157 /* Enable and connect the first one adapter to the NAT */
1158 if (mData->mSlot == 0)
1159 {
1160 mData->mEnabled = true;
1161 mData->mAttachmentType = NetworkAttachmentType_NAT;
1162 mData->mCableConnected = true;
1163 }
1164}
1165
1166// private methods
1167////////////////////////////////////////////////////////////////////////////////
1168
1169/**
1170 * Worker routine for detach handling. No locking, no notifications.
1171
1172 * @note Must be called from under the object's write lock.
1173 */
1174void NetworkAdapter::detach()
1175{
1176 AssertReturnVoid (isWriteLockOnCurrentThread());
1177
1178 switch (mData->mAttachmentType)
1179 {
1180 case NetworkAttachmentType_Null:
1181 {
1182 /* nothing to do here */
1183 break;
1184 }
1185 case NetworkAttachmentType_NAT:
1186 {
1187 break;
1188 }
1189 case NetworkAttachmentType_HostInterface:
1190 {
1191 /* reset handle and device name */
1192 mData->mHostInterface = "";
1193 break;
1194 }
1195 case NetworkAttachmentType_Internal:
1196 {
1197 mData->mInternalNetwork.setNull();
1198 break;
1199 }
1200 case NetworkAttachmentType_HostOnly:
1201 {
1202 break;
1203 }
1204 }
1205
1206 mData->mAttachmentType = NetworkAttachmentType_Null;
1207}
1208
1209/**
1210 * Generates a new unique MAC address based on our vendor ID and
1211 * parts of a GUID.
1212 *
1213 * @note Must be called from under the object's write lock or within the init
1214 * span.
1215 */
1216void NetworkAdapter::generateMACAddress()
1217{
1218 /*
1219 * Our strategy is as follows: the first three bytes are our fixed
1220 * vendor ID (080027). The remaining 3 bytes will be taken from the
1221 * start of a GUID. This is a fairly safe algorithm.
1222 */
1223 char strMAC[13];
1224 Guid guid;
1225 guid.create();
1226 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1227 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1228 LogFlowThisFunc (("generated MAC: '%s'\n", strMAC));
1229 mData->mMACAddress = strMAC;
1230}
1231/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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