Index: /trunk/include/VBox/intnetinline.h
===================================================================
--- /trunk/include/VBox/intnetinline.h	(revision 28036)
+++ /trunk/include/VBox/intnetinline.h	(revision 28037)
@@ -82,7 +82,7 @@
     pSG->GsoCtx.cbMaxSeg= 0;
     pSG->GsoCtx.offHdr1 = 0;
-    pSG->GsoCtx.cbHdr1  = 0;
     pSG->GsoCtx.offHdr2 = 0;
-    pSG->GsoCtx.cbHdr2  = 0;
+    pSG->GsoCtx.au8Unused[0] = 0;
+    pSG->GsoCtx.au8Unused[1] = 0;
 #if ARCH_BITS == 64
     pSG->uPadding       = 0;
@@ -120,7 +120,7 @@
     pSG->GsoCtx.cbMaxSeg= pGso->cbMaxSeg;
     pSG->GsoCtx.offHdr1 = pGso->offHdr1;
-    pSG->GsoCtx.cbHdr1  = pGso->cbHdr1;
     pSG->GsoCtx.offHdr2 = pGso->offHdr2;
-    pSG->GsoCtx.cbHdr2  = pGso->cbHdr2;
+    pSG->GsoCtx.au8Unused[0] = 0;
+    pSG->GsoCtx.au8Unused[1] = 0;
 #if ARCH_BITS == 64
     pSG->uPadding       = 0;
Index: /trunk/include/VBox/pdmnetinline.h
===================================================================
--- /trunk/include/VBox/pdmnetinline.h	(revision 28036)
+++ /trunk/include/VBox/pdmnetinline.h	(revision 28037)
@@ -52,15 +52,13 @@
 
     PDMNETWORKGSOTYPE const enmType = (PDMNETWORKGSOTYPE)pGso->u8Type;
-    if (RT_UNLIKELY(enmType <= PDMNETWORKGSOTYPE_INVALID || enmType >= PDMNETWORKGSOTYPE_END))
+    if (RT_UNLIKELY( enmType <= PDMNETWORKGSOTYPE_INVALID || enmType >= PDMNETWORKGSOTYPE_END ))
         return false;
 
     /* all types requires both headers. */
-    if (RT_UNLIKELY(pGso->offHdr1 < sizeof(RTNETETHERHDR)))
-        return false;
-    if (RT_UNLIKELY(pGso->offHdr2 < sizeof(RTNETETHERHDR)))
-        return false;
-    if (RT_UNLIKELY(pGso->offHdr2 < (unsigned)pGso->offHdr1 + pGso->cbHdr1))
-        return false;
-    if (RT_UNLIKELY(pGso->cbHdrs  < (unsigned)pGso->offHdr2 + pGso->cbHdr2))
+    if (RT_UNLIKELY( pGso->offHdr1 < sizeof(RTNETETHERHDR) ))
+        return false;
+    if (RT_UNLIKELY( pGso->offHdr2 <= pGso->offHdr1 ))
+        return false;
+    if (RT_UNLIKELY( pGso->cbHdrs  <= pGso->offHdr2 ))
         return false;
 
@@ -70,17 +68,15 @@
         case PDMNETWORKGSOTYPE_IPV4_TCP:
         case PDMNETWORKGSOTYPE_IPV4_UDP:
-            if (RT_UNLIKELY(pGso->cbHdr1 < sizeof(RTNETIPV4_MIN_LEN)))
+            if (RT_UNLIKELY( (unsigned)pGso->offHdr2 - pGso->offHdr1 < RTNETIPV4_MIN_LEN ))
+                return false;
+            break;
+        case PDMNETWORKGSOTYPE_IPV6_TCP:
+        case PDMNETWORKGSOTYPE_IPV6_UDP:
+            if (RT_UNLIKELY( (unsigned)pGso->offHdr2 - pGso->offHdr1 < RTNETIPV6_MIN_LEN ))
                 return false;
             break;
         case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP:
         case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP:
