Index: /trunk/src/VBox/Devices/Network/DrvNetShaper.cpp
===================================================================
--- /trunk/src/VBox/Devices/Network/DrvNetShaper.cpp	(revision 40705)
+++ /trunk/src/VBox/Devices/Network/DrvNetShaper.cpp	(revision 40706)
@@ -403,4 +403,5 @@
         rc = VINF_SUCCESS;
 
+    pThis->Filter.pIDrvNet = &pThis->INetworkDown;
     rc = PDMDrvHlpNetShaperAttach(pDrvIns, pThis->pszBwGroup, &pThis->Filter);
     if (RT_FAILURE(rc))
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 40705)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 40706)
@@ -710,4 +710,8 @@
 endif
 
+ifdef VBOX_WITH_NETSHAPER
+VBoxC_DEFS += VBOX_WITH_NETSHAPER
+endif
+
 ifeq ($(KBUILD_TARGET),darwin)
 VBoxC_ORDERDEPS += $(VBoxC_0_OUTDIR)/VBoxC.def
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 40705)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 40706)
@@ -3708,6 +3708,4 @@
         ComObjPtr<IBandwidthGroup> pBwGroup;
         Bstr strBwGroup;
-        PNETSHAPER pShaper = NULL;
-        PNETSHAPERFILTER pFilter = NULL;
         hrc = aNetworkAdapter->COMGETTER(BandwidthGroup)(pBwGroup.asOutParam());            H();
 
Index: /trunk/src/VBox/VMM/VMMR3/PDMNetShaper.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMNetShaper.cpp	(revision 40705)
+++ /trunk/src/VBox/VMM/VMMR3/PDMNetShaper.cpp	(revision 40706)
@@ -87,4 +87,6 @@
     /** Critical section protecting all members below. */
     RTCRITSECT               cs;
+    /** Pending TX thread. */
+    PPDMTHREAD               hTxThread;
     /** Pointer to the first bandwidth group. */
     PPDMNSBWGROUP            pBwGroupsHead;
@@ -221,4 +223,25 @@
 }
 
+static void pdmNsBwGroupXmitPending(PPDMNSBWGROUP pBwGroup)
+{
+    int rc = RTCritSectEnter(&pBwGroup->cs); AssertRC(rc);
+
+    PPDMNSFILTER pFilter = pBwGroup->pFiltersHead;
+    while (pFilter)
+    {
+        bool fChoked = ASMAtomicXchgBool(&pFilter->fChoked, false);
+        LogFlowFunc(("pFilter=%#p fChoked=%RTbool\n", pFilter, fChoked));
+        if (fChoked && pFilter->pIDrvNet)
+        {
+            LogFlowFunc(("Calling pfnXmitPending for pFilter=%#p\n", pFilter));
+            pFilter->pIDrvNet->pfnXmitPending(pFilter->pIDrvNet);
+        }
+
+        pFilter = pFilter->pNext;
+    }
+
+    rc = RTCritSectLeave(&pBwGroup->cs); AssertRC(rc);
+}
+
 static void pdmNsFilterLink(PPDMNSFILTER pFilter)
 {
@@ -316,4 +339,5 @@
 bool PDMR3NsAllocateBandwidth(PPDMNSFILTER pFilter, uint32_t cbTransfer)
 {
+    AssertPtrReturn(pFilter, VERR_INVALID_POINTER);
     if (!VALID_PTR(pFilter->pBwGroupR3))
         return true;
@@ -328,5 +352,8 @@
 
     if (cbTransfer > uTokens)
+    {
         fAllowed = false;
+        ASMAtomicWriteBool(&pFilter->fChoked, true);
+    }
     else
     {
@@ -338,7 +365,44 @@
     LogFlowFunc(("BwGroup=%#p{%s} cbTransfer=%u uTokens=%u uTokensAdded=%u fAllowed=%RTbool\n",
                  pBwGroup, pBwGroup->pszName, cbTransfer, uTokens, uTokensAdded, fAllowed));
-    return true; // @todo: i need to implement TX thread first! return fAllowed;
-}
-
+    return fAllowed;
+}
+
+/**
+ * I/O thread for pending TX.
+ *
+ * @returns VINF_SUCCESS (ignored).
+ * @param   pVM         The VM handle.
+ * @param   pThread     The PDM thread data.
+ */
+static DECLCALLBACK(int) pdmR3NsTxThread(PVM pVM, PPDMTHREAD pThread)
+{
+    PPDMNETSHAPER pShaper = (PPDMNETSHAPER)pThread->pvUser;
+    LogFlow(("pdmR3NsTxThread: pShaper=%p\n", pShaper));
+    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
+    {
+        RTThreadSleep(PDM_NETSHAPER_MAX_LATENCY);
+        /* Go over all bandwidth groups/filters calling pfnXmitPending */
+        int rc = RTCritSectEnter(&pShaper->cs); AssertRC(rc);
+        PPDMNSBWGROUP pBwGroup = pShaper->pBwGroupsHead;
+        while (pBwGroup)
+        {
+            pdmNsBwGroupXmitPending(pBwGroup);
+            pBwGroup = pBwGroup->pNext;
+        }
+        rc = RTCritSectLeave(&pShaper->cs); AssertRC(rc);
+    }
+    return VINF_SUCCESS;
+}
+
+/**
+ * @copydoc FNPDMTHREADWAKEUPINT
+ */
+static DECLCALLBACK(int) pdmR3NsTxWakeUp(PVM pVM, PPDMTHREAD pThread)
+{
+    PPDMNETSHAPER pShaper = (PPDMNETSHAPER)pThread->pvUser;
+    LogFlow(("pdmR3NsTxWakeUp: pShaper=%p\n", pShaper));
+    /* Nothing to do */
+    return VINF_SUCCESS;
+}
 
 /**
@@ -433,6 +497,16 @@
                           ("Network shaper was already initialized\n"));
 
-                pUVM->pdm.s.pNetShaper = pNetShaper;
-                return VINF_SUCCESS;
+                char szDesc[256];
+                static unsigned iThread;
+
+                RTStrPrintf(szDesc, sizeof(szDesc), "PDMNSTXThread-%d", ++iThread);
+                rc = PDMR3ThreadCreate(pVM, &pNetShaper->hTxThread, pNetShaper,
+                                       pdmR3NsTxThread, pdmR3NsTxWakeUp, 0,
+                                       RTTHREADTYPE_IO, szDesc);
+                if (RT_SUCCESS(rc))
+                {
+                    pUVM->pdm.s.pNetShaper = pNetShaper;
+                    return VINF_SUCCESS;
+                }
             }
 
