summaryrefslogtreecommitdiff
path: root/src/VBox/Devices/Network/SrvIntNetR0.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/Network/SrvIntNetR0.cpp')
-rw-r--r--src/VBox/Devices/Network/SrvIntNetR0.cpp130
1 files changed, 98 insertions, 32 deletions
diff --git a/src/VBox/Devices/Network/SrvIntNetR0.cpp b/src/VBox/Devices/Network/SrvIntNetR0.cpp
index 8338e71ad..9fd7e40e7 100644
--- a/src/VBox/Devices/Network/SrvIntNetR0.cpp
+++ b/src/VBox/Devices/Network/SrvIntNetR0.cpp
@@ -1,4 +1,4 @@
-/* $Id: SrvIntNetR0.cpp 29635 2010-05-18 13:42:54Z vboxsync $ */
+/* $Id: SrvIntNetR0.cpp 29707 2010-05-20 16:49:16Z vboxsync $ */
/** @file
* Internal networking - The ring 0 service.
*/
@@ -220,7 +220,8 @@ typedef struct INTNETIF
/** Whether the interface is active or not.
* This is shadowed by INTNETMACTABENTRY::fActive. */
bool fActive;
- /** Whether someone is currently in the destructor. */
+ /** Whether someone is currently in the destructor or has indicated that
+ * the end is nigh by means of IntNetR0IfAbortWait. */
bool volatile fDestroying;
/** Number of yields done to try make the interface read pending data.
* We will stop yielding when this reaches a threshold assuming that the VM is
@@ -264,6 +265,8 @@ typedef struct INTNETIF
* This is NULL when it's in use as a precaution against unserialized
* transmitting. This is grown when new interfaces are added to the network. */
PINTNETDSTTAB volatile pDstTab;
+ /** Pointer to the trunk's per interface data. Can be NULL. */
+ void *pvIfData;
} INTNETIF;
/** Pointer to an internal network interface. */
typedef INTNETIF *PINTNETIF;
@@ -2474,10 +2477,11 @@ static void intnetR0IfSend(PINTNETIF pIf, PINTNETIF pIfSender, PINTNETSG pSG, PC
* The caller holds the trunk lock.
*
* @param pThis The trunk.
+ * @param pIfSender The IF sending the frame.
* @param pSG Pointer to the gather list.
* @param fDst The destination flags.
*/
-static int intnetR0TrunkIfSendGsoFallback(PINTNETTRUNKIF pThis, PINTNETSG pSG, uint32_t fDst)
+static int intnetR0TrunkIfSendGsoFallback(PINTNETTRUNKIF pThis, PINTNETIF pIfSender, PINTNETSG pSG, uint32_t fDst)
{
/*
* Since we're only using this for GSO frame comming from the internal
@@ -2512,7 +2516,7 @@ static int intnetR0TrunkIfSendGsoFallback(PINTNETTRUNKIF pThis, PINTNETSG pSG, u
u.SG.aSegs[1].pv = (uint8_t *)pSG->aSegs[0].pv + offSegPayload;
u.SG.aSegs[1].cb = (uint32_t)cbSegPayload;
- int rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, &u.SG, fDst);
+ int rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pIfSender->pvIfData, &u.SG, fDst);
if (RT_FAILURE(rc))
return rc;
}
@@ -2635,9 +2639,9 @@ static void intnetR0TrunkIfSend(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork, P
int rc;
if ( pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID
|| intnetR0TrunkIfCanHandleGsoFrame(pThis, pSG, fDst) )
- rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pSG, fDst);
+ rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pIfSender->pvIfData, pSG, fDst);
else
- rc = intnetR0TrunkIfSendGsoFallback(pThis, pSG, fDst);
+ rc = intnetR0TrunkIfSendGsoFallback(pThis, pIfSender, pSG, fDst);
/** @todo failure statistics? */
Log2(("intnetR0TrunkIfSend: %Rrc fDst=%d\n", rc, fDst)); NOREF(rc);
@@ -3639,7 +3643,7 @@ INTNETR0DECL(int) IntNetR0IfSetMacAddress(INTNETIFHANDLE hIf, PSUPDRVSESSION pSe
Log(("IntNetR0IfSetMacAddress: pfnNotifyMacAddress hIf=%RX32\n", hIf));
PINTNETTRUNKIFPORT pIfPort = pTrunk->pIfPort;
if (pIfPort)
- pIfPort->pfnNotifyMacAddress(pIfPort, hIf, pMac);
+ pIfPort->pfnNotifyMacAddress(pIfPort, pIf->pvIfData, pMac);
intnetR0BusyDecTrunk(pTrunk);
}
}
@@ -3840,10 +3844,14 @@ INTNETR0DECL(int) IntNetR0IfWait(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, ui
Log(("IntNetR0IfWait: returns VERR_INVALID_HANDLE\n"));
return VERR_INVALID_HANDLE;
}
- const INTNETIFHANDLE hIfSelf = pIf->hIf;
- const RTSEMEVENT hRecvEvent = pIf->hRecvEvent;
+
+ const INTNETIFHANDLE hIfSelf = pIf->hIf;
+ const RTSEMEVENT hRecvEvent = pIf->hRecvEvent;
+ const bool fDestroying = ASMAtomicReadBool(&pIf->fDestroying);
if ( hIfSelf != hIf /* paranoia */
- && hRecvEvent != NIL_RTSEMEVENT)
+ || hRecvEvent == NIL_RTSEMEVENT
+ || fDestroying
+ )
{
Log(("IntNetR0IfWait: returns VERR_SEM_DESTROYED\n"));
return VERR_SEM_DESTROYED;
@@ -3898,6 +3906,79 @@ INTNETR0DECL(int) IntNetR0IfWaitReq(PSUPDRVSESSION pSession, PINTNETIFWAITREQ pR
/**
+ * Wake up any threads waiting on the interface.
+ *
+ * @returns VBox status code.
+ * @param hIf The interface handle.
+ * @param pSession The caller's session.
+ * @param fNoMoreWaits When set, no more waits are permitted.
+ */
+INTNETR0DECL(int) IntNetR0IfAbortWait(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fNoMoreWaits)
+{
+ Log4(("IntNetR0IfAbortWait: hIf=%RX32 fNoMoreWaits=%RTbool\n", hIf, fNoMoreWaits));
+
+ /*
+ * Get and validate essential handles.
+ */
+ PINTNET pIntNet = g_pIntNet;
+ AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
+ AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
+
+ PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
+ if (!pIf)
+ {
+ Log(("IntNetR0IfAbortWait: returns VERR_INVALID_HANDLE\n"));
+ return VERR_INVALID_HANDLE;
+ }
+
+ const INTNETIFHANDLE hIfSelf = pIf->hIf;
+ const RTSEMEVENT hRecvEvent = pIf->hRecvEvent;
+ const bool fDestroying = ASMAtomicReadBool(&pIf->fDestroying);
+ if ( hIfSelf != hIf /* paranoia */
+ || hRecvEvent == NIL_RTSEMEVENT
+ || fDestroying
+ )
+ {
+ Log(("IntNetR0IfAbortWait: returns VERR_SEM_DESTROYED\n"));
+ return VERR_SEM_DESTROYED;
+ }
+
+ /*
+ * Set fDestroying if requested to do so and then wake up all the sleeping
+ * threads (usually just one). We leave the semaphore in the signalled
+ * state so the next caller will return immediately.
+ */
+ if (fNoMoreWaits)
+ ASMAtomicWriteBool(&pIf->fDestroying, true);
+
+ uint32_t cSleepers = ASMAtomicReadU32(&pIf->cSleepers) + 1;
+ while (cSleepers-- > 0)
+ {
+ int rc = RTSemEventSignal(pIf->hRecvEvent);
+ AssertRC(rc);
+ }
+
+ Log4(("IntNetR0IfWait: returns %Rrc\n", VINF_SUCCESS));
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * VMMR0 request wrapper for IntNetR0IfAbortWait.
+ *
+ * @returns see IntNetR0IfWait.
+ * @param pSession The caller's session.
+ * @param pReq The request packet.
+ */
+INTNETR0DECL(int) IntNetR0IfAbortWaitReq(PSUPDRVSESSION pSession, PINTNETIFABORTWAITREQ pReq)
+{
+ if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
+ return VERR_INVALID_PARAMETER;
+ return IntNetR0IfAbortWait(pReq->hIf, pSession, pReq->fNoMoreWaits);
+}
+
+
+/**
* Close an interface.
*
* @returns VBox status code.
@@ -3911,34 +3992,18 @@ INTNETR0DECL(int) IntNetR0IfClose(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession)
/*
* Validate and free the handle.
- *
- * We grab the big mutex before we free the handle to avoid any handle
- * confusion on the trunk.
*/
PINTNET pIntNet = g_pIntNet;
AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
- RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
-
PINTNETIF pIf = (PINTNETIF)RTHandleTableFreeWithCtx(pIntNet->hHtIfs, hIf, pSession);
if (!pIf)
- {
- RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
return VERR_INVALID_HANDLE;
- }
/* Mark the handle as freed so intnetR0IfDestruct won't free it again. */
ASMAtomicWriteU32(&pIf->hIf, INTNET_HANDLE_INVALID);
- /* Notify the trunk that the interface has been disconnected. */
- PINTNETNETWORK pNetwork = pIf->pNetwork;
- PINTNETTRUNKIF pTrunk = pNetwork ? pNetwork->MacTab.pTrunk : NULL;
- if (pTrunk && pTrunk->pIfPort)
- pTrunk->pIfPort->pfnDisconnectInterface(pTrunk->pIfPort, hIf);
-
- RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
-
/*
* Signal the event semaphore to wake up any threads in IntNetR0IfWait
* and give them a moment to get out and release the interface.
@@ -4042,10 +4107,9 @@ static DECLCALLBACK(void) intnetR0IfDestruct(void *pvObj, void *pvUser1, void *p
RTSpinlockReleaseNoInts(pNetwork->hAddrSpinlock, &Tmp);
- /* If we freed the handle just now, notify the trunk about the
- interface being destroyed. */
- if (hIf != INTNET_HANDLE_INVALID && pTrunk && pTrunk->pIfPort)
- pTrunk->pIfPort->pfnDisconnectInterface(pTrunk->pIfPort, hIf);
+ /* Notify the trunk about the interface being destroyed. */
+ if (pTrunk && pTrunk->pIfPort)
+ pTrunk->pIfPort->pfnDisconnectInterface(pTrunk->pIfPort, pIf->pvIfData);
/* Wait for the interface to quiesce while we still can. */
intnetR0BusyWait(pNetwork, &pIf->cBusy);
@@ -4189,6 +4253,7 @@ static int intnetR0NetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSess
pIf->hRecvInSpinlock = NIL_RTSPINLOCK;
pIf->cBusy = 0;
//pIf->pDstTab = NULL;
+ //pIf->pvIfData = NULL;
for (int i = kIntNetAddrType_Invalid + 1; i < kIntNetAddrType_End && RT_SUCCESS(rc); i++)
rc = intnetR0IfAddrCacheInit(&pIf->aAddrCache[i], (INTNETADDRTYPE)i,
@@ -4259,7 +4324,7 @@ static int intnetR0NetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSess
{
Log(("intnetR0NetworkCreateIf: pfnConnectInterface hIf=%RX32\n", pIf->hIf));
if (pTrunk->pIfPort)
- rc = pTrunk->pIfPort->pfnConnectInterface(pTrunk->pIfPort, pIf->hIf);
+ rc = pTrunk->pIfPort->pfnConnectInterface(pTrunk->pIfPort, pIf, &pIf->pvIfData);
intnetR0BusyDecTrunk(pTrunk);
}
if (RT_SUCCESS(rc))
@@ -4409,13 +4474,14 @@ static DECLCALLBACK(INTNETSWDECISION) intnetR0TrunkIfPortPreRecv(PINTNETTRUNKSWP
/** @copydoc INTNETTRUNKSWPORT::pfnRecv */
-static DECLCALLBACK(bool) intnetR0TrunkIfPortRecv(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG, uint32_t fSrc)
+static DECLCALLBACK(bool) intnetR0TrunkIfPortRecv(PINTNETTRUNKSWPORT pSwitchPort, void *pvIf, PINTNETSG pSG, uint32_t fSrc)
{
PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
/* assert some sanity */
AssertPtr(pSG);
Assert(fSrc);
+ NOREF(pvIf); /* later */
/*
* Mark the trunk as busy, make sure we've got a network and that there are