Index: trunk/src/VBox/Devices/USB/usbip/USBProxyDevice-usbip.cpp
===================================================================
--- trunk/src/VBox/Devices/USB/usbip/USBProxyDevice-usbip.cpp	(revision 58170)
+++ trunk/src/VBox/Devices/USB/usbip/USBProxyDevice-usbip.cpp	(revision 60550)
@@ -231,4 +231,5 @@
 typedef UsbIpReqSubmit *PUsbIpReqSubmit;
 #pragma pack()
+AssertCompileSize(UsbIpReqSubmit, 48);
 
 /**
@@ -256,4 +257,5 @@
 typedef UsbIpRetSubmit *PUsbIpRetSubmit;
 #pragma pack()
+AssertCompileSize(UsbIpRetSubmit, 48);
 
 /**
@@ -267,8 +269,11 @@
     /** The sequence number to unlink. */
     uint32_t       u32SeqNum;
+    /** Padding - unused. */
+    uint8_t        abPadding[24];
 } UsbIpReqUnlink;
 /** Pointer to a URB unlink request. */
 typedef UsbIpReqUnlink *PUsbIpReqUnlink;
 #pragma pack()
+AssertCompileSize(UsbIpReqUnlink, 48);
 
 /**
@@ -282,8 +287,11 @@
     /** Status of the request. */
     int32_t        u32Status;
+    /** Padding - unused. */
+    uint8_t        abPadding[24];
 } UsbIpRetUnlink;
 /** Pointer to a URB unlink request. */
 typedef UsbIpRetUnlink *PUsbIpRetUnlink;
 #pragma pack()
+AssertCompileSize(UsbIpRetUnlink, 48);
 
 /**
@@ -335,4 +343,8 @@
     /** Sequence number the assigned URB is identified by. */
     uint32_t           u32SeqNumUrb;
+    /** Sequence number of the unlink command if the URB was cancelled. */
+    uint32_t           u32SeqNumUrbUnlink;
+    /** Flag whether the URB was cancelled. */
+    bool               fCancelled;
     /** Pointer to the VUSB URB. */
     PVUSBURB           pVUsbUrb;
@@ -845,4 +857,7 @@
 
     UsbIpReqSubmit ReqSubmit;
+
+    RT_ZERO(ReqSubmit);
+
     uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
     ReqSubmit.Hdr.u32ReqRet           = USBIP_CMD_SUBMIT;
@@ -883,5 +898,5 @@
  * @param  u32SeqNum         The sequence number to search for.
  */
