VirtualBox

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

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

Main & FEs: 3002: GUI/Main enhancements for 64 bits guests implemented.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.2 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 return E_NOTIMPL;
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 return E_NOTIMPL;
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 return E_NOTIMPL;
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 return E_NOTIMPL;
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 return E_NOTIMPL;
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 return E_NOTIMPL;
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 if (!aOsType)
1305 return;
1306
1307 bool e1000enabled = false;
1308#ifdef VBOX_WITH_E1000
1309 e1000enabled = true;
1310#endif // VBOX_WITH_E1000
1311
1312 NetworkAdapterType_T defaultType = aOsType->networkAdapterType();
1313
1314 /* Set default network adapter for this OS type */
1315 if (defaultType == NetworkAdapterType_I82540EM ||
1316 defaultType == NetworkAdapterType_I82543GC)
1317 {
1318 if (e1000enabled) mData->mAdapterType = defaultType;
1319 }
1320 else mData->mAdapterType = defaultType;
1321
1322 /* Enable and connect the first one adapter to the NAT */
1323 if (mData->mSlot == 0)
1324 {
1325 mData->mEnabled = true;
1326 mData->mAttachmentType = NetworkAttachmentType_NAT;
1327 mData->mCableConnected = true;
1328 }
1329}
1330
1331// private methods
1332////////////////////////////////////////////////////////////////////////////////
1333
1334/**
1335 * Worker routine for detach handling. No locking, no notifications.
1336
1337 * @note Must be called from under the object's write lock.
1338 */
1339void NetworkAdapter::detach()
1340{
1341 AssertReturnVoid (isWriteLockOnCurrentThread());
1342
1343 switch (mData->mAttachmentType)
1344 {
1345 case NetworkAttachmentType_Null:
1346 {
1347 /* nothing to do here */
1348 break;
1349 }
1350 case NetworkAttachmentType_NAT:
1351 {
1352 break;
1353 }
1354 case NetworkAttachmentType_HostInterface:
1355 {
1356 /* reset handle and device name */
1357#ifndef VBOX_WITH_UNIXY_TAP_NETWORKING
1358 mData->mHostInterface = "";
1359#endif
1360#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
1361 mData->mHostInterface.setNull();
1362 mData->mTAPFD = NIL_RTFILE;
1363#endif
1364 break;
1365 }
1366 case NetworkAttachmentType_Internal:
1367 {
1368 mData->mInternalNetwork.setNull();
1369 break;
1370 }
1371 }
1372
1373 mData->mAttachmentType = NetworkAttachmentType_Null;
1374}
1375
1376/**
1377 * Generates a new unique MAC address based on our vendor ID and
1378 * parts of a GUID.
1379 *
1380 * @note Must be called from under the object's write lock or within the init
1381 * span.
1382 */
1383void NetworkAdapter::generateMACAddress()
1384{
1385 /*
1386 * Our strategy is as follows: the first three bytes are our fixed
1387 * vendor ID (080027). The remaining 3 bytes will be taken from the
1388 * start of a GUID. This is a fairly safe algorithm.
1389 */
1390 char strMAC[13];
1391 Guid guid;
1392 guid.create();
1393 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1394 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1395 LogFlowThisFunc (("generated MAC: '%s'\n", strMAC));
1396 mData->mMACAddress = strMAC;
1397}
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