VirtualBox

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

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

#2954 & #3569: Linux TAP driver is embedded to vboxnetflt. API, VBoxManage and VirtualBox now provide host-only network attachment on Linux.

  • 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
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::AttachToHostOnlyNetwork()
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 /* don't do anything if we're already host interface attached */
794 if (mData->mAttachmentType != NetworkAttachmentType_HostOnly)
795 {
796 mData.backup();
797
798 /* first detach the current attachment */
799 detach();
800
801 mData->mAttachmentType = NetworkAttachmentType_HostOnly;
802
803 /* leave the lock before informing callbacks */
804 alock.unlock();
805
806 mParent->onNetworkAdapterChange (this);
807 }
808
809 return S_OK;
810}
811
812STDMETHODIMP NetworkAdapter::Detach()
813{
814 AutoCaller autoCaller (this);
815 CheckComRCReturnRC (autoCaller.rc());
816
817 /* the machine needs to be mutable */
818 Machine::AutoMutableStateDependency adep (mParent);
819 CheckComRCReturnRC (adep.rc());
820
821 AutoWriteLock alock (this);
822
823 if (mData->mAttachmentType != NetworkAttachmentType_Null)
824 {
825 mData.backup();
826
827 detach();
828
829 /* leave the lock before informing callbacks */
830 alock.unlock();
831
832 mParent->onNetworkAdapterChange (this);
833 }
834
835 return S_OK;
836}
837
838// public methods only for internal purposes
839////////////////////////////////////////////////////////////////////////////////
840
841/**
842 * Loads settings from the given adapter node.
843 * May be called once right after this object creation.
844 *
845 * @param aAdapterNode <Adapter> node.
846 *
847 * @note Locks this object for writing.
848 */
849HRESULT NetworkAdapter::loadSettings (const settings::Key &aAdapterNode)
850{
851 using namespace settings;
852
853 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
854
855 AutoCaller autoCaller (this);
856 AssertComRCReturnRC (autoCaller.rc());
857
858 AutoWriteLock alock (this);
859
860 /* Note: we assume that the default values for attributes of optional
861 * nodes are assigned in the Data::Data() constructor and don't do it
862 * here. It implies that this method may only be called after constructing
863 * a new BIOSSettings object while all its data fields are in the default
864 * values. Exceptions are fields whose creation time defaults don't match
865 * values that should be applied when these fields are not explicitly set
866 * in the settings file (for backwards compatibility reasons). This takes
867 * place when a setting of a newly created object must default to A while
868 * the same setting of an object loaded from the old settings file must
869 * default to B. */
870
871 HRESULT rc = S_OK;
872
873 /* type (optional, defaults to Am79C970A) */
874 const char *adapterType = aAdapterNode.stringValue ("type");
875
876 if (strcmp (adapterType, "Am79C970A") == 0)
877 mData->mAdapterType = NetworkAdapterType_Am79C970A;
878 else if (strcmp (adapterType, "Am79C973") == 0)
879 mData->mAdapterType = NetworkAdapterType_Am79C973;
880 else if (strcmp (adapterType, "82540EM") == 0)
881 mData->mAdapterType = NetworkAdapterType_I82540EM;
882 else if (strcmp (adapterType, "82543GC") == 0)
883 mData->mAdapterType = NetworkAdapterType_I82543GC;
884 else
885 ComAssertMsgFailedRet (("Invalid adapter type '%s'", adapterType),
886 E_FAIL);
887
888 /* enabled (required) */
889 mData->mEnabled = aAdapterNode.value <bool> ("enabled");
890 /* MAC address (can be null) */
891 rc = COMSETTER(MACAddress) (Bstr (aAdapterNode.stringValue ("MACAddress")));
892 CheckComRCReturnRC (rc);
893 /* cable (required) */
894 mData->mCableConnected = aAdapterNode.value <bool> ("cable");
895 /* line speed (defaults to 100 Mbps) */
896 mData->mLineSpeed = aAdapterNode.value <ULONG> ("speed");
897 /* tracing (defaults to false) */
898 mData->mTraceEnabled = aAdapterNode.value <bool> ("trace");
899 mData->mTraceFile = aAdapterNode.stringValue ("tracefile");
900
901 /* One of NAT, HostInerface, Internal or nothing */
902 Key attachmentNode;
903
904 if (!(attachmentNode = aAdapterNode.findKey ("NAT")).isNull())
905 {
906 /* NAT */
907
908 /* optional */
909 mData->mNATNetwork = attachmentNode.stringValue ("network");
910
911 rc = AttachToNAT();
912 CheckComRCReturnRC (rc);
913 }
914 else
915 if (!(attachmentNode = aAdapterNode.findKey ("HostInterface")).isNull())
916 {
917 /* Host Interface Networking */
918
919 Bstr name = attachmentNode.stringValue ("name");
920 /* name can be empty, but not null */
921 ComAssertRet (!name.isNull(), E_FAIL);
922
923 rc = COMSETTER(HostInterface) (name);
924 CheckComRCReturnRC (rc);
925
926 rc = AttachToHostInterface();
927 CheckComRCReturnRC (rc);
928 }
929 else
930 if (!(attachmentNode = aAdapterNode.findKey ("InternalNetwork")).isNull())
931 {
932 /* Internal Networking */
933
934 /* required */
935 mData->mInternalNetwork = attachmentNode.stringValue ("name");
936 Assert (!mData->mInternalNetwork.isNull());
937
938 rc = AttachToInternalNetwork();
939 CheckComRCReturnRC (rc);
940 }
941 else
942 if (!(attachmentNode = aAdapterNode.findKey ("HostOnlyNetwork")).isNull())
943 {
944 /* Host Interface Networking */
945 rc = AttachToHostOnlyNetwork();
946 CheckComRCReturnRC (rc);
947 }
948 else
949 {
950 /* Adapter has no children */
951 rc = Detach();
952 CheckComRCReturnRC (rc);
953 }
954
955 return S_OK;
956}
957
958/**
959 * Saves settings to the given adapter node.
960 *
961 * Note that the given Adapter node is comletely empty on input.
962 *
963 * @param aAdapterNode <Adapter> node.
964 *
965 * @note Locks this object for reading.
966 */
967HRESULT NetworkAdapter::saveSettings (settings::Key &aAdapterNode)
968{
969 using namespace settings;
970
971 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
972
973 AutoCaller autoCaller (this);
974 AssertComRCReturnRC (autoCaller.rc());
975
976 AutoReadLock alock (this);
977
978 aAdapterNode.setValue <bool> ("enabled", !!mData->mEnabled);
979 aAdapterNode.setValue <Bstr> ("MACAddress", mData->mMACAddress);
980 aAdapterNode.setValue <bool> ("cable", !!mData->mCableConnected);
981
982 aAdapterNode.setValue <ULONG> ("speed", mData->mLineSpeed);
983
984 if (mData->mTraceEnabled)
985 aAdapterNode.setValue <bool> ("trace", true);
986
987 aAdapterNode.setValueOr <Bstr> ("tracefile", mData->mTraceFile, Bstr::Null);
988
989 const char *typeStr = NULL;
990 switch (mData->mAdapterType)
991 {
992 case NetworkAdapterType_Am79C970A:
993 typeStr = "Am79C970A";
994 break;
995 case NetworkAdapterType_Am79C973:
996 typeStr = "Am79C973";
997 break;
998 case NetworkAdapterType_I82540EM:
999 typeStr = "82540EM";
1000 break;
1001 case NetworkAdapterType_I82543GC:
1002 typeStr = "82543GC";
1003 break;
1004 default:
1005 ComAssertMsgFailedRet (("Invalid network adapter type: %d",
1006 mData->mAdapterType),
1007 E_FAIL);
1008 }
1009 aAdapterNode.setStringValue ("type", typeStr);
1010
1011 switch (mData->mAttachmentType)
1012 {
1013 case NetworkAttachmentType_Null:
1014 {
1015 /* do nothing -- empty content */
1016 break;
1017 }
1018 case NetworkAttachmentType_NAT:
1019 {
1020 Key attachmentNode = aAdapterNode.createKey ("NAT");
1021 if (!mData->mNATNetwork.isEmpty())
1022 attachmentNode.setValue <Bstr> ("network",
1023 mData->mNATNetwork);
1024 break;
1025 }
1026 case NetworkAttachmentType_HostInterface:
1027 {
1028 Key attachmentNode = aAdapterNode.createKey ("HostInterface");
1029 Assert (!mData->mHostInterface.isNull());
1030 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1031 break;
1032 }
1033 case NetworkAttachmentType_Internal:
1034 {
1035 Key attachmentNode = aAdapterNode.createKey ("InternalNetwork");
1036 Assert (!mData->mInternalNetwork.isEmpty());
1037 attachmentNode.setValue <Bstr> ("name", mData->mInternalNetwork);
1038 break;
1039 }
1040 case NetworkAttachmentType_HostOnly:
1041 {
1042 Key attachmentNode = aAdapterNode.createKey ("HostOnlyNetwork");
1043 break;
1044 }
1045 default:
1046 {
1047 ComAssertFailedRet (E_FAIL);
1048 }
1049 }
1050
1051 return S_OK;
1052}
1053
1054/**
1055 * @note Locks this object for writing.
1056 */
1057bool NetworkAdapter::rollback()
1058{
1059 /* sanity */
1060 AutoCaller autoCaller (this);
1061 AssertComRCReturn (autoCaller.rc(), false);
1062
1063 AutoWriteLock alock (this);
1064
1065 bool changed = false;
1066
1067 if (mData.isBackedUp())
1068 {
1069 /* we need to check all data to see whether anything will be changed
1070 * after rollback */
1071 changed = mData.hasActualChanges();
1072 mData.rollback();
1073 }
1074
1075 return changed;
1076}
1077
1078/**
1079 * @note Locks this object for writing, together with the peer object (also
1080 * for writing) if there is one.
1081 */
1082void NetworkAdapter::commit()
1083{
1084 /* sanity */
1085 AutoCaller autoCaller (this);
1086 AssertComRCReturnVoid (autoCaller.rc());
1087
1088 /* sanity too */
1089 AutoCaller peerCaller (mPeer);
1090 AssertComRCReturnVoid (peerCaller.rc());
1091
1092 /* lock both for writing since we modify both (mPeer is "master" so locked
1093 * first) */
1094 AutoMultiWriteLock2 alock (mPeer, this);
1095
1096 if (mData.isBackedUp())
1097 {
1098 mData.commit();
1099 if (mPeer)
1100 {
1101 /* attach new data to the peer and reshare it */
1102 mPeer->mData.attach (mData);
1103 }
1104 }
1105}
1106
1107/**
1108 * @note Locks this object for writing, together with the peer object
1109 * represented by @a aThat (locked for reading).
1110 */
1111void NetworkAdapter::copyFrom (NetworkAdapter *aThat)
1112{
1113 AssertReturnVoid (aThat != NULL);
1114
1115 /* sanity */
1116 AutoCaller autoCaller (this);
1117 AssertComRCReturnVoid (autoCaller.rc());
1118
1119 /* sanity too */
1120 AutoCaller thatCaller (aThat);
1121 AssertComRCReturnVoid (thatCaller.rc());
1122
1123 /* peer is not modified, lock it for reading (aThat is "master" so locked
1124 * first) */
1125 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
1126
1127 /* this will back up current data */
1128 mData.assignCopy (aThat->mData);
1129}
1130
1131void NetworkAdapter::applyDefaults (GuestOSType *aOsType)
1132{
1133 AssertReturnVoid (aOsType != NULL);
1134
1135 /* sanity */
1136 AutoCaller autoCaller (this);
1137 AssertComRCReturnVoid (autoCaller.rc());
1138
1139 AutoWriteLock alock (this);
1140
1141 bool e1000enabled = false;
1142#ifdef VBOX_WITH_E1000
1143 e1000enabled = true;
1144#endif // VBOX_WITH_E1000
1145
1146 NetworkAdapterType_T defaultType = aOsType->networkAdapterType();
1147
1148 /* Set default network adapter for this OS type */
1149 if (defaultType == NetworkAdapterType_I82540EM ||
1150 defaultType == NetworkAdapterType_I82543GC)
1151 {
1152 if (e1000enabled) mData->mAdapterType = defaultType;
1153 }
1154 else mData->mAdapterType = defaultType;
1155
1156 /* Enable and connect the first one adapter to the NAT */
1157 if (mData->mSlot == 0)
1158 {
1159 mData->mEnabled = true;
1160 mData->mAttachmentType = NetworkAttachmentType_NAT;
1161 mData->mCableConnected = true;
1162 }
1163}
1164
1165// private methods
1166////////////////////////////////////////////////////////////////////////////////
1167
1168/**
1169 * Worker routine for detach handling. No locking, no notifications.
1170
1171 * @note Must be called from under the object's write lock.
1172 */
1173void NetworkAdapter::detach()
1174{
1175 AssertReturnVoid (isWriteLockOnCurrentThread());
1176
1177 switch (mData->mAttachmentType)
1178 {
1179 case NetworkAttachmentType_Null:
1180 {
1181 /* nothing to do here */
1182 break;
1183 }
1184 case NetworkAttachmentType_NAT:
1185 {
1186 break;
1187 }
1188 case NetworkAttachmentType_HostInterface:
1189 {
1190 /* reset handle and device name */
1191 mData->mHostInterface = "";
1192 break;
1193 }
1194 case NetworkAttachmentType_Internal:
1195 {
1196 mData->mInternalNetwork.setNull();
1197 break;
1198 }
1199 case NetworkAttachmentType_HostOnly:
1200 {
1201 break;
1202 }
1203 }
1204
1205 mData->mAttachmentType = NetworkAttachmentType_Null;
1206}
1207
1208/**
1209 * Generates a new unique MAC address based on our vendor ID and
1210 * parts of a GUID.
1211 *
1212 * @note Must be called from under the object's write lock or within the init
1213 * span.
1214 */
1215void NetworkAdapter::generateMACAddress()
1216{
1217 /*
1218 * Our strategy is as follows: the first three bytes are our fixed
1219 * vendor ID (080027). The remaining 3 bytes will be taken from the
1220 * start of a GUID. This is a fairly safe algorithm.
1221 */
1222 char strMAC[13];
1223 Guid guid;
1224 guid.create();
1225 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1226 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1227 LogFlowThisFunc (("generated MAC: '%s'\n", strMAC));
1228 mData->mMACAddress = strMAC;
1229}
1230/* 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