VirtualBox

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

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

#3285: Improve error handling API to include unique error numbers

The mega commit that implements Main-wide usage of new CheckCom*
macros, mostly CheckComArgNotNull, CheckComArgStrNotEmptyOrNull,
CheckComArgOutSafeArrayPointerValid, CheckComArgExpr.
Note that some methods incorrectly returned E_INVALIDARG where they
should have returned E_POINTER and vice versa. If any higher level
function tests these, they will behave differently now...

Special thanks to: vi macros, making it easy to semi-automatically
find and replace several hundred instances of if (!aName) ...

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