diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 73 |
1 files changed, 43 insertions, 30 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 71e5353b30c8..ee61b3fc4cae 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -845,6 +845,42 @@ out: | |||
845 | return ret; | 845 | return ret; |
846 | } | 846 | } |
847 | 847 | ||
848 | |||
849 | /** | ||
850 | * first_packet_length - return length of first packet in receive queue | ||
851 | * @sk: socket | ||
852 | * | ||
853 | * Drops all bad checksum frames, until a valid one is found. | ||
854 | * Returns the length of found skb, or 0 if none is found. | ||
855 | */ | ||
856 | static unsigned int first_packet_length(struct sock *sk) | ||
857 | { | ||
858 | struct sk_buff_head list_kill, *rcvq = &sk->sk_receive_queue; | ||
859 | struct sk_buff *skb; | ||
860 | unsigned int res; | ||
861 | |||
862 | __skb_queue_head_init(&list_kill); | ||
863 | |||
864 | spin_lock_bh(&rcvq->lock); | ||
865 | while ((skb = skb_peek(rcvq)) != NULL && | ||
866 | udp_lib_checksum_complete(skb)) { | ||
867 | UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, | ||
868 | IS_UDPLITE(sk)); | ||
869 | __skb_unlink(skb, rcvq); | ||
870 | __skb_queue_tail(&list_kill, skb); | ||
871 | } | ||
872 | res = skb ? skb->len : 0; | ||
873 | spin_unlock_bh(&rcvq->lock); | ||
874 | |||
875 | if (!skb_queue_empty(&list_kill)) { | ||
876 | lock_sock(sk); | ||
877 | __skb_queue_purge(&list_kill); | ||
878 | sk_mem_reclaim_partial(sk); | ||
879 | release_sock(sk); | ||
880 | } | ||
881 | return res; | ||
882 | } | ||
883 | |||
848 | /* | 884 | /* |
849 | * IOCTL requests applicable to the UDP protocol | 885 | * IOCTL requests applicable to the UDP protocol |
850 | */ | 886 | */ |
@@ -861,21 +897,16 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
861 | 897 | ||
862 | case SIOCINQ: | 898 | case SIOCINQ: |
863 | { | 899 | { |
864 | struct sk_buff *skb; | 900 | unsigned int amount = first_packet_length(sk); |
865 | unsigned long amount; | ||
866 | 901 | ||
867 | amount = 0; | 902 | if (amount) |
868 | spin_lock_bh(&sk->sk_receive_queue.lock); | ||
869 | skb = skb_peek(&sk->sk_receive_queue); | ||
870 | if (skb != NULL) { | ||
871 | /* | 903 | /* |
872 | * We will only return the amount | 904 | * We will only return the amount |
873 | * of this packet since that is all | 905 | * of this packet since that is all |
874 | * that will be read. | 906 | * that will be read. |
875 | */ | 907 | */ |
876 | amount = skb->len - sizeof(struct udphdr); | 908 | amount -= sizeof(struct udphdr); |
877 | } | 909 | |
878 | spin_unlock_bh(&sk->sk_receive_queue.lock); | ||
879 | return put_user(amount, (int __user *)arg); | 910 | return put_user(amount, (int __user *)arg); |
880 | } | 911 | } |
881 | 912 | ||
@@ -1544,29 +1575,11 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
1544 | { | 1575 | { |
1545 | unsigned int mask = datagram_poll(file, sock, wait); | 1576 | unsigned int mask = datagram_poll(file, sock, wait); |
1546 | struct sock *sk = sock->sk; | 1577 | struct sock *sk = sock->sk; |
1547 | int is_lite = IS_UDPLITE(sk); | ||
1548 | 1578 | ||
1549 | /* Check for false positives due to checksum errors */ | 1579 | /* Check for false positives due to checksum errors */ |
1550 | if ((mask & POLLRDNORM) && | 1580 | if ((mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) && |
1551 | !(file->f_flags & O_NONBLOCK) && | 1581 | !(sk->sk_shutdown & RCV_SHUTDOWN) && !first_packet_length(sk)) |
1552 | !(sk->sk_shutdown & RCV_SHUTDOWN)) { | 1582 | mask &= ~(POLLIN | POLLRDNORM); |
1553 | struct sk_buff_head *rcvq = &sk->sk_receive_queue; | ||
1554 | struct sk_buff *skb; | ||
1555 | |||
1556 | spin_lock_bh(&rcvq->lock); | ||
1557 | while ((skb = skb_peek(rcvq)) != NULL && | ||
1558 | udp_lib_checksum_complete(skb)) { | ||
1559 | UDP_INC_STATS_BH(sock_net(sk), | ||
1560 | UDP_MIB_INERRORS, is_lite); | ||
1561 | __skb_unlink(skb, rcvq); | ||
1562 | kfree_skb(skb); | ||
1563 | } | ||
1564 | spin_unlock_bh(&rcvq->lock); | ||
1565 | |||
1566 | /* nothing to see, move along */ | ||
1567 | if (skb == NULL) | ||
1568 | mask &= ~(POLLIN | POLLRDNORM); | ||
1569 | } | ||
1570 | 1583 | ||
1571 | return mask; | 1584 | return mask; |
1572 | 1585 | ||