diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 385eb79cf6aa..75735c9a6a9d 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -2803,6 +2803,8 @@ void tcp4_proc_exit(void) | |||
2803 | struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) | 2803 | struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) |
2804 | { | 2804 | { |
2805 | const struct iphdr *iph = skb_gro_network_header(skb); | 2805 | const struct iphdr *iph = skb_gro_network_header(skb); |
2806 | __wsum wsum; | ||
2807 | __sum16 sum; | ||
2806 | 2808 | ||
2807 | switch (skb->ip_summed) { | 2809 | switch (skb->ip_summed) { |
2808 | case CHECKSUM_COMPLETE: | 2810 | case CHECKSUM_COMPLETE: |
@@ -2811,11 +2813,22 @@ struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) | |||
2811 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 2813 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
2812 | break; | 2814 | break; |
2813 | } | 2815 | } |
2814 | 2816 | flush: | |
2815 | /* fall through */ | ||
2816 | case CHECKSUM_NONE: | ||
2817 | NAPI_GRO_CB(skb)->flush = 1; | 2817 | NAPI_GRO_CB(skb)->flush = 1; |
2818 | return NULL; | 2818 | return NULL; |
2819 | |||
2820 | case CHECKSUM_NONE: | ||
2821 | wsum = csum_tcpudp_nofold(iph->saddr, iph->daddr, | ||
2822 | skb_gro_len(skb), IPPROTO_TCP, 0); | ||
2823 | sum = csum_fold(skb_checksum(skb, | ||
2824 | skb_gro_offset(skb), | ||
2825 | skb_gro_len(skb), | ||
2826 | wsum)); | ||
2827 | if (sum) | ||
2828 | goto flush; | ||
2829 | |||
2830 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
2831 | break; | ||
2819 | } | 2832 | } |
2820 | 2833 | ||
2821 | return tcp_gro_receive(head, skb); | 2834 | return tcp_gro_receive(head, skb); |