gro: Only verify TCP checksums for candidates
authorHerbert Xu <herbert@gondor.apana.org.au>
Fri, 22 Nov 2013 02:31:29 +0000 (10:31 +0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 23 Nov 2013 22:46:19 +0000 (14:46 -0800)
In some cases we may receive IP packets that are longer than
their stated lengths.  Such packets are never merged in GRO.
However, we may end up computing their checksums incorrectly
and end up allowing packets with a bogus checksum enter our
stack with the checksum status set as verified.

Since such packets are rare and not performance-critical, this
patch simply skips the checksum verification for them.

Reported-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Acked-by: Alexander Duyck <alexander.h.duyck@intel.com>
Thanks,
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/tcp_offload.c
net/ipv6/tcpv6_offload.c

index a2b68a108eae69170c8d915be778c9aeebf0f371..55aeec93014023ba08b6126230b8a73e1aebf032 100644 (file)
@@ -276,6 +276,10 @@ static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *
        __wsum wsum;
        __sum16 sum;
 
+       /* Don't bother verifying checksum if we're going to flush anyway. */
+       if (NAPI_GRO_CB(skb)->flush)
+               goto skip_csum;
+
        switch (skb->ip_summed) {
        case CHECKSUM_COMPLETE:
                if (!tcp_v4_check(skb_gro_len(skb), iph->saddr, iph->daddr,
@@ -301,6 +305,7 @@ flush:
                break;
        }
 
+skip_csum:
        return tcp_gro_receive(head, skb);
 }
 
index c1097c79890070e3d04517cecb7f0b263c0a4fc7..71923d14127a412d6356a6965456b94c82db46cc 100644 (file)
@@ -39,6 +39,10 @@ static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
        __wsum wsum;
        __sum16 sum;
 
+       /* Don't bother verifying checksum if we're going to flush anyway. */
+       if (NAPI_GRO_CB(skb)->flush)
+               goto skip_csum;
+
        switch (skb->ip_summed) {
        case CHECKSUM_COMPLETE:
                if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
@@ -65,6 +69,7 @@ flush:
                break;
        }
 
+skip_csum:
        return tcp_gro_receive(head, skb);
 }