VirtualBox

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

Last change on this file since 107402 was 107267, checked in by vboxsync, 2 months ago

Main/API,UI: bugref:10810 Based on Brent's patch, added UsbNet support into Main API and UI

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