VirtualBox

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

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

scm: cleaning up todos

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.3 KB
Line 
1/* $Id: NetworkAdapterImpl.cpp 63563 2016-08-16 14:04:28Z 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 aAdapterNode <Adapter> node.
1018 *
1019 * @note Locks this object for writing.
1020 */
1021HRESULT NetworkAdapter::i_loadSettings(BandwidthControl *bwctl,
1022 const settings::NetworkAdapter &data)
1023{
1024 AutoCaller autoCaller(this);
1025 AssertComRCReturnRC(autoCaller.rc());
1026
1027 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1028
1029 /* Note: we assume that the default values for attributes of optional
1030 * nodes are assigned in the Data::Data() constructor and don't do it
1031 * here. It implies that this method may only be called after constructing
1032 * a new BIOSSettings object while all its data fields are in the default
1033 * values. Exceptions are fields whose creation time defaults don't match
1034 * values that should be applied when these fields are not explicitly set
1035 * in the settings file (for backwards compatibility reasons). This takes
1036 * place when a setting of a newly created object must default to A while
1037 * the same setting of an object loaded from the old settings file must
1038 * default to B. */
1039
1040 HRESULT rc = S_OK;
1041
1042 /* MAC address (can be null) */
1043 rc = i_updateMacAddress(data.strMACAddress);
1044 if (FAILED(rc)) return rc;
1045
1046 mData.assignCopy(&data);
1047
1048 if (mData->strBandwidthGroup.isNotEmpty())
1049 {
1050 ComObjPtr<BandwidthGroup> group;
1051 rc = bwctl->i_getBandwidthGroupByName(data.strBandwidthGroup, group, true);
1052 if (FAILED(rc)) return rc;
1053 group->i_reference();
1054 }
1055
1056 // Load NAT engine settings.
1057 mNATEngine->i_loadSettings(data.nat);
1058
1059 // leave the lock before setting attachment type
1060 alock.release();
1061
1062 rc = COMSETTER(AttachmentType)(data.mode);
1063 if (FAILED(rc)) return rc;
1064
1065 return S_OK;
1066}
1067
1068/**
1069 * Saves settings to the given adapter node.
1070 *
1071 * Note that the given Adapter node is completely empty on input.
1072 *
1073 * @param aAdapterNode <Adapter> node.
1074 *
1075 * @note Locks this object for reading.
1076 */
1077HRESULT NetworkAdapter::i_saveSettings(settings::NetworkAdapter &data)
1078{
1079 AutoCaller autoCaller(this);
1080 AssertComRCReturnRC(autoCaller.rc());
1081
1082 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1083
1084 data = *mData.data();
1085
1086 mNATEngine->i_saveSettings(data.nat);
1087
1088 return S_OK;
1089}
1090
1091/**
1092 * Returns true if any setter method has modified settings of this instance.
1093 * @return
1094 */
1095bool NetworkAdapter::i_isModified() {
1096
1097 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1098
1099 bool fChanged = mData.isBackedUp();
1100 fChanged |= (mData->type == NetworkAttachmentType_NAT? mNATEngine->i_isModified() : false);
1101 return fChanged;
1102}
1103
1104/**
1105 * @note Locks this object for writing.
1106 */
1107void NetworkAdapter::i_rollback()
1108{
1109 /* sanity */
1110 AutoCaller autoCaller(this);
1111 AssertComRCReturnVoid(autoCaller.rc());
1112
1113 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1114
1115 mNATEngine->i_rollback();
1116
1117 mData.rollback();
1118}
1119
1120/**
1121 * @note Locks this object for writing, together with the peer object (also
1122 * for writing) if there is one.
1123 */
1124void NetworkAdapter::i_commit()
1125{
1126 /* sanity */
1127 AutoCaller autoCaller(this);
1128 AssertComRCReturnVoid(autoCaller.rc());
1129
1130 /* sanity too */
1131 AutoCaller peerCaller(mPeer);
1132 AssertComRCReturnVoid(peerCaller.rc());
1133
1134 /* lock both for writing since we modify both (mPeer is "master" so locked
1135 * first) */
1136 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
1137
1138 mNATEngine->i_commit();
1139
1140 if (mData.isBackedUp())
1141 {
1142 mData.commit();
1143 if (mPeer)
1144 {
1145 /* attach new data to the peer and reshare it */
1146 mPeer->mData.attach(mData);
1147 }
1148 }
1149}
1150
1151/**
1152 * @note Locks this object for writing, together with the peer object
1153 * represented by @a aThat (locked for reading).
1154 */
1155void NetworkAdapter::i_copyFrom(NetworkAdapter *aThat)
1156{
1157 AssertReturnVoid(aThat != NULL);
1158
1159 /* sanity */
1160 AutoCaller autoCaller(this);
1161 AssertComRCReturnVoid(autoCaller.rc());
1162
1163 /* sanity too */
1164 AutoCaller thatCaller(aThat);
1165 AssertComRCReturnVoid(thatCaller.rc());
1166
1167 mNATEngine->i_copyFrom(aThat->mNATEngine);
1168
1169 /* peer is not modified, lock it for reading (aThat is "master" so locked
1170 * first) */
1171 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1172 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1173
1174 /* this will back up current data */
1175 mData.assignCopy(aThat->mData);
1176
1177}
1178
1179void NetworkAdapter::i_applyDefaults(GuestOSType *aOsType)
1180{
1181 AssertReturnVoid(aOsType != NULL);
1182
1183 /* sanity */
1184 AutoCaller autoCaller(this);
1185 AssertComRCReturnVoid(autoCaller.rc());
1186
1187 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1188
1189 bool e1000enabled = false;
1190#ifdef VBOX_WITH_E1000
1191 e1000enabled = true;
1192#endif // VBOX_WITH_E1000
1193
1194 NetworkAdapterType_T defaultType = aOsType->i_networkAdapterType();
1195
1196 /* Set default network adapter for this OS type */
1197 if (defaultType == NetworkAdapterType_I82540EM ||
1198 defaultType == NetworkAdapterType_I82543GC ||
1199 defaultType == NetworkAdapterType_I82545EM)
1200 {
1201 if (e1000enabled) mData->type = defaultType;
1202 }
1203 else mData->type = defaultType;
1204
1205 /* Enable the first one adapter to the NAT */
1206 if (mData->ulSlot == 0)
1207 {
1208 mData->fEnabled = true;
1209 if (mData->strMACAddress.isEmpty())
1210 i_generateMACAddress();
1211 mData->mode = NetworkAttachmentType_NAT;
1212 }
1213 mData->fCableConnected = true;
1214}
1215
1216ComObjPtr<NetworkAdapter> NetworkAdapter::i_getPeer()
1217{
1218 return mPeer;
1219}
1220
1221
1222// private methods
1223////////////////////////////////////////////////////////////////////////////////
1224
1225/**
1226 * Generates a new unique MAC address based on our vendor ID and
1227 * parts of a GUID.
1228 *
1229 * @note Must be called from under the object's write lock or within the init
1230 * span.
1231 */
1232void NetworkAdapter::i_generateMACAddress()
1233{
1234 Utf8Str mac;
1235 Host::i_generateMACAddress(mac);
1236 LogFlowThisFunc(("generated MAC: '%s'\n", mac.c_str()));
1237 mData->strMACAddress = mac;
1238}
1239
1240HRESULT NetworkAdapter::getBandwidthGroup(ComPtr<IBandwidthGroup> &aBandwidthGroup)
1241{
1242 LogFlowThisFuncEnter();
1243
1244 HRESULT hrc = S_OK;
1245
1246 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1247
1248 if (mData->strBandwidthGroup.isNotEmpty())
1249 {
1250 ComObjPtr<BandwidthGroup> pBwGroup;
1251 hrc = mParent->i_getBandwidthGroup(mData->strBandwidthGroup, pBwGroup, true /* fSetError */);
1252
1253 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence
1254 * of the group was checked when it was attached. */
1255 if (SUCCEEDED(hrc))
1256 pBwGroup.queryInterfaceTo(aBandwidthGroup.asOutParam());
1257 }
1258
1259 LogFlowThisFuncLeave();
1260 return hrc;
1261}
1262
1263HRESULT NetworkAdapter::setBandwidthGroup(const ComPtr<IBandwidthGroup> &aBandwidthGroup)
1264{
1265 LogFlowThisFuncEnter();
1266
1267 /* the machine needs to be mutable */
1268 AutoMutableOrSavedStateDependency adep(mParent);
1269 if (FAILED(adep.rc())) return adep.rc();
1270
1271 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1272
1273 IBandwidthGroup *iBw = aBandwidthGroup;
1274 Utf8Str strBwGroup;
1275 if (aBandwidthGroup)
1276 strBwGroup = static_cast<BandwidthGroup *>(iBw)->i_getName();
1277
1278 if (mData->strBandwidthGroup != strBwGroup)
1279 {
1280 ComObjPtr<BandwidthGroup> pBwGroup;
1281 if (!strBwGroup.isEmpty())
1282 {
1283 HRESULT hrc = mParent->i_getBandwidthGroup(strBwGroup, pBwGroup, false /* fSetError */);
1284 NOREF(hrc);
1285 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence
1286 of the group was checked when it was attached. */
1287 }
1288
1289 i_updateBandwidthGroup(pBwGroup);
1290
1291 // leave the lock before informing callbacks
1292 alock.release();
1293
1294 AutoWriteLock mlock(mParent COMMA_LOCKVAL_SRC_POS);
1295 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
1296 mlock.release();
1297
1298 /** @todo changeAdapter=???. */
1299 mParent->i_onNetworkAdapterChange(this, FALSE);
1300 }
1301
1302 LogFlowThisFuncLeave();
1303 return S_OK;
1304}
1305
1306void NetworkAdapter::i_updateBandwidthGroup(BandwidthGroup *aBwGroup)
1307{
1308 LogFlowThisFuncEnter();
1309 Assert(isWriteLockOnCurrentThread());
1310
1311 ComObjPtr<BandwidthGroup> pOldBwGroup;
1312 if (!mData->strBandwidthGroup.isEmpty())
1313 {
1314 HRESULT hrc = mParent->i_getBandwidthGroup(mData->strBandwidthGroup, pOldBwGroup, false /* fSetError */);
1315 NOREF(hrc);
1316 Assert(SUCCEEDED(hrc)); /* This is not allowed to fail because the existence of
1317 the group was checked when it was attached. */
1318 }
1319
1320 mData.backup();
1321 if (!pOldBwGroup.isNull())
1322 {
1323 pOldBwGroup->i_release();
1324 mData->strBandwidthGroup = Utf8Str::Empty;
1325 }
1326
1327 if (aBwGroup)
1328 {
1329 mData->strBandwidthGroup = aBwGroup->i_getName();
1330 aBwGroup->i_reference();
1331 }
1332
1333 LogFlowThisFuncLeave();
1334}
1335
1336
1337HRESULT NetworkAdapter::i_checkAndSwitchFromNatNetworking(com::Utf8Str networkName)
1338{
1339 HRESULT hrc;
1340 MachineState_T state;
1341
1342 hrc = mParent->COMGETTER(State)(&state);
1343 if (FAILED(hrc))
1344 return hrc;
1345
1346 if ( state == MachineState_Running
1347 || state == MachineState_Paused)
1348 {
1349 Bstr bstrName;
1350 hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
1351 LogRel(("VM '%ls' stops using NAT network '%s'\n", bstrName.raw(), networkName.c_str()));
1352 int natCount = mParent->i_getVirtualBox()->i_natNetworkRefDec(Bstr(networkName).raw());
1353 if (natCount == -1)
1354 return E_INVALIDARG; /* no such network */
1355 }
1356
1357 return S_OK;
1358}
1359
1360
1361HRESULT NetworkAdapter::i_switchToNatNetworking(const com::Utf8Str &aNatNetworkName)
1362{
1363 HRESULT hrc;
1364 MachineState_T state;
1365
1366 hrc = mParent->COMGETTER(State)(&state);
1367 if (FAILED(hrc))
1368 return hrc;
1369
1370 if ( state == MachineState_Running
1371 || state == MachineState_Paused)
1372 {
1373 Bstr bstrName;
1374 hrc = mParent->COMGETTER(Name)(bstrName.asOutParam());
1375 LogRel(("VM '%ls' starts using NAT network '%s'\n", bstrName.raw(), aNatNetworkName.c_str()));
1376 int natCount = mParent->i_getVirtualBox()->i_natNetworkRefInc(Bstr(aNatNetworkName).raw());
1377 if (natCount == -1)
1378 return E_INVALIDARG; /* not found */
1379 }
1380
1381 return S_OK;
1382}
1383/* 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