VirtualBox

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

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

API: weed out NULL strings, as many clients cannot use them

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