Index: /trunk/include/VBox/intnet.h
===================================================================
--- /trunk/include/VBox/intnet.h	(revision 10680)
+++ /trunk/include/VBox/intnet.h	(revision 10681)
@@ -337,10 +337,10 @@
      * @returns The old setting.
      *
-     * @param   pIfPort     Pointer to this structure.
+     * @param   pSwitchPort Pointer to this structure.
      * @param   fEnable     Whether to enable or disable it.
      *
      * @remarks Will grab the network semaphore.
      */
-    DECLR0CALLBACKMEMBER(bool, pfnSetSGPhys,(PINTNETTRUNKSWPORT pIfPort, bool fEnable));
+    DECLR0CALLBACKMEMBER(bool, pfnSetSGPhys,(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable));
 
     /**
@@ -350,5 +350,5 @@
      *          false if it should hit the wire.
      *
-     * @param   pIfPort     Pointer to this structure.
+     * @param   pSwitchPort Pointer to this structure.
      * @param   pSG         The (scatter /) gather structure for the frame.
      *                      This will only be use during the call, so a temporary one can
@@ -360,15 +360,15 @@
      * @remark  NAT and TAP will use this interface.
      */
-    DECLR0CALLBACKMEMBER(bool, pfnRecv,(PINTNETTRUNKSWPORT pIfPort, PINTNETSG pSG, uint32_t fSrc));
+    DECLR0CALLBACKMEMBER(bool, pfnRecv,(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG, uint32_t fSrc));
 
     /**
      * Retain a SG.
      *
-     * @param   pIfPort     Pointer to this structure.
+     * @param   pSwitchPort Pointer to this structure.
      * @param   pSG         Pointer to the (scatter /) gather structure.
      *
      * @remarks Will not grab any locks.
      */
-    DECLR0CALLBACKMEMBER(void, pfnSGRetain,(PINTNETTRUNKSWPORT pIfPort, PINTNETSG pSG));
+    DECLR0CALLBACKMEMBER(void, pfnSGRetain,(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG));
 
     /**
@@ -378,10 +378,10 @@
      * be done in an asynchronous manner.
      *
-     * @param   pIfPort     Pointer to this structure.
+     * @param   pSwitchPort Pointer to this structure.
      * @param   pSG         Pointer to the (scatter /) gather structure.
      *
      * @remarks Will grab the network semaphore.
      */
-    DECLR0CALLBACKMEMBER(void, pfnSGRelease,(PINTNETTRUNKSWPORT pIfPort, PINTNETSG pSG));
+    DECLR0CALLBACKMEMBER(void, pfnSGRelease,(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG));
 
     /** Structure version number. (INTNETTRUNKSWPORT_VERSION) */
Index: /trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp
===================================================================
--- /trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp	(revision 10680)
+++ /trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp	(revision 10681)
@@ -36,4 +36,5 @@
 #include <iprt/assert.h>
 #include <iprt/string.h>
+#include <iprt/time.h>
 
 
@@ -97,12 +98,20 @@
 {
     /** The port interface we present to the component. */
-    INTNETTRUNKSWPORT   SwitchPort;
+    INTNETTRUNKSWPORT       SwitchPort;
     /** The port interface we get from the component. */
-    PINTNETTRUNKIFPORT  pIfPort;
+    PINTNETTRUNKIFPORT      pIfPort;
     /** The trunk mutex that serializes all calls <b>to</b> the component. */
-    RTSEMFASTMUTEX      FastMutex;
+    RTSEMFASTMUTEX          FastMutex;
+    /** Pointer to the network we're connect to.
+     * This may be NULL if we're orphaned? */
+    struct INTNETNETWORK   *pNetwork;
+    /** Whether to supply physical addresses with the outbound SGs. */
+    bool volatile           fPhysSG;
 } INTNETTRUNKIF;
 /** Pointer to a trunk interface. */
 typedef INTNETTRUNKIF *PINTNETTRUNKIF;
+
+/** Converts a pointer to INTNETTRUNKIF::SwitchPort to a PINTNETTRUNKIF. */
+#define INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort) ((PINTNETTRUNKIF)(pSwitchPort))
 
 
@@ -118,4 +127,7 @@
      * This is protected by the INTNET::FastMutex. */
     PINTNETIF               pIFs;
+    /** Pointer to the trunk interface.
+     * Can be NULL if there is no trunk connection. */
+    PINTNETTRUNKIF          pTrunkIF;
     /** The network mutex.
      * It protects everything dealing with this network. */