-            if (RT_UNLIKELY(pGso->cbHdr1 < sizeof(RTNETIPV4_MIN_LEN)))
-                return false;
-            if (RT_UNLIKELY(pGso->offHdr1 + pGso->cbHdr1 + RTNETIPV6_MIN_LEN > pGso->offHdr2))
-                return false;
-            break;
-        case PDMNETWORKGSOTYPE_IPV6_TCP:
-        case PDMNETWORKGSOTYPE_IPV6_UDP:
-            if (RT_UNLIKELY(pGso->cbHdr1 < sizeof(RTNETIPV6_MIN_LEN)))
+            if (RT_UNLIKELY( (unsigned)pGso->offHdr2 - pGso->offHdr1 < RTNETIPV4_MIN_LEN + RTNETIPV6_MIN_LEN ))
                 return false;
             break;
@@ -97,5 +93,5 @@
         case PDMNETWORKGSOTYPE_IPV6_TCP:
         case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP:
-            if (RT_UNLIKELY(pGso->cbHdr2 < sizeof(RTNETTCP_MIN_LEN)))
+            if (RT_UNLIKELY( (unsigned)pGso->cbHdrs - pGso->offHdr2 < RTNETTCP_MIN_LEN ))
                 return false;
             break;
@@ -103,5 +99,5 @@
         case PDMNETWORKGSOTYPE_IPV6_UDP:
         case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP:
-            if (RT_UNLIKELY(pGso->cbHdr2 < sizeof(RTNETUDP_MIN_LEN)))
+            if (RT_UNLIKELY( (unsigned)pGso->cbHdrs - pGso->offHdr2 < RTNETUDP_MIN_LEN ))
                 return false;
             break;
@@ -113,7 +109,7 @@
 
     /* There must be at more than one segment. */
-    if (RT_UNLIKELY(cbFrame <= pGso->cbHdrs))
-        return false;
-    if (RT_UNLIKELY(cbFrame - pGso->cbHdrs < pGso->cbMaxSeg))
+    if (RT_UNLIKELY( cbFrame <= pGso->cbHdrs ))
+        return false;
+    if (RT_UNLIKELY( cbFrame - pGso->cbHdrs < pGso->cbMaxSeg ))
         return false;
 
@@ -215,8 +211,7 @@
 {
     PRTNETIPV6 pIpHdr  = (PRTNETIPV6)&pbSegHdrs[offIpHdr];
-    uint32_t cbPayload = cbHdrs - offIpHdr + sizeof(*pIpHdr) + cbSegPayload;
+    uint16_t cbPayload = (uint16_t)(cbHdrs - (offIpHdr + sizeof(RTNETIPV6)) + cbSegPayload);
     pIpHdr->ip6_plen   = RT_H2N_U16(cbPayload);
-    cbPayload         -= (offPktHdr - offPktHdr - sizeof(*pIpHdr));
-    return RTNetIPv6PseudoChecksumEx(pIpHdr, bProtocol, (uint16_t)cbPayload);
+    return RTNetIPv6PseudoChecksumEx(pIpHdr, bProtocol, (uint16_t)(cbHdrs - offPktHdr + cbSegPayload));
 }
 
@@ -309,5 +304,5 @@
         case PDMNETWORKGSOTYPE_IPV6_TCP:
             pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrs,
-                                                         pGso->cbHdr2, RTNETIPV4_PROT_TCP),
+                                                         pGso->offHdr2, RTNETIPV4_PROT_TCP),
                                   pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg,
                                   pGso->cbHdrs, iSeg + 1 == cSegs);
@@ -315,5 +310,5 @@
         case PDMNETWORKGSOTYPE_IPV6_UDP:
             pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrs,
-                                                         pGso->cbHdr2, RTNETIPV4_PROT_UDP),
+                                                         pGso->offHdr2, RTNETIPV4_PROT_UDP),
                                   pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrs);
             break;
