VirtualBox

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

Last change on this file since 22138 was 21961, checked in by vboxsync, 15 years ago

NetworkAttachment: trigger the network attachment change only when AttachTo* API are called

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.9 KB
Line 
1/* $Id: NetworkAdapterImpl.cpp 21961 2009-08-04 14:59:48Z vboxsync $ */
2/** @file
3 * Implementation of INetworkAdaptor in VBoxSVC.
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, FALSE);
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, FALSE);
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 || !*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, FALSE);
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(HostInterface)(BSTR *aHostInterface)
399{
400 CheckComArgOutPointerValid(aHostInterface);
401
402 AutoCaller autoCaller(this);
403 CheckComRCReturnRC(autoCaller.rc());
404
405 AutoReadLock alock(this);
406
407 mData->mHostInterface.cloneTo(aHostInterface);
408
409 return S_OK;
410}
411
412STDMETHODIMP NetworkAdapter::COMSETTER(HostInterface)(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->mHostInterface != aHostInterface)
430 {
431 mData.backup();
432 mData->mHostInterface = aHostInterface;
433
434 /* leave the lock before informing callbacks */
435 alock.unlock();
436
437 mParent->onNetworkAdapterChange (this, FALSE);
438 }
439
440 return S_OK;
441}
442
443STDMETHODIMP NetworkAdapter::COMGETTER(InternalNetwork) (BSTR *aInternalNetwork)
444{
445 CheckComArgOutPointerValid(aInternalNetwork);
446
447 AutoCaller autoCaller(this);
448 CheckComRCReturnRC(autoCaller.rc());
449
450 AutoReadLock alock(this);
451
452 mData->mInternalNetwork.cloneTo(aInternalNetwork);
453
454 return S_OK;
455}
456
457STDMETHODIMP NetworkAdapter::COMSETTER(InternalNetwork) (IN_BSTR aInternalNetwork)
458{
459 AutoCaller autoCaller(this);
460 CheckComRCReturnRC(autoCaller.rc());
461
462 /* the machine needs to be mutable */
463 Machine::AutoMutableStateDependency adep (mParent);
464 CheckComRCReturnRC(adep.rc());
465
466 AutoWriteLock alock(this);
467
468 if (mData->mInternalNetwork != aInternalNetwork)
469 {
470 /* if an empty/null string is to be set, internal networking must be
471 * turned off */
472 if ( (aInternalNetwork == NULL || *aInternalNetwork == '\0')
473 && mData->mAttachmentType == NetworkAttachmentType_Internal)
474 {
475 return setError (E_FAIL,
476 tr ("Empty or null internal network name is not valid"));
477 }
478
479 mData.backup();
480 mData->mInternalNetwork = aInternalNetwork;
481
482 /* leave the lock before informing callbacks */
483 alock.unlock();
484
485 mParent->onNetworkAdapterChange (this, FALSE);
486 }
487
488 return S_OK;
489}
490
491STDMETHODIMP NetworkAdapter::COMGETTER(NATNetwork) (BSTR *aNATNetwork)
492{
493 CheckComArgOutPointerValid(aNATNetwork);
494
495 AutoCaller autoCaller(this);
496 CheckComRCReturnRC(autoCaller.rc());
497
498 AutoReadLock alock(this);
499
500 mData->mNATNetwork.cloneTo(aNATNetwork);
501
502 return S_OK;
503}
504
505STDMETHODIMP NetworkAdapter::COMSETTER(NATNetwork) (IN_BSTR aNATNetwork)
506{
507 AutoCaller autoCaller(this);
508 CheckComRCReturnRC(autoCaller.rc());
509
510 /* the machine needs to be mutable */
511 Machine::AutoMutableStateDependency adep (mParent);
512 CheckComRCReturnRC(adep.rc());
513
514 AutoWriteLock alock(this);
515
516 if (mData->mNATNetwork != aNATNetwork)
517 {
518 mData.backup();
519 mData->mNATNetwork = aNATNetwork;
520
521 /* leave the lock before informing callbacks */
522 alock.unlock();
523
524 mParent->onNetworkAdapterChange (this, FALSE);
525 }
526
527 return S_OK;
528}
529
530STDMETHODIMP NetworkAdapter::COMGETTER(CableConnected) (BOOL *aConnected)
531{
532 CheckComArgOutPointerValid(aConnected);
533
534 AutoCaller autoCaller(this);
535 CheckComRCReturnRC(autoCaller.rc());
536
537 AutoReadLock alock(this);
538
539 *aConnected = mData->mCableConnected;
540
541 return S_OK;
542}
543
544STDMETHODIMP NetworkAdapter::COMSETTER(CableConnected) (BOOL aConnected)
545{
546 AutoCaller autoCaller(this);
547 CheckComRCReturnRC(autoCaller.rc());
548
549 /* the machine needs to be mutable */
550 Machine::AutoMutableStateDependency adep (mParent);
551 CheckComRCReturnRC(adep.rc());
552
553 AutoWriteLock alock(this);
554
555 if (aConnected != mData->mCableConnected)
556 {
557 mData.backup();
558 mData->mCableConnected = aConnected;
559
560 /* leave the lock before informing callbacks */
561 alock.unlock();
562
563 mParent->onNetworkAdapterChange (this, FALSE);
564 }
565
566 return S_OK;
567}
568
569STDMETHODIMP NetworkAdapter::COMGETTER(LineSpeed) (ULONG *aSpeed)
570{
571 CheckComArgOutPointerValid(aSpeed);
572
573 AutoCaller autoCaller(this);
574 CheckComRCReturnRC(autoCaller.rc());
575
576 AutoReadLock alock(this);
577
578 *aSpeed = mData->mLineSpeed;
579
580 return S_OK;
581}
582
583STDMETHODIMP NetworkAdapter::COMSETTER(LineSpeed) (ULONG aSpeed)
584{
585 AutoCaller autoCaller(this);
586 CheckComRCReturnRC(autoCaller.rc());
587
588 /* the machine needs to be mutable */
589 Machine::AutoMutableStateDependency adep (mParent);
590 CheckComRCReturnRC(adep.rc());
591
592 AutoWriteLock alock(this);
593
594 if (aSpeed != mData->mLineSpeed)
595 {
596 mData.backup();
597 mData->mLineSpeed = aSpeed;
598
599 /* leave the lock before informing callbacks */
600 alock.unlock();
601
602 mParent->onNetworkAdapterChange (this, FALSE);
603 }
604
605 return S_OK;
606}
607
608STDMETHODIMP NetworkAdapter::COMGETTER(TraceEnabled) (BOOL *aEnabled)
609{
610 CheckComArgOutPointerValid(aEnabled);
611
612 AutoCaller autoCaller(this);
613 CheckComRCReturnRC(autoCaller.rc());
614
615 AutoReadLock alock(this);
616
617 *aEnabled = mData->mTraceEnabled;
618 return S_OK;
619}
620
621STDMETHODIMP NetworkAdapter::COMSETTER(TraceEnabled) (BOOL aEnabled)
622{
623 AutoCaller autoCaller(this);
624 CheckComRCReturnRC(autoCaller.rc());
625
626 /* the machine needs to be mutable */
627 Machine::AutoMutableStateDependency adep (mParent);
628 CheckComRCReturnRC(adep.rc());
629
630 AutoWriteLock alock(this);
631
632 if (aEnabled != mData->mTraceEnabled)
633 {
634 mData.backup();
635 mData->mTraceEnabled = aEnabled;
636
637 /* leave the lock before informing callbacks */
638 alock.unlock();
639
640 mParent->onNetworkAdapterChange (this, FALSE);
641 }
642
643 return S_OK;
644}
645
646STDMETHODIMP NetworkAdapter::COMGETTER(TraceFile) (BSTR *aTraceFile)
647{
648 CheckComArgOutPointerValid(aTraceFile);
649
650 AutoCaller autoCaller(this);
651 CheckComRCReturnRC(autoCaller.rc());
652
653 AutoReadLock alock(this);
654
655 mData->mTraceFile.cloneTo(aTraceFile);
656
657 return S_OK;
658}
659
660STDMETHODIMP NetworkAdapter::COMSETTER(TraceFile) (IN_BSTR aTraceFile)
661{
662 AutoCaller autoCaller(this);
663 CheckComRCReturnRC(autoCaller.rc());
664
665 /* the machine needs to be mutable */
666 Machine::AutoMutableStateDependency adep (mParent);
667 CheckComRCReturnRC(adep.rc());
668
669 AutoWriteLock alock(this);
670
671 if (mData->mTraceFile != aTraceFile)
672 {
673 mData.backup();
674 mData->mTraceFile = aTraceFile;
675
676 /* leave the lock before informing callbacks */
677 alock.unlock();
678
679 mParent->onNetworkAdapterChange (this, FALSE);
680 }
681
682 return S_OK;
683}
684
685// INetworkAdapter methods
686////////////////////////////////////////////////////////////////////////////////
687
688STDMETHODIMP NetworkAdapter::AttachToNAT()
689{
690 AutoCaller autoCaller(this);
691 CheckComRCReturnRC(autoCaller.rc());
692
693 /* the machine needs to be mutable */
694 Machine::AutoMutableStateDependency adep (mParent);
695 CheckComRCReturnRC(adep.rc());
696
697 AutoWriteLock alock(this);
698
699 if (mData->mAttachmentType != NetworkAttachmentType_NAT)
700 {
701 mData.backup();
702
703 // Commented this for now as it resets the parameter mData->mNATNetwork
704 // which is essential while changing the Attachment dynamically.
705 //detach();
706
707 mData->mAttachmentType = NetworkAttachmentType_NAT;
708
709 /* leave the lock before informing callbacks */
710 alock.unlock();
711
712 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
713 if (FAILED (rc))
714 {
715 /* If changing the attachment failed then we can't assume
716 * that the previous attachment will attach correctly
717 * and thus return error along with dettaching all
718 * attachments.
719 */
720 Detach();
721 return rc;
722 }
723 }
724
725 return S_OK;
726}
727
728STDMETHODIMP NetworkAdapter::AttachToBridgedInterface()
729{
730 AutoCaller autoCaller(this);
731 CheckComRCReturnRC(autoCaller.rc());
732
733 /* the machine needs to be mutable */
734 Machine::AutoMutableStateDependency adep (mParent);
735 CheckComRCReturnRC(adep.rc());
736
737 AutoWriteLock alock(this);
738
739 /* don't do anything if we're already host interface attached */
740 if (mData->mAttachmentType != NetworkAttachmentType_Bridged)
741 {
742 mData.backup();
743
744 /* first detach the current attachment */
745 // Commented this for now as it reset the parameter mData->mHostInterface
746 // which is essential while changing the Attachment dynamically.
747 //detach();
748
749 mData->mAttachmentType = NetworkAttachmentType_Bridged;
750
751 /* leave the lock before informing callbacks */
752 alock.unlock();
753
754 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
755 if (FAILED (rc))
756 {
757 /* If changing the attachment failed then we can't assume
758 * that the previous attachment will attach correctly
759 * and thus return error along with dettaching all
760 * attachments.
761 */
762 Detach();
763 return rc;
764 }
765 }
766
767 return S_OK;
768}
769
770STDMETHODIMP NetworkAdapter::AttachToInternalNetwork()
771{
772 AutoCaller autoCaller(this);
773 CheckComRCReturnRC(autoCaller.rc());
774
775 /* the machine needs to be mutable */
776 Machine::AutoMutableStateDependency adep (mParent);
777 CheckComRCReturnRC(adep.rc());
778
779 AutoWriteLock alock(this);
780
781 /* don't do anything if we're already internal network attached */
782 if (mData->mAttachmentType != NetworkAttachmentType_Internal)
783 {
784 mData.backup();
785
786 /* first detach the current attachment */
787 // Commented this for now as it reset the parameter mData->mInternalNetwork
788 // which is essential while changing the Attachment dynamically.
789 //detach();
790
791 /* there must an internal network name */
792 if (mData->mInternalNetwork.isEmpty())
793 {
794 LogRel (("Internal network name not defined, "
795 "setting to default \"intnet\"\n"));
796 mData->mInternalNetwork = "intnet";
797 }
798
799 mData->mAttachmentType = NetworkAttachmentType_Internal;
800
801 /* leave the lock before informing callbacks */
802 alock.unlock();
803
804 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
805 if (FAILED (rc))
806 {
807 /* If changing the attachment failed then we can't assume
808 * that the previous attachment will attach correctly
809 * and thus return error along with dettaching all
810 * attachments.
811 */
812 Detach();
813 return rc;
814 }
815 }
816
817 return S_OK;
818}
819
820STDMETHODIMP NetworkAdapter::AttachToHostOnlyInterface()
821{
822 AutoCaller autoCaller(this);
823 CheckComRCReturnRC(autoCaller.rc());
824
825 /* the machine needs to be mutable */
826 Machine::AutoMutableStateDependency adep (mParent);
827 CheckComRCReturnRC(adep.rc());
828
829 AutoWriteLock alock(this);
830
831 /* don't do anything if we're already host interface attached */
832 if (mData->mAttachmentType != NetworkAttachmentType_HostOnly)
833 {
834 mData.backup();
835
836 /* first detach the current attachment */
837 // Commented this for now as it reset the parameter mData->mHostInterface
838 // which is essential while changing the Attachment dynamically.
839 //detach();
840
841 mData->mAttachmentType = NetworkAttachmentType_HostOnly;
842
843 /* leave the lock before informing callbacks */
844 alock.unlock();
845
846 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
847 if (FAILED (rc))
848 {
849 /* If changing the attachment failed then we can't assume
850 * that the previous attachment will attach correctly
851 * and thus return error along with dettaching all
852 * attachments.
853 */
854 Detach();
855 return rc;
856 }
857 }
858
859 return S_OK;
860}
861
862STDMETHODIMP NetworkAdapter::Detach()
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_Null)
874 {
875 mData.backup();
876
877 detach();
878
879 /* leave the lock before informing callbacks */
880 alock.unlock();
881
882 mParent->onNetworkAdapterChange (this, TRUE);
883 }
884
885 return S_OK;
886}
887
888// public methods only for internal purposes
889////////////////////////////////////////////////////////////////////////////////
890
891/**
892 * Loads settings from the given adapter node.
893 * May be called once right after this object creation.
894 *
895 * @param aAdapterNode <Adapter> node.
896 *
897 * @note Locks this object for writing.
898 */
899HRESULT NetworkAdapter::loadSettings (const settings::Key &aAdapterNode)
900{
901 using namespace settings;
902
903 AssertReturn(!aAdapterNode.isNull(), E_FAIL);
904
905 AutoCaller autoCaller(this);
906 AssertComRCReturnRC(autoCaller.rc());
907
908 AutoWriteLock alock(this);
909
910 /* Note: we assume that the default values for attributes of optional
911 * nodes are assigned in the Data::Data() constructor and don't do it
912 * here. It implies that this method may only be called after constructing
913 * a new BIOSSettings object while all its data fields are in the default
914 * values. Exceptions are fields whose creation time defaults don't match
915 * values that should be applied when these fields are not explicitly set
916 * in the settings file (for backwards compatibility reasons). This takes
917 * place when a setting of a newly created object must default to A while
918 * the same setting of an object loaded from the old settings file must
919 * default to B. */
920
921 HRESULT rc = S_OK;
922
923 /* type (optional, defaults to Am79C970A) */
924 const char *adapterType = aAdapterNode.stringValue ("type");
925
926 if (strcmp (adapterType, "Am79C970A") == 0)
927 mData->mAdapterType = NetworkAdapterType_Am79C970A;
928 else if (strcmp (adapterType, "Am79C973") == 0)
929 mData->mAdapterType = NetworkAdapterType_Am79C973;
930 else if (strcmp (adapterType, "82540EM") == 0)
931 mData->mAdapterType = NetworkAdapterType_I82540EM;
932 else if (strcmp (adapterType, "82543GC") == 0)
933 mData->mAdapterType = NetworkAdapterType_I82543GC;
934 else if (strcmp (adapterType, "82545EM") == 0)
935 mData->mAdapterType = NetworkAdapterType_I82545EM;
936 else
937 ComAssertMsgFailedRet (("Invalid adapter type '%s'", adapterType),
938 E_FAIL);
939
940 /* enabled (required) */
941 mData->mEnabled = aAdapterNode.value <bool> ("enabled");
942 /* MAC address (can be null) */
943 rc = COMSETTER(MACAddress) (Bstr (aAdapterNode.stringValue ("MACAddress")));
944 CheckComRCReturnRC(rc);
945 /* cable (required) */
946 mData->mCableConnected = aAdapterNode.value <bool> ("cable");
947 /* line speed (defaults to 100 Mbps) */
948 mData->mLineSpeed = aAdapterNode.value <ULONG> ("speed");
949 /* tracing (defaults to false) */
950 mData->mTraceEnabled = aAdapterNode.value <bool> ("trace");
951 mData->mTraceFile = aAdapterNode.stringValue ("tracefile");
952
953 /* One of NAT, HostInerface, Internal or nothing */
954 Key attachmentNode;
955
956 if (!(attachmentNode = aAdapterNode.findKey ("NAT")).isNull())
957 {
958 /* NAT */
959
960 /* optional */
961 mData->mNATNetwork = attachmentNode.stringValue ("network");
962
963 rc = AttachToNAT();
964 CheckComRCReturnRC(rc);
965 }
966 else
967 if (!(attachmentNode = aAdapterNode.findKey ("HostInterface")).isNull() /* backwards compatibility */
968 || !(attachmentNode = aAdapterNode.findKey ("BridgedInterface")).isNull())
969 {
970 /* Host Interface Networking */
971
972 Bstr name = attachmentNode.stringValue ("name");
973 /* name can be empty, but not null */
974 ComAssertRet (!name.isNull(), E_FAIL);
975
976 rc = COMSETTER(HostInterface) (name);
977 CheckComRCReturnRC(rc);
978
979 rc = AttachToBridgedInterface();
980 CheckComRCReturnRC(rc);
981 }
982 else
983 if (!(attachmentNode = aAdapterNode.findKey ("InternalNetwork")).isNull())
984 {
985 /* Internal Networking */
986
987 /* required */
988 mData->mInternalNetwork = attachmentNode.stringValue ("name");
989 Assert (!mData->mInternalNetwork.isNull());
990
991 rc = AttachToInternalNetwork();
992 CheckComRCReturnRC(rc);
993 }
994 else
995 if (!(attachmentNode = aAdapterNode.findKey ("HostOnlyInterface")).isNull())
996 {
997#if defined(VBOX_WITH_NETFLT)
998 Bstr name = attachmentNode.stringValue ("name");
999 /* name can be empty, but not null */
1000 ComAssertRet (!name.isNull(), E_FAIL);
1001
1002 rc = COMSETTER(HostInterface) (name);
1003 CheckComRCReturnRC(rc);
1004#endif
1005
1006 /* Host Interface Networking */
1007 rc = AttachToHostOnlyInterface();
1008 CheckComRCReturnRC(rc);
1009 }
1010 else
1011 {
1012 /* Adapter has no children */
1013 rc = Detach();
1014 CheckComRCReturnRC(rc);
1015 }
1016
1017 return S_OK;
1018}
1019
1020/**
1021 * Saves settings to the given adapter node.
1022 *
1023 * Note that the given Adapter node is comletely empty on input.
1024 *
1025 * @param aAdapterNode <Adapter> node.
1026 *
1027 * @note Locks this object for reading.
1028 */
1029HRESULT NetworkAdapter::saveSettings (settings::Key &aAdapterNode)
1030{
1031 using namespace settings;
1032
1033 AssertReturn(!aAdapterNode.isNull(), E_FAIL);
1034
1035 AutoCaller autoCaller(this);
1036 AssertComRCReturnRC(autoCaller.rc());
1037
1038 AutoReadLock alock(this);
1039
1040 aAdapterNode.setValue <bool> ("enabled", !!mData->mEnabled);
1041 aAdapterNode.setValue <Bstr> ("MACAddress", mData->mMACAddress);
1042 aAdapterNode.setValue <bool> ("cable", !!mData->mCableConnected);
1043
1044 aAdapterNode.setValue <ULONG> ("speed", mData->mLineSpeed);
1045
1046 if (mData->mTraceEnabled)
1047 aAdapterNode.setValue <bool> ("trace", true);
1048
1049 aAdapterNode.setValueOr <Bstr> ("tracefile", mData->mTraceFile, Bstr::Null);
1050
1051 const char *typeStr = NULL;
1052 switch (mData->mAdapterType)
1053 {
1054 case NetworkAdapterType_Am79C970A:
1055 typeStr = "Am79C970A";
1056 break;
1057 case NetworkAdapterType_Am79C973:
1058 typeStr = "Am79C973";
1059 break;
1060 case NetworkAdapterType_I82540EM:
1061 typeStr = "82540EM";
1062 break;
1063 case NetworkAdapterType_I82543GC:
1064 typeStr = "82543GC";
1065 break;
1066 case NetworkAdapterType_I82545EM:
1067 typeStr = "82545EM";
1068 break;
1069 default:
1070 ComAssertMsgFailedRet (("Invalid network adapter type: %d",
1071 mData->mAdapterType),
1072 E_FAIL);
1073 }
1074 aAdapterNode.setStringValue ("type", typeStr);
1075
1076 switch (mData->mAttachmentType)
1077 {
1078 case NetworkAttachmentType_Null:
1079 {
1080 /* do nothing -- empty content */
1081 break;
1082 }
1083 case NetworkAttachmentType_NAT:
1084 {
1085 Key attachmentNode = aAdapterNode.createKey ("NAT");
1086 if (!mData->mNATNetwork.isEmpty())
1087 attachmentNode.setValue <Bstr> ("network",
1088 mData->mNATNetwork);
1089 break;
1090 }
1091 case NetworkAttachmentType_Bridged:
1092 {
1093 Key attachmentNode = aAdapterNode.createKey ("BridgedInterface");
1094 Assert (!mData->mHostInterface.isNull());
1095 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1096 break;
1097 }
1098 case NetworkAttachmentType_Internal:
1099 {
1100 Key attachmentNode = aAdapterNode.createKey ("InternalNetwork");
1101 Assert (!mData->mInternalNetwork.isEmpty());
1102 attachmentNode.setValue <Bstr> ("name", mData->mInternalNetwork);
1103 break;
1104 }
1105 case NetworkAttachmentType_HostOnly:
1106 {
1107 Key attachmentNode = aAdapterNode.createKey ("HostOnlyInterface");
1108#if defined(VBOX_WITH_NETFLT)
1109 Assert (!mData->mHostInterface.isNull());
1110 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1111#endif
1112 break;
1113 }
1114 default:
1115 {
1116 ComAssertFailedRet (E_FAIL);
1117 }
1118 }
1119
1120 return S_OK;
1121}
1122
1123/**
1124 * @note Locks this object for writing.
1125 */
1126bool NetworkAdapter::rollback()
1127{
1128 /* sanity */
1129 AutoCaller autoCaller(this);
1130 AssertComRCReturn (autoCaller.rc(), false);
1131
1132 AutoWriteLock alock(this);
1133
1134 bool changed = false;
1135
1136 if (mData.isBackedUp())
1137 {
1138 /* we need to check all data to see whether anything will be changed
1139 * after rollback */
1140 changed = mData.hasActualChanges();
1141 mData.rollback();
1142 }
1143
1144 return changed;
1145}
1146
1147/**
1148 * @note Locks this object for writing, together with the peer object (also
1149 * for writing) if there is one.
1150 */
1151void NetworkAdapter::commit()
1152{
1153 /* sanity */
1154 AutoCaller autoCaller(this);
1155 AssertComRCReturnVoid (autoCaller.rc());
1156
1157 /* sanity too */
1158 AutoCaller peerCaller (mPeer);
1159 AssertComRCReturnVoid (peerCaller.rc());
1160
1161 /* lock both for writing since we modify both (mPeer is "master" so locked
1162 * first) */
1163 AutoMultiWriteLock2 alock (mPeer, this);
1164
1165 if (mData.isBackedUp())
1166 {
1167 mData.commit();
1168 if (mPeer)
1169 {
1170 /* attach new data to the peer and reshare it */
1171 mPeer->mData.attach (mData);
1172 }
1173 }
1174}
1175
1176/**
1177 * @note Locks this object for writing, together with the peer object
1178 * represented by @a aThat (locked for reading).
1179 */
1180void NetworkAdapter::copyFrom (NetworkAdapter *aThat)
1181{
1182 AssertReturnVoid (aThat != NULL);
1183
1184 /* sanity */
1185 AutoCaller autoCaller(this);
1186 AssertComRCReturnVoid (autoCaller.rc());
1187
1188 /* sanity too */
1189 AutoCaller thatCaller (aThat);
1190 AssertComRCReturnVoid (thatCaller.rc());
1191
1192 /* peer is not modified, lock it for reading (aThat is "master" so locked
1193 * first) */
1194 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
1195
1196 /* this will back up current data */
1197 mData.assignCopy (aThat->mData);
1198}
1199
1200void NetworkAdapter::applyDefaults (GuestOSType *aOsType)
1201{
1202 AssertReturnVoid (aOsType != NULL);
1203
1204 /* sanity */
1205 AutoCaller autoCaller(this);
1206 AssertComRCReturnVoid (autoCaller.rc());
1207
1208 AutoWriteLock alock(this);
1209
1210 bool e1000enabled = false;
1211#ifdef VBOX_WITH_E1000
1212 e1000enabled = true;
1213#endif // VBOX_WITH_E1000
1214
1215 NetworkAdapterType_T defaultType = aOsType->networkAdapterType();
1216
1217 /* Set default network adapter for this OS type */
1218 if (defaultType == NetworkAdapterType_I82540EM ||
1219 defaultType == NetworkAdapterType_I82543GC ||
1220 defaultType == NetworkAdapterType_I82545EM)
1221 {
1222 if (e1000enabled) mData->mAdapterType = defaultType;
1223 }
1224 else mData->mAdapterType = defaultType;
1225
1226 /* Enable and connect the first one adapter to the NAT */
1227 if (mData->mSlot == 0)
1228 {
1229 mData->mEnabled = true;
1230 mData->mAttachmentType = NetworkAttachmentType_NAT;
1231 mData->mCableConnected = true;
1232 }
1233}
1234
1235// private methods
1236////////////////////////////////////////////////////////////////////////////////
1237
1238/**
1239 * Worker routine for detach handling. No locking, no notifications.
1240
1241 * @note Must be called from under the object's write lock.
1242 */
1243void NetworkAdapter::detach()
1244{
1245 AssertReturnVoid (isWriteLockOnCurrentThread());
1246
1247 switch (mData->mAttachmentType)
1248 {
1249 case NetworkAttachmentType_Null:
1250 {
1251 /* nothing to do here */
1252 break;
1253 }
1254 case NetworkAttachmentType_NAT:
1255 {
1256 break;
1257 }
1258 case NetworkAttachmentType_Bridged:
1259 {
1260 /* reset handle and device name */
1261 mData->mHostInterface = "";
1262 break;
1263 }
1264 case NetworkAttachmentType_Internal:
1265 {
1266 mData->mInternalNetwork.setNull();
1267 break;
1268 }
1269 case NetworkAttachmentType_HostOnly:
1270 {
1271#if defined(VBOX_WITH_NETFLT)
1272 /* reset handle and device name */
1273 mData->mHostInterface = "";
1274#endif
1275 break;
1276 }
1277 }
1278
1279 mData->mAttachmentType = NetworkAttachmentType_Null;
1280}
1281
1282/**
1283 * Generates a new unique MAC address based on our vendor ID and
1284 * parts of a GUID.
1285 *
1286 * @note Must be called from under the object's write lock or within the init
1287 * span.
1288 */
1289void NetworkAdapter::generateMACAddress()
1290{
1291 /*
1292 * Our strategy is as follows: the first three bytes are our fixed
1293 * vendor ID (080027). The remaining 3 bytes will be taken from the
1294 * start of a GUID. This is a fairly safe algorithm.
1295 */
1296 char strMAC[13];
1297 Guid guid;
1298 guid.create();
1299 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1300 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1301 LogFlowThisFunc(("generated MAC: '%s'\n", strMAC));
1302 mData->mMACAddress = strMAC;
1303}
1304/* 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