{
        u64 cd_cmd, cd_tso_len, cd_mss;
        struct ipv6hdr *ipv6h;
-       struct tcphdr *tcph;
        struct iphdr *iph;
-       u32 l4len;
+       union {
+               struct tcphdr *tcp;
+               unsigned char *hdr;
+       } l4;
+       u32 paylen, l4_offset;
        int err;
 
        if (skb->ip_summed != CHECKSUM_PARTIAL)
 
        iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
        ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
+       l4.hdr = skb->encapsulation ? skb_inner_transport_header(skb) :
+                                     skb_transport_header(skb);
 
        if (iph->version == 4) {
-               tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
                iph->tot_len = 0;
                iph->check = 0;
-               tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-                                                0, IPPROTO_TCP, 0);
-       } else if (ipv6h->version == 6) {
-               tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
+       } else {
                ipv6h->payload_len = 0;
-               tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
-                                              0, IPPROTO_TCP, 0);
        }
 
-       l4len = skb->encapsulation ? inner_tcp_hdrlen(skb) : tcp_hdrlen(skb);
-       *hdr_len = (skb->encapsulation
-                   ? (skb_inner_transport_header(skb) - skb->data)
-                   : skb_transport_offset(skb)) + l4len;
+       /* determine offset of inner transport header */
+       l4_offset = l4.hdr - skb->data;
+
+       /* remove payload length from inner checksum */
+       paylen = (__force u16)l4.tcp->check;
+       paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+       l4.tcp->check = ~csum_fold((__force __wsum)paylen);
+
+       /* compute length of segmentation header */
+       *hdr_len = (l4.tcp->doff * 4) + l4_offset;
 
        /* find the field values */
        cd_cmd = I40E_TX_CTX_DESC_TSO;
 
 {
        u64 cd_cmd, cd_tso_len, cd_mss;
        struct ipv6hdr *ipv6h;
-       struct tcphdr *tcph;
        struct iphdr *iph;
-       u32 l4len;
+       union {
+               struct tcphdr *tcp;
+               unsigned char *hdr;
+       } l4;
+       u32 paylen, l4_offset;
        int err;
 
        if (skb->ip_summed != CHECKSUM_PARTIAL)
 
        iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
        ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
+       l4.hdr = skb->encapsulation ? skb_inner_transport_header(skb) :
+                                     skb_transport_header(skb);
 
        if (iph->version == 4) {
-               tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
                iph->tot_len = 0;
                iph->check = 0;
-               tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-                                                0, IPPROTO_TCP, 0);
-       } else if (ipv6h->version == 6) {
-               tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
+       } else {
                ipv6h->payload_len = 0;
-               tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
-                                              0, IPPROTO_TCP, 0);
        }
 
-       l4len = skb->encapsulation ? inner_tcp_hdrlen(skb) : tcp_hdrlen(skb);
-       *hdr_len = (skb->encapsulation
-                   ? (skb_inner_transport_header(skb) - skb->data)
-                   : skb_transport_offset(skb)) + l4len;
+       /* determine offset of inner transport header */
+       l4_offset = l4.hdr - skb->data;
+
+       /* remove payload length from inner checksum */
+       paylen = (__force u16)l4.tcp->check;
+       paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+       l4.tcp->check = ~csum_fold((__force __wsum)paylen);
+
+       /* compute length of segmentation header */
+       *hdr_len = (l4.tcp->doff * 4) + l4_offset;
 
        /* find the field values */
        cd_cmd = I40E_TX_CTX_DESC_TSO;