Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 27ab2568 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

[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: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c8fecf22
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1549,7 +1549,7 @@ extern int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
							int hlen,
							struct iovec *iov);
extern void	       skb_free_datagram(struct sock *sk, struct sk_buff *skb);
extern void	       skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
extern int	       skb_kill_datagram(struct sock *sk, struct sk_buff *skb,
					 unsigned int flags);
extern __wsum	       skb_checksum(const struct sk_buff *skb, int offset,
				    int len, __wsum csum);
+8 −1
Original line number Diff line number Diff line
@@ -217,20 +217,27 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
 *	This function currently only disables BH when acquiring the
 *	sk_receive_queue lock.  Therefore it must not be used in a
 *	context where that lock is acquired in an IRQ context.
 *
 *	It returns 0 if the packet was removed by us.
 */

void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
{
	int err = 0;

	if (flags & MSG_PEEK) {
		err = -ENOENT;
		spin_lock_bh(&sk->sk_receive_queue.lock);
		if (skb == skb_peek(&sk->sk_receive_queue)) {
			__skb_unlink(skb, &sk->sk_receive_queue);
			atomic_dec(&skb->users);
			err = 0;
		}
		spin_unlock_bh(&sk->sk_receive_queue.lock);
	}

	kfree_skb(skb);
	return err;
}

EXPORT_SYMBOL(skb_kill_datagram);
+2 −3
Original line number Diff line number Diff line
@@ -899,10 +899,9 @@ out:
	return err;

csum_copy_err:
	if (!skb_kill_datagram(sk, skb, flags))
		UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);

	skb_kill_datagram(sk, skb, flags);

	if (noblock)
		return -EAGAIN;
	goto try_again;
+2 −2
Original line number Diff line number Diff line
@@ -207,8 +207,8 @@ out:
	return err;

csum_copy_err:
	if (!skb_kill_datagram(sk, skb, flags))
		UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
	skb_kill_datagram(sk, skb, flags);

	if (flags & MSG_DONTWAIT)
		return -EAGAIN;