|
@@ -2269,9 +2269,12 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
|
|
{
|
|
{
|
|
u64 cd_cmd, cd_tso_len, cd_mss;
|
|
u64 cd_cmd, cd_tso_len, cd_mss;
|
|
struct ipv6hdr *ipv6h;
|
|
struct ipv6hdr *ipv6h;
|
|
- struct tcphdr *tcph;
|
|
|
|
struct iphdr *iph;
|
|
struct iphdr *iph;
|
|
- u32 l4len;
|
|
|
|
|
|
+ union {
|
|
|
|
+ struct tcphdr *tcp;
|
|
|
|
+ unsigned char *hdr;
|
|
|
|
+ } l4;
|
|
|
|
+ u32 paylen, l4_offset;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
|
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
|
@@ -2286,24 +2289,26 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
|
|
|
|
|
|
iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
|
|
iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
|
|
ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_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) {
|
|
if (iph->version == 4) {
|
|
- tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
|
|
|
|
iph->tot_len = 0;
|
|
iph->tot_len = 0;
|
|
iph->check = 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;
|
|
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 */
|
|
/* find the field values */
|
|
cd_cmd = I40E_TX_CTX_DESC_TSO;
|
|
cd_cmd = I40E_TX_CTX_DESC_TSO;
|