diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2005-11-10 16:01:24 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-11-10 16:01:24 -0500 |
commit | fb286bb2990a107009dbf25f6ffebeb7df77f9be (patch) | |
tree | 0eede2c37f1b3831e59601933eebf6b82be75ffc /net/sunrpc | |
parent | 1064e944d03eb7a72c0fa11236d5e69cfd877a71 (diff) |
[NET]: Detect hardware rx checksum faults correctly
Here is the patch that introduces the generic skb_checksum_complete
which also checks for hardware RX checksum faults. If that happens,
it'll call netdev_rx_csum_fault which currently prints out a stack
trace with the device name. In future it can turn off RX checksum.
I've converted every spot under net/ that does RX checksum checks to
use skb_checksum_complete or __skb_checksum_complete with the
exceptions of:
* Those places where checksums are done bit by bit. These will call
netdev_rx_csum_fault directly.
* The following have not been completely checked/converted:
ipmr
ip_vs
netfilter
dccp
This patch is based on patches and suggestions from Stephen Hemminger
and David S. Miller.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/socklib.c | 5 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 9 |
2 files changed, 8 insertions, 6 deletions
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index 8f97e90f36c8..eb330d4f66d6 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c | |||
@@ -6,6 +6,9 @@ | |||
6 | * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> | 6 | * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/compiler.h> | ||
10 | #include <linux/netdevice.h> | ||
11 | #include <linux/skbuff.h> | ||
9 | #include <linux/types.h> | 12 | #include <linux/types.h> |
10 | #include <linux/pagemap.h> | 13 | #include <linux/pagemap.h> |
11 | #include <linux/udp.h> | 14 | #include <linux/udp.h> |
@@ -165,6 +168,8 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) | |||
165 | return -1; | 168 | return -1; |
166 | if ((unsigned short)csum_fold(desc.csum)) | 169 | if ((unsigned short)csum_fold(desc.csum)) |
167 | return -1; | 170 | return -1; |
171 | if (unlikely(skb->ip_summed == CHECKSUM_HW)) | ||
172 | netdev_rx_csum_fault(skb->dev); | ||
168 | return 0; | 173 | return 0; |
169 | no_checksum: | 174 | no_checksum: |
170 | if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0) | 175 | if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0) |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index f16e7cdd6150..e50e7cf43737 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -623,12 +623,9 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
623 | /* we can use it in-place */ | 623 | /* we can use it in-place */ |
624 | rqstp->rq_arg.head[0].iov_base = skb->data + sizeof(struct udphdr); | 624 | rqstp->rq_arg.head[0].iov_base = skb->data + sizeof(struct udphdr); |
625 | rqstp->rq_arg.head[0].iov_len = len; | 625 | rqstp->rq_arg.head[0].iov_len = len; |
626 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) { | 626 | if (skb_checksum_complete(skb)) { |
627 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { | 627 | skb_free_datagram(svsk->sk_sk, skb); |
628 | skb_free_datagram(svsk->sk_sk, skb); | 628 | return 0; |
629 | return 0; | ||
630 | } | ||
631 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
632 | } | 629 | } |
633 | rqstp->rq_skbuff = skb; | 630 | rqstp->rq_skbuff = skb; |
634 | } | 631 | } |