VirtualBox

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

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

iprt/cpputils.h -> iprt/cpp/utils.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.8 KB
Line 
1/* $Id: NetworkAdapterImpl.cpp 25346 2009-12-13 16:21:19Z 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 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
910
911 /* Note: we assume that the default values for attributes of optional
912 * nodes are assigned in the Data::Data() constructor and don't do it
913 * here. It implies that this method may only be called after constructing
914 * a new BIOSSettings object while all its data fields are in the default
915 * values. Exceptions are fields whose creation time defaults don't match
916 * values that should be applied when these fields are not explicitly set
917 * in the settings file (for backwards compatibility reasons). This takes
918 * place when a setting of a newly created object must default to A while
919 * the same setting of an object loaded from the old settings file must
920 * default to B. */
921
922 HRESULT rc = S_OK;
923
924 mData->mAdapterType = data.type;
925 mData->mEnabled = data.fEnabled;
926 /* MAC address (can be null) */
927 rc = COMSETTER(MACAddress)(Bstr(data.strMACAddress));
928 if (FAILED(rc)) return rc;
929 /* cable (required) */
930 mData->mCableConnected = data.fCableConnected;
931 /* line speed (defaults to 100 Mbps) */
932 mData->mLineSpeed = data.ulLineSpeed;
933 /* tracing (defaults to false) */
934 mData->mTraceEnabled = data.fTraceEnabled;
935 mData->mTraceFile = data.strTraceFile;
936
937 switch (data.mode)
938 {
939 case NetworkAttachmentType_NAT:
940 mData->mNATNetwork = data.strName;
941 if (mData->mNATNetwork.isNull())
942 mData->mNATNetwork = "";
943 rc = AttachToNAT();
944 if (FAILED(rc)) return rc;
945 break;
946
947 case NetworkAttachmentType_Bridged:
948 rc = COMSETTER(HostInterface)(Bstr(data.strName));
949 if (FAILED(rc)) return rc;
950 rc = AttachToBridgedInterface();
951 if (FAILED(rc)) return rc;
952 break;
953
954 case NetworkAttachmentType_Internal:
955 mData->mInternalNetwork = data.strName;
956 Assert(!mData->mInternalNetwork.isNull());
957
958 rc = AttachToInternalNetwork();
959 if (FAILED(rc)) return rc;
960 break;
961
962 case NetworkAttachmentType_HostOnly:
963#if defined(VBOX_WITH_NETFLT)
964 rc = COMSETTER(HostInterface)(Bstr(data.strName));
965 if (FAILED(rc)) return rc;
966#endif
967 rc = AttachToHostOnlyInterface();
968 if (FAILED(rc)) return rc;
969 break;
970
971 case NetworkAttachmentType_Null:
972 rc = Detach();
973 if (FAILED(rc)) return rc;
974 break;
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::NetworkAdapter &data)
990{
991 AutoCaller autoCaller(this);
992 AssertComRCReturnRC(autoCaller.rc());
993
994 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
995
996 data.fEnabled = !!mData->mEnabled;
997 data.strMACAddress = mData->mMACAddress;
998 data.fCableConnected = !!mData->mCableConnected;
999
1000 data.ulLineSpeed = mData->mLineSpeed;
1001
1002 data.fTraceEnabled = !!mData->mTraceEnabled;
1003
1004 data.strTraceFile = mData->mTraceFile;
1005
1006 data.type = mData->mAdapterType;
1007
1008 switch (data.mode = mData->mAttachmentType)
1009 {
1010 case NetworkAttachmentType_Null:
1011 data.strName.setNull();
1012 break;
1013
1014 case NetworkAttachmentType_NAT:
1015 data.strName = mData->mNATNetwork;
1016 break;
1017
1018 case NetworkAttachmentType_Bridged:
1019 data.strName = mData->mHostInterface;
1020 break;
1021
1022 case NetworkAttachmentType_Internal:
1023 data.strName = mData->mInternalNetwork;
1024 break;
1025
1026 case NetworkAttachmentType_HostOnly:
1027 data.strName = mData->mHostInterface;
1028 break;
1029 }
1030
1031 return S_OK;
1032}
1033
1034/**
1035 * @note Locks this object for writing.
1036 */
1037bool NetworkAdapter::rollback()
1038{
1039 /* sanity */
1040 AutoCaller autoCaller(this);
1041 AssertComRCReturn (autoCaller.rc(), false);
1042
1043 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1044
1045 bool changed = false;
1046
1047 if (mData.isBackedUp())
1048 {
1049 /* we need to check all data to see whether anything will be changed
1050 * after rollback */
1051 changed = mData.hasActualChanges();
1052 mData.rollback();
1053 }
1054
1055 return changed;
1056}
1057
1058/**
1059 * @note Locks this object for writing, together with the peer object (also
1060 * for writing) if there is one.
1061 */
1062void NetworkAdapter::commit()
1063{
1064 /* sanity */
1065 AutoCaller autoCaller(this);
1066 AssertComRCReturnVoid (autoCaller.rc());
1067
1068 /* sanity too */
1069 AutoCaller peerCaller (mPeer);
1070 AssertComRCReturnVoid (peerCaller.rc());
1071
1072 /* lock both for writing since we modify both (mPeer is "master" so locked
1073 * first) */
1074 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
1075
1076 if (mData.isBackedUp())
1077 {
1078 mData.commit();
1079 if (mPeer)
1080 {
1081 /* attach new data to the peer and reshare it */
1082 mPeer->mData.attach (mData);
1083 }
1084 }
1085}
1086
1087/**
1088 * @note Locks this object for writing, together with the peer object
1089 * represented by @a aThat (locked for reading).
1090 */
1091void NetworkAdapter::copyFrom (NetworkAdapter *aThat)
1092{
1093 AssertReturnVoid (aThat != NULL);
1094
1095 /* sanity */
1096 AutoCaller autoCaller(this);
1097 AssertComRCReturnVoid (autoCaller.rc());
1098
1099 /* sanity too */
1100 AutoCaller thatCaller (aThat);
1101 AssertComRCReturnVoid (thatCaller.rc());
1102
1103 /* peer is not modified, lock it for reading (aThat is "master" so locked
1104 * first) */
1105 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1106 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1107
1108 /* this will back up current data */
1109 mData.assignCopy (aThat->mData);
1110}
1111
1112void NetworkAdapter::applyDefaults (GuestOSType *aOsType)
1113{
1114 AssertReturnVoid (aOsType != NULL);
1115
1116 /* sanity */
1117 AutoCaller autoCaller(this);
1118 AssertComRCReturnVoid (autoCaller.rc());
1119
1120 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1121
1122 bool e1000enabled = false;
1123#ifdef VBOX_WITH_E1000
1124 e1000enabled = true;
1125#endif // VBOX_WITH_E1000
1126
1127 NetworkAdapterType_T defaultType = aOsType->networkAdapterType();
1128
1129 /* Set default network adapter for this OS type */
1130 if (defaultType == NetworkAdapterType_I82540EM ||
1131 defaultType == NetworkAdapterType_I82543GC ||
1132 defaultType == NetworkAdapterType_I82545EM)
1133 {
1134 if (e1000enabled) mData->mAdapterType = defaultType;
1135 }
1136 else mData->mAdapterType = defaultType;
1137
1138 /* Enable and connect the first one adapter to the NAT */
1139 if (mData->mSlot == 0)
1140 {
1141 mData->mEnabled = true;
1142 mData->mAttachmentType = NetworkAttachmentType_NAT;
1143 mData->mCableConnected = true;
1144 }
1145}
1146
1147// private methods
1148////////////////////////////////////////////////////////////////////////////////
1149
1150/**
1151 * Worker routine for detach handling. No locking, no notifications.
1152
1153 * @note Must be called from under the object's write lock.
1154 */
1155void NetworkAdapter::detach()
1156{
1157 AssertReturnVoid (isWriteLockOnCurrentThread());
1158
1159 switch (mData->mAttachmentType)
1160 {
1161 case NetworkAttachmentType_Null:
1162 {
1163 /* nothing to do here */
1164 break;
1165 }
1166 case NetworkAttachmentType_NAT:
1167 {
1168 break;
1169 }
1170 case NetworkAttachmentType_Bridged:
1171 {
1172 /* reset handle and device name */
1173 mData->mHostInterface = "";
1174 break;
1175 }
1176 case NetworkAttachmentType_Internal:
1177 {
1178 mData->mInternalNetwork.setNull();
1179 break;
1180 }
1181 case NetworkAttachmentType_HostOnly:
1182 {
1183#if defined(VBOX_WITH_NETFLT)
1184 /* reset handle and device name */
1185 mData->mHostInterface = "";
1186#endif
1187 break;
1188 }
1189 }
1190
1191 mData->mAttachmentType = NetworkAttachmentType_Null;
1192}
1193
1194/**
1195 * Generates a new unique MAC address based on our vendor ID and
1196 * parts of a GUID.
1197 *
1198 * @note Must be called from under the object's write lock or within the init
1199 * span.
1200 */
1201void NetworkAdapter::generateMACAddress()
1202{
1203 /*
1204 * Our strategy is as follows: the first three bytes are our fixed
1205 * vendor ID (080027). The remaining 3 bytes will be taken from the
1206 * start of a GUID. This is a fairly safe algorithm.
1207 */
1208 char strMAC[13];
1209 Guid guid;
1210 guid.create();
1211 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1212 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1213 LogFlowThisFunc(("generated MAC: '%s'\n", strMAC));
1214 mData->mMACAddress = strMAC;
1215}
1216/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use