VirtualBox

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

Last change on this file since 22873 was 22866, checked in by vboxsync, 15 years ago

#3987: Virtio PCI + Net skeleton.

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