@@ -321,5 +316,5 @@
             pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs);
             pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1),
-                                                         cbSegPayload, pGso->cbHdrs, pGso->cbHdr2, RTNETIPV4_PROT_TCP),
+                                                         cbSegPayload, pGso->cbHdrs, pGso->offHdr2, RTNETIPV4_PROT_TCP),
                                   pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg,
                                   pGso->cbHdrs, iSeg + 1 == cSegs);
@@ -328,5 +323,5 @@
             pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs);
             pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1),
-                                                         cbSegPayload, pGso->cbHdrs, pGso->cbHdr2, RTNETIPV4_PROT_UDP),
+                                                         cbSegPayload, pGso->cbHdrs, pGso->offHdr2, RTNETIPV4_PROT_UDP),
                                   pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrs);
             break;
@@ -402,5 +397,5 @@
         case PDMNETWORKGSOTYPE_IPV6_TCP:
             pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrs,
-                                                         pGso->cbHdr2, RTNETIPV4_PROT_TCP),
+                                                         pGso->offHdr2, RTNETIPV4_PROT_TCP),
                                   pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg,
                                   pGso->cbHdrs, iSeg + 1 == cSegs);
@@ -408,5 +403,5 @@
         case PDMNETWORKGSOTYPE_IPV6_UDP:
             pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrs,
-                                                         pGso->cbHdr2, RTNETIPV4_PROT_UDP),
+                                                         pGso->offHdr2, RTNETIPV4_PROT_UDP),
                                   pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrs);
             break;
@@ -414,5 +409,5 @@
             pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs);
             pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1),
-                                                         cbSegPayload, pGso->cbHdrs, pGso->cbHdr2, RTNETIPV4_PROT_TCP),
+                                                         cbSegPayload, pGso->cbHdrs, pGso->offHdr2, RTNETIPV4_PROT_TCP),
                                   pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg,
                                   pGso->cbHdrs, iSeg + 1 == cSegs);
@@ -421,5 +416,5 @@
             pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrs);
             pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1),
-                                                         cbSegPayload, pGso->cbHdrs, pGso->cbHdr2, RTNETIPV4_PROT_UDP),
+                                                         cbSegPayload, pGso->cbHdrs, pGso->offHdr2, RTNETIPV4_PROT_UDP),
                                   pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrs);
             break;
Index: /trunk/include/VBox/types.h
===================================================================
--- /trunk/include/VBox/types.h	(revision 28036)
+++ /trunk/include/VBox/types.h	(revision 28037)
@@ -744,7 +744,7 @@
     /** Invalid zero value. */
     PDMNETWORKGSOTYPE_INVALID = 0,
-    /** TCP/IPv4. */
+    /** TCP/IPv4 - no CWR/ECE encoding. */
     PDMNETWORKGSOTYPE_IPV4_TCP,
-    /** TCP/IPv6. */
+    /** TCP/IPv6 - no CWR/ECE encoding. */
     PDMNETWORKGSOTYPE_IPV6_TCP,
     /** UDP/IPv4. */
@@ -752,5 +752,5 @@
     /** UDP/IPv6. */
     PDMNETWORKGSOTYPE_IPV6_UDP,
-    /** TCP/IPv6 over IPv4 tunneling.
+    /** TCP/IPv6 over IPv4 tunneling - no CWR/ECE encoding.
      * The header offsets and sizes relates to IPv4 and TCP, the IPv6 header is
      * figured out as needed.
@@ -788,11 +788,8 @@
     /** Offset of the first header (IPv4 / IPv6).  0 if not not needed. */
     uint8_t             offHdr1;
-    /** The size of the first header (IPv4 / IPv6).  0 if not not needed. */
-    uint8_t             cbHdr1;
-
     /** Offset of the second header (TCP / UDP).  0 if not not needed. */
     uint8_t             offHdr2;
