VirtualBox

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

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

Main: #3424: Bumped XML format version to 1.6 and so that the auto-converter will delete old <HostInterface> nodes containing TAPSetup/TAPTerminate attributes. Removed all (obsolete) sections of code in #ifdef VBOX_WITH_UNIXY_TAP_NETWORKING (that uses these attributes); removed the define itself.

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