VirtualBox

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

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

Main: INetworkAdapter separate properties for hostonly & bridged interface names

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