-    /** The size of the second header (TCP / UDP).  0 if not not needed. */
-    uint8_t             cbHdr2;
+    /** Unused. */
+    uint8_t             au8Unused[2];
 } PDMNETWORKGSO;
 /** Pointer to a GSO context. */
Index: /trunk/src/VBox/Devices/Network/DevE1000.cpp
===================================================================
--- /trunk/src/VBox/Devices/Network/DevE1000.cpp	(revision 28036)
+++ /trunk/src/VBox/Devices/Network/DevE1000.cpp	(revision 28037)
@@ -56,4 +56,5 @@
 #include <VBox/pdmdev.h>
 #include <VBox/pdmnetifs.h>
+#include <VBox/pdmnetinline.h>
 #include <VBox/tm.h>
 #include <VBox/vm.h>
@@ -1007,4 +1008,7 @@
     /** TX: Context used for ordinary packets. */
     E1KTXCTX    contextNormal;
+    /** GSO context. u8Type is set to PDMNETWORKGSOTYPE_INVALID when not
+     *  applicable to the current TSE mode. */
+    PDMNETWORKGSO GsoCtx;
 #if 1 /** @todo bird/buffering: change this to a 240 bytes buffer of the headers when TSE=1. */
     /** TX: Transmit packet buffer. */
@@ -2815,4 +2819,68 @@
 
 
+/**
+ * Sets up the GSO context according to the TSE new context descriptor.
+ *
+ * @param   pGso                The GSO context to setup.
+ * @param   pCtx                The context descriptor.
+ */
+DECLINLINE(void) e1kSetupGsoCtx(PPDMNETWORKGSO pGso, E1KTXCTX const *pCtx)
+{
+    pGso->u8Type = PDMNETWORKGSOTYPE_INVALID;
+
+    /*
+     * See if the context descriptor describes something that could be TCP or
+     * UDP over IPv[46].
+     */
+    /* Check the header ordering and spacing: 1. Ethernet, 2. IP, 3. TCP/UDP. */
+    if (RT_UNLIKELY( pCtx->ip.u8CSS < sizeof(RTNETETHERHDR) ))
+        return;
+    if (RT_UNLIKELY( pCtx->tu.u8CSS     < (size_t)pCtx->ip.u8CSS + (pCtx->dw2.fIP  ? RTNETIPV4_MIN_LEN : RTNETIPV6_MIN_LEN) ))
+        return;
+    if (RT_UNLIKELY(   pCtx->dw2.fTCP
+                     ? pCtx->dw3.u8HDRLEN <  (size_t)pCtx->tu.u8CSS + RTNETTCP_MIN_LEN
+                     : pCtx->dw3.u8HDRLEN != (size_t)pCtx->tu.u8CSS + RTNETUDP_MIN_LEN ))
+        return;
+
+    /* The end of the TCP/UDP checksum should stop at the end of the packet or at least after the headers. */
+    if (RT_UNLIKELY( pCtx->tu.u16CSE > 0 && pCtx->tu.u16CSE <= pCtx->dw3.u8HDRLEN ))
+        return;
+
+    /* IPv4 checksum offset. */
+    if (RT_UNLIKELY( pCtx->dw2.fIP && pCtx->ip.u8CSO - pCtx->ip.u8CSS != RT_OFFSETOF(RTNETIPV4, ip_sum) ))
+        return;
+
+    /* TCP/UDP checksum offsets. */
+    if (RT_UNLIKELY( pCtx->tu.u8CSO - pCtx->tu.u8CSS != ( pCtx->dw2.fTCP
+                                                         ? RT_OFFSETOF(RTNETTCP, th_sum)
+                                                         : RT_OFFSETOF(RTNETUDP, uh_sum) ) ))
+        return;
+
+    /*
+     * We're good for now - we'll do more checks when seeing the data.
+     * So, figure the type of offloading and setup the context.
+     */
+    if (pCtx->dw2.fIP)
+    {
+        if (pCtx->dw2.fTCP)
+            pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_TCP;
+        else
+            pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_UDP;
+        /** @todo Detect IPv4-IPv6 tunneling (need test setup since linux doesn't do
+         *        this yet it seems)... */
+    }
+    else
+    {
+        if (pCtx->dw2.fTCP)
+            pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_TCP;
+        else
+            pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_UDP;
+    }
+    pGso->offHdr1  = pCtx->ip.u8CSS;
+    pGso->offHdr2  = pCtx->tu.u8CSS;
+    pGso->cbHdrs   = pCtx->dw3.u8HDRLEN;
+    pGso->cbMaxSeg = pCtx->dw3.u16MSS;
+    Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), pGso->cbMaxSeg * 5));
+}
 
 /**
@@ -3238,4 +3306,5 @@
                 pState->u32PayRemain = pDesc->context.dw2.u20PAYLEN;
                 pState->u16HdrRemain = pDesc->context.dw3.u8HDRLEN;
+                e1kSetupGsoCtx(&pState->GsoCtx, &pDesc->context);
             }
             else
@@ -4783,4 +4852,8 @@
         rc = SSMR3GetMem(pSSM, &pState->contextNormal, sizeof(pState->contextNormal));
         AssertRCReturn(rc, rc);
+
+        /* derived state  */
+        e1kSetupGsoCtx(&pState->GsoCtx, &pState->contextTSE);
+
         E1kLog(("%s State has been restored\n", INSTANCE(pState)));
         e1kDumpState(pState);
