aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-12-05 04:51:58 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:56:32 -0500
commit27ab2568649d5ba6c5a20212079b7c4f6da4ca0d (patch)
tree19bb85e73d7deb0adf40386af3117c2f397b653d
parentc8fecf2242a0ab7230210665986b8ef915e1ae9e (diff)
[UDP]: Avoid repeated counting of checksum errors due to peeking
Currently it is possible for two processes to peek on the same socket and end up incrementing the error counter twice for the same packet. This patch fixes it by making skb_kill_datagram return whether it succeeded in unlinking the packet and only incrementing the counter if it did. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/skbuff.h2
-rw-r--r--net/core/datagram.c9
-rw-r--r--net/ipv4/udp.c5
-rw-r--r--net/ipv6/udp.c4
4 files changed, 13 insertions, 7 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index d39f53ef66bb..17b3f70fbbc3 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1549,7 +1549,7 @@ extern int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
1549 int hlen, 1549 int hlen,
1550 struct iovec *iov); 1550 struct iovec *iov);
1551extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); 1551extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
1552extern void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, 1552extern int skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
1553 unsigned int flags); 1553 unsigned int flags);
1554extern __wsum skb_checksum(const struct sk_buff *skb, int offset, 1554extern __wsum skb_checksum(const struct sk_buff *skb, int offset,
1555 int len, __wsum csum); 1555 int len, __wsum csum);
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 029b93e246b4..fbd6c76436d0 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -217,20 +217,27 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
217 * This function currently only disables BH when acquiring the 217 * This function currently only disables BH when acquiring the
218 * sk_receive_queue lock. Therefore it must not be used in a 218 * sk_receive_queue lock. Therefore it must not be used in a
219 * context where that lock is acquired in an IRQ context. 219 * context where that lock is acquired in an IRQ context.
220 *
221 * It returns 0 if the packet was removed by us.
220 */ 222 */
221 223
222void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) 224int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
223{ 225{
226 int err = 0;
227
224 if (flags & MSG_PEEK) { 228 if (flags & MSG_PEEK) {
229 err = -ENOENT;
225 spin_lock_bh(&sk->sk_receive_queue.lock); 230 spin_lock_bh(&sk->sk_receive_queue.lock);
226 if (skb == skb_peek(&sk->sk_receive_queue)) { 231 if (skb == skb_peek(&sk->sk_receive_queue)) {
227 __skb_unlink(skb, &sk->sk_receive_queue); 232 __skb_unlink(skb, &sk->sk_receive_queue);
228 atomic_dec(&skb->users); 233 atomic_dec(&skb->users);
234 err = 0;
229 } 235 }
230 spin_unlock_bh(&sk->sk_receive_queue.lock); 236 spin_unlock_bh(&sk->sk_receive_queue.lock);
231 } 237 }
232 238
233 kfree_skb(skb); 239 kfree_skb(skb);
240 return err;
234} 241}
235 242
236EXPORT_SYMBOL(skb_kill_datagram); 243EXPORT_SYMBOL(skb_kill_datagram);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d0283b7fcec5..f50de5d5218d 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -899,9 +899,8 @@ out:
899 return err; 899 return err;
900 900
901csum_copy_err: 901csum_copy_err:
902 UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); 902 if (!skb_kill_datagram(sk, skb, flags))
903 903 UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
904 skb_kill_datagram(sk, skb, flags);
905 904
906 if (noblock) 905 if (noblock)
907 return -EAGAIN; 906 return -EAGAIN;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 77ab31b99232..87bccec9882a 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -207,8 +207,8 @@ out:
207 return err; 207 return err;
208 208
209csum_copy_err: 209csum_copy_err:
210 UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); 210 if (!skb_kill_datagram(sk, skb, flags))
211 skb_kill_datagram(sk, skb, flags); 211 UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
212 212
213 if (flags & MSG_DONTWAIT) 213 if (flags & MSG_DONTWAIT)
214 return -EAGAIN; 214 return -EAGAIN;