VirtualBox

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

Last change on this file since 8343 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.5 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 /* we don't allow null strings */
606 if (!aInternalNetwork)
607 return E_POINTER;
608
609 AutoCaller autoCaller (this);
610 CheckComRCReturnRC (autoCaller.rc());
611
612 AutoReadLock alock (this);
613
614 mData->mInternalNetwork.cloneTo (aInternalNetwork);
615
616 return S_OK;
617}
618
619STDMETHODIMP NetworkAdapter::COMSETTER(InternalNetwork) (INPTR BSTR aInternalNetwork)
620{
621 if (!aInternalNetwork)
622 return E_INVALIDARG;
623
624 AutoCaller autoCaller (this);
625 CheckComRCReturnRC (autoCaller.rc());
626
627 /* the machine needs to be mutable */
628 Machine::AutoMutableStateDependency adep (mParent);
629 CheckComRCReturnRC (adep.rc());
630
631 AutoWriteLock alock (this);
632
633 if (mData->mInternalNetwork != aInternalNetwork)
634 {
635 /* if an empty string is to be set, internal networking must be turned off */
636 if ( (aInternalNetwork == Bstr(""))
637 && (mData->mAttachmentType = NetworkAttachmentType_Internal))
638 {
639 return setError (E_FAIL, tr ("Empty internal network name is not valid"));
640 }
641
642 mData.backup();
643 mData->mInternalNetwork = aInternalNetwork;
644
645 /* leave the lock before informing callbacks */
646 alock.unlock();
647
648 mParent->onNetworkAdapterChange (this);
649 }
650
651 return S_OK;
652}
653
654STDMETHODIMP NetworkAdapter::COMGETTER(CableConnected) (BOOL *aConnected)
655{
656 if (!aConnected)
657 return E_POINTER;
658
659 AutoCaller autoCaller (this);
660 CheckComRCReturnRC (autoCaller.rc());
661
662 AutoReadLock alock (this);
663
664 *aConnected = mData->mCableConnected;
665
666 return S_OK;
667}
668
669STDMETHODIMP NetworkAdapter::COMSETTER(CableConnected) (BOOL aConnected)
670{
671 AutoCaller autoCaller (this);
672 CheckComRCReturnRC (autoCaller.rc());
673
674 /* the machine needs to be mutable */
675 Machine::AutoMutableStateDependency adep (mParent);
676 CheckComRCReturnRC (adep.rc());
677
678 AutoWriteLock alock (this);
679
680 if (aConnected != mData->mCableConnected)
681 {
682 mData.backup();
683 mData->mCableConnected = aConnected;
684
685 /* leave the lock before informing callbacks */
686 alock.unlock();
687
688 mParent->onNetworkAdapterChange (this);
689 }
690
691 return S_OK;
692}
693
694STDMETHODIMP NetworkAdapter::COMGETTER(LineSpeed) (ULONG *aSpeed)
695{
696 if (!aSpeed)
697 return E_POINTER;
698
699 AutoCaller autoCaller (this);
700 CheckComRCReturnRC (autoCaller.rc());
701
702 AutoReadLock alock (this);
703
704 *aSpeed = mData->mLineSpeed;
705
706 return S_OK;
707}
708
709STDMETHODIMP NetworkAdapter::COMSETTER(LineSpeed) (ULONG aSpeed)
710{
711 AutoCaller autoCaller (this);
712 CheckComRCReturnRC (autoCaller.rc());
713
714 /* the machine needs to be mutable */
715 Machine::AutoMutableStateDependency adep (mParent);
716 CheckComRCReturnRC (adep.rc());
717
718 AutoWriteLock alock (this);
719
720 if (aSpeed != mData->mLineSpeed)
721 {
722 mData.backup();
723 mData->mLineSpeed = aSpeed;
724
725 /* leave the lock before informing callbacks */
726 alock.unlock();
727
728 mParent->onNetworkAdapterChange (this);
729 }
730
731 return S_OK;
732}
733
734STDMETHODIMP NetworkAdapter::COMGETTER(TraceEnabled) (BOOL *aEnabled)
735{
736 if (!aEnabled)
737 return E_POINTER;
738
739 AutoCaller autoCaller (this);
740 CheckComRCReturnRC (autoCaller.rc());
741
742 AutoReadLock alock (this);
743
744 *aEnabled = mData->mTraceEnabled;
745 return S_OK;
746}
747
748STDMETHODIMP NetworkAdapter::COMSETTER(TraceEnabled) (BOOL aEnabled)
749{
750 AutoCaller autoCaller (this);
751 CheckComRCReturnRC (autoCaller.rc());
752
753 /* the machine needs to be mutable */
754 Machine::AutoMutableStateDependency adep (mParent);
755 CheckComRCReturnRC (adep.rc());
756
757 AutoWriteLock alock (this);
758
759 if (aEnabled != mData->mTraceEnabled)
760 {
761 mData.backup();
762 mData->mTraceEnabled = aEnabled;
763
764 /* leave the lock before informing callbacks */
765 alock.unlock();
766
767 mParent->onNetworkAdapterChange (this);
768 }
769
770 return S_OK;
771}
772
773STDMETHODIMP NetworkAdapter::COMGETTER(TraceFile) (BSTR *aTraceFile)
774{
775 if (!aTraceFile)
776 return E_POINTER;
777
778 AutoCaller autoCaller (this);
779 CheckComRCReturnRC (autoCaller.rc());
780
781 AutoReadLock alock (this);
782
783 mData->mTraceFile.cloneTo (aTraceFile);
784
785 return S_OK;
786}
787
788STDMETHODIMP NetworkAdapter::COMSETTER(TraceFile) (INPTR BSTR aTraceFile)
789{
790 AutoCaller autoCaller (this);
791 CheckComRCReturnRC (autoCaller.rc());
792
793 /* the machine needs to be mutable */
794 Machine::AutoMutableStateDependency adep (mParent);
795 CheckComRCReturnRC (adep.rc());
796
797 AutoWriteLock alock (this);
798
799 if (mData->mTraceFile != aTraceFile)
800 {
801 mData.backup();
802 mData->mTraceFile = aTraceFile;
803
804 /* leave the lock before informing callbacks */
805 alock.unlock();
806
807 mParent->onNetworkAdapterChange (this);
808 }
809
810 return S_OK;
811}
812
813// INetworkAdapter methods
814////////////////////////////////////////////////////////////////////////////////
815
816STDMETHODIMP NetworkAdapter::AttachToNAT()
817{
818 AutoCaller autoCaller (this);
819 CheckComRCReturnRC (autoCaller.rc());
820
821 /* the machine needs to be mutable */
822 Machine::AutoMutableStateDependency adep (mParent);
823 CheckComRCReturnRC (adep.rc());
824
825 AutoWriteLock alock (this);
826
827 if (mData->mAttachmentType != NetworkAttachmentType_NAT)
828 {
829 mData.backup();
830
831 detach();
832
833 mData->mAttachmentType = NetworkAttachmentType_NAT;
834
835 /* leave the lock before informing callbacks */
836 alock.unlock();
837
838 mParent->onNetworkAdapterChange (this);
839 }
840
841 return S_OK;
842}
843
844STDMETHODIMP NetworkAdapter::AttachToHostInterface()
845{
846 AutoCaller autoCaller (this);
847 CheckComRCReturnRC (autoCaller.rc());
848
849 /* the machine needs to be mutable */
850 Machine::AutoMutableStateDependency adep (mParent);
851 CheckComRCReturnRC (adep.rc());
852
853 AutoWriteLock alock (this);
854
855 /* don't do anything if we're already host interface attached */
856 if (mData->mAttachmentType != NetworkAttachmentType_HostInterface)
857 {
858 mData.backup();
859
860 /* first detach the current attachment */
861 detach();
862
863 mData->mAttachmentType = NetworkAttachmentType_HostInterface;
864
865 /* leave the lock before informing callbacks */
866 alock.unlock();
867
868 mParent->onNetworkAdapterChange (this);
869 }
870
871 return S_OK;
872}
873
874STDMETHODIMP NetworkAdapter::AttachToInternalNetwork()
875{
876 AutoCaller autoCaller (this);
877 CheckComRCReturnRC (autoCaller.rc());
878
879 /* the machine needs to be mutable */
880 Machine::AutoMutableStateDependency adep (mParent);
881 CheckComRCReturnRC (adep.rc());
882
883 AutoWriteLock alock (this);
884
885 /* don't do anything if we're already internal network attached */
886 if (mData->mAttachmentType != NetworkAttachmentType_Internal)
887 {
888 mData.backup();
889
890 /* first detach the current attachment */
891 detach();
892
893 /* there must an internal network name */
894 if ( !mData->mInternalNetwork
895 || (mData->mInternalNetwork == Bstr ("")))
896 {
897 LogRel (("Internal network name not defined, "
898 "setting to default \"intnet\"\n"));
899 mData->mInternalNetwork = Bstr ("intnet");
900 }
901
902 mData->mAttachmentType = NetworkAttachmentType_Internal;
903
904 /* leave the lock before informing callbacks */
905 alock.unlock();
906
907 mParent->onNetworkAdapterChange (this);
908 }
909
910 return S_OK;
911}
912
913STDMETHODIMP NetworkAdapter::Detach()
914{
915 AutoCaller autoCaller (this);
916 CheckComRCReturnRC (autoCaller.rc());
917
918 /* the machine needs to be mutable */
919 Machine::AutoMutableStateDependency adep (mParent);
920 CheckComRCReturnRC (adep.rc());
921
922 AutoWriteLock alock (this);
923
924 if (mData->mAttachmentType != NetworkAttachmentType_Null)
925 {
926 mData.backup();
927
928 detach();
929
930 /* leave the lock before informing callbacks */
931 alock.unlock();
932
933 mParent->onNetworkAdapterChange (this);
934 }
935
936 return S_OK;
937}
938
939// public methods only for internal purposes
940////////////////////////////////////////////////////////////////////////////////
941
942/**
943 * Loads settings from the given adapter node.
944 * May be called once right after this object creation.
945 *
946 * @param aAdapterNode <Adapter> node.
947 *
948 * @note Locks this object for writing.
949 */
950HRESULT NetworkAdapter::loadSettings (const settings::Key &aAdapterNode)
951{
952 using namespace settings;
953
954 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
955
956 AutoCaller autoCaller (this);
957 AssertComRCReturnRC (autoCaller.rc());
958
959 AutoWriteLock alock (this);
960
961 /* Note: we assume that the default values for attributes of optional
962 * nodes are assigned in the Data::Data() constructor and don't do it
963 * here. It implies that this method may only be called after constructing
964 * a new BIOSSettings object while all its data fields are in the default
965 * values. Exceptions are fields whose creation time defaults don't match
966 * values that should be applied when these fields are not explicitly set
967 * in the settings file (for backwards compatibility reasons). This takes
968 * place when a setting of a newly created object must default to A while
969 * the same setting of an object loaded from the old settings file must
970 * default to B. */
971
972 HRESULT rc = S_OK;
973
974 /* type (optional, defaults to Am79C970A) */
975 const char *adapterType = aAdapterNode.stringValue ("type");
976
977 if (strcmp (adapterType, "Am79C970A") == 0)
978 mData->mAdapterType = NetworkAdapterType_Am79C970A;
979 else if (strcmp (adapterType, "Am79C973") == 0)
980 mData->mAdapterType = NetworkAdapterType_Am79C973;
981 else if (strcmp (adapterType, "82540EM") == 0)
982 mData->mAdapterType = NetworkAdapterType_I82540EM;
983 else
984 ComAssertMsgFailedRet (("Invalid adapter type '%s'", adapterType),
985 E_FAIL);
986
987 /* enabled (required) */
988 mData->mEnabled = aAdapterNode.value <bool> ("enabled");
989 /* MAC address (can be null) */
990 rc = COMSETTER(MACAddress) (Bstr (aAdapterNode.stringValue ("MACAddress")));
991 CheckComRCReturnRC (rc);
992 /* cable (required) */
993 mData->mCableConnected = aAdapterNode.value <bool> ("cable");
994 /* line speed (defaults to 100 Mbps) */
995 mData->mLineSpeed = aAdapterNode.value <ULONG> ("speed");
996 /* tracing (defaults to false) */
997 mData->mTraceEnabled = aAdapterNode.value <bool> ("trace");
998 mData->mTraceFile = aAdapterNode.stringValue ("tracefile");
999
1000 /* One of NAT, HostInerface, Internal or nothing */
1001 Key attachmentNode;
1002
1003 if (!(attachmentNode = aAdapterNode.findKey ("NAT")).isNull())
1004 {
1005 /* NAT */
1006
1007 rc = AttachToNAT();
1008 CheckComRCReturnRC (rc);
1009 }
1010 else
1011 if (!(attachmentNode = aAdapterNode.findKey ("HostInterface")).isNull())
1012 {
1013 /* Host Interface Networking */
1014
1015 Bstr name = attachmentNode.stringValue ("name");
1016#ifdef RT_OS_WINDOWS
1017 /* name can be empty on Win32, but not null */
1018 ComAssertRet (!name.isNull(), E_FAIL);
1019#endif
1020 rc = COMSETTER(HostInterface) (name);
1021 CheckComRCReturnRC (rc);
1022
1023#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
1024 /* optopnal */
1025 mData->mTAPSetupApplication = attachmentNode.stringValue ("TAPSetup");
1026 mData->mTAPTerminateApplication = attachmentNode.stringValue ("TAPTerminate");
1027#endif /* VBOX_WITH_UNIXY_TAP_NETWORKING */
1028
1029 rc = AttachToHostInterface();
1030 CheckComRCReturnRC (rc);
1031 }
1032 else
1033 if (!(attachmentNode = aAdapterNode.findKey ("InternalNetwork")).isNull())
1034 {
1035 /* Internal Networking */
1036
1037 /* required */
1038 mData->mInternalNetwork = attachmentNode.stringValue ("name");
1039
1040 rc = AttachToInternalNetwork();
1041 CheckComRCReturnRC (rc);
1042 }
1043 else
1044 {
1045 /* Adapter has no children */
1046 rc = Detach();
1047 CheckComRCReturnRC (rc);
1048 }
1049
1050 return S_OK;
1051}
1052
1053/**
1054 * Saves settings to the given adapter node.
1055 *
1056 * Note that the given Adapter node is comletely empty on input.
1057 *
1058 * @param aAdapterNode <Adapter> node.
1059 *
1060 * @note Locks this object for reading.
1061 */
1062HRESULT NetworkAdapter::saveSettings (settings::Key &aAdapterNode)
1063{
1064 using namespace settings;
1065
1066 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
1067
1068 AutoCaller autoCaller (this);
1069 AssertComRCReturnRC (autoCaller.rc());
1070
1071 AutoReadLock alock (this);
1072
1073 aAdapterNode.setValue <bool> ("enabled", !!mData->mEnabled);
1074 aAdapterNode.setValue <Bstr> ("MACAddress", mData->mMACAddress);
1075 aAdapterNode.setValue <bool> ("cable", !!mData->mCableConnected);
1076
1077 aAdapterNode.setValue <ULONG> ("speed", mData->mLineSpeed);
1078
1079 if (mData->mTraceEnabled)
1080 aAdapterNode.setValue <bool> ("trace", true);
1081
1082 aAdapterNode.setValueOr <Bstr> ("tracefile", mData->mTraceFile, Bstr::Null);
1083
1084 const char *typeStr = NULL;
1085 switch (mData->mAdapterType)
1086 {
1087 case NetworkAdapterType_Am79C970A:
1088 typeStr = "Am79C970A";
1089 break;
1090 case NetworkAdapterType_Am79C973:
1091 typeStr = "Am79C973";
1092 break;
1093 case NetworkAdapterType_I82540EM:
1094 typeStr = "82540EM";
1095 break;
1096 default:
1097 ComAssertMsgFailedRet (("Invalid network adapter type: %d\n",
1098 mData->mAdapterType),
1099 E_FAIL);
1100 }
1101 aAdapterNode.setStringValue ("type", typeStr);
1102
1103 switch (mData->mAttachmentType)
1104 {
1105 case NetworkAttachmentType_Null:
1106 {
1107 /* do nothing -- empty content */
1108 break;
1109 }
1110 case NetworkAttachmentType_NAT:
1111 {
1112 Key attachmentNode = aAdapterNode.createKey ("NAT");
1113 break;
1114 }
1115 case NetworkAttachmentType_HostInterface:
1116 {
1117 Key attachmentNode = aAdapterNode.createKey ("HostInterface");
1118#ifdef RT_OS_WINDOWS
1119 Assert (!mData->mHostInterface.isNull());
1120#endif
1121#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
1122 if (!mData->mHostInterface.isEmpty())
1123#endif
1124 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1125#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
1126 if (!mData->mTAPSetupApplication.isEmpty())
1127 attachmentNode.setValue <Bstr> ("TAPSetup",
1128 mData->mTAPSetupApplication);
1129 if (!mData->mTAPTerminateApplication.isEmpty())
1130 attachmentNode.setValue <Bstr> ("TAPTerminate",
1131 mData->mTAPTerminateApplication);
1132#endif /* VBOX_WITH_UNIXY_TAP_NETWORKING */
1133 break;
1134 }
1135 case NetworkAttachmentType_Internal:
1136 {
1137 Key attachmentNode = aAdapterNode.createKey ("InternalNetwork");
1138 Assert (!mData->mInternalNetwork.isNull());
1139 attachmentNode.setValue <Bstr> ("name", mData->mInternalNetwork);
1140 break;
1141 }
1142 default:
1143 {
1144 ComAssertFailedRet (E_FAIL);
1145 }
1146 }
1147
1148 return S_OK;
1149}
1150
1151/**
1152 * @note Locks this object for writing.
1153 */
1154bool NetworkAdapter::rollback()
1155{
1156 /* sanity */
1157 AutoCaller autoCaller (this);
1158 AssertComRCReturn (autoCaller.rc(), false);
1159
1160 AutoWriteLock alock (this);
1161
1162 bool changed = false;
1163
1164 if (mData.isBackedUp())
1165 {
1166 /* we need to check all data to see whether anything will be changed
1167 * after rollback */
1168 changed = mData.hasActualChanges();
1169 mData.rollback();
1170 }
1171
1172 return changed;
1173}
1174
1175/**
1176 * @note Locks this object for writing, together with the peer object (also
1177 * for writing) if there is one.
1178 */
1179void NetworkAdapter::commit()
1180{
1181 /* sanity */
1182 AutoCaller autoCaller (this);
1183 AssertComRCReturnVoid (autoCaller.rc());
1184
1185 /* sanity too */
1186 AutoCaller peerCaller (mPeer);
1187 AssertComRCReturnVoid (peerCaller.rc());
1188
1189 /* lock both for writing since we modify both (mPeer is "master" so locked
1190 * first) */
1191 AutoMultiWriteLock2 alock (mPeer, this);
1192
1193 if (mData.isBackedUp())
1194 {
1195 mData.commit();
1196 if (mPeer)
1197 {
1198 /* attach new data to the peer and reshare it */
1199 mPeer->mData.attach (mData);
1200 }
1201 }
1202}
1203
1204/**
1205 * @note Locks this object for writing, together with the peer object
1206 * represented by @a aThat (locked for reading).
1207 */
1208void NetworkAdapter::copyFrom (NetworkAdapter *aThat)
1209{
1210 AssertReturnVoid (aThat != NULL);
1211
1212 /* sanity */
1213 AutoCaller autoCaller (this);
1214 AssertComRCReturnVoid (autoCaller.rc());
1215
1216 /* sanity too */
1217 AutoCaller thatCaller (aThat);
1218 AssertComRCReturnVoid (thatCaller.rc());
1219
1220 /* peer is not modified, lock it for reading (aThat is "master" so locked
1221 * first) */
1222 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
1223
1224 /* this will back up current data */
1225 mData.assignCopy (aThat->mData);
1226}
1227
1228// private methods
1229////////////////////////////////////////////////////////////////////////////////
1230
1231/**
1232 * Worker routine for detach handling. No locking, no notifications.
1233
1234 * @note Must be called from under the object's write lock.
1235 */
1236void NetworkAdapter::detach()
1237{
1238 AssertReturnVoid (isWriteLockOnCurrentThread());
1239
1240 switch (mData->mAttachmentType)
1241 {
1242 case NetworkAttachmentType_Null:
1243 {
1244 /* nothing to do here */
1245 break;
1246 }
1247 case NetworkAttachmentType_NAT:
1248 {
1249 break;
1250 }
1251 case NetworkAttachmentType_HostInterface:
1252 {
1253 /* reset handle and device name */
1254#ifdef RT_OS_WINDOWS
1255 mData->mHostInterface = "";
1256#endif
1257#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
1258 mData->mHostInterface.setNull();
1259 mData->mTAPFD = NIL_RTFILE;
1260#endif
1261 break;
1262 }
1263 case NetworkAttachmentType_Internal:
1264 {
1265 mData->mInternalNetwork.setNull();
1266 break;
1267 }
1268 }
1269
1270 mData->mAttachmentType = NetworkAttachmentType_Null;
1271}
1272
1273/**
1274 * Generates a new unique MAC address based on our vendor ID and
1275 * parts of a GUID.
1276 *
1277 * @note Must be called from under the object's write lock or within the init
1278 * span.
1279 */
1280void NetworkAdapter::generateMACAddress()
1281{
1282 /*
1283 * Our strategy is as follows: the first three bytes are our fixed
1284 * vendor ID (080027). The remaining 3 bytes will be taken from the
1285 * start of a GUID. This is a fairly safe algorithm.
1286 */
1287 char strMAC[13];
1288 Guid guid;
1289 guid.create();
1290 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1291 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1292 LogFlowThisFunc (("generated MAC: '%s'\n", strMAC));
1293 mData->mMACAddress = strMAC;
1294}
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