VirtualBox

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

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

Network: check for change in network attachment type and allow only legal ones.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.6 KB
Line 
1/* $Id: NetworkAdapterImpl.cpp 21817 2009-07-27 14:52:56Z 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);
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 || !*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(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);
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);
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);
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);
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);
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);
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);
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 mParent->onNetworkAdapterChange (this);
713 }
714
715 return S_OK;
716}
717
718STDMETHODIMP NetworkAdapter::AttachToBridgedInterface()
719{
720 AutoCaller autoCaller (this);
721 CheckComRCReturnRC (autoCaller.rc());
722
723 /* the machine needs to be mutable */
724 Machine::AutoMutableStateDependency adep (mParent);
725 CheckComRCReturnRC (adep.rc());
726
727 AutoWriteLock alock (this);
728
729 /* don't do anything if we're already host interface attached */
730 if (mData->mAttachmentType != NetworkAttachmentType_Bridged)
731 {
732 mData.backup();
733
734 /* first detach the current attachment */
735 // Commented this for now as it reset the parameter mData->mHostInterface
736 // which is essential while changing the Attachment dynamically.
737 //detach();
738
739 mData->mAttachmentType = NetworkAttachmentType_Bridged;
740
741 /* leave the lock before informing callbacks */
742 alock.unlock();
743
744 mParent->onNetworkAdapterChange (this);
745 }
746
747 return S_OK;
748}
749
750STDMETHODIMP NetworkAdapter::AttachToInternalNetwork()
751{
752 AutoCaller autoCaller (this);
753 CheckComRCReturnRC (autoCaller.rc());
754
755 /* the machine needs to be mutable */
756 Machine::AutoMutableStateDependency adep (mParent);
757 CheckComRCReturnRC (adep.rc());
758
759 AutoWriteLock alock (this);
760
761 /* don't do anything if we're already internal network attached */
762 if (mData->mAttachmentType != NetworkAttachmentType_Internal)
763 {
764 mData.backup();
765
766 /* first detach the current attachment */
767 // Commented this for now as it reset the parameter mData->mInternalNetwork
768 // which is essential while changing the Attachment dynamically.
769 //detach();
770
771 /* there must an internal network name */
772 if (mData->mInternalNetwork.isEmpty())
773 {
774 LogRel (("Internal network name not defined, "
775 "setting to default \"intnet\"\n"));
776 mData->mInternalNetwork = "intnet";
777 }
778
779 mData->mAttachmentType = NetworkAttachmentType_Internal;
780
781 /* leave the lock before informing callbacks */
782 alock.unlock();
783
784 mParent->onNetworkAdapterChange (this);
785 }
786
787 return S_OK;
788}
789
790STDMETHODIMP NetworkAdapter::AttachToHostOnlyInterface()
791{
792 AutoCaller autoCaller (this);
793 CheckComRCReturnRC (autoCaller.rc());
794
795 /* the machine needs to be mutable */
796 Machine::AutoMutableStateDependency adep (mParent);
797 CheckComRCReturnRC (adep.rc());
798
799 AutoWriteLock alock (this);
800
801 /* don't do anything if we're already host interface attached */
802 if (mData->mAttachmentType != NetworkAttachmentType_HostOnly)
803 {
804 mData.backup();
805
806 /* first detach the current attachment */
807 // Commented this for now as it reset the parameter mData->mHostInterface
808 // which is essential while changing the Attachment dynamically.
809 //detach();
810
811 mData->mAttachmentType = NetworkAttachmentType_HostOnly;
812
813 /* leave the lock before informing callbacks */
814 alock.unlock();
815
816 mParent->onNetworkAdapterChange (this);
817 }
818
819 return S_OK;
820}
821
822STDMETHODIMP NetworkAdapter::Detach()
823{
824 AutoCaller autoCaller (this);
825 CheckComRCReturnRC (autoCaller.rc());
826
827 /* the machine needs to be mutable */
828 Machine::AutoMutableStateDependency adep (mParent);
829 CheckComRCReturnRC (adep.rc());
830
831 AutoWriteLock alock (this);
832
833 if (mData->mAttachmentType != NetworkAttachmentType_Null)
834 {
835 mData.backup();
836
837 detach();
838
839 /* leave the lock before informing callbacks */
840 alock.unlock();
841
842 mParent->onNetworkAdapterChange (this);
843 }
844
845 return S_OK;
846}
847
848// public methods only for internal purposes
849////////////////////////////////////////////////////////////////////////////////
850
851/**
852 * Loads settings from the given adapter node.
853 * May be called once right after this object creation.
854 *
855 * @param aAdapterNode <Adapter> node.
856 *
857 * @note Locks this object for writing.
858 */
859HRESULT NetworkAdapter::loadSettings (const settings::Key &aAdapterNode)
860{
861 using namespace settings;
862
863 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
864
865 AutoCaller autoCaller (this);
866 AssertComRCReturnRC (autoCaller.rc());
867
868 AutoWriteLock alock (this);
869
870 /* Note: we assume that the default values for attributes of optional
871 * nodes are assigned in the Data::Data() constructor and don't do it
872 * here. It implies that this method may only be called after constructing
873 * a new BIOSSettings object while all its data fields are in the default
874 * values. Exceptions are fields whose creation time defaults don't match
875 * values that should be applied when these fields are not explicitly set
876 * in the settings file (for backwards compatibility reasons). This takes
877 * place when a setting of a newly created object must default to A while
878 * the same setting of an object loaded from the old settings file must
879 * default to B. */
880
881 HRESULT rc = S_OK;
882
883 /* type (optional, defaults to Am79C970A) */
884 const char *adapterType = aAdapterNode.stringValue ("type");
885
886 if (strcmp (adapterType, "Am79C970A") == 0)
887 mData->mAdapterType = NetworkAdapterType_Am79C970A;
888 else if (strcmp (adapterType, "Am79C973") == 0)
889 mData->mAdapterType = NetworkAdapterType_Am79C973;
890 else if (strcmp (adapterType, "82540EM") == 0)
891 mData->mAdapterType = NetworkAdapterType_I82540EM;
892 else if (strcmp (adapterType, "82543GC") == 0)
893 mData->mAdapterType = NetworkAdapterType_I82543GC;
894 else if (strcmp (adapterType, "82545EM") == 0)
895 mData->mAdapterType = NetworkAdapterType_I82545EM;
896 else
897 ComAssertMsgFailedRet (("Invalid adapter type '%s'", adapterType),
898 E_FAIL);
899
900 /* enabled (required) */
901 mData->mEnabled = aAdapterNode.value <bool> ("enabled");
902 /* MAC address (can be null) */
903 rc = COMSETTER(MACAddress) (Bstr (aAdapterNode.stringValue ("MACAddress")));
904 CheckComRCReturnRC (rc);
905 /* cable (required) */
906 mData->mCableConnected = aAdapterNode.value <bool> ("cable");
907 /* line speed (defaults to 100 Mbps) */
908 mData->mLineSpeed = aAdapterNode.value <ULONG> ("speed");
909 /* tracing (defaults to false) */
910 mData->mTraceEnabled = aAdapterNode.value <bool> ("trace");
911 mData->mTraceFile = aAdapterNode.stringValue ("tracefile");
912
913 /* One of NAT, HostInerface, Internal or nothing */
914 Key attachmentNode;
915
916 if (!(attachmentNode = aAdapterNode.findKey ("NAT")).isNull())
917 {
918 /* NAT */
919
920 /* optional */
921 mData->mNATNetwork = attachmentNode.stringValue ("network");
922
923 rc = AttachToNAT();
924 CheckComRCReturnRC (rc);
925 }
926 else
927 if (!(attachmentNode = aAdapterNode.findKey ("HostInterface")).isNull() /* backwards compatibility */
928 || !(attachmentNode = aAdapterNode.findKey ("BridgedInterface")).isNull())
929 {
930 /* Host Interface Networking */
931
932 Bstr name = attachmentNode.stringValue ("name");
933 /* name can be empty, but not null */
934 ComAssertRet (!name.isNull(), E_FAIL);
935
936 rc = COMSETTER(HostInterface) (name);
937 CheckComRCReturnRC (rc);
938
939 rc = AttachToBridgedInterface();
940 CheckComRCReturnRC (rc);
941 }
942 else
943 if (!(attachmentNode = aAdapterNode.findKey ("InternalNetwork")).isNull())
944 {
945 /* Internal Networking */
946
947 /* required */
948 mData->mInternalNetwork = attachmentNode.stringValue ("name");
949 Assert (!mData->mInternalNetwork.isNull());
950
951 rc = AttachToInternalNetwork();
952 CheckComRCReturnRC (rc);
953 }
954 else
955 if (!(attachmentNode = aAdapterNode.findKey ("HostOnlyInterface")).isNull())
956 {
957#if defined(VBOX_WITH_NETFLT)
958 Bstr name = attachmentNode.stringValue ("name");
959 /* name can be empty, but not null */
960 ComAssertRet (!name.isNull(), E_FAIL);
961
962 rc = COMSETTER(HostInterface) (name);
963 CheckComRCReturnRC (rc);
964#endif
965
966 /* Host Interface Networking */
967 rc = AttachToHostOnlyInterface();
968 CheckComRCReturnRC (rc);
969 }
970 else
971 {
972 /* Adapter has no children */
973 rc = Detach();
974 CheckComRCReturnRC (rc);
975 }
976
977 return S_OK;
978}
979
980/**
981 * Saves settings to the given adapter node.
982 *
983 * Note that the given Adapter node is comletely empty on input.
984 *
985 * @param aAdapterNode <Adapter> node.
986 *
987 * @note Locks this object for reading.
988 */
989HRESULT NetworkAdapter::saveSettings (settings::Key &aAdapterNode)
990{
991 using namespace settings;
992
993 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
994
995 AutoCaller autoCaller (this);
996 AssertComRCReturnRC (autoCaller.rc());
997
998 AutoReadLock alock (this);
999
1000 aAdapterNode.setValue <bool> ("enabled", !!mData->mEnabled);
1001 aAdapterNode.setValue <Bstr> ("MACAddress", mData->mMACAddress);
1002 aAdapterNode.setValue <bool> ("cable", !!mData->mCableConnected);
1003
1004 aAdapterNode.setValue <ULONG> ("speed", mData->mLineSpeed);
1005
1006 if (mData->mTraceEnabled)
1007 aAdapterNode.setValue <bool> ("trace", true);
1008
1009 aAdapterNode.setValueOr <Bstr> ("tracefile", mData->mTraceFile, Bstr::Null);
1010
1011 const char *typeStr = NULL;
1012 switch (mData->mAdapterType)
1013 {
1014 case NetworkAdapterType_Am79C970A:
1015 typeStr = "Am79C970A";
1016 break;
1017 case NetworkAdapterType_Am79C973:
1018 typeStr = "Am79C973";
1019 break;
1020 case NetworkAdapterType_I82540EM:
1021 typeStr = "82540EM";
1022 break;
1023 case NetworkAdapterType_I82543GC:
1024 typeStr = "82543GC";
1025 break;
1026 case NetworkAdapterType_I82545EM:
1027 typeStr = "82545EM";
1028 break;
1029 default:
1030 ComAssertMsgFailedRet (("Invalid network adapter type: %d",
1031 mData->mAdapterType),
1032 E_FAIL);
1033 }
1034 aAdapterNode.setStringValue ("type", typeStr);
1035
1036 switch (mData->mAttachmentType)
1037 {
1038 case NetworkAttachmentType_Null:
1039 {
1040 /* do nothing -- empty content */
1041 break;
1042 }
1043 case NetworkAttachmentType_NAT:
1044 {
1045 Key attachmentNode = aAdapterNode.createKey ("NAT");
1046 if (!mData->mNATNetwork.isEmpty())
1047 attachmentNode.setValue <Bstr> ("network",
1048 mData->mNATNetwork);
1049 break;
1050 }
1051 case NetworkAttachmentType_Bridged:
1052 {
1053 Key attachmentNode = aAdapterNode.createKey ("BridgedInterface");
1054 Assert (!mData->mHostInterface.isNull());
1055 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1056 break;
1057 }
1058 case NetworkAttachmentType_Internal:
1059 {
1060 Key attachmentNode = aAdapterNode.createKey ("InternalNetwork");
1061 Assert (!mData->mInternalNetwork.isEmpty());
1062 attachmentNode.setValue <Bstr> ("name", mData->mInternalNetwork);
1063 break;
1064 }
1065 case NetworkAttachmentType_HostOnly:
1066 {
1067 Key attachmentNode = aAdapterNode.createKey ("HostOnlyInterface");
1068#if defined(VBOX_WITH_NETFLT)
1069 Assert (!mData->mHostInterface.isNull());
1070 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1071#endif
1072 break;
1073 }
1074 default:
1075 {
1076 ComAssertFailedRet (E_FAIL);
1077 }
1078 }
1079
1080 return S_OK;
1081}
1082
1083/**
1084 * @note Locks this object for writing.
1085 */
1086bool NetworkAdapter::rollback()
1087{
1088 /* sanity */
1089 AutoCaller autoCaller (this);
1090 AssertComRCReturn (autoCaller.rc(), false);
1091
1092 AutoWriteLock alock (this);
1093
1094 bool changed = false;
1095
1096 if (mData.isBackedUp())
1097 {
1098 /* we need to check all data to see whether anything will be changed
1099 * after rollback */
1100 changed = mData.hasActualChanges();
1101 mData.rollback();
1102 }
1103
1104 return changed;
1105}
1106
1107/**
1108 * @note Locks this object for writing, together with the peer object (also
1109 * for writing) if there is one.
1110 */
1111void NetworkAdapter::commit()
1112{
1113 /* sanity */
1114 AutoCaller autoCaller (this);
1115 AssertComRCReturnVoid (autoCaller.rc());
1116
1117 /* sanity too */
1118 AutoCaller peerCaller (mPeer);
1119 AssertComRCReturnVoid (peerCaller.rc());
1120
1121 /* lock both for writing since we modify both (mPeer is "master" so locked
1122 * first) */
1123 AutoMultiWriteLock2 alock (mPeer, this);
1124
1125 if (mData.isBackedUp())
1126 {
1127 mData.commit();
1128 if (mPeer)
1129 {
1130 /* attach new data to the peer and reshare it */
1131 mPeer->mData.attach (mData);
1132 }
1133 }
1134}
1135
1136/**
1137 * @note Locks this object for writing, together with the peer object
1138 * represented by @a aThat (locked for reading).
1139 */
1140void NetworkAdapter::copyFrom (NetworkAdapter *aThat)
1141{
1142 AssertReturnVoid (aThat != NULL);
1143
1144 /* sanity */
1145 AutoCaller autoCaller (this);
1146 AssertComRCReturnVoid (autoCaller.rc());
1147
1148 /* sanity too */
1149 AutoCaller thatCaller (aThat);
1150 AssertComRCReturnVoid (thatCaller.rc());
1151
1152 /* peer is not modified, lock it for reading (aThat is "master" so locked
1153 * first) */
1154 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
1155
1156 /* this will back up current data */
1157 mData.assignCopy (aThat->mData);
1158}
1159
1160void NetworkAdapter::applyDefaults (GuestOSType *aOsType)
1161{
1162 AssertReturnVoid (aOsType != NULL);
1163
1164 /* sanity */
1165 AutoCaller autoCaller (this);
1166 AssertComRCReturnVoid (autoCaller.rc());
1167
1168 AutoWriteLock alock (this);
1169
1170 bool e1000enabled = false;
1171#ifdef VBOX_WITH_E1000
1172 e1000enabled = true;
1173#endif // VBOX_WITH_E1000
1174
1175 NetworkAdapterType_T defaultType = aOsType->networkAdapterType();
1176
1177 /* Set default network adapter for this OS type */
1178 if (defaultType == NetworkAdapterType_I82540EM ||
1179 defaultType == NetworkAdapterType_I82543GC ||
1180 defaultType == NetworkAdapterType_I82545EM)
1181 {
1182 if (e1000enabled) mData->mAdapterType = defaultType;
1183 }
1184 else mData->mAdapterType = defaultType;
1185
1186 /* Enable and connect the first one adapter to the NAT */
1187 if (mData->mSlot == 0)
1188 {
1189 mData->mEnabled = true;
1190 mData->mAttachmentType = NetworkAttachmentType_NAT;
1191 mData->mCableConnected = true;
1192 }
1193}
1194
1195// private methods
1196////////////////////////////////////////////////////////////////////////////////
1197
1198/**
1199 * Worker routine for detach handling. No locking, no notifications.
1200
1201 * @note Must be called from under the object's write lock.
1202 */
1203void NetworkAdapter::detach()
1204{
1205 AssertReturnVoid (isWriteLockOnCurrentThread());
1206
1207 switch (mData->mAttachmentType)
1208 {
1209 case NetworkAttachmentType_Null:
1210 {
1211 /* nothing to do here */
1212 break;
1213 }
1214 case NetworkAttachmentType_NAT:
1215 {
1216 break;
1217 }
1218 case NetworkAttachmentType_Bridged:
1219 {
1220 /* reset handle and device name */
1221 mData->mHostInterface = "";
1222 break;
1223 }
1224 case NetworkAttachmentType_Internal:
1225 {
1226 mData->mInternalNetwork.setNull();
1227 break;
1228 }
1229 case NetworkAttachmentType_HostOnly:
1230 {
1231#if defined(VBOX_WITH_NETFLT)
1232 /* reset handle and device name */
1233 mData->mHostInterface = "";
1234#endif
1235 break;
1236 }
1237 }
1238
1239 mData->mAttachmentType = NetworkAttachmentType_Null;
1240}
1241
1242/**
1243 * Generates a new unique MAC address based on our vendor ID and
1244 * parts of a GUID.
1245 *
1246 * @note Must be called from under the object's write lock or within the init
1247 * span.
1248 */
1249void NetworkAdapter::generateMACAddress()
1250{
1251 /*
1252 * Our strategy is as follows: the first three bytes are our fixed
1253 * vendor ID (080027). The remaining 3 bytes will be taken from the
1254 * start of a GUID. This is a fairly safe algorithm.
1255 */
1256 char strMAC[13];
1257 Guid guid;
1258 guid.create();
1259 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1260 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1261 LogFlowThisFunc (("generated MAC: '%s'\n", strMAC));
1262 mData->mMACAddress = strMAC;
1263}
1264/* 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