summaryrefslogtreecommitdiff
path: root/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c')
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c402
1 files changed, 241 insertions, 161 deletions
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c b/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c
index 2a2fc9c93..e49e64b47 100644
--- a/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c
+++ b/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c
@@ -1,10 +1,10 @@
-/* $Id: VBoxNetFlt.c $ */
+/* $Id: VBoxNetFlt.c 29150 2010-05-06 13:13:03Z vboxsync $ */
/** @file
* VBoxNetFlt - Network Filter Driver (Host), Common Code.
*/
/*
- * Copyright (C) 2008-2009 Sun Microsystems, Inc.
+ * Copyright (C) 2008-2009 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -13,32 +13,65 @@
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
- * Clara, CA 95054 USA or visit http://www.sun.com if you need
- * additional information or have any questions.
*/
/** @page pg_netflt VBoxNetFlt - Network Interface Filter
*
- * This is a kernel module that attaches to a real interface on the host
- * and filters and injects packets.
+ * This is a kernel module that attaches to a real interface on the host and
+ * filters and injects packets.
*
* In the big picture we're one of the three trunk interface on the internal
* network, the one named "NIC Filter Driver": @image html Networking_Overview.gif
*
*
- * @section sec_netflt_msc Locking / Sequence Diagrams
+ * @section sec_netflt_locking Locking and Potential Races
+ *
+ * The main challenge here is to make sure the netfilter and internal network
+ * instances won't be destroyed while someone is calling into them.
+ *
+ * The main calls into or out of of the filter driver are:
+ * - Send.
+ * - Async send completion (not implemented yet)
+ * - Release by the internal network.
+ * - Receive.
+ * - Disappearance of the host networking interface.
+ * - Reappearance of the host networking interface.
+ *
+ * The latter two calls are can be caused by driver unloading/loading or the
+ * device being physical unplugged (e.g. a USB network device). Actually, the
+ * unload scenario must fervently be prevent as it will cause panics because the
+ * internal network will assume the trunk is around until it releases it.
+ * @todo Need to figure which host allow unloading and block/fix it.
+ *
+ * Currently the netfilter instance lives until the internal network releases
+ * it. So, it is the internal networks responsibility to make sure there are no
+ * active calls when it releases the trunk and destroys the network. The
+ * netfilter assists in this by providing INTNETTRUNKIFPORT::pfnSetState and
+ * INTNETTRUNKIFPORT::pfnWaitForIdle. The trunk state is used to enable/disable
+ * promiscuous mode on the hardware NIC (or similar activation) as well
+ * indicating that disconnect is imminent and no further calls shall be made
+ * into the internal network. After changing the state to disconnecting and
+ * prior to invoking INTNETTRUNKIFPORT::pfnDisconnectAndRelease, the internal
+ * network will use INTNETTRUNKIFPORT::pfnWaitForIdle to wait for any still
+ * active calls to complete.
+ *
+ * The netfilter employs a busy counter and an internal state in addition to the
+ * public trunk state. All these variables are protected using a spinlock.
+ *
+ *
+ * @section sec_netflt_msc Locking / Sequence Diagrams - OBSOLETE
+ *
+ * !OBSOLETE! - THIS WAS THE OLD APPROACH!
*
* This secion contains a few sequence diagrams describing the problematic
* transitions of a host interface filter instance.
*
* The thing that makes it all a bit problematic is that multiple events may
* happen at the same time, and that we have to be very careful to avoid
- * deadlocks caused by mixing our locks with the ones in the host kernel.
- * The main events are receive, send, async send completion, disappearance of
- * the host networking interface and it's reappearance. The latter two events
- * are can be caused by driver unloading/loading or the device being physical
+ * deadlocks caused by mixing our locks with the ones in the host kernel. The
+ * main events are receive, send, async send completion, disappearance of the
+ * host networking interface and its reappearance. The latter two events are
+ * can be caused by driver unloading/loading or the device being physical
* unplugged (e.g. a USB network device).
*
* The strategy for dealing with these issues are:
@@ -52,7 +85,7 @@
* using a spinlock.
*
*
- * @subsection subsec_netflt_msc_dis_rel Disconnect from the network and release
+ * @subsection subsec_netflt_msc_dis_rel Disconnect from the network and release - OBSOLETE
*
* @msc
* VM, IntNet, NetFlt, Kernel, Wire;
@@ -117,7 +150,7 @@
*
*
*
- * @subsection subsec_netflt_msc_hif_rm Host Interface Removal
+ * @subsection subsec_netflt_msc_hif_rm Host Interface Removal - OBSOLETE
*
* The ifnet_t (pIf) is a tricky customer as any reference to it can potentially
* race the filter detaching. The simple way of solving it on Darwin is to guard
@@ -157,7 +190,7 @@
*
*
*
- * @subsection subsec_netflt_msc_hif_rm Host Interface Rediscovery
+ * @subsection subsec_netflt_msc_hif_rm Host Interface Rediscovery - OBSOLETE
*
* The rediscovery is performed when we receive a send request and a certain
* period have elapsed since the last attempt, i.e. we're polling it. We
@@ -341,15 +374,28 @@ static void vboxNetFltUnlinkLocked(PVBOXNETFLTGLOBALS pGlobals, PVBOXNETFLTINS p
*/
static bool vboxNetFltMaybeRediscovered(PVBOXNETFLTINS pThis)
{
- RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
- uint64_t Now = RTTimeNanoTS();
- bool fRediscovered;
- bool fDoIt;
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ uint64_t Now;
+ bool fRediscovered;
+ bool fDoIt;
+
+ /*
+ * Don't do rediscovery if we're called with preemption disabled.
+ *
+ * Note! This may cause trouble if we're always called with preemptioni
+ * disabled and vboxNetFltOsMaybeRediscovered actually does some real
+ * work. For the time being though, only Darwin and FreeBSD depends
+ * on these call outs and neither supports sending with preemption
+ * disabled.
+ */
+ if (!RTThreadPreemptIsEnabled(NIL_RTTHREAD))
+ return false;
/*
* Rediscovered already? Time to try again?
*/
- RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ Now = RTTimeNanoTS();
+ RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
fRediscovered = !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
fDoIt = !fRediscovered
@@ -358,7 +404,7 @@ static bool vboxNetFltMaybeRediscovered(PVBOXNETFLTINS pThis)
if (fDoIt)
ASMAtomicWriteBool(&pThis->fRediscoveryPending, true);
- RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+ RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
/*
* Call the OS specific code to do the job.
@@ -375,39 +421,18 @@ static bool vboxNetFltMaybeRediscovered(PVBOXNETFLTINS pThis)
ASMAtomicWriteBool(&pThis->fRediscoveryPending, false);
if (fRediscovered)
- vboxNetFltPortOsSetActive(pThis, pThis->fActive);
+ /** @todo this isn't 100% serialized. */
+ vboxNetFltPortOsSetActive(pThis, pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE);
}
return fRediscovered;
}
-#ifdef RT_WITH_W64_UNWIND_HACK
-# if defined(RT_OS_WINDOWS) && defined(RT_ARCH_AMD64)
-# define NETFLT_DECL_CALLBACK(type) DECLASM(DECLHIDDEN(type))
-# define NETFLT_CALLBACK(_n) netfltNtWrap##_n
-
-NETFLT_DECL_CALLBACK(int) NETFLT_CALLBACK(vboxNetFltPortXmit)(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst);
-NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortIsPromiscuous)(PINTNETTRUNKIFPORT pIfPort);
-NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortGetMacAddress)(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac);
-NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortIsHostMac)(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac);
-NETFLT_DECL_CALLBACK(int) NETFLT_CALLBACK(vboxNetFltPortWaitForIdle)(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies);
-NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortSetActive)(PINTNETTRUNKIFPORT pIfPort, bool fActive);
-NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortDisconnectAndRelease)(PINTNETTRUNKIFPORT pIfPort);
-NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortRetain)(PINTNETTRUNKIFPORT pIfPort);
-NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortRelease)(PINTNETTRUNKIFPORT pIfPort);
-
-# else
-# error "UNSUPPORTED (RT_WITH_W64_UNWIND_HACK)"
-# endif
-#else
-# define NETFLT_DECL_CALLBACK(type) static DECLCALLBACK(type)
-# define NETFLT_CALLBACK(_n) _n
-#endif
/**
* @copydoc INTNETTRUNKIFPORT::pfnXmit
*/
-NETFLT_DECL_CALLBACK(int) vboxNetFltPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
+static DECLCALLBACK(int) vboxNetFltPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
{
PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
int rc = VINF_SUCCESS;
@@ -419,92 +444,27 @@ NETFLT_DECL_CALLBACK(int) vboxNetFltPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNET
AssertPtr(pSG);
Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, VERR_INVALID_STATE);
- Assert(pThis->fActive);
/*
* Do a busy retain and then make sure we're connected to the interface
* before invoking the OS specific code.
*/
- vboxNetFltRetain(pThis, true /* fBusy */);
- if ( !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost)
- || vboxNetFltMaybeRediscovered(pThis))
- rc = vboxNetFltPortOsXmit(pThis, pSG, fDst);
- vboxNetFltRelease(pThis, true /* fBusy */);
+ if (RT_LIKELY(vboxNetFltTryRetainBusyActive(pThis)))
+ {
+ if ( !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost)
+ || vboxNetFltMaybeRediscovered(pThis))
+ rc = vboxNetFltPortOsXmit(pThis, pSG, fDst);
+ vboxNetFltRelease(pThis, true /* fBusy */);
+ }
return rc;
}
/**
- * @copydoc INTNETTRUNKIFPORT::pfnIsPromiscuous
- */
-NETFLT_DECL_CALLBACK(bool) vboxNetFltPortIsPromiscuous(PINTNETTRUNKIFPORT pIfPort)
-{
- PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
-
- /*
- * Input validation.
- */
- AssertPtr(pThis);
- Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
- Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
- Assert(pThis->fActive);
-
- /*
- * Ask the OS specific code.
- */
- return vboxNetFltPortOsIsPromiscuous(pThis);
-}
-
-
-/**
- * @copydoc INTNETTRUNKIFPORT::pfnGetMacAddress
- */
-NETFLT_DECL_CALLBACK(void) vboxNetFltPortGetMacAddress(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac)
-{
- PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
-
- /*
- * Input validation.
- */
- AssertPtr(pThis);
- Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
- Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
- Assert(pThis->fActive);
-
- /*
- * Forward the question to the OS specific code.
- */
- vboxNetFltPortOsGetMacAddress(pThis, pMac);
-}
-
-
-/**
- * @copydoc INTNETTRUNKIFPORT::pfnIsHostMac
- */
-NETFLT_DECL_CALLBACK(bool) vboxNetFltPortIsHostMac(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac)
-{
- PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
-
- /*
- * Input validation.
- */
- AssertPtr(pThis);
- Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
- Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
- Assert(pThis->fActive);
-
- /*
- * Ask the OS specific code.
- */
- return vboxNetFltPortOsIsHostMac(pThis, pMac);
-}
-
-
-/**
* @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
*/
-NETFLT_DECL_CALLBACK(int) vboxNetFltPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
+static DECLCALLBACK(int) vboxNetFltPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
{
PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
int rc;
@@ -515,7 +475,7 @@ NETFLT_DECL_CALLBACK(int) vboxNetFltPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort,
AssertPtr(pThis);
Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, VERR_INVALID_STATE);
- AssertReturn(!pThis->fActive, VERR_INVALID_STATE);
+ AssertReturn(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING, VERR_INVALID_STATE);
/*
* Go to sleep on the semaphore after checking the busy count.
@@ -533,11 +493,13 @@ NETFLT_DECL_CALLBACK(int) vboxNetFltPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort,
/**
- * @copydoc INTNETTRUNKIFPORT::pfnSetActive
+ * @copydoc INTNETTRUNKIFPORT::pfnSetState
*/
-NETFLT_DECL_CALLBACK(bool) vboxNetFltPortSetActive(PINTNETTRUNKIFPORT pIfPort, bool fActive)
+static DECLCALLBACK(INTNETTRUNKIFSTATE) vboxNetFltPortSetState(PINTNETTRUNKIFPORT pIfPort, INTNETTRUNKIFSTATE enmState)
{
- PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+ PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ INTNETTRUNKIFSTATE enmOldTrunkState;
/*
* Input validation.
@@ -545,35 +507,39 @@ NETFLT_DECL_CALLBACK(bool) vboxNetFltPortSetActive(PINTNETTRUNKIFPORT pIfPort, b
AssertPtr(pThis);
AssertPtr(pThis->pGlobals);
Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
- AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, false);
+ AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, INTNETTRUNKIFSTATE_INVALID);
+ AssertReturn(enmState > INTNETTRUNKIFSTATE_INVALID && enmState < INTNETTRUNKIFSTATE_END,
+ INTNETTRUNKIFSTATE_INVALID);
/*
- * We're assuming that the caller is serializing the calls, so we don't
- * have to be extremely careful here. Just update first and then call
- * the OS specific code, the update must be serialized for various reasons.
+ * Take the lock and change the state.
*/
- if (ASMAtomicReadBool(&pThis->fActive) != fActive)
- {
- RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
- RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
- ASMAtomicWriteBool(&pThis->fActive, fActive);
- RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+ RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
+ enmOldTrunkState = pThis->enmTrunkState;
+ if (enmOldTrunkState != enmState)
+ ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmTrunkState, enmState);
+ RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
- vboxNetFltPortOsSetActive(pThis, fActive);
- }
- else
- fActive = !fActive;
- return !fActive;
+ /*
+ * If the state change indicates that the trunk has become active or
+ * inactive, call the OS specific part so they can work the promiscuous
+ * settings and such.
+ * Note! The caller makes sure there are no concurrent pfnSetState calls.
+ */
+ if ((enmOldTrunkState == INTNETTRUNKIFSTATE_ACTIVE) != (enmState == INTNETTRUNKIFSTATE_ACTIVE))
+ vboxNetFltPortOsSetActive(pThis, (enmState == INTNETTRUNKIFSTATE_ACTIVE));
+
+ return enmOldTrunkState;
}
/**
* @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
*/
-NETFLT_DECL_CALLBACK(void) vboxNetFltPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
+static DECLCALLBACK(void) vboxNetFltPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
{
PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
- RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
/*
* Serious paranoia.
@@ -587,24 +553,24 @@ NETFLT_DECL_CALLBACK(void) vboxNetFltPortDisconnectAndRelease(PINTNETTRUNKIFPORT
Assert(pThis->szName[0]);
Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
- Assert(!pThis->fActive);
+ Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING);
Assert(!pThis->fRediscoveryPending);
Assert(!pThis->cBusy);
/*
* Disconnect and release it.
*/
- RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
vboxNetFltSetState(pThis, kVBoxNetFltInsState_Disconnecting);
- RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+ RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
vboxNetFltOsDisconnectIt(pThis);
pThis->pSwitchPort = NULL;
#ifdef VBOXNETFLT_STATIC_CONFIG
- RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+ RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
vboxNetFltSetState(pThis, kVBoxNetFltInsState_Unconnected);
- RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+ RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
#endif
vboxNetFltRelease(pThis, false /* fBusy */);
@@ -634,7 +600,7 @@ static bool vboxNetFltDestroyInstance(PVBOXNETFLTINS pThis)
#else
Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Disconnecting);
#endif
- Assert(!pThis->fActive);
+ Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING);
Assert(!pThis->fRediscoveryPending);
Assert(!pThis->cRefs);
Assert(!pThis->cBusy);
@@ -725,7 +691,7 @@ DECLHIDDEN(void) vboxNetFltRelease(PVBOXNETFLTINS pThis, bool fBusy)
/**
* @copydoc INTNETTRUNKIFPORT::pfnRetain
*/
-NETFLT_DECL_CALLBACK(void) vboxNetFltPortRelease(PINTNETTRUNKIFPORT pIfPort)
+static DECLCALLBACK(void) vboxNetFltPortRelease(PINTNETTRUNKIFPORT pIfPort)
{
PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
vboxNetFltRelease(pThis, false /* fBusy */);
@@ -775,9 +741,104 @@ DECLHIDDEN(void) vboxNetFltRetain(PVBOXNETFLTINS pThis, bool fBusy)
/**
+ * Tries to retain the device as busy if the trunk is active.
+ *
+ * This is used before calling pfnRecv or pfnPreRecv.
+ *
+ * @returns true if we succeeded in retaining a busy reference to the active
+ * device. false if we failed.
+ * @param pThis The instance.
+ */
+DECLHIDDEN(bool) vboxNetFltTryRetainBusyActive(PVBOXNETFLTINS pThis)
+{
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ uint32_t cRefs;
+ bool fRc;
+
+ /*
+ * Paranoid Android.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
+ Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
+ && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
+ AssertPtr(pThis->pGlobals);
+ Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
+ Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
+ Assert(pThis->szName[0]);
+
+ /*
+ * Do the retaining and checking behind the spinlock.
+ */
+ RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
+ fRc = pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE;
+ if (fRc)
+ {
+ cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ AssertMsg(cRefs > 1 && cRefs < UINT32_MAX / 2, ("%d\n", cRefs)); NOREF(cRefs);
+
+ cRefs = ASMAtomicIncU32(&pThis->cBusy);
+ AssertMsg(cRefs >= 1 && cRefs < UINT32_MAX / 2, ("%d\n", cRefs)); NOREF(cRefs);
+ }
+ RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
+
+ return fRc;
+}
+
+
+/**
+ * Tries to retain the device as busy if the trunk is not disconnecting.
+ *
+ * This is used before reporting stuff to the internal network.
+ *
+ * @returns true if we succeeded in retaining a busy reference to the active
+ * device. false if we failed.
+ * @param pThis The instance.
+ */
+DECLHIDDEN(bool) vboxNetFltTryRetainBusyNotDisconnected(PVBOXNETFLTINS pThis)
+{
+ RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+ uint32_t cRefs;
+ bool fRc;
+
+ /*
+ * Paranoid Android.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
+ Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
+ && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
+ AssertPtr(pThis->pGlobals);
+ Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
+ Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
+ Assert(pThis->szName[0]);
+
+ /*
+ * Do the retaining and checking behind the spinlock.
+ */
+ RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
+ fRc = pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE
+ || pThis->enmTrunkState == INTNETTRUNKIFSTATE_INACTIVE;
+ if (fRc)
+ {
+ cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ AssertMsg(cRefs > 1 && cRefs < UINT32_MAX / 2, ("%d\n", cRefs)); NOREF(cRefs);
+
+ cRefs = ASMAtomicIncU32(&pThis->cBusy);
+ AssertMsg(cRefs >= 1 && cRefs < UINT32_MAX / 2, ("%d\n", cRefs)); NOREF(cRefs);
+ }
+ RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
+
+ return fRc;
+}
+
+
+/**
* @copydoc INTNETTRUNKIFPORT::pfnRetain
*/
-NETFLT_DECL_CALLBACK(void) vboxNetFltPortRetain(PINTNETTRUNKIFPORT pIfPort)
+static DECLCALLBACK(void) vboxNetFltPortRetain(PINTNETTRUNKIFPORT pIfPort)
{
PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
vboxNetFltRetain(pThis, false /* fBusy */);
@@ -804,13 +865,19 @@ static int vboxNetFltConnectIt(PVBOXNETFLTINS pThis, PINTNETTRUNKSWPORT pSwitchP
/*
* Validate state.
*/
- Assert(!pThis->fActive);
Assert(!pThis->fRediscoveryPending);
Assert(!pThis->cBusy);
#ifdef VBOXNETFLT_STATIC_CONFIG
Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Unconnected);
+ /* INTNETTRUNKIFSTATE_DISCONNECTING means "not connected" here
+ * we use the INTNETTRUNKIFSTATE_DISCONNECTING state for consistency of cases when trunk
+ * was never connected and was connected and disconnected.
+ * In the latter case we end up with INTNETTRUNKIFSTATE_DICONNECTING,
+ * so use the same state for the former */
+ Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING);
#else
Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Initializing);
+ Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_INACTIVE);
#endif
/*
@@ -827,7 +894,16 @@ static int vboxNetFltConnectIt(PVBOXNETFLTINS pThis, PINTNETTRUNKSWPORT pSwitchP
else
pThis->pSwitchPort = NULL;
- Assert(!pThis->fActive);
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ /* INTNETTRUNKIFSTATE_DISCONNECTING means "not connected" here
+ * we use the INTNETTRUNKIFSTATE_DISCONNECTING state for consistency of cases when trunk
+ * was never connected and was connected and disconnected.
+ * In the latter case we end up with INTNETTRUNKIFSTATE_DISCONNECTING,
+ * so use the same state for the former */
+ Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING);
+#else
+ Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_INACTIVE);
+#endif
return rc;
}
@@ -861,21 +937,25 @@ static int vboxNetFltNewInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszNam
return VERR_INTNET_FLT_IF_FAILED;
pNew->pNext = NULL;
pNew->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
- pNew->MyPort.pfnRetain = NETFLT_CALLBACK(vboxNetFltPortRetain);
- pNew->MyPort.pfnRelease = NETFLT_CALLBACK(vboxNetFltPortRelease);
- pNew->MyPort.pfnDisconnectAndRelease= NETFLT_CALLBACK(vboxNetFltPortDisconnectAndRelease);
- pNew->MyPort.pfnSetActive = NETFLT_CALLBACK(vboxNetFltPortSetActive);
- pNew->MyPort.pfnWaitForIdle = NETFLT_CALLBACK(vboxNetFltPortWaitForIdle);
- pNew->MyPort.pfnGetMacAddress = NETFLT_CALLBACK(vboxNetFltPortGetMacAddress);
- pNew->MyPort.pfnIsHostMac = NETFLT_CALLBACK(vboxNetFltPortIsHostMac);
- pNew->MyPort.pfnIsPromiscuous = NETFLT_CALLBACK(vboxNetFltPortIsPromiscuous);
- pNew->MyPort.pfnXmit = NETFLT_CALLBACK(vboxNetFltPortXmit);
+ pNew->MyPort.pfnRetain = vboxNetFltPortRetain;
+ pNew->MyPort.pfnRelease = vboxNetFltPortRelease;
+ pNew->MyPort.pfnDisconnectAndRelease= vboxNetFltPortDisconnectAndRelease;
+ pNew->MyPort.pfnSetState = vboxNetFltPortSetState;
+ pNew->MyPort.pfnWaitForIdle = vboxNetFltPortWaitForIdle;
+ pNew->MyPort.pfnXmit = vboxNetFltPortXmit;
pNew->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
- pNew->pSwitchPort = NULL;
+ pNew->pSwitchPort = pSwitchPort;
pNew->pGlobals = pGlobals;
pNew->hSpinlock = NIL_RTSPINLOCK;
pNew->enmState = kVBoxNetFltInsState_Initializing;
- pNew->fActive = false;
+#ifdef VBOXNETFLT_STATIC_CONFIG
+ /* for consistency of cases when trunk was never connected and was connected and disconnected.
+ * In the latter case we end up with INTNETTRUNKIFSTATE_DISCONNECTING,
+ * so use the same state for the former */
+ pNew->enmTrunkState = INTNETTRUNKIFSTATE_DISCONNECTING;
+#else
+ pNew->enmTrunkState = INTNETTRUNKIFSTATE_INACTIVE;
+#endif
pNew->fDisconnectedFromHost = false;
pNew->fRediscoveryPending = false;
pNew->fDisablePromiscuous = fNoPromisc;