diff options
author | Wei Yongjun <yjwei@cn.fujitsu.com> | 2011-04-06 14:40:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-07 02:05:01 -0400 |
commit | 912d398d28b4359c2fb1f3763f1ce4f86de8350e (patch) | |
tree | 5e5e0c4120ccff8b3885dc2660e37634115c8bac /include/net/sock.h | |
parent | 7b1b3afadf33627e707c5038af991ae2ce9b5ac5 (diff) |
net: fix skb_add_data_nocache() to calc csum correctly
commit c6e1a0d12ca7b4f22c58e55a16beacfb7d3d8462 broken the calc
(net: Allow no-cache copy from user on transmit)
of checksum, which may cause some tcp packets be dropped because
incorrect checksum. ssh does not work under today's net-next-2.6
tree.
Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
Acked-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net/sock.h')
-rw-r--r-- | include/net/sock.h | 15 |
1 files changed, 8 insertions, 7 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index 43bd515e92fd..9cbf23c815f5 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -1392,14 +1392,14 @@ static inline void sk_nocaps_add(struct sock *sk, int flags) | |||
1392 | 1392 | ||
1393 | static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, | 1393 | static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, |
1394 | char __user *from, char *to, | 1394 | char __user *from, char *to, |
1395 | int copy) | 1395 | int copy, int offset) |
1396 | { | 1396 | { |
1397 | if (skb->ip_summed == CHECKSUM_NONE) { | 1397 | if (skb->ip_summed == CHECKSUM_NONE) { |
1398 | int err = 0; | 1398 | int err = 0; |
1399 | __wsum csum = csum_and_copy_from_user(from, to, copy, 0, &err); | 1399 | __wsum csum = csum_and_copy_from_user(from, to, copy, 0, &err); |
1400 | if (err) | 1400 | if (err) |
1401 | return err; | 1401 | return err; |
1402 | skb->csum = csum_block_add(skb->csum, csum, skb->len); | 1402 | skb->csum = csum_block_add(skb->csum, csum, offset); |
1403 | } else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) { | 1403 | } else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) { |
1404 | if (!access_ok(VERIFY_READ, from, copy) || | 1404 | if (!access_ok(VERIFY_READ, from, copy) || |
1405 | __copy_from_user_nocache(to, from, copy)) | 1405 | __copy_from_user_nocache(to, from, copy)) |
@@ -1413,11 +1413,12 @@ static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, | |||
1413 | static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb, | 1413 | static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb, |
1414 | char __user *from, int copy) | 1414 | char __user *from, int copy) |
1415 | { | 1415 | { |
1416 | int err; | 1416 | int err, offset = skb->len; |
1417 | 1417 | ||
1418 | err = skb_do_copy_data_nocache(sk, skb, from, skb_put(skb, copy), copy); | 1418 | err = skb_do_copy_data_nocache(sk, skb, from, skb_put(skb, copy), |
1419 | copy, offset); | ||
1419 | if (err) | 1420 | if (err) |
1420 | __skb_trim(skb, skb->len); | 1421 | __skb_trim(skb, offset); |
1421 | 1422 | ||
1422 | return err; | 1423 | return err; |
1423 | } | 1424 | } |
@@ -1429,8 +1430,8 @@ static inline int skb_copy_to_page_nocache(struct sock *sk, char __user *from, | |||
1429 | { | 1430 | { |
1430 | int err; | 1431 | int err; |
1431 | 1432 | ||
1432 | err = skb_do_copy_data_nocache(sk, skb, from, | 1433 | err = skb_do_copy_data_nocache(sk, skb, from, page_address(page) + off, |
1433 | page_address(page) + off, copy); | 1434 | copy, skb->len); |
1434 | if (err) | 1435 | if (err) |
1435 | return err; | 1436 | return err; |
1436 | 1437 | ||