VirtualBox

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

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

Older 82543GC chip support, works in linux only.

  • 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 case NetworkAdapterType_I82543GC:
1140 typeStr = "82543GC";
1141 break;
1142 default:
1143 ComAssertMsgFailedRet (("Invalid network adapter type: %d\n",
1144 mData->mAdapterType),
1145 E_FAIL);
1146 }
1147 aAdapterNode.setStringValue ("type", typeStr);
1148
1149 switch (mData->mAttachmentType)
1150 {
1151 case NetworkAttachmentType_Null:
1152 {
1153 /* do nothing -- empty content */
1154 break;
1155 }
1156 case NetworkAttachmentType_NAT:
1157 {
1158 Key attachmentNode = aAdapterNode.createKey ("NAT");
1159 if (!mData->mNATNetwork.isEmpty())
1160 attachmentNode.setValue <Bstr> ("network",
1161 mData->mNATNetwork);
1162 break;
1163 }
1164 case NetworkAttachmentType_HostInterface:
1165 {
1166 Key attachmentNode = aAdapterNode.createKey ("HostInterface");
1167#ifdef RT_OS_WINDOWS
1168 Assert (!mData->mHostInterface.isNull());
1169#endif
1170#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
1171 if (!mData->mHostInterface.isEmpty())
1172#endif
1173 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1174#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
1175 if (!mData->mTAPSetupApplication.isEmpty())
1176 attachmentNode.setValue <Bstr> ("TAPSetup",
1177 mData->mTAPSetupApplication);
1178 if (!mData->mTAPTerminateApplication.isEmpty())
1179 attachmentNode.setValue <Bstr> ("TAPTerminate",
1180 mData->mTAPTerminateApplication);
1181#endif /* VBOX_WITH_UNIXY_TAP_NETWORKING */
1182 break;
1183 }
1184 case NetworkAttachmentType_Internal:
1185 {
1186 Key attachmentNode = aAdapterNode.createKey ("InternalNetwork");
1187 Assert (!mData->mInternalNetwork.isEmpty());
1188 attachmentNode.setValue <Bstr> ("name", mData->mInternalNetwork);
1189 break;
1190 }
1191 default:
1192 {
1193 ComAssertFailedRet (E_FAIL);
1194 }
1195 }
1196
1197 return S_OK;
1198}
1199
1200/**
1201 * @note Locks this object for writing.
1202 */
1203bool NetworkAdapter::rollback()
1204{
1205 /* sanity */
1206 AutoCaller autoCaller (this);
1207 AssertComRCReturn (autoCaller.rc(), false);
1208
1209 AutoWriteLock alock (this);
1210
1211 bool changed = false;
1212
1213 if (mData.isBackedUp())
1214 {
1215 /* we need to check all data to see whether anything will be changed
1216 * after rollback */
1217 changed = mData.hasActualChanges();
1218 mData.rollback();
1219 }
1220
1221 return changed;
1222}
1223
1224/**
1225 * @note Locks this object for writing, together with the peer object (also
1226 * for writing) if there is one.
1227 */
1228void NetworkAdapter::commit()
1229{
1230 /* sanity */
1231 AutoCaller autoCaller (this);
1232 AssertComRCReturnVoid (autoCaller.rc());
1233
1234 /* sanity too */
1235 AutoCaller peerCaller (mPeer);
1236 AssertComRCReturnVoid (peerCaller.rc());
1237
1238 /* lock both for writing since we modify both (mPeer is "master" so locked
1239 * first) */
1240 AutoMultiWriteLock2 alock (mPeer, this);
1241
1242 if (mData.isBackedUp())
1243 {
1244 mData.commit();
1245 if (mPeer)
1246 {
1247 /* attach new data to the peer and reshare it */
1248 mPeer->mData.attach (mData);
1249 }
1250 }
1251}
1252
1253/**
1254 * @note Locks this object for writing, together with the peer object
1255 * represented by @a aThat (locked for reading).
1256 */
1257void NetworkAdapter::copyFrom (NetworkAdapter *aThat)
1258{
1259 AssertReturnVoid (aThat != NULL);
1260
1261 /* sanity */
1262 AutoCaller autoCaller (this);
1263 AssertComRCReturnVoid (autoCaller.rc());
1264
1265 /* sanity too */
1266 AutoCaller thatCaller (aThat);
1267 AssertComRCReturnVoid (thatCaller.rc());
1268
1269 /* peer is not modified, lock it for reading (aThat is "master" so locked
1270 * first) */
1271 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
1272
1273 /* this will back up current data */
1274 mData.assignCopy (aThat->mData);
1275}
1276
1277// private methods
1278////////////////////////////////////////////////////////////////////////////////
1279
1280/**
1281 * Worker routine for detach handling. No locking, no notifications.
1282
1283 * @note Must be called from under the object's write lock.
1284 */
1285void NetworkAdapter::detach()
1286{
1287 AssertReturnVoid (isWriteLockOnCurrentThread());
1288
1289 switch (mData->mAttachmentType)
1290 {
1291 case NetworkAttachmentType_Null:
1292 {
1293 /* nothing to do here */
1294 break;
1295 }
1296 case NetworkAttachmentType_NAT:
1297 {
1298 break;
1299 }
1300 case NetworkAttachmentType_HostInterface:
1301 {
1302 /* reset handle and device name */
1303#ifdef RT_OS_WINDOWS
1304 mData->mHostInterface = "";
1305#endif
1306#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
1307 mData->mHostInterface.setNull();
1308 mData->mTAPFD = NIL_RTFILE;
1309#endif
1310 break;
1311 }
1312 case NetworkAttachmentType_Internal:
1313 {
1314 mData->mInternalNetwork.setNull();
1315 break;
1316 }
1317 }
1318
1319 mData->mAttachmentType = NetworkAttachmentType_Null;
1320}
1321
1322/**
1323 * Generates a new unique MAC address based on our vendor ID and
1324 * parts of a GUID.
1325 *
1326 * @note Must be called from under the object's write lock or within the init
1327 * span.
1328 */
1329void NetworkAdapter::generateMACAddress()
1330{
1331 /*
1332 * Our strategy is as follows: the first three bytes are our fixed
1333 * vendor ID (080027). The remaining 3 bytes will be taken from the
1334 * start of a GUID. This is a fairly safe algorithm.
1335 */
1336 char strMAC[13];
1337 Guid guid;
1338 guid.create();
1339 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1340 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1341 LogFlowThisFunc (("generated MAC: '%s'\n", strMAC));
1342 mData->mMACAddress = strMAC;
1343}
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