VirtualBox

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

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

Disabled access to 82543GC

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

© 2023 Oracle
ContactPrivacy policyTerms of Use