aboutsummaryrefslogtreecommitdiffstats
path: root/net
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 /net
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>
Diffstat (limited to 'net')
-rw-r--r--net/core/datagram.c9
-rw-r--r--net/ipv4/udp.c5
-rw-r--r--net/ipv6/udp.c4
3 files changed, 12 insertions, 6 deletions
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;