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 | |
| 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>
| -rw-r--r-- | include/linux/netdevice.h | 7 | ||||
| -rw-r--r-- | include/linux/skbuff.h | 27 | ||||
| -rw-r--r-- | include/net/tcp.h | 3 | ||||
| -rw-r--r-- | net/core/datagram.c | 21 | ||||
| -rw-r--r-- | net/core/dev.c | 12 | ||||
| -rw-r--r-- | net/core/netpoll.c | 18 | ||||
| -rw-r--r-- | net/ipv4/icmp.c | 6 | ||||
| -rw-r--r-- | net/ipv4/igmp.c | 19 | ||||
| -rw-r--r-- | net/ipv4/ip_gre.c | 15 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_proto_icmp.c | 11 | ||||
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 24 | ||||
| -rw-r--r-- | net/ipv4/udp.c | 7 | ||||
| -rw-r--r-- | net/ipv6/icmp.c | 21 | ||||
| -rw-r--r-- | net/ipv6/raw.c | 42 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 20 | ||||
| -rw-r--r-- | net/ipv6/udp.c | 25 | ||||
| -rw-r--r-- | net/rxrpc/transport.c | 15 | ||||
| -rw-r--r-- | net/sunrpc/socklib.c | 5 | ||||
| -rw-r--r-- | net/sunrpc/svcsock.c | 9 |
19 files changed, 173 insertions, 134 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c6efce4a04a4..936f8b76114e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
| @@ -927,6 +927,13 @@ extern int netdev_max_backlog; | |||
| 927 | extern int weight_p; | 927 | extern int weight_p; |
| 928 | extern int netdev_set_master(struct net_device *dev, struct net_device *master); | 928 | extern int netdev_set_master(struct net_device *dev, struct net_device *master); |
| 929 | extern int skb_checksum_help(struct sk_buff *skb, int inward); | 929 | extern int skb_checksum_help(struct sk_buff *skb, int inward); |
| 930 | #ifdef CONFIG_BUG | ||
| 931 | extern void netdev_rx_csum_fault(struct net_device *dev); | ||
| 932 | #else | ||
| 933 | static inline void netdev_rx_csum_fault(struct net_device *dev) | ||
| 934 | { | ||
| 935 | } | ||
| 936 | #endif | ||
| 930 | /* rx skb timestamps */ | 937 | /* rx skb timestamps */ |
| 931 | extern void net_enable_timestamp(void); | 938 | extern void net_enable_timestamp(void); |
| 932 | extern void net_disable_timestamp(void); | 939 | extern void net_disable_timestamp(void); |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 83010231db99..0a8ea8b35816 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
| @@ -1236,8 +1236,7 @@ extern unsigned int datagram_poll(struct file *file, struct socket *sock, | |||
| 1236 | extern int skb_copy_datagram_iovec(const struct sk_buff *from, | 1236 | extern int skb_copy_datagram_iovec(const struct sk_buff *from, |
| 1237 | int offset, struct iovec *to, | 1237 | int offset, struct iovec *to, |
| 1238 | int size); | 1238 | int size); |
| 1239 | extern int skb_copy_and_csum_datagram_iovec(const | 1239 | extern int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, |
| 1240 | struct sk_buff *skb, | ||
| 1241 | int hlen, | 1240 | int hlen, |
| 1242 | struct iovec *iov); | 1241 | struct iovec *iov); |
| 1243 | extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); | 1242 | extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); |
| @@ -1305,6 +1304,30 @@ static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval * | |||
| 1305 | 1304 | ||
| 1306 | extern void __net_timestamp(struct sk_buff *skb); | 1305 | extern void __net_timestamp(struct sk_buff *skb); |
| 1307 | 1306 | ||
| 1307 | extern unsigned int __skb_checksum_complete(struct sk_buff *skb); | ||
| 1308 | |||
| 1309 | /** | ||
| 1310 | * skb_checksum_complete - Calculate checksum of an entire packet | ||
| 1311 | * @skb: packet to process | ||
| 1312 | * | ||
| 1313 | * This function calculates the checksum over the entire packet plus | ||
| 1314 | * the value of skb->csum. The latter can be used to supply the | ||
| 1315 | * checksum of a pseudo header as used by TCP/UDP. It returns the | ||
| 1316 | * checksum. | ||
| 1317 | * | ||
| 1318 | * For protocols that contain complete checksums such as ICMP/TCP/UDP, | ||
| 1319 | * this function can be used to verify that checksum on received | ||
| 1320 | * packets. In that case the function should return zero if the | ||
| 1321 | * checksum is correct. In particular, this function will return zero | ||
| 1322 | * if skb->ip_summed is CHECKSUM_UNNECESSARY which indicates that the | ||
| 1323 | * hardware has already verified the correctness of the checksum. | ||
| 1324 | */ | ||
| 1325 | static inline unsigned int skb_checksum_complete(struct sk_buff *skb) | ||
| 1326 | { | ||
| 1327 | return skb->ip_summed != CHECKSUM_UNNECESSARY && | ||
| 1328 | __skb_checksum_complete(skb); | ||
| 1329 | } | ||
| 1330 | |||
| 1308 | #ifdef CONFIG_NETFILTER | 1331 | #ifdef CONFIG_NETFILTER |
| 1309 | static inline void nf_conntrack_put(struct nf_conntrack *nfct) | 1332 | static inline void nf_conntrack_put(struct nf_conntrack *nfct) |
| 1310 | { | 1333 | { |
diff --git a/include/net/tcp.h b/include/net/tcp.h index c24339c4e310..96cc3b434e40 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 28 | #include <linux/cache.h> | 28 | #include <linux/cache.h> |
| 29 | #include <linux/percpu.h> | 29 | #include <linux/percpu.h> |
| 30 | #include <linux/skbuff.h> | ||
| 30 | 31 | ||
| 31 | #include <net/inet_connection_sock.h> | 32 | #include <net/inet_connection_sock.h> |
| 32 | #include <net/inet_timewait_sock.h> | 33 | #include <net/inet_timewait_sock.h> |
| @@ -852,7 +853,7 @@ static __inline__ u16 tcp_v4_check(struct tcphdr *th, int len, | |||
| 852 | 853 | ||
| 853 | static __inline__ int __tcp_checksum_complete(struct sk_buff *skb) | 854 | static __inline__ int __tcp_checksum_complete(struct sk_buff *skb) |
| 854 | { | 855 | { |
| 855 | return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); | 856 | return __skb_checksum_complete(skb); |
| 856 | } | 857 | } |
| 857 | 858 | ||
| 858 | static __inline__ int tcp_checksum_complete(struct sk_buff *skb) | 859 | static __inline__ int tcp_checksum_complete(struct sk_buff *skb) |
diff --git a/net/core/datagram.c b/net/core/datagram.c index d219435d086c..1bcfef51ac58 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
| @@ -350,6 +350,20 @@ fault: | |||
| 350 | return -EFAULT; | 350 | return -EFAULT; |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | unsigned int __skb_checksum_complete(struct sk_buff *skb) | ||
| 354 | { | ||
| 355 | unsigned int sum; | ||
| 356 | |||
| 357 | sum = (u16)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); | ||
| 358 | if (likely(!sum)) { | ||
| 359 | if (unlikely(skb->ip_summed == CHECKSUM_HW)) | ||
| 360 | netdev_rx_csum_fault(skb->dev); | ||
| 361 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 362 | } | ||
| 363 | return sum; | ||
| 364 | } | ||
| 365 | EXPORT_SYMBOL(__skb_checksum_complete); | ||
| 366 | |||
| 353 | /** | 367 | /** |
| 354 | * skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec. | 368 | * skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec. |
| 355 | * @skb: skbuff | 369 | * @skb: skbuff |
| @@ -363,7 +377,7 @@ fault: | |||
| 363 | * -EFAULT - fault during copy. Beware, in this case iovec | 377 | * -EFAULT - fault during copy. Beware, in this case iovec |
| 364 | * can be modified! | 378 | * can be modified! |
| 365 | */ | 379 | */ |
| 366 | int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, | 380 | int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, |
| 367 | int hlen, struct iovec *iov) | 381 | int hlen, struct iovec *iov) |
| 368 | { | 382 | { |
| 369 | unsigned int csum; | 383 | unsigned int csum; |
| @@ -376,8 +390,7 @@ int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, | |||
| 376 | iov++; | 390 | iov++; |
| 377 | 391 | ||
| 378 | if (iov->iov_len < chunk) { | 392 | if (iov->iov_len < chunk) { |
| 379 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk + hlen, | 393 | if (__skb_checksum_complete(skb)) |
| 380 | skb->csum))) | ||
| 381 | goto csum_error; | 394 | goto csum_error; |
| 382 | if (skb_copy_datagram_iovec(skb, hlen, iov, chunk)) | 395 | if (skb_copy_datagram_iovec(skb, hlen, iov, chunk)) |
| 383 | goto fault; | 396 | goto fault; |
| @@ -388,6 +401,8 @@ int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, | |||
| 388 | goto fault; | 401 | goto fault; |
| 389 | if ((unsigned short)csum_fold(csum)) | 402 | if ((unsigned short)csum_fold(csum)) |
| 390 | goto csum_error; | 403 | goto csum_error; |
| 404 | if (unlikely(skb->ip_summed == CHECKSUM_HW)) | ||
| 405 | netdev_rx_csum_fault(skb->dev); | ||
| 391 | iov->iov_len -= chunk; | 406 | iov->iov_len -= chunk; |
| 392 | iov->iov_base += chunk; | 407 | iov->iov_base += chunk; |
| 393 | } | 408 | } |
diff --git a/net/core/dev.c b/net/core/dev.c index 8d1541595277..0b48e294aafe 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -1108,6 +1108,18 @@ out: | |||
| 1108 | return ret; | 1108 | return ret; |
| 1109 | } | 1109 | } |
| 1110 | 1110 | ||
| 1111 | /* Take action when hardware reception checksum errors are detected. */ | ||
| 1112 | #ifdef CONFIG_BUG | ||
| 1113 | void netdev_rx_csum_fault(struct net_device *dev) | ||
| 1114 | { | ||
| 1115 | if (net_ratelimit()) { | ||
| 1116 | printk(KERN_ERR "%s: hw csum failure.\n", dev->name); | ||
| 1117 | dump_stack(); | ||
| 1118 | } | ||
| 1119 | } | ||
| 1120 | EXPORT_SYMBOL(netdev_rx_csum_fault); | ||
| 1121 | #endif | ||
| 1122 | |||
| 1111 | #ifdef CONFIG_HIGHMEM | 1123 | #ifdef CONFIG_HIGHMEM |
| 1112 | /* Actually, we should eliminate this check as soon as we know, that: | 1124 | /* Actually, we should eliminate this check as soon as we know, that: |
| 1113 | * 1. IOMMU is present and allows to map all the memory. | 1125 | * 1. IOMMU is present and allows to map all the memory. |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 802fe11efad0..49424a42a2c0 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
| @@ -101,16 +101,20 @@ void netpoll_queue(struct sk_buff *skb) | |||
| 101 | static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, | 101 | static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, |
| 102 | unsigned short ulen, u32 saddr, u32 daddr) | 102 | unsigned short ulen, u32 saddr, u32 daddr) |
| 103 | { | 103 | { |
| 104 | if (uh->check == 0) | 104 | unsigned int psum; |
| 105 | |||
| 106 | if (uh->check == 0 || skb->ip_summed == CHECKSUM_UNNECESSARY) | ||
| 105 | return 0; | 107 | return 0; |
| 106 | 108 | ||
| 107 | if (skb->ip_summed == CHECKSUM_HW) | 109 | psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); |
| 108 | return csum_tcpudp_magic( | 110 | |
| 109 | saddr, daddr, ulen, IPPROTO_UDP, skb->csum); | 111 | if (skb->ip_summed == CHECKSUM_HW && |
| 112 | !(u16)csum_fold(csum_add(psum, skb->csum))) | ||
| 113 | return 0; | ||
| 110 | 114 | ||
| 111 | skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); | 115 | skb->csum = psum; |
| 112 | 116 | ||
| 113 | return csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); | 117 | return __skb_checksum_complete(skb); |
| 114 | } | 118 | } |
| 115 | 119 | ||
| 116 | /* | 120 | /* |
| @@ -489,7 +493,7 @@ int __netpoll_rx(struct sk_buff *skb) | |||
| 489 | 493 | ||
| 490 | if (ulen != len) | 494 | if (ulen != len) |
| 491 | goto out; | 495 | goto out; |
| 492 | if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr) < 0) | 496 | if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) |
| 493 | goto out; | 497 | goto out; |
| 494 | if (np->local_ip && np->local_ip != ntohl(iph->daddr)) | 498 | if (np->local_ip && np->local_ip != ntohl(iph->daddr)) |
| 495 | goto out; | 499 | goto out; |
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 175e093ec564..e3eceecd0496 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
| @@ -934,11 +934,11 @@ int icmp_rcv(struct sk_buff *skb) | |||
| 934 | case CHECKSUM_HW: | 934 | case CHECKSUM_HW: |
| 935 | if (!(u16)csum_fold(skb->csum)) | 935 | if (!(u16)csum_fold(skb->csum)) |
| 936 | break; | 936 | break; |
| 937 | LIMIT_NETDEBUG(KERN_DEBUG "icmp v4 hw csum failure\n"); | 937 | /* fall through */ |
| 938 | case CHECKSUM_NONE: | 938 | case CHECKSUM_NONE: |
| 939 | if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) | 939 | skb->csum = 0; |
| 940 | if (__skb_checksum_complete(skb)) | ||
| 940 | goto error; | 941 | goto error; |
| 941 | default:; | ||
| 942 | } | 942 | } |
| 943 | 943 | ||
| 944 | if (!pskb_pull(skb, sizeof(struct icmphdr))) | 944 | if (!pskb_pull(skb, sizeof(struct icmphdr))) |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index c6247fc84060..c04607b49212 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
| @@ -872,11 +872,18 @@ int igmp_rcv(struct sk_buff *skb) | |||
| 872 | return 0; | 872 | return 0; |
| 873 | } | 873 | } |
| 874 | 874 | ||
| 875 | if (!pskb_may_pull(skb, sizeof(struct igmphdr)) || | 875 | if (!pskb_may_pull(skb, sizeof(struct igmphdr))) |
| 876 | (u16)csum_fold(skb_checksum(skb, 0, len, 0))) { | 876 | goto drop; |
| 877 | in_dev_put(in_dev); | 877 | |
| 878 | kfree_skb(skb); | 878 | switch (skb->ip_summed) { |
| 879 | return 0; | 879 | case CHECKSUM_HW: |
| 880 | if (!(u16)csum_fold(skb->csum)) | ||
| 881 | break; | ||
| 882 | /* fall through */ | ||
| 883 | case CHECKSUM_NONE: | ||
| 884 | skb->csum = 0; | ||
| 885 | if (__skb_checksum_complete(skb)) | ||
| 886 | goto drop; | ||
| 880 | } | 887 | } |
| 881 | 888 | ||
| 882 | ih = skb->h.igmph; | 889 | ih = skb->h.igmph; |
| @@ -906,6 +913,8 @@ int igmp_rcv(struct sk_buff *skb) | |||
| 906 | default: | 913 | default: |
| 907 | NETDEBUG(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type); | 914 | NETDEBUG(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type); |
| 908 | } | 915 | } |
| 916 | |||
| 917 | drop: | ||
| 909 | in_dev_put(in_dev); | 918 | in_dev_put(in_dev); |
| 910 | kfree_skb(skb); | 919 | kfree_skb(skb); |
| 911 | return 0; | 920 | return 0; |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 896ce3f8f53a..4e9c74b54b15 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
| @@ -577,15 +577,16 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
| 577 | goto drop_nolock; | 577 | goto drop_nolock; |
| 578 | 578 | ||
| 579 | if (flags&GRE_CSUM) { | 579 | if (flags&GRE_CSUM) { |
| 580 | if (skb->ip_summed == CHECKSUM_HW) { | 580 | switch (skb->ip_summed) { |
| 581 | case CHECKSUM_HW: | ||
| 581 | csum = (u16)csum_fold(skb->csum); | 582 | csum = (u16)csum_fold(skb->csum); |
| 582 | if (csum) | 583 | if (!csum) |
| 583 | skb->ip_summed = CHECKSUM_NONE; | 584 | break; |
| 584 | } | 585 | /* fall through */ |
| 585 | if (skb->ip_summed == CHECKSUM_NONE) { | 586 | case CHECKSUM_NONE: |
| 586 | skb->csum = skb_checksum(skb, 0, skb->len, 0); | 587 | skb->csum = 0; |
| 588 | csum = __skb_checksum_complete(skb); | ||
| 587 | skb->ip_summed = CHECKSUM_HW; | 589 | skb->ip_summed = CHECKSUM_HW; |
| 588 | csum = (u16)csum_fold(skb->csum); | ||
| 589 | } | 590 | } |
| 590 | offset += 4; | 591 | offset += 4; |
| 591 | } | 592 | } |
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c index 5198f3a1e2cd..e4d6b268e8c4 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/in.h> | 13 | #include <linux/in.h> |
| 14 | #include <linux/icmp.h> | 14 | #include <linux/icmp.h> |
| 15 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
| 16 | #include <linux/skbuff.h> | ||
| 16 | #include <net/ip.h> | 17 | #include <net/ip.h> |
| 17 | #include <net/checksum.h> | 18 | #include <net/checksum.h> |
| 18 | #include <linux/netfilter.h> | 19 | #include <linux/netfilter.h> |
| @@ -230,19 +231,15 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, | |||
| 230 | case CHECKSUM_HW: | 231 | case CHECKSUM_HW: |
| 231 | if (!(u16)csum_fold(skb->csum)) | 232 | if (!(u16)csum_fold(skb->csum)) |
| 232 | break; | 233 | break; |
| 233 | if (LOG_INVALID(IPPROTO_ICMP)) | 234 | /* fall through */ |
| 234 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
| 235 | "ip_ct_icmp: bad HW ICMP checksum "); | ||
| 236 | return -NF_ACCEPT; | ||
| 237 | case CHECKSUM_NONE: | 235 | case CHECKSUM_NONE: |
| 238 | if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) { | 236 | skb->csum = 0; |
| 237 | if (__skb_checksum_complete(skb)) { | ||
| 239 | if (LOG_INVALID(IPPROTO_ICMP)) | 238 | if (LOG_INVALID(IPPROTO_ICMP)) |
| 240 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | 239 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, |
| 241 | "ip_ct_icmp: bad ICMP checksum "); | 240 | "ip_ct_icmp: bad ICMP checksum "); |
| 242 | return -NF_ACCEPT; | 241 | return -NF_ACCEPT; |
| 243 | } | 242 | } |
| 244 | default: | ||
| 245 | break; | ||
| 246 | } | 243 | } |
| 247 | 244 | ||
| 248 | checksum_skipped: | 245 | checksum_skipped: |
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; |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e0bd1013cb0d..2422a5f7195d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
| @@ -761,7 +761,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
| 761 | 761 | ||
| 762 | static __inline__ int __udp_checksum_complete(struct sk_buff *skb) | 762 | static __inline__ int __udp_checksum_complete(struct sk_buff *skb) |
| 763 | { | 763 | { |
| 764 | return (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); | 764 | return __skb_checksum_complete(skb); |
| 765 | } | 765 | } |
| 766 | 766 | ||
| 767 | static __inline__ int udp_checksum_complete(struct sk_buff *skb) | 767 | static __inline__ int udp_checksum_complete(struct sk_buff *skb) |
| @@ -1100,11 +1100,8 @@ static int udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, | |||
| 1100 | if (uh->check == 0) { | 1100 | if (uh->check == 0) { |
| 1101 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1101 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 1102 | } else if (skb->ip_summed == CHECKSUM_HW) { | 1102 | } else if (skb->ip_summed == CHECKSUM_HW) { |
| 1103 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 1104 | if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) | 1103 | if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) |
| 1105 | return 0; | 1104 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 1106 | LIMIT_NETDEBUG(KERN_DEBUG "udp v4 hw csum failure.\n"); | ||
| 1107 | skb->ip_summed = CHECKSUM_NONE; | ||
| 1108 | } | 1105 | } |
| 1109 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | 1106 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) |
| 1110 | skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); | 1107 | skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 23e540365a14..1bdf0fb8bf8a 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
| @@ -585,17 +585,16 @@ static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) | |||
| 585 | daddr = &skb->nh.ipv6h->daddr; | 585 | daddr = &skb->nh.ipv6h->daddr; |
| 586 | 586 | ||
| 587 | /* Perform checksum. */ | 587 | /* Perform checksum. */ |
| 588 | if (skb->ip_summed == CHECKSUM_HW) { | 588 | switch (skb->ip_summed) { |
| 589 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 589 | case CHECKSUM_HW: |
| 590 | if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, | 590 | if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, |
| 591 | skb->csum)) { | 591 | skb->csum)) |
| 592 | LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 hw checksum failed\n"); | 592 | break; |
| 593 | skb->ip_summed = CHECKSUM_NONE; | 593 | /* fall through */ |
| 594 | } | 594 | case CHECKSUM_NONE: |
| 595 | } | 595 | skb->csum = ~csum_ipv6_magic(saddr, daddr, skb->len, |
| 596 | if (skb->ip_summed == CHECKSUM_NONE) { | 596 | IPPROTO_ICMPV6, 0); |
| 597 | if (csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, | 597 | if (__skb_checksum_complete(skb)) { |
| 598 | skb_checksum(skb, 0, skb->len, 0))) { | ||
| 599 | LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n", | 598 | LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n", |
| 600 | NIP6(*saddr), NIP6(*daddr)); | 599 | NIP6(*saddr), NIP6(*daddr)); |
| 601 | goto discard_it; | 600 | goto discard_it; |
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 { |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d746d3b27efb..62c0e5bd931c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -1401,20 +1401,18 @@ out: | |||
| 1401 | static int tcp_v6_checksum_init(struct sk_buff *skb) | 1401 | static int tcp_v6_checksum_init(struct sk_buff *skb) |
| 1402 | { | 1402 | { |
| 1403 | if (skb->ip_summed == CHECKSUM_HW) { | 1403 | if (skb->ip_summed == CHECKSUM_HW) { |
| 1404 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 1405 | if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | 1404 | if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, |
| 1406 | &skb->nh.ipv6h->daddr,skb->csum)) | 1405 | &skb->nh.ipv6h->daddr,skb->csum)) { |
| 1406 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 1407 | return 0; | 1407 | return 0; |
| 1408 | LIMIT_NETDEBUG(KERN_DEBUG "hw tcp v6 csum failed\n"); | 1408 | } |
| 1409 | } | 1409 | } |
| 1410 | |||
| 1411 | skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | ||
| 1412 | &skb->nh.ipv6h->daddr, 0); | ||
| 1413 | |||
| 1410 | if (skb->len <= 76) { | 1414 | if (skb->len <= 76) { |
| 1411 | if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | 1415 | return __skb_checksum_complete(skb); |
| 1412 | &skb->nh.ipv6h->daddr,skb_checksum(skb, 0, skb->len, 0))) | ||
| 1413 | return -1; | ||
| 1414 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 1415 | } else { | ||
| 1416 | skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | ||
| 1417 | &skb->nh.ipv6h->daddr,0); | ||
| 1418 | } | 1416 | } |
| 1419 | return 0; | 1417 | return 0; |
| 1420 | } | 1418 | } |
| @@ -1575,7 +1573,7 @@ static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) | |||
| 1575 | goto discard_it; | 1573 | goto discard_it; |
| 1576 | 1574 | ||
| 1577 | if ((skb->ip_summed != CHECKSUM_UNNECESSARY && | 1575 | if ((skb->ip_summed != CHECKSUM_UNNECESSARY && |
| 1578 | tcp_v6_checksum_init(skb) < 0)) | 1576 | tcp_v6_checksum_init(skb))) |
| 1579 | goto bad_packet; | 1577 | goto bad_packet; |
| 1580 | 1578 | ||
| 1581 | th = skb->h.th; | 1579 | th = skb->h.th; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index bf9519341fd3..e671153b47b2 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -248,7 +248,7 @@ try_again: | |||
| 248 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 248 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, |
| 249 | copied); | 249 | copied); |
| 250 | } else if (msg->msg_flags&MSG_TRUNC) { | 250 | } else if (msg->msg_flags&MSG_TRUNC) { |
| 251 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) | 251 | if (__skb_checksum_complete(skb)) |
| 252 | goto csum_copy_err; | 252 | goto csum_copy_err; |
| 253 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, | 253 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, |
| 254 | copied); | 254 | copied); |
| @@ -363,13 +363,10 @@ static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
| 363 | return -1; | 363 | return -1; |
| 364 | } | 364 | } |
| 365 | 365 | ||
| 366 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) { | 366 | if (skb_checksum_complete(skb)) { |
| 367 | if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { | 367 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); |
| 368 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 368 | kfree_skb(skb); |
| 369 | kfree_skb(skb); | 369 | return 0; |
| 370 | return 0; | ||
| 371 | } | ||
| 372 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 373 | } | 370 | } |
| 374 | 371 | ||
| 375 | if (sock_queue_rcv_skb(sk,skb)<0) { | 372 | if (sock_queue_rcv_skb(sk,skb)<0) { |
| @@ -491,13 +488,10 @@ static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) | |||
| 491 | uh = skb->h.uh; | 488 | uh = skb->h.uh; |
| 492 | } | 489 | } |
| 493 | 490 | ||
| 494 | if (skb->ip_summed==CHECKSUM_HW) { | 491 | if (skb->ip_summed == CHECKSUM_HW && |
| 492 | !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) | ||
| 495 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 493 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 496 | if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) { | 494 | |
| 497 | LIMIT_NETDEBUG(KERN_DEBUG "udp v6 hw csum failure.\n"); | ||
| 498 | skb->ip_summed = CHECKSUM_NONE; | ||
| 499 | } | ||
| 500 | } | ||
| 501 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | 495 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) |
| 502 | skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0); | 496 | skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0); |
| 503 | 497 | ||
| @@ -521,8 +515,7 @@ static int udpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) | |||
| 521 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) | 515 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) |
| 522 | goto discard; | 516 | goto discard; |
| 523 | 517 | ||
| 524 | if (skb->ip_summed != CHECKSUM_UNNECESSARY && | 518 | if (skb_checksum_complete(skb)) |
| 525 | (unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) | ||
| 526 | goto discard; | 519 | goto discard; |
| 527 | UDP6_INC_STATS_BH(UDP_MIB_NOPORTS); | 520 | UDP6_INC_STATS_BH(UDP_MIB_NOPORTS); |
| 528 | 521 | ||
diff --git a/net/rxrpc/transport.c b/net/rxrpc/transport.c index 122c086ee2db..dbe6105e83a5 100644 --- a/net/rxrpc/transport.c +++ b/net/rxrpc/transport.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/in.h> | 23 | #include <linux/in.h> |
| 24 | #include <linux/in6.h> | 24 | #include <linux/in6.h> |
| 25 | #include <linux/icmp.h> | 25 | #include <linux/icmp.h> |
| 26 | #include <linux/skbuff.h> | ||
| 26 | #include <net/sock.h> | 27 | #include <net/sock.h> |
| 27 | #include <net/ip.h> | 28 | #include <net/ip.h> |
| 28 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | 29 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) |
| @@ -475,15 +476,11 @@ void rxrpc_trans_receive_packet(struct rxrpc_transport *trans) | |||
| 475 | 476 | ||
| 476 | /* we'll probably need to checksum it (didn't call | 477 | /* we'll probably need to checksum it (didn't call |
| 477 | * sock_recvmsg) */ | 478 | * sock_recvmsg) */ |
| 478 | if (pkt->ip_summed != CHECKSUM_UNNECESSARY) { | 479 | if (skb_checksum_complete(pkt)) { |
| 479 | if ((unsigned short) | 480 | kfree_skb(pkt); |
| 480 | csum_fold(skb_checksum(pkt, 0, pkt->len, | 481 | rxrpc_krxiod_queue_transport(trans); |
| 481 | pkt->csum))) { | 482 | _leave(" CSUM failed"); |
| 482 | kfree_skb(pkt); | 483 | return; |
| 483 | rxrpc_krxiod_queue_transport(trans); | ||
| 484 | _leave(" CSUM failed"); | ||
| 485 | return; | ||
| 486 | } | ||
| 487 | } | 484 | } |
| 488 | 485 | ||
| 489 | addr = pkt->nh.iph->saddr; | 486 | addr = pkt->nh.iph->saddr; |
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 | } |
