VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/NetworkAdapterImpl.cpp@ 65082

Last change on this file since 65082 was 65063, checked in by vboxsync, 8 years ago

Main: doxygen fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.4 KB
Line 
1/* $Id: NetworkAdapterImpl.cpp 65063 2017-01-03 11:15:49Z vboxsync $ */
2/** @file
3 * Implementation of INetworkAdapter in VBoxSVC.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
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
18#include "NetworkAdapterImpl.h"
19#include "NATEngineImpl.h"
20#include "AutoCaller.h"
21#include "Logging.h"
22#include "MachineImpl.h"
23#include "GuestOSTypeImpl.h"
24#include "HostImpl.h"
25#include "SystemPropertiesImpl.h"
26#include "VirtualBoxImpl.h"
27
28#include <iprt/ctype.h>
29#include <iprt/string.h>
30#include <iprt/cpp/utils.h>
31
32#include <VBox/err.h>
33#include <VBox/settings.h>
34
35#include "AutoStateDep.h"
36
37// constructor / destructor
38////////////////////////////////////////////////////////////////////////////////
39
40NetworkAdapter::NetworkAdapter()
41 : mParent(NULL)
42{
43}
44
45NetworkAdapter::~NetworkAdapter()
46{
47}
48
49HRESULT NetworkAdapter::FinalConstruct()
50{
51 return BaseFinalConstruct();
52}
53
54void NetworkAdapter::FinalRelease()
55{
56 uninit();
57 BaseFinalRelease();
58}
59
60// public initializer/uninitializer for internal purposes only
61////////////////////////////////////////////////////////////////////////////////
62
63/**
64 * Initializes the network adapter object.
65 *
66 * @param aParent Handle of the parent object.
67 */
68HRESULT NetworkAdapter::init(Machine *aParent, ULONG uSlot)
69{
70 LogFlowThisFunc(("aParent=%p, uSlot=%d\n", aParent, uSlot));
71
72 ComAssertRet(aParent, E_INVALIDARG);
73 uint32_t maxNetworkAdapters = Global::getMaxNetworkAdapters(aParent->i_getChipsetType());
74 ComAssertRet(uSlot < maxNetworkAdapters, E_INVALIDARG);
75
76 /* Enclose the state transition NotReady->InInit->Ready */
77 AutoInitSpan autoInitSpan(this);
78 AssertReturn(autoInitSpan.isOk(), E_FAIL);
79
80 unconst(mParent) = aParent;
81 unconst(mNATEngine).createObject();
82 mNATEngine->init(aParent, this);
83 /* mPeer is left null */
84
85 mData.allocate();
86
87 /* initialize data */
88 mData->ulSlot = uSlot;
89
90 /* default to Am79C973 */
91 mData->type = NetworkAdapterType_Am79C973;
92
93 /* Confirm a successful initialization */
94 autoInitSpan.setSucceeded();
95
96 return S_OK;
97}
98
99/**
100 * Initializes the network adapter object given another network adapter object
101 * (a kind of copy constructor). This object shares data with
102 * the object passed as an argument.
103 *
104 * @param aReshare
105 * When false, the original object will remain a data owner.
106 * Otherwise, data ownership will be transferred from the original
107 * object to this one.
108 *
109 * @note This object must be destroyed before the original object
110 * it shares data with is destroyed.
111 *
112 * @note Locks @a aThat object for reading.
113 */
114HRESULT NetworkAdapter::init(Machine *aParent, NetworkAdapter *aThat, bool aReshare /* = false */)
115{
116 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n", aParent, aThat, aReshare));
117
118 ComAssertRet(aParent && aThat, E_INVALIDARG);
119
120 /* Enclose the state transition NotReady->InInit->Ready */
121 AutoInitSpan autoInitSpan(this);
122 AssertReturn(autoInitSpan.isOk(), E_FAIL);
123
124 unconst(mParent) = aParent;
125 /* mPeer is left null */
126
127 unconst(mNATEngine).createObject();
128 mNATEngine->init(aParent, this, aThat->mNATEngine);
129
130 /* sanity */
131 AutoCaller thatCaller(aThat);
132 AssertComRCReturnRC(thatCaller.rc());
133
134 if (aReshare)
135 {
136 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
137
138 unconst(aThat->mPeer) = this;
139 mData.attach(aThat->mData);
140 }
141 else
142 {
143 unconst(mPeer) = aThat;
144
145 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
146 mData.share(aThat->mData);
147 }
148
149 /* Confirm a successful initialization */
150 autoInitSpan.setSucceeded();
151
152 return S_OK;
153}
154
155/**
156 * Initializes the guest object given another guest object
157 * (a kind of copy constructor). This object makes a private copy of data
158 * of the original object passed as an argument.
159 *
160 * @note Locks @a aThat object for reading.
161 */
162HRESULT NetworkAdapter::initCopy(Machine *aParent, NetworkAdapter *aThat)
163{
164 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
165
166 ComAssertRet(aParent && aThat, E_INVALIDARG);
167
168 /* Enclose the state transition NotReady->InInit->Ready */
169 AutoInitSpan autoInitSpan(this);
170 AssertReturn(autoInitSpan.isOk(), E_FAIL);
171
172 unconst(mParent) = aParent;
173 /* mPeer is left null */
174
175 unconst(mNATEngine).createObject();
176 mNATEngine->initCopy(aParent, this, aThat->mNATEngine);
177
178 /* sanity */
179 AutoCaller thatCaller(aThat);
180 AssertComRCReturnRC(thatCaller.rc());
181
182 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
183 mData.attachCopy(aThat->mData);
184
185 /* Confirm a successful initialization */
186 autoInitSpan.setSucceeded();
187
188 return S_OK;
189}
190
191/**
192 * Uninitializes the instance and sets the ready flag to FALSE.
193 * Called either from FinalRelease() or by the parent when it gets destroyed.
194 */
195void NetworkAdapter::uninit()
196{
197 LogFlowThisFunc(("\n"));
198
199 /* Enclose the state transition Ready->InUninit->NotReady */
200 AutoUninitSpan autoUninitSpan(this);
201 if (autoUninitSpan.uninitDone())
202 return;
203
204 mData.free();
205
206 unconst(mNATEngine).setNull();
207 unconst(mPeer) = NULL;
208 unconst(mParent) = NULL;
209}
210
211// wrapped INetworkAdapter properties
212////////////////////////////////////////////////////////////////////////////////
213HRESULT NetworkAdapter::getAdapterType(NetworkAdapterType_T *aAdapterType)
214{
215 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
216
217 *aAdapterType = mData->type;
218
219 return S_OK;
220}
221
222HRESULT NetworkAdapter::setAdapterType(NetworkAdapterType_T aAdapterType)
223{
224 /* the machine needs to be mutable */
225 AutoMutableStateDependency adep(mParent);
226 if (FAILED(adep.rc())) return adep.rc();
227
228 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
229
230 /* make sure the value is allowed */
231 switch (aAdapterType)
232 {
233 case NetworkAdapterType_Am79C970A:
234 case NetworkAdapterType_Am79C973:
235#ifdef VBOX_WITH_E1000
236 case NetworkAdapterType_I82540EM:
237 case NetworkAdapterType_I82543GC:
238 case NetworkAdapterType_I82545EM:
239#endif
240#ifdef VBOX_WITH_VIRTIO
241 case NetworkAdapterType_Virtio:
242#endif /* VBOX_WITH_VIRTIO */
243 break;
244 default:
245 return setError(E_FAIL,
246 tr("Invalid network adapter type '%d'"),
247 aAdapterType);
248 }
249
250 if (mData->type != aAdapterType)
251 {
252 mData.backup();
253 mData->type = aAdapterType;
254
255 // leave the lock before informing callbacks
256 alock.release();
257
258 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
259 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
260 mlock.release();
261
262 /* Changing the network adapter type during runtime is not allowed,
263 * therefore no immediate change in CFGM logic => changeAdapter=FALSE. */
264 mParent->i_onNetworkAdapterChange(this, FALSE);
265 }
266
267 return S_OK;
268}
269
270
271HRESULT NetworkAdapter::getSlot(ULONG *uSlot)
272{
273 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
274
275 *uSlot = mData->ulSlot;
276
277 return S_OK;
278}
279
280HRESULT NetworkAdapter::getEnabled(BOOL *aEnabled)
281{
282 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
283
284 *aEnabled = mData->fEnabled;
285
286 return S_OK;
287}
288
289HRESULT NetworkAdapter::setEnabled(BOOL aEnabled)
290{
291 /* the machine needs to be mutable */
292 AutoMutableStateDependency adep(mParent);
293 if (FAILED(adep.rc())) return adep.rc();
294
295 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
296
297 if (mData->fEnabled != RT_BOOL(aEnabled))
298 {
299 mData.backup();
300 mData->fEnabled = RT_BOOL(aEnabled);
301 if (RT_BOOL(aEnabled) && mData->strMACAddress.isEmpty())
302 i_generateMACAddress();
303
304 // leave the lock before informing callbacks
305 alock.release();
306
307 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
308 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
309 mlock.release();
310
311 /* Disabling the network adapter during runtime is not allowed
312 * therefore no immediate change in CFGM logic => changeAdapter=FALSE. */
313 mParent->i_onNetworkAdapterChange(this, FALSE);
314 }
315
316 return S_OK;
317}
318
319HRESULT NetworkAdapter::getMACAddress(com::Utf8Str &aMACAddress)
320{
321 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
322
323 ComAssertRet(!mData->fEnabled || !mData->strMACAddress.isEmpty(), E_FAIL);
324
325 aMACAddress = mData->strMACAddress;
326
327 return S_OK;
328}
329
330HRESULT NetworkAdapter::i_updateMacAddress(Utf8Str aMACAddress)
331{
332 HRESULT rc = S_OK;
333
334 /*
335 * Are we supposed to generate a MAC?
336 */
337 if (mData->fEnabled && aMACAddress.isEmpty())
338 i_generateMACAddress();
339 else
340 {
341 if (mData->strMACAddress != aMACAddress)
342 {
343 if (mData->fEnabled || !aMACAddress.isEmpty())
344 {
345 /*
346 * Verify given MAC address
347 */
348 char *macAddressStr = aMACAddress.mutableRaw();
349 int i = 0;
350 while ((i < 13) && macAddressStr && *macAddressStr && (rc == S_OK))
351 {
352 char c = *macAddressStr;
353 /* canonicalize hex digits to capital letters */
354 if (c >= 'a' && c <= 'f')
355 {
356 c = (char)RTLocCToUpper(c);
357 *macAddressStr = c;
358 }
359 /* we only accept capital letters */
360 if ( (c < '0' || c > '9')
361 && (c < 'A' || c > 'F'))
362 rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
363 /* the second digit must have even value for unicast addresses */
364 if ( (i == 1)
365 && (!!(c & 1) == (c >= '0' && c <= '9')))
366 rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
367
368 macAddressStr++;
369 i++;
370 }
371 /* we must have parsed exactly 12 characters */
372 if (i != 12)
373 rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
374 }
375
376 if (SUCCEEDED(rc))
377 mData->strMACAddress = aMACAddress;
378 }
379 }
380
381 return rc;
382}
383
384HRESULT NetworkAdapter::setMACAddress(const com::Utf8Str &aMACAddress)
385{
386 /* the machine needs to be mutable */
387 AutoMutableStateDependency adep(mParent);
388 if (FAILED(adep.rc())) return adep.rc();
389
390 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
391 mData.backup();
392
393 HRESULT rc = i_updateMacAddress(aMACAddress);
394 if (SUCCEEDED(rc))
395 {
396 // leave the lock before informing callbacks
397 alock.release();
398
399 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
400 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
401 mlock.release();
402
403 /* Changing the MAC via the Main API during runtime is not allowed,
404 * therefore no immediate change in CFGM logic => changeAdapter=FALSE. */
405 mParent->i_onNetworkAdapterChange(this, FALSE);
406 }
407
408 return rc;
409}
410
411HRESULT NetworkAdapter::getAttachmentType(NetworkAttachmentType_T *aAttachmentType)
412{
413 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
414
415 *aAttachmentType = mData->mode;
416
417 return S_OK;
418}
419
420HRESULT NetworkAdapter::setAttachmentType(NetworkAttachmentType_T aAttachmentType)
421{
422 /* the machine needs to be mutable */
423 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
424 if (FAILED(adep.rc())) return adep.rc();
425
426 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
427
428 if (mData->mode != aAttachmentType)
429 {
430 mData.backup();
431
432 /* there must an internal network name */
433 if (mData->strInternalNetworkName.isEmpty())
434 {
435 Log(("Internal network name not defined, setting to default \"intnet\"\n"));
436 mData->strInternalNetworkName = "intnet";
437 }
438
439 /* there must a NAT network name */
440 if (mData->strNATNetworkName.isEmpty())
441 {
442 Log(("NAT network name not defined, setting to default \"NatNetwork\"\n"));
443 mData->strNATNetworkName = "NatNetwork";
444 }
445
446 NetworkAttachmentType_T oldAttachmentType = mData->mode;
447 mData->mode = aAttachmentType;
448
449 // leave the lock before informing callbacks
450 alock.release();
451
452 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
453 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
454 mlock.release();
455
456 if (oldAttachmentType == NetworkAttachmentType_NATNetwork)
457 i_checkAndSwitchFromNatNetworking(mData->strNATNetworkName);
458
459 if (aAttachmentType == NetworkAttachmentType_NATNetwork)
460 i_switchToNatNetworking(mData->strNATNetworkName);
461
462 /* Adapt the CFGM logic and notify the guest => changeAdapter=TRUE. */
463 mParent->i_onNetworkAdapterChange(this, TRUE);
464 }
465
466 return S_OK;
467}
468
469HRESULT NetworkAdapter::getBridgedInterface(com::Utf8Str &aBridgedInterface)
470{
471 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
472
473 aBridgedInterface = mData->strBridgedName;
474
475 return S_OK;
476}
477
478HRESULT NetworkAdapter::setBridgedInterface(const com::Utf8Str &aBridgedInterface)
479{
480 /* the machine needs to be mutable */
481 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
482 if (FAILED(adep.rc())) return adep.rc();
483
484 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
485
486 if (mData->strBridgedName != aBridgedInterface)
487 {
488 /* if an empty/null string is to be set, bridged interface must be
489 * turned off */
490 if (aBridgedInterface.isEmpty()
491 && mData->mode == NetworkAttachmentType_Bridged)
492 {
493 return setError(E_FAIL,
494 tr("Empty or null bridged interface name is not valid"));
495 }
496
497 mData.backup();
498 mData->strBridgedName = aBridgedInterface;
499
500 // leave the lock before informing callbacks
501 alock.release();
502
503 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
504 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
505 mlock.release();
506
507 /* When changing the host adapter, adapt the CFGM logic to make this
508 * change immediately effect and to notify the guest that the network
509 * might have changed, therefore changeAdapter=TRUE. */
510 mParent->i_onNetworkAdapterChange(this, TRUE);
511 }
512
513 return S_OK;
514}
515
516HRESULT NetworkAdapter::getHostOnlyInterface(com::Utf8Str &aHostOnlyInterface)
517{
518 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
519
520 aHostOnlyInterface = mData->strHostOnlyName;
521
522 return S_OK;
523}
524
525HRESULT NetworkAdapter::setHostOnlyInterface(const com::Utf8Str &aHostOnlyInterface)
526{
527 /* the machine needs to be mutable */
528 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
529 if (FAILED(adep.rc())) return adep.rc();
530
531 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
532
533 if (mData->strHostOnlyName != aHostOnlyInterface)
534 {
535 /* if an empty/null string is to be set, host only interface must be
536 * turned off */
537 if ( aHostOnlyInterface.isEmpty()
538 && mData->mode == NetworkAttachmentType_HostOnly)
539 {
540 return setError(E_FAIL,
541 tr("Empty or null host only interface name is not valid"));
542 }
543
544 mData.backup();
545 mData->strHostOnlyName = aHostOnlyInterface;
546
547 // leave the lock before informing callbacks
548 alock.release();
549
550 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
551 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
552 mlock.release();
553
554 /* When changing the host adapter, adapt the CFGM logic to make this
555 * change immediately effect and to notify the guest that the network
556 * might have changed, therefore changeAdapter=TRUE. */
557 mParent->i_onNetworkAdapterChange(this, TRUE);
558 }
559
560 return S_OK;
561}
562
563
564HRESULT NetworkAdapter::getInternalNetwork(com::Utf8Str &aInternalNetwork)
565{
566 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
567
568 aInternalNetwork = mData->strInternalNetworkName;
569
570 return S_OK;
571}
572
573HRESULT NetworkAdapter::setInternalNetwork(const com::Utf8Str &aInternalNetwork)
574{
575 /* the machine needs to be mutable */
576 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
577 if (FAILED(adep.rc())) return adep.rc();
578
579 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
580
581 if (mData->strInternalNetworkName != aInternalNetwork)
582 {
583 /* if an empty/null string is to be set, internal networking must be
584 * turned off */
585 if (aInternalNetwork.isEmpty() && mData->mode == NetworkAttachmentType_Internal)
586 {
587 return setError(E_FAIL,
588 tr("Empty or null internal network name is not valid"));
589 }
590 mData.backup();
591 mData->strInternalNetworkName = aInternalNetwork;
592
593 // leave the lock before informing callbacks
594 alock.release();
595
596 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
597 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
598 mlock.release();
599
600 /* When changing the internal network, adapt the CFGM logic to make this
601 * change immediately effect and to notify the guest that the network
602 * might have changed, therefore changeAdapter=TRUE. */
603 mParent->i_onNetworkAdapterChange(this, TRUE);
604 }
605
606 return S_OK;
607}
608
609HRESULT NetworkAdapter::getNATNetwork(com::Utf8Str &aNATNetwork)
610{
611 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
612
613 aNATNetwork = mData->strNATNetworkName;
614
615 return S_OK;
616}
617
618
619HRESULT NetworkAdapter::setNATNetwork(const com::Utf8Str &aNATNetwork)
620{
621 /* the machine needs to be mutable */
622 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
623 if (FAILED(adep.rc())) return adep.rc();
624
625 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
626
627 if (mData->strNATNetworkName != aNATNetwork)
628 {
629 /* if an empty/null string is to be set, host only interface must be
630 * turned off */
631 if (aNATNetwork.isEmpty()
632 && mData->mode == NetworkAttachmentType_NATNetwork)
633 return setError(E_FAIL,
634 tr("Empty or null NAT network name is not valid"));
635
636 mData.backup();
637
638 Bstr oldNatNetworkName = mData->strNATNetworkName;
639 mData->strNATNetworkName = aNATNetwork;
640
641 // leave the lock before informing callbacks
642 alock.release();
643
644 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
645 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
646 mlock.release();
647 i_checkAndSwitchFromNatNetworking(oldNatNetworkName.raw());
648
649 i_switchToNatNetworking(aNATNetwork);
650 /* When changing the host adapter, adapt the CFGM logic to make this
651 * change immediately effect and to notify the guest that the network
652 * might have changed, therefore changeAdapter=TRUE. */
653 mParent->i_onNetworkAdapterChange(this, TRUE);
654 }
655
656 return S_OK;
657}
658
659HRESULT NetworkAdapter::getGenericDriver(com::Utf8Str &aGenericDriver)
660{
661 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
662
663 aGenericDriver = mData->strGenericDriver;
664
665 return S_OK;
666}
667
668HRESULT NetworkAdapter::setGenericDriver(const com::Utf8Str &aGenericDriver)
669{
670 /* the machine needs to be mutable */
671 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
672 if (FAILED(adep.rc())) return adep.rc();
673
674 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
675
676 if (mData->strGenericDriver != aGenericDriver)
677 {
678 mData.backup();
679 mData->strGenericDriver = aGenericDriver;
680
681 /* leave the lock before informing callbacks */
682 alock.release();
683
684 mParent->i_onNetworkAdapterChange(this, FALSE);
685 }
686
687 return S_OK;
688}
689
690
691HRESULT NetworkAdapter::getCableConnected(BOOL *aConnected)
692{
693 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
694
695 *aConnected = mData->fCableConnected;
696
697 return S_OK;
698}
699
700
701HRESULT NetworkAdapter::setCableConnected(BOOL aConnected)
702{
703 /* the machine needs to be mutable */
704 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
705 if (FAILED(adep.rc())) return adep.rc();
706
707 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
708
709 if (RT_BOOL(aConnected) != mData->fCableConnected)
710 {
711 mData.backup();
712 mData->fCableConnected = RT_BOOL(aConnected);
713
714 // leave the lock before informing callbacks
715 alock.release();
716
717 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
718 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
719 mlock.release();
720
721 /* No change in CFGM logic => changeAdapter=FALSE. */
722 mParent->i_onNetworkAdapterChange(this, FALSE);
723 }
724
725 return S_OK;
726}
727
728
729HRESULT NetworkAdapter::getLineSpeed(ULONG *aSpeed)
730{
731 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
732
733 *aSpeed = mData->ulLineSpeed;
734
735 return S_OK;
736}
737
738HRESULT NetworkAdapter::setLineSpeed(ULONG aSpeed)
739{
740 /* the machine needs to be mutable */
741 AutoMutableStateDependency adep(mParent);
742 if (FAILED(adep.rc())) return adep.rc();
743
744 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
745
746 if (aSpeed != mData->ulLineSpeed)
747 {
748 mData.backup();
749 mData->ulLineSpeed = aSpeed;
750
751 // leave the lock before informing callbacks
752 alock.release();
753
754 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
755 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
756 mlock.release();
757
758 /* No change in CFGM logic => changeAdapter=FALSE. */
759 mParent->i_onNetworkAdapterChange(this, FALSE);
760 }
761
762 return S_OK;
763}
764
765HRESULT NetworkAdapter::getPromiscModePolicy(NetworkAdapterPromiscModePolicy_T *aPromiscModePolicy)
766{
767 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
768
769 *aPromiscModePolicy = mData->enmPromiscModePolicy;
770
771 return S_OK;
772}
773
774HRESULT NetworkAdapter::setPromiscModePolicy(NetworkAdapterPromiscModePolicy_T aPromiscModePolicy)
775{
776 /* the machine needs to be mutable */
777 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
778 if (FAILED(adep.rc())) return adep.rc();
779
780 switch (aPromiscModePolicy)
781 {
782 case NetworkAdapterPromiscModePolicy_Deny:
783 case NetworkAdapterPromiscModePolicy_AllowNetwork:
784 case NetworkAdapterPromiscModePolicy_AllowAll:
785 break;
786 default:
787 return setError(E_INVALIDARG, tr("Invalid promiscuous mode policy (%d)"), aPromiscModePolicy);
788 }
789
790 AutoCaller autoCaller(this);
791 HRESULT hrc = autoCaller.rc();
792
793 if (SUCCEEDED(hrc))
794 {
795 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
796 if (aPromiscModePolicy != mData->enmPromiscModePolicy)
797 {
798 mData.backup();
799 mData->enmPromiscModePolicy = aPromiscModePolicy;
800
801 alock.release();
802 mParent->i_setModifiedLock(Machine::IsModified_NetworkAdapters);
803 mParent->i_onNetworkAdapterChange(this, TRUE);
804 }
805 }
806
807 return hrc;
808}
809
810
811HRESULT NetworkAdapter::getTraceEnabled(BOOL *aEnabled)
812{
813
814 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
815
816 *aEnabled = mData->fTraceEnabled;
817
818 return S_OK;
819}
820
821HRESULT NetworkAdapter::setTraceEnabled(BOOL aEnabled)
822{
823 /* the machine needs to be mutable */
824 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
825 if (FAILED(adep.rc())) return adep.rc();
826
827 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
828
829 if (RT_BOOL(aEnabled) != mData->fTraceEnabled)
830 {
831 mData.backup();
832 mData->fTraceEnabled = RT_BOOL(aEnabled);
833
834 // leave the lock before informing callbacks
835 alock.release();
836
837 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
838 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
839 mlock.release();
840
841 /* Adapt the CFGM logic changeAdapter=TRUE */
842 mParent->i_onNetworkAdapterChange(this, TRUE);
843 }
844
845 return S_OK;
846}
847
848HRESULT NetworkAdapter::getTraceFile(com::Utf8Str &aTraceFile)
849{
850 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
851
852 aTraceFile = mData->strTraceFile;
853
854 return S_OK;
855}
856
857
858HRESULT NetworkAdapter::setTraceFile(const com::Utf8Str &aTraceFile)
859{
860 /* the machine needs to be mutable */
861 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
862 if (FAILED(adep.rc())) return adep.rc();
863
864 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
865
866 if (mData->strTraceFile != aTraceFile)
867 {
868 mData.backup();
869 mData->strTraceFile = aTraceFile;
870
871 // leave the lock before informing callbacks
872 alock.release();
873
874 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
875 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
876 mlock.release();
877
878 /* We change the 'File' => changeAdapter=TRUE. */
879 mParent->i_onNetworkAdapterChange(this, TRUE);
880 }
881
882 return S_OK;
883}
884
885HRESULT NetworkAdapter::getNATEngine(ComPtr<INATEngine> &aNATEngine)
886{
887 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
888
889 aNATEngine = mNATEngine;
890
891 return S_OK;
892}
893
894HRESULT NetworkAdapter::getBootPriority(ULONG *aBootPriority)
895{
896 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
897
898 *aBootPriority = mData->ulBootPriority;
899
900 return S_OK;
901}
902
903HRESULT NetworkAdapter::setBootPriority(ULONG aBootPriority)
904{
905 /* the machine needs to be mutable */
906 AutoMutableStateDependency adep(mParent);
907 if (FAILED(adep.rc())) return adep.rc();
908
909 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
910
911 if (aBootPriority != mData->ulBootPriority)
912 {
913 mData.backup();
914 mData->ulBootPriority = aBootPriority;
915
916 // leave the lock before informing callbacks
917 alock.release();
918
919 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS); // mParent is const, no need to lock
920 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
921 mlock.release();
922
923 /* No change in CFGM logic => changeAdapter=FALSE. */
924 mParent->i_onNetworkAdapterChange(this, FALSE);
925 }
926
927 return S_OK;
928}
929
930// wrapped INetworkAdapter methods
931////////////////////////////////////////////////////////////////////////////////
932
933HRESULT NetworkAdapter::getProperty(const com::Utf8Str &aKey, com::Utf8Str &aValue)
934{
935 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
936 aValue = "";
937 settings::StringsMap::const_iterator it = mData->genericProperties.find(aKey);
938 if (it != mData->genericProperties.end())
939 aValue = it->second; // source is a Utf8Str
940
941 return S_OK;
942}
943
944HRESULT NetworkAdapter::setProperty(const com::Utf8Str &aKey, const com::Utf8Str &aValue)
945{
946 LogFlowThisFunc(("\n"));
947 /* The machine needs to be mutable. */
948 AutoMutableOrSavedOrRunningStateDependency adep(mParent);
949 if (FAILED(adep.rc())) return adep.rc();
950 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
951 bool fGenericChange = (mData->mode == NetworkAttachmentType_Generic);
952 /* Generic properties processing.
953 * Look up the old value first; if nothing's changed then do nothing.
954 */
955 Utf8Str strOldValue;
956 settings::StringsMap::const_iterator it = mData->genericProperties.find(aKey);
957 if (it != mData->genericProperties.end())
958 strOldValue = it->second;
959
960 if (strOldValue != aValue)
961 {
962 if (aValue.isEmpty())
963 mData->genericProperties.erase(aKey);
964 else
965 mData->genericProperties[aKey] = aValue;
966
967 /* leave the lock before informing callbacks */
968 alock.release();
969
970 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
971 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
972 mlock.release();
973
974 /* Avoid deadlock when the event triggers a call to a method of this
975 * interface. */
976 adep.release();
977
978 mParent->i_onNetworkAdapterChange(this, fGenericChange);
979 }
980
981 return S_OK;
982}
983
984HRESULT NetworkAdapter::getProperties(const com::Utf8Str &aNames,
985 std::vector<com::Utf8Str> &aReturnNames,
986 std::vector<com::Utf8Str> &aReturnValues)
987{
988 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
989
990 /// @todo make use of aNames according to the documentation
991 NOREF(aNames);
992 aReturnNames.resize(mData->genericProperties.size());
993 aReturnValues.resize(mData->genericProperties.size());
994
995 size_t i = 0;
996
997 for (settings::StringsMap::const_iterator it = mData->genericProperties.begin();
998 it != mData->genericProperties.end();
999 ++it, ++i)
1000 {
1001 aReturnNames[i] = it->first;
1002 aReturnValues[i] = it->second;
1003 }
1004
1005 return S_OK;
1006}
1007
1008
1009
1010// public methods only for internal purposes
1011////////////////////////////////////////////////////////////////////////////////
1012
1013/**
1014 * Loads settings from the given adapter node.
1015 * May be called once right after this object creation.
1016 *
1017 * @param bwctl bandwidth control object.
1018 * @param data Configuration settings.
1019 *
1020 * @note Locks this object for writing.
1021 */
1022HRESULT NetworkAdapter::i_loadSettings(BandwidthControl *bwctl,
1023 const settings::NetworkAdapter &data)
1024{
1025 AutoCaller autoCaller(this);
1026 AssertComRCReturnRC(autoCaller.rc());
1027
1028 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1029
1030 /* Note: we assume that the default values for attributes of optional
1031 * nodes are assigned in the Data::Data() constructor and don't do it
1032 * here. It implies that this method may only be called after constructing
1033 * a new BIOSSettings object while all its data fields are in the default
1034 * values. Exceptions are fields whose creation time defaults don't match
1035 * values that should be applied when these fields are not explicitly set
1036 * in the settings file (for backwards compatibility reasons). This takes
1037 * place when a setting of a newly created object must default to A while
1038 * the same setting of an object loaded from the old settings file must
1039 * default to B. */
1040
1041 HRESULT rc = S_OK;
1042
1043 /* MAC address (can be null) */
1044 rc = i_updateMacAddress(data.strMACAddress);
1045 if (FAILED(rc)) return rc;
1046
1047 mData.assignCopy(&data);
1048
1049 if (mData->strBandwidthGroup.isNotEmpty())
1050 {
1051 ComObjPtr<BandwidthGroup> group;
1052 rc = bwctl->i_getBandwidthGroupByName(data.strBandwidthGroup, group, true);
1053 if (FAILED(rc)) return rc;
1054 group->i_reference();
1055 }
1056
1057 // Load NAT engine settings.
1058 mNATEngine->i_loadSettings(data.nat);
1059
1060 // leave the lock before setting attachment type
1061 alock.release();
1062
1063 rc = COMSETTER(AttachmentType)(data.mode);
1064 if (FAILED(rc)) return rc;
1065
1066 return S_OK;
1067}
1068
1069/**
1070 * Saves settings to the given adapter node.
1071 *
1072 * Note that the given Adapter node is completely empty on input.
1073 *
1074 * @param data Configuration settings.
1075 *
1076 * @note Locks this object for reading.
1077 */
1078HRESULT NetworkAdapter::i_saveSettings(settings::NetworkAdapter &data)
1079{
1080 AutoCaller autoCaller(this);
1081 AssertComRCReturnRC(autoCaller.rc());
1082
1083 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1084
1085 data = *mData.data();
1086
1087 mNATEngine->i_saveSettings(data.nat);
1088
1089 return S_OK;
1090}
1091
1092/**
1093 * Returns true if any setter method has modified settings of this instance.
1094 * @return
1095 */
1096bool NetworkAdapter::i_isModified() {
1097
1098 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1099
1100 bool fChanged = mData.isBackedUp();
1101 fChanged |= (mData->type == NetworkAttachmentType_NAT? mNATEngine->i_isModified() : false);
1102 return fChanged;
1103}
1104
1105/**
1106 * @note Locks this object for writing.
1107 */
1108void NetworkAdapter::i_rollback()
1109{
1110 /* sanity */
1111 AutoCaller autoCaller(this);
1112 AssertComRCReturnVoid(autoCaller.rc());
1113
1114 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1115
1116 mNATEngine->i_rollback();
1117
1118 mData.rollback();
1119}
1120
1121/**
1122 * @note Locks this object for writing, together with the peer object (also
1123 * for writing) if there is one.
1124 */
1125void NetworkAdapter::i_commit()
1126{
1127 /* sanity */
1128 AutoCaller autoCaller(this);
1129 AssertComRCReturnVoid(autoCaller.rc());
1130
1131 /* sanity too */
1132 AutoCaller peerCaller(mPeer);
1133 AssertComRCReturnVoid(peerCaller.rc());
1134
1135 /* lock both for writing since we modify both (mPeer is "master" so locked
1136 * first) */
1137 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
1138
1139 mNATEngine->i_commit();
1140
1141 if (mData.isBackedUp())
1142 {
1143 mData.commit();
1144 if (mPeer)
1145 {
1146 /* attach new data to the peer and reshare it */
1147 mPeer->mData.attach(mData);
1148 }
1149 }
1150}
1151
1152/**
1153 * @note Locks this object for writing, together with the peer object
1154 * represented by @a aThat (locked for reading).
1155 */
1156void NetworkAdapter::i_copyFrom(NetworkAdapter *aThat)
1157{
1158 AssertReturnVoid(aThat != NULL);
1159
1160 /* sanity */
1161 AutoCaller autoCaller(this);
1162 AssertComRCReturnVoid(autoCaller.rc());
1163
1164 /* sanity too */
1165 AutoCaller thatCaller(aThat);
1166 AssertComRCReturnVoid(thatCaller.rc());
1167
1168 mNATEngine->i_copyFrom(aThat->mNATEngine);
1169
1170 /* peer is not modified, lock it for reading (aThat is "master" so locked
1171 * first) */
1172 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1173 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1174
1175 /* this will back up current data */
1176 mData.assignCopy(aThat->mData);
1177
1178}
1179
1180void NetworkAdapter::i_applyDefaults(GuestOSType *aOsType)
1181{
1182 AssertReturnVoid(aOsType != NULL);
1183
1184 /* sanity */
1185 AutoCaller autoCaller(this);
1186 AssertComRCReturnVoid(autoCaller.rc());
1187
1188 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1189
1190 bool e1000enabled = false;
1191#ifdef VBOX_WITH_E1000
1192 e1000enabled = true;
1193#endif // VBOX_WITH_E1000
1194
1195 NetworkAdapterType_T defaultType = aOsType->i_networkAdapterType();
1196
1197 /* Set default network adapter for this OS type */
1198 if (defaultType == NetworkAdapterType_I82540EM ||
1199 defaultType == NetworkAdapterType_I82543GC ||
1200 defaultType == NetworkAdapterType_I82545EM)
1201 {
1202 if (e1000enabled) mData->type = defaultType;
1203 }
1204 else mData->type = defaultType;
1205
1206 /* Enable the first one adapter to the NAT */
1207 if (mData->ulSlot == 0)
1208 {
1209 mData->fEnabled = true;
1210 if (mData->strMACAddress.isEmpty())
1211 i_generateMACAddress();
1212 mData->mode = NetworkAttachmentType_NAT;
1213 }
1214 mData->fCableConnected = true;
1215}
1216
1217ComObjPtr<NetworkAdapter> NetworkAdapter::i_getPeer()
1218{
1219 return mPeer;
1220}
1221
1222
1223// private methods
1224////////////////////////////////////////////////////////////////////////////////
1225
1226/**
1227 * Generates a new unique MAC address based on our vendor ID and
1228 * parts of a GUID.
1229 *
1230 * @note Must be called from under the object's write lock or within the init
1231 * span.
1232 */
1233void NetworkAdapter::i_generateMACAddress()
1234{
1235 Utf8Str mac;
1236 Host::i_generateMACAddress(mac);
1237 LogFlowThisFunc(("generated MAC: '%s'\n", mac.c_str()));
1238 mData->strMACAddress = mac;
1239}
1240
1241HRESULT NetworkAdapter::getBandwidthGroup(ComPtr<IBandwidthGroup> &aBandwidthGroup)
1242{
1243 LogFlowThisFuncEnter();
1244
1245 HRESULT hrc = S_OK;
1246
1247 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1248
1249 if (mData->strBandwidthGroup.isNotEmpty())
1250 {
1251 ComObjPtr<BandwidthGroup> pBwGroup;
1252 hrc = mParent->i_getBandwidthGroup(mData->strBandwidthGroup, pBwGroup, true /* fSetError */);
1253
1254 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence
1255 * of the group was checked when it was attached. */
1256 if (SUCCEEDED(hrc))
1257 pBwGroup.queryInterfaceTo(aBandwidthGroup.asOutParam());
1258 }
1259
1260 LogFlowThisFuncLeave();
1261 return hrc;
1262}
1263
1264HRESULT NetworkAdapter::setBandwidthGroup(const ComPtr<IBandwidthGroup> &aBandwidthGroup)
1265{
1266 LogFlowThisFuncEnter();
1267
1268 /* the machine needs to be mutable */
1269 AutoMutableOrSavedStateDependency adep(mParent);
1270 if (FAILED(adep.rc())) return adep.rc();
1271
1272 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1273
1274 IBandwidthGroup *iBw = aBandwidthGroup;
1275 Utf8Str strBwGroup;
1276 if (aBandwidthGroup)
1277 strBwGroup = static_cast<BandwidthGroup *>(iBw)->i_getName();
1278
1279 if (mData->strBandwidthGroup != strBwGroup)
1280 {
1281 ComObjPtr<BandwidthGroup> pBwGroup;
1282 if (!strBwGroup.isEmpty())
1283 {
1284 HRESULT hrc = mParent->i_getBandwidthGroup(strBwGroup, pBwGroup, false /* fSetError */);
1285 NOREF(hrc);
1286 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence
1287 of the group was checked when it was attached. */
1288 }
1289
1290 i_updateBandwidthGroup(pBwGroup);
1291
1292 // leave the lock before informing callbacks
1293 alock.release();
1294
1295 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
1296 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
1297 mlock.release();
1298
1299 /** @todo changeAdapter=???. */
1300 mParent->i_onNetworkAdapterChange(this, FALSE);
1301 }
1302
1303 LogFlowThisFuncLeave();
1304 return S_OK;
1305}
1306
1307void NetworkAdapter::i_updateBandwidthGroup(BandwidthGroup *aBwGroup)
1308{
1309 LogFlowThisFuncEnter();
1310 Assert(isWriteLockOnCurrentThread());
1311
1312 ComObjPtr<BandwidthGroup> pOldBwGroup;
1313 if (!mData->strBandwidthGroup.isEmpty())
1314 {
1315 HRESULT hrc = mParent->i_getBandwidthGroup(mData->strBandwidthGroup, pOldBwGroup, false /* fSetError */);
1316 NOREF(hrc);
1317 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of
1318 the group was checked when it was attached. */
1319 }
1320
1321 mData.backup();
1322 if (!pOldBwGroup.isNull())
1323 {
1324 pOldBwGroup->i_release();
1325 mData->strBandwidthGroup = Utf8Str::Empty;
1326 }
1327
1328 if (aBwGroup)
1329 {
1330 mData->strBandwidthGroup = aBwGroup->i_getName();
1331 aBwGroup->i_reference();
1332 }
1333
1334 LogFlowThisFuncLeave();
1335}
1336
1337
1338HRESULT NetworkAdapter::i_checkAndSwitchFromNatNetworking(com::Utf8Str networkName)
1339{
1340 HRESULT hrc;
1341 MachineState_T state;
1342
1343 hrc = mParent->COMGETTER(State)(&state);
1344 if (FAILED(hrc))
1345 return hrc;
1346
1347 if ( state == MachineState_Running
1348 || state == MachineState_Paused)
1349 {
1350 Bstr bstrName;
1351 hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
1352 LogRel(("VM '%ls' stops using NAT network '%s'\n", bstrName.raw(), networkName.c_str()));
1353 int natCount = mParent->i_getVirtualBox()->i_natNetworkRefDec(Bstr(networkName).raw());
1354 if (natCount == -1)
1355 return E_INVALIDARG; /* no such network */
1356 }
1357
1358 return S_OK;
1359}
1360
1361
1362HRESULT NetworkAdapter::i_switchToNatNetworking(const com::Utf8Str &aNatNetworkName)
1363{
1364 HRESULT hrc;
1365 MachineState_T state;
1366
1367 hrc = mParent->COMGETTER(State)(&state);
1368 if (FAILED(hrc))
1369 return hrc;
1370
1371 if ( state == MachineState_Running
1372 || state == MachineState_Paused)
1373 {
1374 Bstr bstrName;
1375 hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
1376 LogRel(("VM '%ls' starts using NAT network '%s'\n", bstrName.raw(), aNatNetworkName.c_str()));
1377 int natCount = mParent->i_getVirtualBox()->i_natNetworkRefInc(Bstr(aNatNetworkName).raw());
1378 if (natCount == -1)
1379 return E_INVALIDARG; /* not found */
1380 }
1381
1382 return S_OK;
1383}
1384/* 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