VirtualBox

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

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