VirtualBox

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

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

Main: Host interface networking on Darwin.

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