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/ipv6/raw.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/ipv6/raw.c')
-rw-r--r-- | net/ipv6/raw.c | 42 |
1 files changed, 16 insertions, 26 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 651c79b41eeb..8e9628f1c4c5 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -298,13 +298,10 @@ void rawv6_err(struct sock *sk, struct sk_buff *skb, | |||
298 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) | 298 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) |
299 | { | 299 | { |
300 | if ((raw6_sk(sk)->checksum || sk->sk_filter) && | 300 | if ((raw6_sk(sk)->checksum || sk->sk_filter) && |
301 | skb->ip_summed != CHECKSUM_UNNECESSARY) { | 301 | skb_checksum_complete(skb)) { |
302 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { | 302 | /* FIXME: increment a raw6 drops counter here */ |
303 | /* FIXME: increment a raw6 drops counter here */ | 303 | kfree_skb(skb); |
304 | kfree_skb(skb); | 304 | return 0; |
305 | return 0; | ||
306 | } | ||
307 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
308 | } | 305 | } |
309 | 306 | ||
310 | /* Charge it to the socket. */ | 307 | /* Charge it to the socket. */ |
@@ -337,32 +334,25 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) | |||
337 | if (!rp->checksum) | 334 | if (!rp->checksum) |
338 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 335 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
339 | 336 | ||
340 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) { | 337 | if (skb->ip_summed == CHECKSUM_HW) { |
341 | if (skb->ip_summed == CHECKSUM_HW) { | 338 | skb_postpull_rcsum(skb, skb->nh.raw, |
342 | skb_postpull_rcsum(skb, skb->nh.raw, | 339 | skb->h.raw - skb->nh.raw); |
343 | skb->h.raw - skb->nh.raw); | 340 | if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr, |
341 | &skb->nh.ipv6h->daddr, | ||
342 | skb->len, inet->num, skb->csum)) | ||
344 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 343 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
345 | if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
346 | &skb->nh.ipv6h->daddr, | ||
347 | skb->len, inet->num, skb->csum)) { | ||
348 | LIMIT_NETDEBUG(KERN_DEBUG "raw v6 hw csum failure.\n"); | ||
349 | skb->ip_summed = CHECKSUM_NONE; | ||
350 | } | ||
351 | } | ||
352 | if (skb->ip_summed == CHECKSUM_NONE) | ||
353 | skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
354 | &skb->nh.ipv6h->daddr, | ||
355 | skb->len, inet->num, 0); | ||
356 | } | 344 | } |
345 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | ||
346 | skb->csum = ~csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
347 | &skb->nh.ipv6h->daddr, | ||
348 | skb->len, inet->num, 0); | ||
357 | 349 | ||
358 | if (inet->hdrincl) { | 350 | if (inet->hdrincl) { |
359 | if (skb->ip_summed != CHECKSUM_UNNECESSARY && | 351 | if (skb_checksum_complete(skb)) { |
360 | (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { | ||
361 | /* FIXME: increment a raw6 drops counter here */ | 352 | /* FIXME: increment a raw6 drops counter here */ |
362 | kfree_skb(skb); | 353 | kfree_skb(skb); |
363 | return 0; | 354 | return 0; |
364 | } | 355 | } |
365 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
366 | } | 356 | } |
367 | 357 | ||
368 | rawv6_rcv_skb(sk, skb); | 358 | rawv6_rcv_skb(sk, skb); |
@@ -407,7 +397,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
407 | if (skb->ip_summed==CHECKSUM_UNNECESSARY) { | 397 | if (skb->ip_summed==CHECKSUM_UNNECESSARY) { |
408 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | 398 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); |
409 | } else if (msg->msg_flags&MSG_TRUNC) { | 399 | } else if (msg->msg_flags&MSG_TRUNC) { |
410 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) | 400 | if (__skb_checksum_complete(skb)) |
411 | goto csum_copy_err; | 401 | goto csum_copy_err; |
412 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | 402 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); |
413 | } else { | 403 | } else { |