VirtualBox

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

Last change on this file since 13538 was 10898, checked in by vboxsync, 16 years ago

Main: Host interface networking on Darwin.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.4 KB
RevLine 
[1]1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
[8155]7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
[1]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
[5999]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.
[8155]16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
[1]20 */
21
22#include "NetworkAdapterImpl.h"
23#include "Logging.h"
24#include "MachineImpl.h"
25
26#include <iprt/string.h>
[3348]27#include <iprt/cpputils.h>
[1]28
[3348]29#include <VBox/err.h>
[1]30
31// constructor / destructor
32////////////////////////////////////////////////////////////////////////////////
33
[3348]34DEFINE_EMPTY_CTOR_DTOR (NetworkAdapter)
35
[1]36HRESULT NetworkAdapter::FinalConstruct()
37{
38 return S_OK;
39}
40
41void NetworkAdapter::FinalRelease()
42{
[3348]43 uninit ();
[1]44}
45
46// public initializer/uninitializer for internal purposes only
47////////////////////////////////////////////////////////////////////////////////
48
49/**
[3348]50 * Initializes the network adapter object.
[1]51 *
[3348]52 * @param aParent Handle of the parent object.
[1]53 */
[3348]54HRESULT NetworkAdapter::init (Machine *aParent, ULONG aSlot)
[1]55{
[3348]56 LogFlowThisFunc (("aParent=%p, aSlot=%d\n", aParent, aSlot));
[1]57
[3348]58 ComAssertRet (aParent, E_INVALIDARG);
59 ComAssertRet (aSlot < SchemaDefs::NetworkAdapterCount, E_INVALIDARG);
[1]60
[3348]61 /* Enclose the state transition NotReady->InInit->Ready */
62 AutoInitSpan autoInitSpan (this);
63 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
[1]64
[3348]65 unconst (mParent) = aParent;
66 /* mPeer is left null */
[1]67
68 mData.allocate();
69
[3348]70 /* initialize data */
71 mData->mSlot = aSlot;
[1]72
[3348]73 /* default to Am79C973 */
[7207]74 mData->mAdapterType = NetworkAdapterType_Am79C973;
[1]75
[3348]76 /* generate the MAC address early to guarantee it is the same both after
77 * changing some other property (i.e. after mData.backup()) and after the
78 * subsequent mData.rollback(). */
[1]79 generateMACAddress();
80
[3348]81 /* Confirm a successful initialization */
82 autoInitSpan.setSucceeded();
83
[1]84 return S_OK;
85}
86
87/**
88 * Initializes the network adapter object given another network adapter object
89 * (a kind of copy constructor). This object shares data with
90 * the object passed as an argument.
91 *
92 * @note This object must be destroyed before the original object
93 * it shares data with is destroyed.
[3348]94 *
95 * @note Locks @a aThat object for reading.
[1]96 */
[3348]97HRESULT NetworkAdapter::init (Machine *aParent, NetworkAdapter *aThat)
[1]98{
[3348]99 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
[1]100
[3348]101 ComAssertRet (aParent && aThat, E_INVALIDARG);
[1]102
[3348]103 /* Enclose the state transition NotReady->InInit->Ready */
104 AutoInitSpan autoInitSpan (this);
105 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
[1]106
[3348]107 unconst (mParent) = aParent;
108 unconst (mPeer) = aThat;
[1]109
[3348]110 AutoCaller thatCaller (aThat);
111 AssertComRCReturnRC (thatCaller.rc());
[1]112
[8083]113 AutoReadLock thatLock (aThat);
[3348]114 mData.share (aThat->mData);
115
116 /* Confirm a successful initialization */
117 autoInitSpan.setSucceeded();
118
[1]119 return S_OK;
120}
121
122/**
123 * Initializes the guest object given another guest object
124 * (a kind of copy constructor). This object makes a private copy of data
125 * of the original object passed as an argument.
[3348]126 *
127 * @note Locks @a aThat object for reading.
[1]128 */
[3348]129HRESULT NetworkAdapter::initCopy (Machine *aParent, NetworkAdapter *aThat)
[1]130{
[3348]131 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
[1]132
[3348]133 ComAssertRet (aParent && aThat, E_INVALIDARG);
[1]134
[3348]135 /* Enclose the state transition NotReady->InInit->Ready */
136 AutoInitSpan autoInitSpan (this);
137 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
[1]138
[3348]139 unconst (mParent) = aParent;
140 /* mPeer is left null */
[1]141
[3348]142 AutoCaller thatCaller (aThat);
143 AssertComRCReturnRC (thatCaller.rc());
[1]144
[8083]145 AutoReadLock thatLock (aThat);
[3348]146 mData.attachCopy (aThat->mData);
147
148 /* Confirm a successful initialization */
149 autoInitSpan.setSucceeded();
150
[1]151 return S_OK;
152}
153
154/**
155 * Uninitializes the instance and sets the ready flag to FALSE.
156 * Called either from FinalRelease() or by the parent when it gets destroyed.
157 */
158void NetworkAdapter::uninit()
159{
[3348]160 LogFlowThisFunc (("\n"));
[1]161
[3348]162 /* Enclose the state transition Ready->InUninit->NotReady */
163 AutoUninitSpan autoUninitSpan (this);
164 if (autoUninitSpan.uninitDone())
165 return;
[1]166
167 mData.free();
168
[3348]169 unconst (mPeer).setNull();
170 unconst (mParent).setNull();
[1]171}
172
173// INetworkAdapter properties
174////////////////////////////////////////////////////////////////////////////////
175
[3348]176STDMETHODIMP NetworkAdapter::COMGETTER(AdapterType) (NetworkAdapterType_T *aAdapterType)
[1]177{
[3348]178 if (!aAdapterType)
[1]179 return E_POINTER;
180
[3348]181 AutoCaller autoCaller (this);
182 CheckComRCReturnRC (autoCaller.rc());
[1]183
[8083]184 AutoReadLock alock (this);
[3348]185
186 *aAdapterType = mData->mAdapterType;
187
[1]188 return S_OK;
189}
190
[3348]191STDMETHODIMP NetworkAdapter::COMSETTER(AdapterType) (NetworkAdapterType_T aAdapterType)
[1]192{
[3348]193 AutoCaller autoCaller (this);
194 CheckComRCReturnRC (autoCaller.rc());
[1]195
[3348]196 /* the machine needs to be mutable */
197 Machine::AutoMutableStateDependency adep (mParent);
198 CheckComRCReturnRC (adep.rc());
[1]199
[8083]200 AutoWriteLock alock (this);
[3348]201
[1]202 /* make sure the value is allowed */
[3348]203 switch (aAdapterType)
[1]204 {
[7207]205 case NetworkAdapterType_Am79C970A:
206 case NetworkAdapterType_Am79C973:
[5755]207#ifdef VBOX_WITH_E1000
[7207]208 case NetworkAdapterType_I82540EM:
[8439]209 case NetworkAdapterType_I82543GC:
[5755]210#endif
[1]211 break;
212 default:
[3348]213 return setError (E_FAIL,
214 tr("Invalid network adapter type '%d'"),
215 aAdapterType);
[1]216 }
217
[3348]218 if (mData->mAdapterType != aAdapterType)
[1]219 {
220 mData.backup();
[3348]221 mData->mAdapterType = aAdapterType;
[1]222
[3348]223 /* leave the lock before informing callbacks */
[1]224 alock.unlock();
[3348]225
[1]226 mParent->onNetworkAdapterChange (this);
227 }
228
229 return S_OK;
230}
231
[3348]232STDMETHODIMP NetworkAdapter::COMGETTER(Slot) (ULONG *aSlot)
[1]233{
[3348]234 if (!aSlot)
[1]235 return E_POINTER;
236
[3348]237 AutoCaller autoCaller (this);
238 CheckComRCReturnRC (autoCaller.rc());
[1]239
[8083]240 AutoReadLock alock (this);
[3348]241
242 *aSlot = mData->mSlot;
243
[1]244 return S_OK;
245}
246
[3348]247STDMETHODIMP NetworkAdapter::COMGETTER(Enabled) (BOOL *aEnabled)
[1]248{
[3348]249 if (!aEnabled)
[1]250 return E_POINTER;
251
[3348]252 AutoCaller autoCaller (this);
253 CheckComRCReturnRC (autoCaller.rc());
[1]254
[8083]255 AutoReadLock alock (this);
[3348]256
257 *aEnabled = mData->mEnabled;
258
[1]259 return S_OK;
260}
261
[3348]262STDMETHODIMP NetworkAdapter::COMSETTER(Enabled) (BOOL aEnabled)
[1]263{
[3348]264 AutoCaller autoCaller (this);
265 CheckComRCReturnRC (autoCaller.rc());
[1]266
[3348]267 /* the machine needs to be mutable */
268 Machine::AutoMutableStateDependency adep (mParent);
269 CheckComRCReturnRC (adep.rc());
[1]270
[8083]271 AutoWriteLock alock (this);
[3348]272
273 if (mData->mEnabled != aEnabled)
[1]274 {
275 mData.backup();
[3348]276 mData->mEnabled = aEnabled;
[1]277
[3348]278 /* leave the lock before informing callbacks */
[1]279 alock.unlock();
[3348]280
[1]281 mParent->onNetworkAdapterChange (this);
282 }
283
284 return S_OK;
285}
286
[3348]287STDMETHODIMP NetworkAdapter::COMGETTER(MACAddress)(BSTR *aMACAddress)
[1]288{
[3348]289 if (!aMACAddress)
[1]290 return E_POINTER;
291
[3348]292 AutoCaller autoCaller (this);
293 CheckComRCReturnRC (autoCaller.rc());
[1]294
[8083]295 AutoReadLock alock (this);
[3348]296
[1]297 ComAssertRet (!!mData->mMACAddress, E_FAIL);
298
[3348]299 mData->mMACAddress.cloneTo (aMACAddress);
[1]300
301 return S_OK;
302}
303
[3348]304STDMETHODIMP NetworkAdapter::COMSETTER(MACAddress)(INPTR BSTR aMACAddress)
[1]305{
[3348]306 AutoCaller autoCaller (this);
307 CheckComRCReturnRC (autoCaller.rc());
[1]308
[3348]309 /* the machine needs to be mutable */
310 Machine::AutoMutableStateDependency adep (mParent);
311 CheckComRCReturnRC (adep.rc());
[1]312
[8083]313 AutoWriteLock alock (this);
[3348]314
[1]315 HRESULT rc = S_OK;
316 bool emitChangeEvent = false;
317
318 /*
319 * Are we supposed to generate a MAC?
320 */
[3348]321 if (!aMACAddress)
[1]322 {
323 mData.backup();
[3348]324
[1]325 generateMACAddress();
326 emitChangeEvent = true;
327 }
328 else
329 {
[3348]330 if (mData->mMACAddress != aMACAddress)
[1]331 {
332 /*
333 * Verify given MAC address
334 */
[3348]335 Utf8Str macAddressUtf = aMACAddress;
[5117]336 char *macAddressStr = macAddressUtf.mutableRaw();
[1]337 int i = 0;
[5117]338 while ((i < 13) && macAddressStr && *macAddressStr && (rc == S_OK))
[1]339 {
340 char c = *macAddressStr;
[5117]341 /* canonicalize hex digits to capital letters */
342 if (c >= 'a' && c <= 'f')
343 {
344 /** @todo the runtime lacks an ascii lower/upper conv */
345 c &= 0xdf;
346 *macAddressStr = c;
347 }
[1]348 /* we only accept capital letters */
349 if (((c < '0') || (c > '9')) &&
350 ((c < 'A') || (c > 'F')))
351 rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
[5378]352 /* the second digit must have even value for unicast addresses */
353 if ((i == 1) && (!!(c & 1) == (c >= '0' && c <= '9')))
[5117]354 rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
[5120]355
[1]356 macAddressStr++;
357 i++;
358 }
359 /* we must have parsed exactly 12 characters */
360 if (i != 12)
361 rc = setError(E_INVALIDARG, tr("Invalid MAC address format"));
362
363 if (SUCCEEDED (rc))
364 {
365 mData.backup();
[3348]366
[5117]367 mData->mMACAddress = macAddressUtf;
[1]368 emitChangeEvent = true;
369 }
370 }
371 }
372
373 if (emitChangeEvent)
374 {
[3348]375 /* leave the lock before informing callbacks */
[1]376 alock.unlock();
[3348]377
[1]378 mParent->onNetworkAdapterChange (this);
379 }
380
381 return rc;
382}
383
[3348]384STDMETHODIMP NetworkAdapter::COMGETTER(AttachmentType)(
385 NetworkAttachmentType_T *aAttachmentType)
[1]386{
[3348]387 if (!aAttachmentType)
[1]388 return E_POINTER;
389
[3348]390 AutoCaller autoCaller (this);
391 CheckComRCReturnRC (autoCaller.rc());
[1]392
[8083]393 AutoReadLock alock (this);
[3348]394
395 *aAttachmentType = mData->mAttachmentType;
396
[1]397 return S_OK;
398}
399
[3348]400STDMETHODIMP NetworkAdapter::COMGETTER(HostInterface)(BSTR *aHostInterface)
[1]401{
[3348]402 if (!aHostInterface)
[1]403 return E_POINTER;
404
[3348]405 AutoCaller autoCaller (this);
406 CheckComRCReturnRC (autoCaller.rc());
[1]407
[8083]408 AutoReadLock alock (this);
[3348]409
410 mData->mHostInterface.cloneTo (aHostInterface);
411
[1]412 return S_OK;
413}
414
[3348]415STDMETHODIMP NetworkAdapter::COMSETTER(HostInterface)(INPTR BSTR aHostInterface)
[1]416{
417 /** @todo Validate input string length. r=dmik: do it in XML schema?*/
418
[10898]419#ifndef VBOX_WITH_UNIXY_TAP_NETWORKING
[1]420 // we don't allow null strings for the host interface on Win32
[10898]421 // (because the @name attribute of <HostInterface> must be always present,
[1]422 // but can be empty).
[3348]423 if (!aHostInterface)
[1]424 return E_INVALIDARG;
[10898]425#else
[1]426 // empty strings are not allowed as path names
[3348]427 if (aHostInterface && !(*aHostInterface))
[1]428 return E_INVALIDARG;
429#endif
430
[8367]431 AutoCaller autoCaller (this);
[3348]432 CheckComRCReturnRC (autoCaller.rc());
[1]433
[3348]434 /* the machine needs to be mutable */
435 Machine::AutoMutableStateDependency adep (mParent);
436 CheckComRCReturnRC (adep.rc());
[1]437
[8083]438 AutoWriteLock alock (this);
[3348]439
440 if (mData->mHostInterface != aHostInterface)
[1]441 {
442 mData.backup();
[3348]443 mData->mHostInterface = aHostInterface;
[1]444
[3348]445 /* leave the lock before informing callbacks */
[1]446 alock.unlock();
[3348]447
448 mParent->onNetworkAdapterChange (this);
[1]449 }
450
451 return S_OK;
452}
453
[10898]454#ifndef RT_OS_WINDOWS /** @todo ifdef VBOX_WITH_UNIXY_TAP_NETWORKING: need to find a way to exclude this in the xidl... */
[3348]455
456STDMETHODIMP NetworkAdapter::COMGETTER(TAPFileDescriptor)(LONG *aTAPFileDescriptor)
[1]457{
[10898]458# ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
[3348]459 if (!aTAPFileDescriptor)
[1]460 return E_POINTER;
461
[3348]462 AutoCaller autoCaller (this);
463 CheckComRCReturnRC (autoCaller.rc());
[1]464
[8083]465 AutoReadLock alock (this);
[1]466
[3348]467 *aTAPFileDescriptor = mData->mTAPFD;
468
[1]469 return S_OK;
[10898]470
471#else
472 return E_NOTIMPL;
473#endif
[1]474}
475
[3348]476STDMETHODIMP NetworkAdapter::COMSETTER(TAPFileDescriptor)(LONG aTAPFileDescriptor)
[1]477{
[10898]478# ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
[1]479 /*
480 * Validate input.
481 */
[3348]482 RTFILE tapFD = aTAPFileDescriptor;
483 if (tapFD != NIL_RTFILE && (LONG)tapFD != aTAPFileDescriptor)
[1]484 {
[3348]485 AssertMsgFailed(("Invalid file descriptor: %ld.\n", aTAPFileDescriptor));
[1]486 return setError (E_INVALIDARG,
[3348]487 tr ("Invalid file descriptor: %ld"), aTAPFileDescriptor);
[1]488 }
489
[3348]490 AutoCaller autoCaller (this);
491 CheckComRCReturnRC (autoCaller.rc());
[1]492
[3348]493 /* the machine needs to be mutable */
494 Machine::AutoMutableStateDependency adep (mParent);
495 CheckComRCReturnRC (adep.rc());
[1]496
[8083]497 AutoWriteLock alock (this);
[3348]498
499 if (mData->mTAPFD != (RTFILE) aTAPFileDescriptor)
[1]500 {
501 mData.backup();
[3348]502 mData->mTAPFD = aTAPFileDescriptor;
[1]503
[3348]504 /* leave the lock before informing callbacks */
[1]505 alock.unlock();
[3348]506
507 mParent->onNetworkAdapterChange (this);
[1]508 }
509
510 return S_OK;
[10898]511#else
512 return E_NOTIMPL;
513#endif
[1]514}
515
[3348]516STDMETHODIMP NetworkAdapter::COMGETTER(TAPSetupApplication) (
517 BSTR *aTAPSetupApplication)
[1]518{
[10898]519# ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
[3348]520 if (!aTAPSetupApplication)
[1]521 return E_POINTER;
522
[3348]523 AutoCaller autoCaller (this);
524 CheckComRCReturnRC (autoCaller.rc());
525
[8083]526 AutoReadLock alock (this);
[3348]527
[1]528 /* we don't have to be in TAP mode to support this call */
[3348]529 mData->mTAPSetupApplication.cloneTo (aTAPSetupApplication);
[1]530
531 return S_OK;
[10898]532#else
533 return E_NOTIMPL;
534#endif
[1]535}
536
[3348]537STDMETHODIMP NetworkAdapter::COMSETTER(TAPSetupApplication) (
538 INPTR BSTR aTAPSetupApplication)
[1]539{
[10898]540# ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
[3348]541 /* empty strings are not allowed as path names */
542 if (aTAPSetupApplication && !(*aTAPSetupApplication))
[1]543 return E_INVALIDARG;
544
[3348]545 AutoCaller autoCaller (this);
546 CheckComRCReturnRC (autoCaller.rc());
[1]547
[3348]548 /* the machine needs to be mutable */
549 Machine::AutoMutableStateDependency adep (mParent);
550 CheckComRCReturnRC (adep.rc());
[1]551
[8083]552 AutoWriteLock alock (this);
[3348]553
554 if (mData->mTAPSetupApplication != aTAPSetupApplication)
[1]555 {
556 mData.backup();
[3348]557 mData->mTAPSetupApplication = aTAPSetupApplication;
[1]558
[3348]559 /* leave the lock before informing callbacks */
[1]560 alock.unlock();
[3348]561
562 mParent->onNetworkAdapterChange (this);
[1]563 }
564
565 return S_OK;
[10898]566#else
567 return E_NOTIMPL;
568#endif
[1]569}
570
[3348]571STDMETHODIMP NetworkAdapter::COMGETTER(TAPTerminateApplication) (
572 BSTR *aTAPTerminateApplication)
[1]573{
[10898]574# ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
[3348]575 if (!aTAPTerminateApplication)
[1]576 return E_POINTER;
577
[3348]578 AutoCaller autoCaller (this);
579 CheckComRCReturnRC (autoCaller.rc());
580
[8083]581 AutoReadLock alock (this);
[3348]582
[1]583 /* we don't have to be in TAP mode to support this call */
[3348]584 mData->mTAPTerminateApplication.cloneTo(aTAPTerminateApplication);
[1]585
586 return S_OK;
[10898]587#else
588 return E_NOTIMPL;
589#endif
[1]590}
591
[3348]592STDMETHODIMP NetworkAdapter::COMSETTER(TAPTerminateApplication) (
593 INPTR BSTR aTAPTerminateApplication)
[1]594{
[10898]595# ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
[3348]596 /* empty strings are not allowed as path names */
597 if (aTAPTerminateApplication && !(*aTAPTerminateApplication))
[1]598 return E_INVALIDARG;
599
[3348]600 AutoCaller autoCaller (this);
601 CheckComRCReturnRC (autoCaller.rc());
[1]602
[3348]603 /* the machine needs to be mutable */
604 Machine::AutoMutableStateDependency adep (mParent);
605 CheckComRCReturnRC (adep.rc());
[1]606
[8083]607 AutoWriteLock alock (this);
[3348]608
609 if (mData->mTAPTerminateApplication != aTAPTerminateApplication)
[1]610 {
611 mData.backup();
[3348]612 mData->mTAPTerminateApplication = aTAPTerminateApplication;
[1]613
[3348]614 /* leave the lock before informing callbacks */
[1]615 alock.unlock();
[3348]616
[1]617 mParent->onNetworkAdapterChange(this);
618 }
619
620 return S_OK;
[10898]621#else
622 return E_NOTIMPL;
623#endif
[1]624}
625
[606]626#endif /* VBOX_WITH_UNIXY_TAP_NETWORKING */
[1]627
[3348]628STDMETHODIMP NetworkAdapter::COMGETTER(InternalNetwork) (BSTR *aInternalNetwork)
[1]629{
[3348]630 if (!aInternalNetwork)
[1]631 return E_POINTER;
632
[3348]633 AutoCaller autoCaller (this);
634 CheckComRCReturnRC (autoCaller.rc());
[1]635
[8083]636 AutoReadLock alock (this);
[3348]637
638 mData->mInternalNetwork.cloneTo (aInternalNetwork);
639
[1]640 return S_OK;
641}
642
[3348]643STDMETHODIMP NetworkAdapter::COMSETTER(InternalNetwork) (INPTR BSTR aInternalNetwork)
[1]644{
[3348]645 AutoCaller autoCaller (this);
646 CheckComRCReturnRC (autoCaller.rc());
[1]647
[3348]648 /* the machine needs to be mutable */
649 Machine::AutoMutableStateDependency adep (mParent);
650 CheckComRCReturnRC (adep.rc());
[1]651
[8083]652 AutoWriteLock alock (this);
[3348]653
654 if (mData->mInternalNetwork != aInternalNetwork)
[1]655 {
[8367]656 /* if an empty/null string is to be set, internal networking must be
657 * turned off */
658 if ( (aInternalNetwork == NULL || *aInternalNetwork == '\0')
659 && mData->mAttachmentType == NetworkAttachmentType_Internal)
[1]660 {
[8367]661 return setError (E_FAIL,
662 tr ("Empty or null internal network name is not valid"));
[1]663 }
664
665 mData.backup();
[3348]666 mData->mInternalNetwork = aInternalNetwork;
[1]667
[3348]668 /* leave the lock before informing callbacks */
[1]669 alock.unlock();
[3348]670
671 mParent->onNetworkAdapterChange (this);
[1]672 }
673
674 return S_OK;
675}
676
[8367]677STDMETHODIMP NetworkAdapter::COMGETTER(NATNetwork) (BSTR *aNATNetwork)
678{
679 if (!aNATNetwork)
680 return E_POINTER;
681
682 AutoCaller autoCaller (this);
683 CheckComRCReturnRC (autoCaller.rc());
684
685 AutoReadLock alock (this);
686
687 mData->mNATNetwork.cloneTo (aNATNetwork);
688
689 return S_OK;
690}
691
692STDMETHODIMP NetworkAdapter::COMSETTER(NATNetwork) (INPTR BSTR aNATNetwork)
693{
694 AutoCaller autoCaller (this);
695 CheckComRCReturnRC (autoCaller.rc());
696
697 /* the machine needs to be mutable */
698 Machine::AutoMutableStateDependency adep (mParent);
699 CheckComRCReturnRC (adep.rc());
700
701 AutoWriteLock alock (this);
702
703 if (mData->mNATNetwork != aNATNetwork)
704 {
705 mData.backup();
706 mData->mNATNetwork = aNATNetwork;
707
708 /* leave the lock before informing callbacks */
709 alock.unlock();
710
711 mParent->onNetworkAdapterChange (this);
712 }
713
714 return S_OK;
715}
716
[3348]717STDMETHODIMP NetworkAdapter::COMGETTER(CableConnected) (BOOL *aConnected)
[1]718{
[3348]719 if (!aConnected)
[1]720 return E_POINTER;
721
[3348]722 AutoCaller autoCaller (this);
723 CheckComRCReturnRC (autoCaller.rc());
[1]724
[8083]725 AutoReadLock alock (this);
[3348]726
727 *aConnected = mData->mCableConnected;
728
[1]729 return S_OK;
730}
731
[3348]732STDMETHODIMP NetworkAdapter::COMSETTER(CableConnected) (BOOL aConnected)
[1]733{
[3348]734 AutoCaller autoCaller (this);
735 CheckComRCReturnRC (autoCaller.rc());
[1]736
[3348]737 /* the machine needs to be mutable */
738 Machine::AutoMutableStateDependency adep (mParent);
739 CheckComRCReturnRC (adep.rc());
[1]740
[8083]741 AutoWriteLock alock (this);
[3348]742
743 if (aConnected != mData->mCableConnected)
[1]744 {
745 mData.backup();
[3348]746 mData->mCableConnected = aConnected;
[1]747
[3348]748 /* leave the lock before informing callbacks */
[1]749 alock.unlock();
[3348]750
751 mParent->onNetworkAdapterChange (this);
[1]752 }
753
754 return S_OK;
755}
756
[5060]757STDMETHODIMP NetworkAdapter::COMGETTER(LineSpeed) (ULONG *aSpeed)
758{
759 if (!aSpeed)
760 return E_POINTER;
761
762 AutoCaller autoCaller (this);
763 CheckComRCReturnRC (autoCaller.rc());
764
[8083]765 AutoReadLock alock (this);
[5060]766
767 *aSpeed = mData->mLineSpeed;
768
769 return S_OK;
770}
771
772STDMETHODIMP NetworkAdapter::COMSETTER(LineSpeed) (ULONG aSpeed)
773{
774 AutoCaller autoCaller (this);
775 CheckComRCReturnRC (autoCaller.rc());
776
777 /* the machine needs to be mutable */
778 Machine::AutoMutableStateDependency adep (mParent);
779 CheckComRCReturnRC (adep.rc());
780
[8083]781 AutoWriteLock alock (this);
[5060]782
783 if (aSpeed != mData->mLineSpeed)
784 {
785 mData.backup();
786 mData->mLineSpeed = aSpeed;
787
788 /* leave the lock before informing callbacks */
789 alock.unlock();
790
791 mParent->onNetworkAdapterChange (this);
792 }
793
794 return S_OK;
795}
796
[3348]797STDMETHODIMP NetworkAdapter::COMGETTER(TraceEnabled) (BOOL *aEnabled)
[1]798{
[3348]799 if (!aEnabled)
[1]800 return E_POINTER;
801
[3348]802 AutoCaller autoCaller (this);
803 CheckComRCReturnRC (autoCaller.rc());
[1]804
[8083]805 AutoReadLock alock (this);
[3348]806
807 *aEnabled = mData->mTraceEnabled;
[1]808 return S_OK;
809}
810
[3348]811STDMETHODIMP NetworkAdapter::COMSETTER(TraceEnabled) (BOOL aEnabled)
[1]812{
[3348]813 AutoCaller autoCaller (this);
814 CheckComRCReturnRC (autoCaller.rc());
[1]815
[3348]816 /* the machine needs to be mutable */
817 Machine::AutoMutableStateDependency adep (mParent);
818 CheckComRCReturnRC (adep.rc());
[1]819
[8083]820 AutoWriteLock alock (this);
[3348]821
822 if (aEnabled != mData->mTraceEnabled)
[1]823 {
824 mData.backup();
[3348]825 mData->mTraceEnabled = aEnabled;
[1]826
[3348]827 /* leave the lock before informing callbacks */
[1]828 alock.unlock();
[3348]829
830 mParent->onNetworkAdapterChange (this);
[1]831 }
832
833 return S_OK;
834}
835
[3348]836STDMETHODIMP NetworkAdapter::COMGETTER(TraceFile) (BSTR *aTraceFile)
[1]837{
[3348]838 if (!aTraceFile)
[1]839 return E_POINTER;
840
[3348]841 AutoCaller autoCaller (this);
842 CheckComRCReturnRC (autoCaller.rc());
[1]843
[8083]844 AutoReadLock alock (this);
[3348]845
846 mData->mTraceFile.cloneTo (aTraceFile);
847
[1]848 return S_OK;
849}
850
[3348]851STDMETHODIMP NetworkAdapter::COMSETTER(TraceFile) (INPTR BSTR aTraceFile)
[1]852{
[3348]853 AutoCaller autoCaller (this);
854 CheckComRCReturnRC (autoCaller.rc());
[1]855
[3348]856 /* the machine needs to be mutable */
857 Machine::AutoMutableStateDependency adep (mParent);
858 CheckComRCReturnRC (adep.rc());
[1]859
[8083]860 AutoWriteLock alock (this);
[1]861
[3348]862 if (mData->mTraceFile != aTraceFile)
863 {
864 mData.backup();
865 mData->mTraceFile = aTraceFile;
[1]866
[3348]867 /* leave the lock before informing callbacks */
868 alock.unlock();
869
870 mParent->onNetworkAdapterChange (this);
871 }
872
[1]873 return S_OK;
874}
875
876// INetworkAdapter methods
877////////////////////////////////////////////////////////////////////////////////
878
879STDMETHODIMP NetworkAdapter::AttachToNAT()
880{
[3348]881 AutoCaller autoCaller (this);
882 CheckComRCReturnRC (autoCaller.rc());
[1]883
[3348]884 /* the machine needs to be mutable */
885 Machine::AutoMutableStateDependency adep (mParent);
886 CheckComRCReturnRC (adep.rc());
[1]887
[8083]888 AutoWriteLock alock (this);
[3348]889
[7207]890 if (mData->mAttachmentType != NetworkAttachmentType_NAT)
[1]891 {
892 mData.backup();
[3348]893
[1]894 detach();
[3348]895
[7207]896 mData->mAttachmentType = NetworkAttachmentType_NAT;
[1]897
[3348]898 /* leave the lock before informing callbacks */
[1]899 alock.unlock();
[3348]900
901 mParent->onNetworkAdapterChange (this);
[1]902 }
903
904 return S_OK;
905}
906
907STDMETHODIMP NetworkAdapter::AttachToHostInterface()
908{
[3348]909 AutoCaller autoCaller (this);
910 CheckComRCReturnRC (autoCaller.rc());
[1]911
[3348]912 /* the machine needs to be mutable */
913 Machine::AutoMutableStateDependency adep (mParent);
914 CheckComRCReturnRC (adep.rc());
[1]915
[8083]916 AutoWriteLock alock (this);
[3348]917
[1]918 /* don't do anything if we're already host interface attached */
[7207]919 if (mData->mAttachmentType != NetworkAttachmentType_HostInterface)
[1]920 {
921 mData.backup();
[3348]922
[1]923 /* first detach the current attachment */
[3348]924 detach();
925
[7207]926 mData->mAttachmentType = NetworkAttachmentType_HostInterface;
[1]927
[3348]928 /* leave the lock before informing callbacks */
[1]929 alock.unlock();
[3348]930
931 mParent->onNetworkAdapterChange (this);
[1]932 }
933
934 return S_OK;
935}
936
937STDMETHODIMP NetworkAdapter::AttachToInternalNetwork()
938{
[3348]939 AutoCaller autoCaller (this);
940 CheckComRCReturnRC (autoCaller.rc());
[1]941
[3348]942 /* the machine needs to be mutable */
943 Machine::AutoMutableStateDependency adep (mParent);
944 CheckComRCReturnRC (adep.rc());
[1]945
[8083]946 AutoWriteLock alock (this);
[3348]947
[1]948 /* don't do anything if we're already internal network attached */
[7207]949 if (mData->mAttachmentType != NetworkAttachmentType_Internal)
[1]950 {
[3348]951 mData.backup();
952
953 /* first detach the current attachment */
954 detach();
955
[1]956 /* there must an internal network name */
[8367]957 if (mData->mInternalNetwork.isEmpty())
[1]958 {
[3348]959 LogRel (("Internal network name not defined, "
960 "setting to default \"intnet\"\n"));
[8367]961 mData->mInternalNetwork = "intnet";
[1]962 }
963
[7207]964 mData->mAttachmentType = NetworkAttachmentType_Internal;
[1]965
[3348]966 /* leave the lock before informing callbacks */
[1]967 alock.unlock();
[3348]968
969 mParent->onNetworkAdapterChange (this);
[1]970 }
971
972 return S_OK;
973}
974
975STDMETHODIMP NetworkAdapter::Detach()
976{
[3348]977 AutoCaller autoCaller (this);
978 CheckComRCReturnRC (autoCaller.rc());
[1]979
[3348]980 /* the machine needs to be mutable */
981 Machine::AutoMutableStateDependency adep (mParent);
982 CheckComRCReturnRC (adep.rc());
[1]983
[8083]984 AutoWriteLock alock (this);
[3348]985
[7207]986 if (mData->mAttachmentType != NetworkAttachmentType_Null)
[1]987 {
988 mData.backup();
[3348]989
[1]990 detach();
991
[3348]992 /* leave the lock before informing callbacks */
[1]993 alock.unlock();
[3348]994
995 mParent->onNetworkAdapterChange (this);
[1]996 }
997
998 return S_OK;
999}
1000
1001// public methods only for internal purposes
1002////////////////////////////////////////////////////////////////////////////////
1003
[5117]1004/**
[6076]1005 * Loads settings from the given adapter node.
1006 * May be called once right after this object creation.
[7207]1007 *
[6076]1008 * @param aAdapterNode <Adapter> node.
[7207]1009 *
1010 * @note Locks this object for writing.
[6076]1011 */
1012HRESULT NetworkAdapter::loadSettings (const settings::Key &aAdapterNode)
1013{
1014 using namespace settings;
1015
1016 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
1017
1018 AutoCaller autoCaller (this);
1019 AssertComRCReturnRC (autoCaller.rc());
1020
[8083]1021 AutoWriteLock alock (this);
[6076]1022
1023 /* Note: we assume that the default values for attributes of optional
1024 * nodes are assigned in the Data::Data() constructor and don't do it
1025 * here. It implies that this method may only be called after constructing
1026 * a new BIOSSettings object while all its data fields are in the default
1027 * values. Exceptions are fields whose creation time defaults don't match
1028 * values that should be applied when these fields are not explicitly set
1029 * in the settings file (for backwards compatibility reasons). This takes
1030 * place when a setting of a newly created object must default to A while
1031 * the same setting of an object loaded from the old settings file must
[7207]1032 * default to B. */
[6076]1033
1034 HRESULT rc = S_OK;
1035
1036 /* type (optional, defaults to Am79C970A) */
1037 const char *adapterType = aAdapterNode.stringValue ("type");
1038
1039 if (strcmp (adapterType, "Am79C970A") == 0)
[7207]1040 mData->mAdapterType = NetworkAdapterType_Am79C970A;
[6076]1041 else if (strcmp (adapterType, "Am79C973") == 0)
[7207]1042 mData->mAdapterType = NetworkAdapterType_Am79C973;
[6135]1043 else if (strcmp (adapterType, "82540EM") == 0)
[7207]1044 mData->mAdapterType = NetworkAdapterType_I82540EM;
[8439]1045 else if (strcmp (adapterType, "82543GC") == 0)
1046 mData->mAdapterType = NetworkAdapterType_I82543GC;
[6076]1047 else
1048 ComAssertMsgFailedRet (("Invalid adapter type '%s'", adapterType),
1049 E_FAIL);
1050
1051 /* enabled (required) */
1052 mData->mEnabled = aAdapterNode.value <bool> ("enabled");
1053 /* MAC address (can be null) */
1054 rc = COMSETTER(MACAddress) (Bstr (aAdapterNode.stringValue ("MACAddress")));
1055 CheckComRCReturnRC (rc);
1056 /* cable (required) */
1057 mData->mCableConnected = aAdapterNode.value <bool> ("cable");
1058 /* line speed (defaults to 100 Mbps) */
1059 mData->mLineSpeed = aAdapterNode.value <ULONG> ("speed");
1060 /* tracing (defaults to false) */
1061 mData->mTraceEnabled = aAdapterNode.value <bool> ("trace");
1062 mData->mTraceFile = aAdapterNode.stringValue ("tracefile");
1063
1064 /* One of NAT, HostInerface, Internal or nothing */
1065 Key attachmentNode;
1066
1067 if (!(attachmentNode = aAdapterNode.findKey ("NAT")).isNull())
1068 {
1069 /* NAT */
1070
[8367]1071 /* optional */
1072 mData->mNATNetwork = attachmentNode.stringValue ("network");
1073
[6076]1074 rc = AttachToNAT();
1075 CheckComRCReturnRC (rc);
1076 }
1077 else
[6344]1078 if (!(attachmentNode = aAdapterNode.findKey ("HostInterface")).isNull())
[6076]1079 {
1080 /* Host Interface Networking */
1081
1082 Bstr name = attachmentNode.stringValue ("name");
[10898]1083#ifndef VBOX_WITH_UNIXY_TAP_NETWORKING
1084 /* name can be empty, but not null */
[6076]1085 ComAssertRet (!name.isNull(), E_FAIL);
1086#endif
1087 rc = COMSETTER(HostInterface) (name);
1088 CheckComRCReturnRC (rc);
1089
1090#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
1091 /* optopnal */
1092 mData->mTAPSetupApplication = attachmentNode.stringValue ("TAPSetup");
1093 mData->mTAPTerminateApplication = attachmentNode.stringValue ("TAPTerminate");
1094#endif /* VBOX_WITH_UNIXY_TAP_NETWORKING */
1095
1096 rc = AttachToHostInterface();
1097 CheckComRCReturnRC (rc);
1098 }
1099 else
1100 if (!(attachmentNode = aAdapterNode.findKey ("InternalNetwork")).isNull())
1101 {
1102 /* Internal Networking */
1103
1104 /* required */
1105 mData->mInternalNetwork = attachmentNode.stringValue ("name");
[8367]1106 Assert (!mData->mInternalNetwork.isNull());
[6076]1107
1108 rc = AttachToInternalNetwork();
1109 CheckComRCReturnRC (rc);
1110 }
1111 else
1112 {
1113 /* Adapter has no children */
1114 rc = Detach();
1115 CheckComRCReturnRC (rc);
1116 }
1117
1118 return S_OK;
1119}
1120
[7207]1121/**
[6076]1122 * Saves settings to the given adapter node.
[7207]1123 *
[6076]1124 * Note that the given Adapter node is comletely empty on input.
1125 *
1126 * @param aAdapterNode <Adapter> node.
[7207]1127 *
1128 * @note Locks this object for reading.
[6076]1129 */
1130HRESULT NetworkAdapter::saveSettings (settings::Key &aAdapterNode)
1131{
1132 using namespace settings;
1133
1134 AssertReturn (!aAdapterNode.isNull(), E_FAIL);
1135
1136 AutoCaller autoCaller (this);
1137 AssertComRCReturnRC (autoCaller.rc());
1138
[8083]1139 AutoReadLock alock (this);
[6076]1140
1141 aAdapterNode.setValue <bool> ("enabled", !!mData->mEnabled);
1142 aAdapterNode.setValue <Bstr> ("MACAddress", mData->mMACAddress);
1143 aAdapterNode.setValue <bool> ("cable", !!mData->mCableConnected);
1144
1145 aAdapterNode.setValue <ULONG> ("speed", mData->mLineSpeed);
1146
1147 if (mData->mTraceEnabled)
1148 aAdapterNode.setValue <bool> ("trace", true);
1149
1150 aAdapterNode.setValueOr <Bstr> ("tracefile", mData->mTraceFile, Bstr::Null);
1151
1152 const char *typeStr = NULL;
1153 switch (mData->mAdapterType)
1154 {
[7207]1155 case NetworkAdapterType_Am79C970A:
[6076]1156 typeStr = "Am79C970A";
1157 break;
[7207]1158 case NetworkAdapterType_Am79C973:
[6076]1159 typeStr = "Am79C973";
1160 break;
[7207]1161 case NetworkAdapterType_I82540EM:
[6135]1162 typeStr = "82540EM";
[8452]1163 break;
[8439]1164 case NetworkAdapterType_I82543GC:
1165 typeStr = "82543GC";
[6135]1166 break;
[6076]1167 default:
1168 ComAssertMsgFailedRet (("Invalid network adapter type: %d\n",
1169 mData->mAdapterType),
1170 E_FAIL);
1171 }
1172 aAdapterNode.setStringValue ("type", typeStr);
1173
1174 switch (mData->mAttachmentType)
1175 {
[7207]1176 case NetworkAttachmentType_Null:
[6076]1177 {
1178 /* do nothing -- empty content */
1179 break;
1180 }
[7207]1181 case NetworkAttachmentType_NAT:
[6076]1182 {
1183 Key attachmentNode = aAdapterNode.createKey ("NAT");
[8367]1184 if (!mData->mNATNetwork.isEmpty())
1185 attachmentNode.setValue <Bstr> ("network",
1186 mData->mNATNetwork);
[6076]1187 break;
1188 }
[7207]1189 case NetworkAttachmentType_HostInterface:
[6076]1190 {
1191 Key attachmentNode = aAdapterNode.createKey ("HostInterface");
[10898]1192#ifndef VBOX_WITH_UNIXY_TAP_NETWORKING
[6076]1193 Assert (!mData->mHostInterface.isNull());
[10898]1194#else
[6076]1195 if (!mData->mHostInterface.isEmpty())
1196#endif
1197 attachmentNode.setValue <Bstr> ("name", mData->mHostInterface);
1198#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
1199 if (!mData->mTAPSetupApplication.isEmpty())
1200 attachmentNode.setValue <Bstr> ("TAPSetup",
1201 mData->mTAPSetupApplication);
1202 if (!mData->mTAPTerminateApplication.isEmpty())
1203 attachmentNode.setValue <Bstr> ("TAPTerminate",
1204 mData->mTAPTerminateApplication);
1205#endif /* VBOX_WITH_UNIXY_TAP_NETWORKING */
1206 break;
1207 }
[7207]1208 case NetworkAttachmentType_Internal:
[6076]1209 {
1210 Key attachmentNode = aAdapterNode.createKey ("InternalNetwork");
[8367]1211 Assert (!mData->mInternalNetwork.isEmpty());
[6076]1212 attachmentNode.setValue <Bstr> ("name", mData->mInternalNetwork);
1213 break;
1214 }
1215 default:
1216 {
1217 ComAssertFailedRet (E_FAIL);
1218 }
1219 }
1220
1221 return S_OK;
1222}
1223
1224/**
[3348]1225 * @note Locks this object for writing.
1226 */
[1]1227bool NetworkAdapter::rollback()
1228{
[3348]1229 /* sanity */
1230 AutoCaller autoCaller (this);
1231 AssertComRCReturn (autoCaller.rc(), false);
1232
[8083]1233 AutoWriteLock alock (this);
[1]1234
1235 bool changed = false;
1236
1237 if (mData.isBackedUp())
1238 {
[3348]1239 /* we need to check all data to see whether anything will be changed
1240 * after rollback */
[1]1241 changed = mData.hasActualChanges();
1242 mData.rollback();
1243 }
1244
1245 return changed;
1246}
1247
[5117]1248/**
[3348]1249 * @note Locks this object for writing, together with the peer object (also
1250 * for writing) if there is one.
1251 */
[1]1252void NetworkAdapter::commit()
1253{
[3348]1254 /* sanity */
1255 AutoCaller autoCaller (this);
1256 AssertComRCReturnVoid (autoCaller.rc());
1257
1258 /* sanity too */
[7992]1259 AutoCaller peerCaller (mPeer);
1260 AssertComRCReturnVoid (peerCaller.rc());
[3348]1261
[7992]1262 /* lock both for writing since we modify both (mPeer is "master" so locked
1263 * first) */
1264 AutoMultiWriteLock2 alock (mPeer, this);
[3348]1265
[1]1266 if (mData.isBackedUp())
1267 {
1268 mData.commit();
1269 if (mPeer)
1270 {
[3348]1271 /* attach new data to the peer and reshare it */
[1]1272 mPeer->mData.attach (mData);
1273 }
1274 }
1275}
1276
[5117]1277/**
[3348]1278 * @note Locks this object for writing, together with the peer object
1279 * represented by @a aThat (locked for reading).
1280 */
[1]1281void NetworkAdapter::copyFrom (NetworkAdapter *aThat)
1282{
[3348]1283 AssertReturnVoid (aThat != NULL);
[1]1284
[3348]1285 /* sanity */
1286 AutoCaller autoCaller (this);
1287 AssertComRCReturnVoid (autoCaller.rc());
1288
1289 /* sanity too */
[7992]1290 AutoCaller thatCaller (aThat);
[3348]1291 AssertComRCReturnVoid (thatCaller.rc());
1292
[7992]1293 /* peer is not modified, lock it for reading (aThat is "master" so locked
1294 * first) */
1295 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
[3348]1296
1297 /* this will back up current data */
[1]1298 mData.assignCopy (aThat->mData);
1299}
1300
1301// private methods
1302////////////////////////////////////////////////////////////////////////////////
1303
1304/**
[3348]1305 * Worker routine for detach handling. No locking, no notifications.
1306
1307 * @note Must be called from under the object's write lock.
[1]1308 */
1309void NetworkAdapter::detach()
1310{
[8083]1311 AssertReturnVoid (isWriteLockOnCurrentThread());
[3348]1312
[1]1313 switch (mData->mAttachmentType)
1314 {
[7207]1315 case NetworkAttachmentType_Null:
[1]1316 {
1317 /* nothing to do here */
1318 break;
1319 }
[7207]1320 case NetworkAttachmentType_NAT:
[1]1321 {
1322 break;
1323 }
[7207]1324 case NetworkAttachmentType_HostInterface:
[1]1325 {
1326 /* reset handle and device name */
[10898]1327#ifndef VBOX_WITH_UNIXY_TAP_NETWORKING
[1]1328 mData->mHostInterface = "";
1329#endif
[606]1330#ifdef VBOX_WITH_UNIXY_TAP_NETWORKING
[1]1331 mData->mHostInterface.setNull();
1332 mData->mTAPFD = NIL_RTFILE;
1333#endif
1334 break;
1335 }
[7207]1336 case NetworkAttachmentType_Internal:
[1]1337 {
1338 mData->mInternalNetwork.setNull();
1339 break;
1340 }
1341 }
1342
[7207]1343 mData->mAttachmentType = NetworkAttachmentType_Null;
[1]1344}
1345
1346/**
[3348]1347 * Generates a new unique MAC address based on our vendor ID and
1348 * parts of a GUID.
1349 *
1350 * @note Must be called from under the object's write lock or within the init
1351 * span.
[1]1352 */
1353void NetworkAdapter::generateMACAddress()
1354{
1355 /*
1356 * Our strategy is as follows: the first three bytes are our fixed
1357 * vendor ID (080027). The remaining 3 bytes will be taken from the
1358 * start of a GUID. This is a fairly safe algorithm.
1359 */
1360 char strMAC[13];
1361 Guid guid;
1362 guid.create();
[3348]1363 RTStrPrintf (strMAC, sizeof(strMAC), "080027%02X%02X%02X",
1364 guid.ptr()->au8[0], guid.ptr()->au8[1], guid.ptr()->au8[2]);
1365 LogFlowThisFunc (("generated MAC: '%s'\n", strMAC));
[1]1366 mData->mMACAddress = strMAC;
1367}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use