diff options
-rw-r--r-- | include/linux/skbuff.h | 2 | ||||
-rw-r--r-- | net/core/datagram.c | 36 | ||||
-rw-r--r-- | net/ipv4/udp.c | 15 | ||||
-rw-r--r-- | net/ipv6/raw.c | 16 | ||||
-rw-r--r-- | net/ipv6/udp.c | 16 |
5 files changed, 44 insertions, 41 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 8c5d6001a923..97f6580ce039 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -1239,6 +1239,8 @@ extern int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, | |||
1239 | int hlen, | 1239 | int hlen, |
1240 | struct iovec *iov); | 1240 | struct iovec *iov); |
1241 | extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); | 1241 | extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); |
1242 | extern void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, | ||
1243 | unsigned int flags); | ||
1242 | extern unsigned int skb_checksum(const struct sk_buff *skb, int offset, | 1244 | extern unsigned int skb_checksum(const struct sk_buff *skb, int offset, |
1243 | int len, unsigned int csum); | 1245 | int len, unsigned int csum); |
1244 | extern int skb_copy_bits(const struct sk_buff *skb, int offset, | 1246 | extern int skb_copy_bits(const struct sk_buff *skb, int offset, |
diff --git a/net/core/datagram.c b/net/core/datagram.c index 1bcfef51ac58..f8d322e1ea92 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/rtnetlink.h> | 47 | #include <linux/rtnetlink.h> |
48 | #include <linux/poll.h> | 48 | #include <linux/poll.h> |
49 | #include <linux/highmem.h> | 49 | #include <linux/highmem.h> |
50 | #include <linux/spinlock.h> | ||
50 | 51 | ||
51 | #include <net/protocol.h> | 52 | #include <net/protocol.h> |
52 | #include <linux/skbuff.h> | 53 | #include <linux/skbuff.h> |
@@ -200,6 +201,41 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb) | |||
200 | } | 201 | } |
201 | 202 | ||
202 | /** | 203 | /** |
204 | * skb_kill_datagram - Free a datagram skbuff forcibly | ||
205 | * @sk: socket | ||
206 | * @skb: datagram skbuff | ||
207 | * @flags: MSG_ flags | ||
208 | * | ||
209 | * This function frees a datagram skbuff that was received by | ||
210 | * skb_recv_datagram. The flags argument must match the one | ||
211 | * used for skb_recv_datagram. | ||
212 | * | ||
213 | * If the MSG_PEEK flag is set, and the packet is still on the | ||
214 | * receive queue of the socket, it will be taken off the queue | ||
215 | * before it is freed. | ||
216 | * | ||
217 | * This function currently only disables BH when acquiring the | ||
218 | * sk_receive_queue lock. Therefore it must not be used in a | ||
219 | * context where that lock is acquired in an IRQ context. | ||
220 | */ | ||
221 | |||
222 | void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) | ||
223 | { | ||
224 | if (flags & MSG_PEEK) { | ||
225 | spin_lock_bh(&sk->sk_receive_queue.lock); | ||
226 | if (skb == skb_peek(&sk->sk_receive_queue)) { | ||
227 | __skb_unlink(skb, &sk->sk_receive_queue); | ||
228 | atomic_dec(&skb->users); | ||
229 | } | ||
230 | spin_unlock_bh(&sk->sk_receive_queue.lock); | ||
231 | } | ||
232 | |||
233 | kfree_skb(skb); | ||
234 | } | ||
235 | |||
236 | EXPORT_SYMBOL(skb_kill_datagram); | ||
237 | |||
238 | /** | ||
203 | * skb_copy_datagram_iovec - Copy a datagram to an iovec. | 239 | * skb_copy_datagram_iovec - Copy a datagram to an iovec. |
204 | * @skb: buffer to copy | 240 | * @skb: buffer to copy |
205 | * @offset: offset in the buffer to start copying from | 241 | * @offset: offset in the buffer to start copying from |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 2422a5f7195d..012c4621e40a 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -846,20 +846,7 @@ out: | |||
846 | csum_copy_err: | 846 | csum_copy_err: |
847 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 847 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); |
848 | 848 | ||
849 | /* Clear queue. */ | 849 | skb_kill_datagram(sk, skb, flags); |
850 | if (flags&MSG_PEEK) { | ||
851 | int clear = 0; | ||
852 | spin_lock_bh(&sk->sk_receive_queue.lock); | ||
853 | if (skb == skb_peek(&sk->sk_receive_queue)) { | ||
854 | __skb_unlink(skb, &sk->sk_receive_queue); | ||
855 | clear = 1; | ||
856 | } | ||
857 | spin_unlock_bh(&sk->sk_receive_queue.lock); | ||
858 | if (clear) | ||
859 | kfree_skb(skb); | ||
860 | } | ||
861 | |||
862 | skb_free_datagram(sk, skb); | ||
863 | 850 | ||
864 | if (noblock) | 851 | if (noblock) |
865 | return -EAGAIN; | 852 | return -EAGAIN; |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index a66900cda2af..66f1d12ea578 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/icmpv6.h> | 32 | #include <linux/icmpv6.h> |
33 | #include <linux/netfilter.h> | 33 | #include <linux/netfilter.h> |
34 | #include <linux/netfilter_ipv6.h> | 34 | #include <linux/netfilter_ipv6.h> |
35 | #include <linux/skbuff.h> | ||
35 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
36 | #include <asm/ioctls.h> | 37 | #include <asm/ioctls.h> |
37 | #include <asm/bug.h> | 38 | #include <asm/bug.h> |
@@ -433,25 +434,14 @@ out: | |||
433 | return err; | 434 | return err; |
434 | 435 | ||
435 | csum_copy_err: | 436 | csum_copy_err: |
436 | /* Clear queue. */ | 437 | skb_kill_datagram(sk, skb, flags); |
437 | if (flags&MSG_PEEK) { | ||
438 | int clear = 0; | ||
439 | spin_lock_bh(&sk->sk_receive_queue.lock); | ||
440 | if (skb == skb_peek(&sk->sk_receive_queue)) { | ||
441 | __skb_unlink(skb, &sk->sk_receive_queue); | ||
442 | clear = 1; | ||
443 | } | ||
444 | spin_unlock_bh(&sk->sk_receive_queue.lock); | ||
445 | if (clear) | ||
446 | kfree_skb(skb); | ||
447 | } | ||
448 | 438 | ||
449 | /* Error for blocking case is chosen to masquerade | 439 | /* Error for blocking case is chosen to masquerade |
450 | as some normal condition. | 440 | as some normal condition. |
451 | */ | 441 | */ |
452 | err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; | 442 | err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; |
453 | /* FIXME: increment a raw6 drops counter here */ | 443 | /* FIXME: increment a raw6 drops counter here */ |
454 | goto out_free; | 444 | goto out; |
455 | } | 445 | } |
456 | 446 | ||
457 | static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, | 447 | static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5cc8731eb55b..d8538dcea813 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/ipv6.h> | 36 | #include <linux/ipv6.h> |
37 | #include <linux/icmpv6.h> | 37 | #include <linux/icmpv6.h> |
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/skbuff.h> | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | 41 | ||
41 | #include <net/sock.h> | 42 | #include <net/sock.h> |
@@ -300,20 +301,7 @@ out: | |||
300 | return err; | 301 | return err; |
301 | 302 | ||
302 | csum_copy_err: | 303 | csum_copy_err: |
303 | /* Clear queue. */ | 304 | skb_kill_datagram(sk, skb, flags); |
304 | if (flags&MSG_PEEK) { | ||
305 | int clear = 0; | ||
306 | spin_lock_bh(&sk->sk_receive_queue.lock); | ||
307 | if (skb == skb_peek(&sk->sk_receive_queue)) { | ||
308 | __skb_unlink(skb, &sk->sk_receive_queue); | ||
309 | clear = 1; | ||
310 | } | ||
311 | spin_unlock_bh(&sk->sk_receive_queue.lock); | ||
312 | if (clear) | ||
313 | kfree_skb(skb); | ||
314 | } | ||
315 | |||
316 | skb_free_datagram(sk, skb); | ||
317 | 305 | ||
318 | if (flags & MSG_DONTWAIT) { | 306 | if (flags & MSG_DONTWAIT) { |
319 | UDP6_INC_STATS_USER(UDP_MIB_INERRORS); | 307 | UDP6_INC_STATS_USER(UDP_MIB_INERRORS); |