VirtualBox

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

Last change on this file since 8429 was 8367, checked in by vboxsync, 17 years ago

Main: Added INetworkAdapter::NATNetwork property.

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