-static PUSBPROXYURBUSBIP usbProxyUsbIpGetUrbFromSeqNum(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNum)
+static PUSBPROXYURBUSBIP usbProxyUsbIpGetInFlightUrbFromSeqNum(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNum)
 {
     bool fFound = false;
@@ -891,4 +906,29 @@
     {
         if (pIt->u32SeqNumUrb == u32SeqNum)
+        {
+            fFound = true;
+            break;
+        }
+    }
+
+    return fFound ? pIt : NULL;
+}
+
+/**
+ * Returns the URB matching the given sequence number from the cancel list.
+ *
+ * @returns pointer to the URB matching the given sequence number or NULL
+ * @param  pProxyDevUsbIp    The USB/IP proxy device data.
+ * @param  u32SeqNum         The sequence number to search for.
+ */
+static PUSBPROXYURBUSBIP usbProxyUsbIpGetCancelledUrbFromSeqNum(PUSBPROXYDEVUSBIP pProxyDevUsbIp, uint32_t u32SeqNum)
+{
+    bool fFound = false;
+    PUSBPROXYURBUSBIP pIt;
+
+    RTListForEach(&pProxyDevUsbIp->ListUrbsInFlight, pIt, USBPROXYURBUSBIP, NodeList)
+    {
+        if (   pIt->u32SeqNumUrbUnlink == u32SeqNum
+            && pIt->fCancelled == true)
         {
             fFound = true;
@@ -981,13 +1021,13 @@
                 case USBPROXYUSBIPRECVSTATE_HDR_RESIDUAL:
                 {
-                    /* Get the URB from the in flight list. */
-                    pProxyDevUsbIp->pUrbUsbIp = usbProxyUsbIpGetUrbFromSeqNum(pProxyDevUsbIp, RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
-                    if (pProxyDevUsbIp->pUrbUsbIp)
+                    /** @todo: Verify that the directions match, verify that the length doesn't exceed the buffer. */
+
+                    switch (RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32ReqRet))
                     {
-                        /** @todo: Verify that the directions match, verify that the length doesn't exceed the buffer. */
-
-                        switch (RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32ReqRet))
-                        {
-                            case USBIP_RET_SUBMIT:
+                        case USBIP_RET_SUBMIT:
+                            /* Get the URB from the in flight list. */
+                            pProxyDevUsbIp->pUrbUsbIp = usbProxyUsbIpGetInFlightUrbFromSeqNum(pProxyDevUsbIp, RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
+                            if (pProxyDevUsbIp->pUrbUsbIp)
+                            {
                                 usbProxyUsbIpRetSubmitN2H(&pProxyDevUsbIp->BufRet.RetSubmit);
 
@@ -1020,17 +1060,23 @@
                                     usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
                                 }
-                                break;
-                            case USBIP_RET_UNLINK:
+                            }
+                            else
+                            {
+                                LogRel(("USB/IP: Received reply with sequence number %u doesn't match any local URB\n", pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
+                                usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
+                            }
+                            break;
+                        case USBIP_RET_UNLINK:
+                            pProxyDevUsbIp->pUrbUsbIp = usbProxyUsbIpGetCancelledUrbFromSeqNum(pProxyDevUsbIp, RT_N2H_U32(pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
+                            if (pProxyDevUsbIp->pUrbUsbIp)
+                            {
                                 usbProxyUsbIpRetUnlinkN2H(&pProxyDevUsbIp->BufRet.RetUnlink);
                                 pUrbUsbIp = pProxyDevUsbIp->pUrbUsbIp;
                                 pUrbUsbIp->pVUsbUrb->enmStatus = usbProxyUsbIpVUsbStatusConvertFromStatus(pProxyDevUsbIp->BufRet.RetUnlink.u32Status);
-                                usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
-                                break;
-                        }
-                    }
-                    else
-                    {
-                        LogRel(("USB/IP: Received reply with sequence number doesn't match any local URB\n", pProxyDevUsbIp->BufRet.Hdr.u32SeqNum));
-                        usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
+                            }
+                            /* else: Probably received the data for the URB and is complete already. */
+
+                            usbProxyUsbIpResetRecvState(pProxyDevUsbIp);
+                            break;
                     }
 
@@ -1119,18 +1165,20 @@
     aSegReq[0].cbSeg = sizeof(ReqSubmit);
 
-
     switch (pUrb->enmType)
     {
         case VUSBXFERTYPE_MSG:
             memcpy(&ReqSubmit.Setup, &pUrb->abData, sizeof(ReqSubmit.Setup));
+            ReqSubmit.u32TransferBufferLength -= sizeof(VUSBSETUP);
             if (pUrb->enmDir == VUSBDIRECTION_OUT)
             {
                 aSegReq[cSegsUsed].cbSeg = pUrb->cbData - sizeof(VUSBSETUP);
                 aSegReq[cSegsUsed].pvSeg = pUrb->abData + sizeof(VUSBSETUP);
-                cSegsUsed++;
+                if (aSegReq[cSegsUsed].cbSeg)
+                    cSegsUsed++;
             }
             LogFlowFunc(("Message (Control) URB\n"));
             break;
         case VUSBXFERTYPE_ISOC:
+            LogFlowFunc(("Isochronous URB\n"));
             ReqSubmit.u32XferFlags |= USBIP_XFER_FLAGS_ISO_ASAP;
             ReqSubmit.u32NumIsocPkts = pUrb->cIsocPkts;
@@ -1161,4 +1209,5 @@
         case VUSBXFERTYPE_BULK:
         case VUSBXFERTYPE_INTR:
+            LogFlowFunc(("Bulk URB\n"));
             if (pUrb->enmDir == VUSBDIRECTION_OUT)
             {
@@ -1467,4 +1516,5 @@
         return VERR_NO_MEMORY;
 
+    pUrbUsbIp->fCancelled = false;
     pUrbUsbIp->pVUsbUrb = pUrb;
     pUrb->Dev.pvPrivate = pUrbUsbIp;
@@ -1547,4 +1597,6 @@
     UsbIpReqUnlink ReqUnlink;
 
+    RT_ZERO(ReqUnlink);
+
     uint32_t u32SeqNum = usbProxyUsbIpSeqNumGet(pProxyDevUsbIp);
     ReqUnlink.Hdr.u32ReqRet           = USBIP_CMD_UNLINK;
@@ -1556,5 +1608,12 @@
 
     usbProxyUsbIpReqUnlinkH2N(&ReqUnlink);
-    return RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqUnlink, sizeof(ReqUnlink));
+    int rc = RTTcpWrite(pProxyDevUsbIp->hSocket, &ReqUnlink, sizeof(ReqUnlink));
+    if (RT_SUCCESS(rc))
+    {
+        pUrbUsbIp->u32SeqNumUrbUnlink = u32SeqNum;
+        pUrbUsbIp->fCancelled         = true;
+    }
+
+    return rc;
 }
 