@@ -191,4 +203,13 @@
     INTNETHT                IfHandles;
 } INTNET;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static PINTNETTRUNKIF intnetTrunkIfRetain(PINTNETTRUNKIF pThis);
+static void intnetTrunkIfRelease(PINTNETTRUNKIF pThis);
+static bool intnetTrunkIfOutLock(PINTNETTRUNKIF pThis);
+static void intnetTrunkIfOutUnlock(PINTNETTRUNKIF pThis);
 
 
@@ -1253,32 +1274,234 @@
 
 
-#ifdef IN_RING0
+
+
 
 /** @copydoc INTNETTRUNKSWPORT::pfnSetSGPhys */
-static DECLCALLBACK(bool) intnetTrunkIfPortSetSGPhys(PINTNETTRUNKSWPORT pIfPort, bool fEnable)
-{
+static DECLCALLBACK(bool) intnetTrunkIfPortSetSGPhys(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable)
+{
+    PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
     AssertMsgFailed(("Not implemented because it wasn't required on Darwin\n"));
+    return ASMAtomicXchgBool(&pThis->fPhysSG, fEnable);
+}
+
+
+/** @copydoc INTNETTRUNKSWPORT::pfnRecv */
+static DECLCALLBACK(bool) intnetTrunkIfPortRecv(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG, uint32_t fSrc)
+{
+    PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
+    PINTNETNETWORK pNetwork = pThis->pNetwork;
+
+    /* assert some sanity */
+    AssertPtrReturn(pNetwork, false);
+    AssertReturn(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX, false);
+    AssertPtr(pSG);
+    Assert(fSrc);
+
+    /*
+     *
+     */
+
+
     return false;
 }
 
 
-/** @copydoc INTNETTRUNKSWPORT::pfnRecv */
-static DECLCALLBACK(bool) intnetTrunkIfPortRecv(PINTNETTRUNKSWPORT pIfPort, PINTNETSG pSG, uint32_t fSrc)
-{
+/** @copydoc INTNETTRUNKSWPORT::pfnSGRetain */
+static DECLCALLBACK(void) intnetTrunkIfPortSGRetain(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
+{
+    PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
+    PINTNETNETWORK pNetwork = pThis->pNetwork;
+
+    /* assert some sanity */
+    AssertPtrReturnVoid(pNetwork);
+    AssertReturnVoid(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX);
+    AssertPtr(pSG);
+    Assert(pSG->cUsers > 0);
+
+    /* do it. */
+    ++pSG->cUsers;
+}
+
+
+/** @copydoc INTNETTRUNKSWPORT::pfnSGRelease */
+static DECLCALLBACK(void) intnetTrunkIfPortSGRelease(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
+{
+    PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
+    PINTNETNETWORK pNetwork = pThis->pNetwork;
+
+    /* assert some sanity */
+    AssertPtrReturnVoid(pNetwork);
+    AssertReturnVoid(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX);
+    AssertPtr(pSG);
+    Assert(pSG->cUsers > 0);
+
+    /*
+     * Free it?
+     */
+    if (!--pSG->cUsers)
+    {
+        /** @todo later */
+    }
+}
+
+
+/**
+ * Retain the trunk interface.
+ *
+ * @returns pThis.
+ *
+ * @param   pThis       The trunk.
+ *
+ * @remarks Any locks.
+ */
+static PINTNETTRUNKIF intnetTrunkIfRetain(PINTNETTRUNKIF pThis)
+{
+    if (pThis && pThis->pIfPort)
+        pThis->pIfPort->pfnRetain(pThis->pIfPort);
+    return pThis;
+}
+
+
+/**
+ * Release the trunk interface.
+ *
+ * @param   pThis       The trunk.
+ */
+static void intnetTrunkIfRelease(PINTNETTRUNKIF pThis)
+{
+    if (pThis && pThis->pIfPort)
+        pThis->pIfPort->pfnRelease(pThis->pIfPort);
+}
+
+
+/**
+ * Takes the out-bound trunk lock.
+ *
+ * This will ensure that pIfPort is valid.
+ *
+ * @returns success indicator.
+ * @param   pThis       The trunk.
+ *
+ * @remarks No locks other than the create/destroy one.
+ */
+static bool intnetTrunkIfOutLock(PINTNETTRUNKIF pThis)
+{
+    AssertPtrReturn(pThis, false);
+    int rc = RTSemFastMutexRequest(pThis->FastMutex);
+    if (RT_SUCCESS(rc))
+    {
+        if (RT_LIKELY(pThis->pIfPort))
+            return true;
+        RTSemFastMutexRelease(pThis->FastMutex);
+    }
+    else
+        AssertMsg(rc == VERR_SEM_DESTROYED, ("%Rrc\n", rc));
     return false;
 }
 
 
-/** @copydoc INTNETTRUNKSWPORT::pfnSGRetain */
-static DECLCALLBACK(void) intnetTrunkIfPortSGRetain(PINTNETTRUNKSWPORT pIfPort, PINTNETSG pSG)
-{
-
-}
-
-
-/** @copydoc INTNETTRUNKSWPORT::pfnSGRelease */
-static DECLCALLBACK(void) intnetTrunkIfPortSGRelease(PINTNETTRUNKSWPORT pIfPort, PINTNETSG pSG)
-{
-
+/**
+ * Releases the out-bound trunk lock.
+ *
+ * @param   pThis       The trunk.
+ */
+static void intnetTrunkIfOutUnlock(PINTNETTRUNKIF pThis)
+{
+    if (pThis)
+    {
+        int rc = RTSemFastMutexRelease(pThis->FastMutex);
+        AssertRC(rc);
+    }
+}
+
+
+/**
+ * Activates the trunk interface.
+ *
+ * @param   pThis       The trunk.
+ * @param   fActive     What to do with it.
+ *
+ * @remarks Caller may only own the create/destroy lock.
+ */
+static void intnetTrunkIfActivate(PINTNETTRUNKIF pThis, bool fActive)
+{
+    if (intnetTrunkIfOutLock(pThis))
+    {
+        pThis->pIfPort->pfnSetActive(pThis->pIfPort, fActive);
+        intnetTrunkIfOutUnlock(pThis);
+    }
+}
+
+
+/**
+ * Shutdown the trunk interface.
+ *
+ * @param   pThis       The trunk.
+ * @param   pNetworks   The network.
+ *
+ * @remarks The caller must *NOT* hold the network lock. The global
+ *          create/destroy lock is fine though.
+ */
+static void intnetTrunkIfDestroy(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork)
+{
+    /* assert sanity */
+    if (!pThis)
+        return;
+    AssertPtr(pThis);
+    Assert(pThis->pNetwork == pNetwork);
+    AssertPtrNull(pThis->pIfPort);
+
+    /*
+     * The interface has already been deactivated, we just to wait for
+     * it to become idle before we can disconnect and release it.
+     */
+    PINTNETTRUNKIFPORT pIfPort = pThis->pIfPort;
+    if (pIfPort)
+    {
+        intnetTrunkIfOutLock(pThis);
+
+        /* unset it */
+        pThis->pIfPort = NULL;
+
+        /* wait in portions so we can complain ever now an then. */
+        uint64_t StartTS = RTTimeSystemNanoTS();
+        int rc = pIfPort->pfnWaitForIdle(pIfPort, 10*1000);
+        if (RT_FAILURE(rc))
+        {
+            LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc).\n",
+                    pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
+            Assert(rc == VERR_TIMEOUT);
+            while (     RT_FAILURE(rc)
+                   &&   RTTimeSystemNanoTS() - StartTS < UINT64_C(30000000000)) /* 30 sec */
+                rc = pIfPort->pfnWaitForIdle(pIfPort, 10*1000);
+            if (rc == VERR_TIMEOUT)
+            {
+                LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc).\n",
+                        pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
+                while (     rc == VERR_TIMEOUT
+                       &&   RTTimeSystemNanoTS() - StartTS < UINT64_C(360000000000)) /* 360 sec */
+                    rc = pIfPort->pfnWaitForIdle(pIfPort, 30*1000);
+                if (RT_FAILURE(rc))
+                {
+                    LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc), giving up.\n",
+                            pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
+                    AssertRC(rc);
+                }
+            }
+        }
+
+        /* disconnect & release it. */
+        pIfPort->pfnDisconnectAndRelease(pIfPort);
+    }
+
+    /*
+     * Free up the resources.
+     */
+    RTSEMFASTMUTEX FastMutex = pThis->FastMutex;
+    pThis->FastMutex = NIL_RTSEMFASTMUTEX;
+    pThis->pNetwork = NULL;
+    RTSemFastMutexRelease(FastMutex);
+    RTSemFastMutexDestroy(FastMutex);
+    RTMemFree(pThis);
 }
 
@@ -1335,7 +1558,10 @@
     pTrunkIF->SwitchPort.u32VersionEnd  = INTNETTRUNKSWPORT_VERSION;
     //pTrunkIF->pIfPort = NULL;
+    pTrunkIF->pNetwork = pNetwork;
+    //pTrunkIF->fPhysSG = false;
     int rc = RTSemFastMutexCreate(&pTrunkIF->FastMutex);
     if (RT_SUCCESS(rc))
     {
+#ifdef IN_RING0 /* (testcase is ring-3) */
         /*
          * Query the factory we want, then use it create and connect the trunk.
@@ -1350,4 +1576,5 @@
             {
                 Assert(pTrunkIF->pIfPort);
+                pNetwork->pTrunkIF = pTrunkIF;
                 LogFlow(("intnetNetworkCreateTrunkConnection: VINF_SUCCESS - pszName=%s szTrunk=%s Network=%s\n",
                          rc, pszName, pNetwork->szTrunk, pNetwork->szName));
@@ -1355,7 +1582,8 @@
             }
         }
-
-        RTMemFree(pTrunkIF);
-    }
+#endif /* IN_RING0 */
+        RTSemFastMutexDestroy(pTrunkIF->FastMutex);
+    }
+    RTMemFree(pTrunkIF);
     LogFlow(("intnetNetworkCreateTrunkConnection: %Rrc - pszName=%s szTrunk=%s Network=%s\n",
              rc, pszName, pNetwork->szTrunk, pNetwork->szName));
@@ -1363,5 +1591,4 @@
 }
 
-#endif /* IN_RING0 */
 
 
@@ -1399,6 +1626,12 @@
     Assert(pNetwork->pIntNet == pIntNet);
 
+    /* take the create/destroy sem. */
     RTSemFastMutexRequest(pIntNet->FastMutex);
 
+    /*
+     * Deactivate the trunk connection first (if any).
+     */
+    if (pNetwork->pTrunkIF)
+        intnetTrunkIfActivate(pNetwork->pTrunkIF, false /* fActive */);
 
     /*
@@ -1421,6 +1654,4 @@
     pNetwork->pvObj = NULL;
 
-    RTSemFastMutexRequest(pNetwork->FastMutex);
-
     /*
      * Because of the undefined order of the per session object dereferencing when closing a session,
@@ -1428,4 +1659,6 @@
      * deal with this by simply orphaning the interfaces.
      */
+    RTSemFastMutexRequest(pNetwork->FastMutex);
+
     PINTNETIF pCur = pNetwork->pIFs;
     while (pCur)
@@ -1437,5 +1670,16 @@
     }
 
