VirtualBox

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

Last change on this file since 6290 was 6135, checked in by vboxsync, 17 years ago

fixes; phy now uses namespace instead of class

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