Index: /trunk/src/VBox/Devices/Network/DrvIntNet.cpp
===================================================================
--- /trunk/src/VBox/Devices/Network/DrvIntNet.cpp	(revision 28036)
+++ /trunk/src/VBox/Devices/Network/DrvIntNet.cpp	(revision 28037)
@@ -518,8 +518,8 @@
                                          cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS, cSegs));
                                 pThis->u64LastReceiveTS = u64Now;
-                                Log2(("drvR3IntNetAsyncIoRun: cbFrame=%#x type=%d cbHdrs=%#x Hdr1=%#x/%#x Hdr2=%#x/%#x MMS=%#x\n"
+                                Log2(("drvR3IntNetAsyncIoRun: cbFrame=%#x type=%d cbHdrs=%#x Hdr1=%#x Hdr2=%#x MMS=%#x\n"
                                       "%.*Rhxd\n",
-                                      cbFrame, pGso->u8Type, pGso->cbHdrs, pGso->offHdr1, pGso->cbHdr1, pGso->offHdr2, pGso->cbHdr2,
-                                      pGso->cbMaxSeg, cbFrame - sizeof(*pGso), pGso + 1));
+                                      cbFrame, pGso->u8Type, pGso->cbHdrs, pGso->offHdr1, pGso->offHdr2, pGso->cbMaxSeg,
+                                      cbFrame - sizeof(*pGso), pGso + 1));
                             }
 #endif
@@ -541,6 +541,6 @@
                         else
                         {
-                            AssertMsgFailed(("cbFrame=%#x type=%d cbHdrs=%#x Hdr1=%#x/%#x Hdr2=%#x/%#x MMS=%#x\n",
-                                             cbFrame, pGso->u8Type, pGso->cbHdrs, pGso->offHdr1, pGso->cbHdr1, pGso->offHdr2, pGso->cbHdr2, pGso->cbMaxSeg));
+                            AssertMsgFailed(("cbFrame=%#x type=%d cbHdrs=%#x Hdr1=%#x Hdr2=%#x MMS=%#x\n",
+                                             cbFrame, pGso->u8Type, pGso->cbHdrs, pGso->offHdr1, pGso->offHdr2, pGso->cbMaxSeg));
                             STAM_REL_COUNTER_INC(&pBuf->cStatBadFrames);
                         }