+    /* Grab and zap the trunk pointer before leaving the mutex. */
+    PINTNETTRUNKIF pTrunkIF = pNetwork->pTrunkIF;
+    pNetwork->pTrunkIF = NULL;
+
     RTSemFastMutexRelease(pNetwork->FastMutex);
+
+    /*
+     * If there is a trunk, delete it.
+     * Note that this may tak a while if we're unlucky...
+     */
+    if (pTrunkIF)
+        intnetTrunkIfDestroy(pTrunkIF, pNetwork);
 
     /*
@@ -1446,4 +1690,5 @@
     RTMemFree(pNetwork);
 
+    /* release the create/destroy sem. (can be done before trunk destruction.) */
     RTSemFastMutexRelease(pIntNet->FastMutex);
 }
Index: /trunk/src/VBox/Devices/Network/testcase/tstIntNet-1.cpp
===================================================================
--- /trunk/src/VBox/Devices/Network/testcase/tstIntNet-1.cpp	(revision 10680)
+++ /trunk/src/VBox/Devices/Network/testcase/tstIntNet-1.cpp	(revision 10681)
@@ -123,4 +123,5 @@
     }
 
+    RTThreadSleep(1000);
     SUPTerm(false /* not forced */);
 
Index: /trunk/src/VBox/Devices/Network/testcase/tstIntNetR0.cpp
===================================================================
--- /trunk/src/VBox/Devices/Network/testcase/tstIntNetR0.cpp	(revision 10680)
+++ /trunk/src/VBox/Devices/Network/testcase/tstIntNetR0.cpp	(revision 10681)
@@ -29,4 +29,6 @@
 #undef INTNETR0DECL
 #define INTNETR0DECL INTNETR3DECL
+#undef DECLR0CALLBACKMEMBER
+#define DECLR0CALLBACKMEMBER(type, name, args) DECLR3CALLBACKMEMBER(type, name, args)
 #include <VBox/intnet.h>
 #include <VBox/sup.h>
