VirtualBox

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

Last change on this file since 25843 was 25843, checked in by vboxsync, 14 years ago

Main: fix deadlock candidates detected by lock validator

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.7 KB
Line 
1/* $Id: NetworkAdapterImpl.cpp 25843 2010-01-14 18:51:32Z 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/cpp/utils.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 COMMA_LOCKVAL_SRC_POS);
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 COMMA_LOCKVAL_SRC_POS);
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
184
185 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
196
197 /* the machine needs to be mutable */
198 Machine::AutoMutableStateDependency adep(mParent);
199 if (FAILED(adep.rc())) return adep.rc();
200
201 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
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.release();
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
243
244 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
257
258 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
259
260 *aEnabled = mData->mEnabled;
261
262 return S_OK;
263}
264
265STDMETHODIMP NetworkAdapter::COMSETTER(Enabled) (BOOL aEnabled)
266{
267 AutoCaller autoCaller(this);
268 if (FAILED(autoCaller.rc())) return autoCaller.rc();
269
270 /* the machine needs to be mutable */
271 Machine::AutoMutableStateDependency adep(mParent);
272 if (FAILED(adep.rc())) return adep.rc();
273
274 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
275
276 if (mData->mEnabled != aEnabled)
277 {
278 mData.backup();
279 mData->mEnabled = aEnabled;
280
281 /* leave the lock before informing callbacks */
282 alock.release();
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
296
297 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
310
311 /* the machine needs to be mutable */
312 Machine::AutoMutableStateDependency adep(mParent);
313 if (FAILED(adep.rc())) return adep.rc();
314
315 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
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.release();
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
393
394 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
407
408 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
409
410 mData->mHostInterface.cloneTo(aHostInterface);
411
412 return S_OK;
413}
414
415STDMETHODIMP NetworkAdapter::COMSETTER(HostInterface)(IN_BSTR aHostInterface)
416{
417 Bstr bstrEmpty("");
418 if (!aHostInterface)
419 aHostInterface = bstrEmpty;
420
421 AutoCaller autoCaller(this);
422 if (FAILED(autoCaller.rc())) return autoCaller.rc();
423
424 /* the machine needs to be mutable */
425 Machine::AutoMutableStateDependency adep(mParent);
426 if (FAILED(adep.rc())) return adep.rc();
427
428 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
429
430 if (mData->mHostInterface != aHostInterface)
431 {
432 mData.backup();
433 mData->mHostInterface = aHostInterface;
434
435 /* leave the lock before informing callbacks */
436 alock.release();
437
438 mParent->onNetworkAdapterChange (this, FALSE);
439 }
440
441 return S_OK;
442}
443
444STDMETHODIMP NetworkAdapter::COMGETTER(InternalNetwork) (BSTR *aInternalNetwork)
445{
446 CheckComArgOutPointerValid(aInternalNetwork);
447
448 AutoCaller autoCaller(this);
449 if (FAILED(autoCaller.rc())) return autoCaller.rc();
450
451 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
452
453 mData->mInternalNetwork.cloneTo(aInternalNetwork);
454
455 return S_OK;
456}
457
458STDMETHODIMP NetworkAdapter::COMSETTER(InternalNetwork) (IN_BSTR aInternalNetwork)
459{
460 AutoCaller autoCaller(this);
461 if (FAILED(autoCaller.rc())) return autoCaller.rc();
462
463 /* the machine needs to be mutable */
464 Machine::AutoMutableStateDependency adep(mParent);
465 if (FAILED(adep.rc())) return adep.rc();
466
467 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
468
469 if (mData->mInternalNetwork != aInternalNetwork)
470 {
471 /* if an empty/null string is to be set, internal networking must be
472 * turned off */
473 if ( (aInternalNetwork == NULL || *aInternalNetwork == '\0')
474 && mData->mAttachmentType == NetworkAttachmentType_Internal)
475 {
476 return setError (E_FAIL,
477 tr ("Empty or null internal network name is not valid"));
478 }
479
480 mData.backup();
481 mData->mInternalNetwork = aInternalNetwork;
482
483 /* leave the lock before informing callbacks */
484 alock.release();
485
486 mParent->onNetworkAdapterChange (this, FALSE);
487 }
488
489 return S_OK;
490}
491
492STDMETHODIMP NetworkAdapter::COMGETTER(NATNetwork) (BSTR *aNATNetwork)
493{
494 CheckComArgOutPointerValid(aNATNetwork);
495
496 AutoCaller autoCaller(this);
497 if (FAILED(autoCaller.rc())) return autoCaller.rc();
498
499 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
500
501 mData->mNATNetwork.cloneTo(aNATNetwork);
502
503 return S_OK;
504}
505
506STDMETHODIMP NetworkAdapter::COMSETTER(NATNetwork) (IN_BSTR aNATNetwork)
507{
508 Bstr bstrEmpty("");
509 if (!aNATNetwork)
510 aNATNetwork = bstrEmpty;
511
512 AutoCaller autoCaller(this);
513 if (FAILED(autoCaller.rc())) return autoCaller.rc();
514
515 /* the machine needs to be mutable */
516 Machine::AutoMutableStateDependency adep(mParent);
517 if (FAILED(adep.rc())) return adep.rc();
518
519 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
520
521 if (mData->mNATNetwork != aNATNetwork)
522 {
523 mData.backup();
524 mData->mNATNetwork = aNATNetwork;
525
526 /* leave the lock before informing callbacks */
527 alock.release();
528
529 mParent->onNetworkAdapterChange (this, FALSE);
530 }
531
532 return S_OK;
533}
534
535STDMETHODIMP NetworkAdapter::COMGETTER(CableConnected) (BOOL *aConnected)
536{
537 CheckComArgOutPointerValid(aConnected);
538
539 AutoCaller autoCaller(this);
540 if (FAILED(autoCaller.rc())) return autoCaller.rc();
541
542 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
543
544 *aConnected = mData->mCableConnected;
545
546 return S_OK;
547}
548
549STDMETHODIMP NetworkAdapter::COMSETTER(CableConnected) (BOOL aConnected)
550{
551 AutoCaller autoCaller(this);
552 if (FAILED(autoCaller.rc())) return autoCaller.rc();
553
554 /* the machine needs to be mutable */
555 Machine::AutoMutableStateDependency adep(mParent);
556 if (FAILED(adep.rc())) return adep.rc();
557
558 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
559
560 if (aConnected != mData->mCableConnected)
561 {
562 mData.backup();
563 mData->mCableConnected = aConnected;
564
565 /* leave the lock before informing callbacks */
566 alock.release();
567
568 mParent->onNetworkAdapterChange (this, FALSE);
569 }
570
571 return S_OK;
572}
573
574STDMETHODIMP NetworkAdapter::COMGETTER(LineSpeed) (ULONG *aSpeed)
575{
576 CheckComArgOutPointerValid(aSpeed);
577
578 AutoCaller autoCaller(this);
579 if (FAILED(autoCaller.rc())) return autoCaller.rc();
580
581 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
582
583 *aSpeed = mData->mLineSpeed;
584
585 return S_OK;
586}
587
588STDMETHODIMP NetworkAdapter::COMSETTER(LineSpeed) (ULONG aSpeed)
589{
590 AutoCaller autoCaller(this);
591 if (FAILED(autoCaller.rc())) return autoCaller.rc();
592
593 /* the machine needs to be mutable */
594 Machine::AutoMutableStateDependency adep(mParent);
595 if (FAILED(adep.rc())) return adep.rc();
596
597 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
598
599 if (aSpeed != mData->mLineSpeed)
600 {
601 mData.backup();
602 mData->mLineSpeed = aSpeed;
603
604 /* leave the lock before informing callbacks */
605 alock.release();
606
607 mParent->onNetworkAdapterChange (this, FALSE);
608 }
609
610 return S_OK;
611}
612
613STDMETHODIMP NetworkAdapter::COMGETTER(TraceEnabled) (BOOL *aEnabled)
614{
615 CheckComArgOutPointerValid(aEnabled);
616
617 AutoCaller autoCaller(this);
618 if (FAILED(autoCaller.rc())) return autoCaller.rc();
619
620 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
621
622 *aEnabled = mData->mTraceEnabled;
623 return S_OK;
624}
625
626STDMETHODIMP NetworkAdapter::COMSETTER(TraceEnabled) (BOOL aEnabled)
627{
628 AutoCaller autoCaller(this);
629 if (FAILED(autoCaller.rc())) return autoCaller.rc();
630
631 /* the machine needs to be mutable */
632 Machine::AutoMutableStateDependency adep(mParent);
633 if (FAILED(adep.rc())) return adep.rc();
634
635 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
636
637 if (aEnabled != mData->mTraceEnabled)
638 {
639 mData.backup();
640 mData->mTraceEnabled = aEnabled;
641
642 /* leave the lock before informing callbacks */
643 alock.release();
644
645 mParent->onNetworkAdapterChange (this, TRUE);
646 }
647
648 return S_OK;
649}
650
651STDMETHODIMP NetworkAdapter::COMGETTER(TraceFile) (BSTR *aTraceFile)
652{
653 CheckComArgOutPointerValid(aTraceFile);
654
655 AutoCaller autoCaller(this);
656 if (FAILED(autoCaller.rc())) return autoCaller.rc();
657
658 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
659
660 mData->mTraceFile.cloneTo(aTraceFile);
661
662 return S_OK;
663}
664
665STDMETHODIMP NetworkAdapter::COMSETTER(TraceFile) (IN_BSTR aTraceFile)
666{
667 AutoCaller autoCaller(this);
668 if (FAILED(autoCaller.rc())) return autoCaller.rc();
669
670 /* the machine needs to be mutable */
671 Machine::AutoMutableStateDependency adep(mParent);
672 if (FAILED(adep.rc())) return adep.rc();
673
674 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
675
676 if (mData->mTraceFile != aTraceFile)
677 {
678 mData.backup();
679 mData->mTraceFile = aTraceFile;
680
681 /* leave the lock before informing callbacks */
682 alock.release();
683
684 mParent->onNetworkAdapterChange (this, FALSE);
685 }
686
687 return S_OK;
688}
689
690// INetworkAdapter methods
691////////////////////////////////////////////////////////////////////////////////
692
693STDMETHODIMP NetworkAdapter::AttachToNAT()
694{
695 AutoCaller autoCaller(this);
696 if (FAILED(autoCaller.rc())) return autoCaller.rc();
697
698 /* the machine needs to be mutable */
699 Machine::AutoMutableStateDependency adep(mParent);
700 if (FAILED(adep.rc())) return adep.rc();
701
702 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
703
704 if (mData->mAttachmentType != NetworkAttachmentType_NAT)
705 {
706 mData.backup();
707
708 // Commented this for now as it resets the parameter mData->mNATNetwork
709 // which is essential while changing the Attachment dynamically.
710 //detach();
711
712 mData->mAttachmentType = NetworkAttachmentType_NAT;
713
714 /* leave the lock before informing callbacks */
715 alock.release();
716
717 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
718 if (FAILED (rc))
719 {
720 /* If changing the attachment failed then we can't assume
721 * that the previous attachment will attach correctly
722 * and thus return error along with dettaching all
723 * attachments.
724 */
725 Detach();
726 return rc;
727 }
728 }
729
730 return S_OK;
731}
732
733STDMETHODIMP NetworkAdapter::AttachToBridgedInterface()
734{
735 AutoCaller autoCaller(this);
736 if (FAILED(autoCaller.rc())) return autoCaller.rc();
737
738 /* the machine needs to be mutable */
739 Machine::AutoMutableStateDependency adep(mParent);
740 if (FAILED(adep.rc())) return adep.rc();
741
742 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
743
744 /* don't do anything if we're already host interface attached */
745 if (mData->mAttachmentType != NetworkAttachmentType_Bridged)
746 {
747 mData.backup();
748
749 /* first detach the current attachment */
750 // Commented this for now as it reset the parameter mData->mHostInterface
751 // which is essential while changing the Attachment dynamically.
752 //detach();
753
754 mData->mAttachmentType = NetworkAttachmentType_Bridged;
755
756 /* leave the lock before informing callbacks */
757 alock.release();
758
759 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
760 if (FAILED (rc))
761 {
762 /* If changing the attachment failed then we can't assume
763 * that the previous attachment will attach correctly
764 * and thus return error along with dettaching all
765 * attachments.
766 */
767 Detach();
768 return rc;
769 }
770 }
771
772 return S_OK;
773}
774
775STDMETHODIMP NetworkAdapter::AttachToInternalNetwork()
776{
777 AutoCaller autoCaller(this);
778 if (FAILED(autoCaller.rc())) return autoCaller.rc();
779
780 /* the machine needs to be mutable */
781 Machine::AutoMutableStateDependency adep(mParent);
782 if (FAILED(adep.rc())) return adep.rc();
783
784 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
785
786 /* don't do anything if we're already internal network attached */
787 if (mData->mAttachmentType != NetworkAttachmentType_Internal)
788 {
789 mData.backup();
790
791 /* first detach the current attachment */
792 // Commented this for now as it reset the parameter mData->mInternalNetwork
793 // which is essential while changing the Attachment dynamically.
794 //detach();
795
796 /* there must an internal network name */
797 if (mData->mInternalNetwork.isEmpty())
798 {
799 LogRel (("Internal network name not defined, "
800 "setting to default \"intnet\"\n"));
801 mData->mInternalNetwork = "intnet";
802 }
803
804 mData->mAttachmentType = NetworkAttachmentType_Internal;
805
806 /* leave the lock before informing callbacks */
807 alock.release();
808
809 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
810 if (FAILED (rc))
811 {
812 /* If changing the attachment failed then we can't assume
813 * that the previous attachment will attach correctly
814 * and thus return error along with dettaching all
815 * attachments.
816 */
817 Detach();
818 return rc;
819 }
820 }
821
822 return S_OK;
823}
824
825STDMETHODIMP NetworkAdapter::AttachToHostOnlyInterface()
826{
827 AutoCaller autoCaller(this);
828 if (FAILED(autoCaller.rc())) return autoCaller.rc();
829
830 /* the machine needs to be mutable */
831 Machine::AutoMutableStateDependency adep(mParent);
832 if (FAILED(adep.rc())) return adep.rc();
833
834 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
835
836 /* don't do anything if we're already host interface attached */
837 if (mData->mAttachmentType != NetworkAttachmentType_HostOnly)
838 {
839 mData.backup();
840
841 /* first detach the current attachment */
842 // Commented this for now as it reset the parameter mData->mHostInterface
843 // which is essential while changing the Attachment dynamically.
844 //detach();
845
846 mData->mAttachmentType = NetworkAttachmentType_HostOnly;
847
848 /* leave the lock before informing callbacks */
849 alock.release();
850
851 HRESULT rc = mParent->onNetworkAdapterChange (this, TRUE);
852 if (FAILED (rc))
853 {
854 /* If changing the attachment failed then we can't assume
855 * that the previous attachment will attach correctly
856 * and thus return error along with dettaching all
857 * attachments.
858 */
859 Detach();
860 return rc;
861 }
862 }
863
864 return S_OK;
865}
866
867STDMETHODIMP NetworkAdapter::Detach()
868{
869 AutoCaller autoCaller(this);
870 if (FAILED(autoCaller.rc())) return autoCaller.rc();
871
872 /* the machine needs to be mutable */
873 Machine::AutoMutableStateDependency adep(mParent);
874 if (FAILED(adep.rc())) return adep.rc();
875
876 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
877
878 if (mData->mAttachmentType != NetworkAttachmentType_Null)
879 {
880 mData.backup();
881
882 detach();
883
884 /* leave the lock before informing callbacks */
885 alock.release();
886
887 mParent->onNetworkAdapterChange (this, TRUE);
888 }
889
890 return S_OK;
891}
892
893// public methods only for internal purposes
894////////////////////////////////////////////////////////////////////////////////
895
896/**
897 * Loads settings from the given adapter node.
898 * May be called once right after this object creation.
899 *
900 * @param aAdapterNode <Adapter> node.
901 *
902 * @note Locks this object for writing.
903 */
904HRESULT NetworkAdapter::loadSettings(const settings::NetworkAdapter &data)
905{
906 AutoCaller autoCaller(this);
907 AssertComRCReturnRC(autoCaller.rc());
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 if (FAILED(rc)) return 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 if (mData->mNATNetwork.isNull())
940 mData->mNATNetwork = "";
941 rc = AttachToNAT();
942 if (FAILED(rc)) return rc;
943 break;
944
945 case NetworkAttachmentType_Bridged:
946 rc = COMSETTER(HostInterface)(Bstr(data.strName));
947 if (FAILED(rc)) return rc;
948 rc = AttachToBridgedInterface();
949 if (FAILED(rc)) return rc;
950 break;
951
952 case NetworkAttachmentType_Internal:
953 mData->mInternalNetwork = data.strName;
954 Assert(!mData->mInternalNetwork.isNull());
955
956 rc = AttachToInternalNetwork();
957 if (FAILED(rc)) return rc;
958 break;
959
960 case NetworkAttachmentType_HostOnly:
961#if defined(VBOX_WITH_NETFLT)
962 rc = COMSETTER(HostInterface)(Bstr(data.strName));
963 if (FAILED(rc)) return rc;
964#endif
965 rc = AttachToHostOnlyInterface();
966 if (FAILED(rc)) return rc;
967 break;
968
969 case NetworkAttachmentType_Null:
970 rc = Detach();
971 if (FAILED(rc)) return rc;
972 break;
973 }
974
975 return S_OK;
976}
977
978/**
979 * Saves settings to the given adapter node.
980 *
981 * Note that the given Adapter node is comletely empty on input.
982 *
983 * @param aAdapterNode <Adapter> node.
984 *
985 * @note Locks this object for reading.
986 */
987HRESULT NetworkAdapter::saveSettings(settings::NetworkAdapter &data)
988{
989 AutoCaller autoCaller(this);
990 AssertComRCReturnRC(autoCaller.rc());
991
992 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
993
994 data.fEnabled = !!mData->mEnabled;
995 data.strMACAddress = mData->mMACAddress;
996 data.fCableConnected = !!mData->mCableConnected;
997
998 data.ulLineSpeed = mData->mLineSpeed;
999
1000 data.fTraceEnabled = !!mData->mTraceEnabled;
1001
1002 data.strTraceFile = mData->mTraceFile;
1003
1004 data.type = mData->mAdapterType;
1005
1006 switch (data.mode = mData->mAttachmentType)
1007 {
1008 case NetworkAttachmentType_Null:
1009 data.strName.setNull();
1010 break;
1011
1012 case NetworkAttachmentType_NAT:
1013 data.strName = mData->mNATNetwork;
1014 break;
1015
1016 case NetworkAttachmentType_Bridged:
1017 data.strName = mData->mHostInterface;
1018 break;
1019
1020 case NetworkAttachmentType_Internal:
1021 data.strName = mData->mInternalNetwork;
1022 break;
1023
1024 case NetworkAttachmentType_HostOnly:
1025 data.strName = mData->mHostInterface;
1026 break;
1027 }
1028
1029 return S_OK;
1030}
1031
1032/**
1033 * @note Locks this object for writing.
1034 */
1035bool NetworkAdapter::rollback()
1036{
1037 /* sanity */
1038 AutoCaller autoCaller(this);
1039 AssertComRCReturn (autoCaller.rc(), false);
1040
1041 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1042
1043 bool changed = false;
1044
1045 if (mData.isBackedUp())
1046 {
1047 /* we need to check all data to see whether anything will be changed
1048 * after rollback */
1049 changed = mData.hasActualChanges();
1050 mData.rollback();
1051 }
1052
1053 return changed;
1054}
1055
1056/**
1057 * @note Locks this object for writing, together with the peer object (also
1058 * for writing) if there is one.
1059 */
1060void NetworkAdapter::commit()
1061{
1062 /* sanity */
1063 AutoCaller autoCaller(this);
1064 AssertComRCReturnVoid (autoCaller.rc());
1065
1066 /* sanity too */
1067 AutoCaller peerCaller (mPeer);
1068 AssertComRCReturnVoid (peerCaller.rc());
1069
1070 /* lock both for writing since we modify both (mPeer is "master" so locked
1071 * first) */
1072 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
1073
1074 if (mData.isBackedUp())
1075 {
1076 mData.commit();
1077 if (mPeer)
1078 {
1079 /* attach new data to the peer and reshare it */
1080 mPeer->mData.attach (mData);
1081 }
1082 }
1083}
1084
1085/**
1086 * @note Locks this object for writing, together with the peer object
1087 * represented by @a aThat (locked for reading).
1088 */
1089void NetworkAdapter::copyFrom (NetworkAdapter *aThat)
1090{
1091 AssertReturnVoid (aThat != NULL);
1092
1093 /* sanity */
1094 AutoCaller autoCaller(this);
1095 AssertComRCReturnVoid (autoCaller.rc());
1096
1097 /* sanity too */
1098 AutoCaller thatCaller (aThat);
1099 AssertComRCReturnVoid (thatCaller.rc());
1100
1101 /* peer is not modified, lock it for reading (aThat is "master" so locked
1102 * first) */
1103 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1104 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1105
1106 /* this will back up current data */
1107 mData.assignCopy (aThat->mData);
1108}
1109
1110void NetworkAdapter::applyDefaults (GuestOSType *aOsType)
1111{
1112 AssertReturnVoid (aOsType != NULL);
1113
1114 /* sanity */
1115 AutoCaller autoCaller(this);
1116 AssertComRCReturnVoid (autoCaller.rc());
1117
1118 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1119
1120 bool e1000enabled = false;
1121#ifdef VBOX_WITH_E1000
1122 e1000enabled = true;
1123#endif // VBOX_WITH_E1000
1124
1125 NetworkAdapterType_T defaultType = aOsType->networkAdapterType();
1126
1127 /* Set default network adapter for this OS type */
1128 if (defaultType == NetworkAdapterType_I82540EM ||
1129 defaultType == NetworkAdapterType_I82543GC ||
1130 defaultType == NetworkAdapterType_I82545EM)
1131 {
1132 if (e1000enabled) mData->mAdapterType = defaultType;
1133 }
1134 else mData->mAdapterType = defaultType;
1135
1136 /* Enable and connect the first one adapter to the NAT */
1137 if (mData->mSlot == 0)
1138 {
1139 mData->mEnabled = true;
1140 mData->mAttachmentType = NetworkAttachmentType_NAT;
1141 mData->mCableConnected = true;
1142 }
1143}
1144
1145// private methods
1146////////////////////////////////////////////////////////////////////////////////
1147
1148/**
1149 * Worker routine for detach handling. No locking, no notifications.
1150
1151 * @note Must be called from under the object's write lock.
1152 */
1153void NetworkAdapter::detach()
1154{
1155 AssertReturnVoid (isWriteLockOnCurrentThread());
1156
1157 switch (mData->mAttachmentType)
1158 {
1159 case NetworkAttachmentType_Null:
1160 {
1161 /* nothing to do here */
1162 break;
1163 }
1164 case NetworkAttachmentType_NAT:
1165 {
1166 break;
1167 }
1168 case NetworkAttachmentType_Bridged:
1169 {
1170 /* reset handle and device name */
1171 mData->mHostInterface = "";
1172 break;
1173 }
1174 case NetworkAttachmentType_Internal:
1175 {
1176 mData->mInternalNetwork.setNull();
1177 break;
1178 }
1179 case NetworkAttachmentType_HostOnly:
1180 {
1181#if defined(VBOX_WITH_NETFLT)
1182 /* reset handle and device name */
1183 mData->mHostInterface = "";
1184#endif
1185 break;
1186 }
1187 }
1188
1189 mData->mAttachmentType = NetworkAttachmentType_Null;
1190}
1191
1192/**
1193 * Generates a new unique MAC address based on our vendor ID and
1194 * parts of a GUID.
1195 *
1196 * @note Must be called from under the object's write lock or within the init
1197 * span.
1198 */
1199void NetworkAdapter::generateMACAddress()
1200{
1201 /*
1202 * Our strategy is as follows: the first three bytes are our fixed
1203 * vendor ID (080027). The remaining 3 bytes will be taken from the
1204 * start of a GUID. This is a fairly safe algorithm.
1205 */
1206 char strMAC[13];
1207 Guid guid;
1208 guid.create();
1209 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1210 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1211 LogFlowThisFunc(("generated MAC: '%s'\n", strMAC));
1212 mData->mMACAddress = strMAC;
1213}
1214/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use