VirtualBox

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

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

Added vim modelines to aid following coding guidelines, like no tabs,
similar to what is already in the xidl file.

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