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/ipv4/tcp_ipv4.c | |
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/ipv4/tcp_ipv4.c')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 24 |
1 files changed, 9 insertions, 15 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 634dabb558fd..ac1fcf5b4ebc 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1110,24 +1110,18 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
1110 | static int tcp_v4_checksum_init(struct sk_buff *skb) | 1110 | static int tcp_v4_checksum_init(struct sk_buff *skb) |
1111 | { | 1111 | { |
1112 | if (skb->ip_summed == CHECKSUM_HW) { | 1112 | if (skb->ip_summed == CHECKSUM_HW) { |
1113 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1114 | if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, | 1113 | if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, |
1115 | skb->nh.iph->daddr, skb->csum)) | 1114 | skb->nh.iph->daddr, skb->csum)) { |
1115 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1116 | return 0; | 1116 | return 0; |
1117 | 1117 | } | |
1118 | LIMIT_NETDEBUG(KERN_DEBUG "hw tcp v4 csum failed\n"); | ||
1119 | skb->ip_summed = CHECKSUM_NONE; | ||
1120 | } | 1118 | } |
1119 | |||
1120 | skb->csum = csum_tcpudp_nofold(skb->nh.iph->saddr, skb->nh.iph->daddr, | ||
1121 | skb->len, IPPROTO_TCP, 0); | ||
1122 | |||
1121 | if (skb->len <= 76) { | 1123 | if (skb->len <= 76) { |
1122 | if (tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, | 1124 | return __skb_checksum_complete(skb); |
1123 | skb->nh.iph->daddr, | ||
1124 | skb_checksum(skb, 0, skb->len, 0))) | ||
1125 | return -1; | ||
1126 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1127 | } else { | ||
1128 | skb->csum = ~tcp_v4_check(skb->h.th, skb->len, | ||
1129 | skb->nh.iph->saddr, | ||
1130 | skb->nh.iph->daddr, 0); | ||
1131 | } | 1125 | } |
1132 | return 0; | 1126 | return 0; |
1133 | } | 1127 | } |
@@ -1219,7 +1213,7 @@ int tcp_v4_rcv(struct sk_buff *skb) | |||
1219 | * provided case of th->doff==0 is elimineted. | 1213 | * provided case of th->doff==0 is elimineted. |
1220 | * So, we defer the checks. */ | 1214 | * So, we defer the checks. */ |
1221 | if ((skb->ip_summed != CHECKSUM_UNNECESSARY && | 1215 | if ((skb->ip_summed != CHECKSUM_UNNECESSARY && |
1222 | tcp_v4_checksum_init(skb) < 0)) | 1216 | tcp_v4_checksum_init(skb))) |
1223 | goto bad_packet; | 1217 | goto bad_packet; |
1224 | 1218 | ||
1225 | th = skb->h.th; | 1219 | th = skb->h.th; |