VirtualBox

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

Last change on this file since 16967 was 16967, checked in by vboxsync, 15 years ago

NetAdp: added a Real property to the IHostNetworkInterface, make the interface name be honored in VM settings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.6 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#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
946 Bstr name = attachmentNode.stringValue ("name");
947 /* name can be empty, but not null */
948 ComAssertRet (!name.isNull(), E_FAIL);
949
950 rc = COMSETTER(HostInterface) (name);
951 CheckComRCReturnRC (rc);
952#endif
953
954 /* Host Interface Networking */
955 rc = AttachToHostOnlyNetwork();
956 CheckComRCReturnRC (rc);
957 }
958 else
959 {
960 /* Adapter has no children */
961 rc = Detach();
962 CheckComRCReturnRC (rc);
963 }
964
965 return S_OK;
966}
967
968/**
969 * Saves settings to the given adapter node.
970 *
971 * Note that the given Adapter node is comletely empty on input.
972 *
973 * @param aAdapterNode <Adapter> node.
974 *
975 * @note Locks this object for reading.
976 */
977HRESULT NetworkAdapter::saveSettings (settings::Key &aAdapterNode)
978{
979 using namespace settings;
980
981 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
982
983 AutoCaller autoCaller (this);
984 AssertComRCReturnRC (autoCaller.rc());
985
986 AutoReadLock alock (this);
987
988 aAdapterNode.setValue <bool> ("enabled", !!mData->mEnabled);
989 aAdapterNode.setValue <Bstr> ("MACAddress", mData->mMACAddress);
990 aAdapterNode.setValue <bool> ("cable", !!mData->mCableConnected);
991
992 aAdapterNode.setValue <ULONG> ("speed", mData->mLineSpeed);
993
994 if (mData->mTraceEnabled)
995 aAdapterNode.setValue <bool> ("trace", true);
996
997 aAdapterNode.setValueOr <Bstr> ("tracefile", mData->mTraceFile, Bstr::Null);
998
999 const char *typeStr = NULL;
1000 switch (mData->mAdapterType)
1001 {
1002 case NetworkAdapterType_Am79C970A:
1003 typeStr = "Am79C970A";
1004 break;
1005 case NetworkAdapterType_Am79C973:
1006 typeStr = "Am79C973";
1007 break;
1008 case NetworkAdapterType_I82540EM:
1009 typeStr = "82540EM";
1010 break;
1011 case NetworkAdapterType_I82543GC:
1012 typeStr = "82543GC";
1013 break;
1014 default:
1015 ComAssertMsgFailedRet (("Invalid network adapter type: %d",
1016 mData->mAdapterType),
1017 E_FAIL);
1018 }
1019 aAdapterNode.setStringValue ("type", typeStr);
1020
1021 switch (mData->mAttachmentType)
1022 {
1023 case NetworkAttachmentType_Null:
1024 {
1025 /* do nothing -- empty content */
1026 break;
1027 }
1028 case NetworkAttachmentType_NAT:
1029 {
1030 Key attachmentNode = aAdapterNode.createKey ("NAT");
1031 if (!mData->mNATNetwork.isEmpty())
1032 attachmentNode.setValue <Bstr> ("network",
1033 mData->mNATNetwork);
1034 break;
1035 }
1036 case NetworkAttachmentType_HostInterface:
1037 {
1038 Key attachmentNode = aAdapterNode.createKey ("HostInterface");
1039 Assert (!mData->mHostInterface.isNull());
1040 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1041 break;
1042 }
1043 case NetworkAttachmentType_Internal:
1044 {
1045 Key attachmentNode = aAdapterNode.createKey ("InternalNetwork");
1046 Assert (!mData->mInternalNetwork.isEmpty());
1047 attachmentNode.setValue <Bstr> ("name", mData->mInternalNetwork);
1048 break;
1049 }
1050 case NetworkAttachmentType_HostOnly:
1051 {
1052 Key attachmentNode = aAdapterNode.createKey ("HostOnlyNetwork");
1053#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
1054 Assert (!mData->mHostInterface.isNull());
1055 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1056#endif
1057 break;
1058 }
1059 default:
1060 {
1061 ComAssertFailedRet (E_FAIL);
1062 }
1063 }
1064
1065 return S_OK;
1066}
1067
1068/**
1069 * @note Locks this object for writing.
1070 */
1071bool NetworkAdapter::rollback()
1072{
1073 /* sanity */
1074 AutoCaller autoCaller (this);
1075 AssertComRCReturn (autoCaller.rc(), false);
1076
1077 AutoWriteLock alock (this);
1078
1079 bool changed = false;
1080
1081 if (mData.isBackedUp())
1082 {
1083 /* we need to check all data to see whether anything will be changed
1084 * after rollback */
1085 changed = mData.hasActualChanges();
1086 mData.rollback();
1087 }
1088
1089 return changed;
1090}
1091
1092/**
1093 * @note Locks this object for writing, together with the peer object (also
1094 * for writing) if there is one.
1095 */
1096void NetworkAdapter::commit()
1097{
1098 /* sanity */
1099 AutoCaller autoCaller (this);
1100 AssertComRCReturnVoid (autoCaller.rc());
1101
1102 /* sanity too */
1103 AutoCaller peerCaller (mPeer);
1104 AssertComRCReturnVoid (peerCaller.rc());
1105
1106 /* lock both for writing since we modify both (mPeer is "master" so locked
1107 * first) */
1108 AutoMultiWriteLock2 alock (mPeer, this);
1109
1110 if (mData.isBackedUp())
1111 {
1112 mData.commit();
1113 if (mPeer)
1114 {
1115 /* attach new data to the peer and reshare it */
1116 mPeer->mData.attach (mData);
1117 }
1118 }
1119}
1120
1121/**
1122 * @note Locks this object for writing, together with the peer object
1123 * represented by @a aThat (locked for reading).
1124 */
1125void NetworkAdapter::copyFrom (NetworkAdapter *aThat)
1126{
1127 AssertReturnVoid (aThat != NULL);
1128
1129 /* sanity */
1130 AutoCaller autoCaller (this);
1131 AssertComRCReturnVoid (autoCaller.rc());
1132
1133 /* sanity too */
1134 AutoCaller thatCaller (aThat);
1135 AssertComRCReturnVoid (thatCaller.rc());
1136
1137 /* peer is not modified, lock it for reading (aThat is "master" so locked
1138 * first) */
1139 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
1140
1141 /* this will back up current data */
1142 mData.assignCopy (aThat->mData);
1143}
1144
1145void NetworkAdapter::applyDefaults (GuestOSType *aOsType)
1146{
1147 AssertReturnVoid (aOsType != NULL);
1148
1149 /* sanity */
1150 AutoCaller autoCaller (this);
1151 AssertComRCReturnVoid (autoCaller.rc());
1152
1153 AutoWriteLock alock (this);
1154
1155 bool e1000enabled = false;
1156#ifdef VBOX_WITH_E1000
1157 e1000enabled = true;
1158#endif // VBOX_WITH_E1000
1159
1160 NetworkAdapterType_T defaultType = aOsType->networkAdapterType();
1161
1162 /* Set default network adapter for this OS type */
1163 if (defaultType == NetworkAdapterType_I82540EM ||
1164 defaultType == NetworkAdapterType_I82543GC)
1165 {
1166 if (e1000enabled) mData->mAdapterType = defaultType;
1167 }
1168 else mData->mAdapterType = defaultType;
1169
1170 /* Enable and connect the first one adapter to the NAT */
1171 if (mData->mSlot == 0)
1172 {
1173 mData->mEnabled = true;
1174 mData->mAttachmentType = NetworkAttachmentType_NAT;
1175 mData->mCableConnected = true;
1176 }
1177}
1178
1179// private methods
1180////////////////////////////////////////////////////////////////////////////////
1181
1182/**
1183 * Worker routine for detach handling. No locking, no notifications.
1184
1185 * @note Must be called from under the object's write lock.
1186 */
1187void NetworkAdapter::detach()
1188{
1189 AssertReturnVoid (isWriteLockOnCurrentThread());
1190
1191 switch (mData->mAttachmentType)
1192 {
1193 case NetworkAttachmentType_Null:
1194 {
1195 /* nothing to do here */
1196 break;
1197 }
1198 case NetworkAttachmentType_NAT:
1199 {
1200 break;
1201 }
1202 case NetworkAttachmentType_HostInterface:
1203 {
1204 /* reset handle and device name */
1205 mData->mHostInterface = "";
1206 break;
1207 }
1208 case NetworkAttachmentType_Internal:
1209 {
1210 mData->mInternalNetwork.setNull();
1211 break;
1212 }
1213 case NetworkAttachmentType_HostOnly:
1214 {
1215#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
1216 /* reset handle and device name */
1217 mData->mHostInterface = "";
1218#endif
1219 break;
1220 }
1221 }
1222
1223 mData->mAttachmentType = NetworkAttachmentType_Null;
1224}
1225
1226/**
1227 * Generates a new unique MAC address based on our vendor ID and
1228 * parts of a GUID.
1229 *
1230 * @note Must be called from under the object's write lock or within the init
1231 * span.
1232 */
1233void NetworkAdapter::generateMACAddress()
1234{
1235 /*
1236 * Our strategy is as follows: the first three bytes are our fixed
1237 * vendor ID (080027). The remaining 3 bytes will be taken from the
1238 * start of a GUID. This is a fairly safe algorithm.
1239 */
1240 char strMAC[13];
1241 Guid guid;
1242 guid.create();
1243 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1244 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1245 LogFlowThisFunc (("generated MAC: '%s'\n", strMAC));
1246 mData->mMACAddress = strMAC;
1247}
1248/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use