udp_poll breaks vpnc

3 messages, 3 authors, 2004-12-15 · open the first message on its own page

udp_poll breaks vpnc

From: Pete Zaitcev <zaitcev@redhat.com>
Date: 2004-12-15 21:14:47

Hi, Guys:

I found that the attached patch breaks VPNC. By looking at strace, it never
gets any poll events about arriving encrypted data. It may be a bug in VPNC,
but this is a rather old binary which I used even on 2.4...

Unfortunately, I cannot investigate it closer at this time, because of, uhh,
some work commitments. Sorry. I do not insist that we back this out, but
let it be known that something was broken.

Cheers,
-- Pete

diff -urp -X dontdiff linux-2.6.10-rc2-bk8-usb/include/net/udp.h linux-2.6.10-rc3-usb/include/net/udp.h
--- linux-2.6.10-rc2-bk8-usb/include/net/udp.h	2004-08-19 17:16:10.000000000 -0700
+++ linux-2.6.10-rc3-usb/include/net/udp.h	2004-12-15 02:01:19.000000000 -0800
@@ -71,6 +71,8 @@ extern int	udp_sendmsg(struct kiocb *ioc
 extern int	udp_rcv(struct sk_buff *skb);
 extern int	udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern int	udp_disconnect(struct sock *sk, int flags);
+extern unsigned int udp_poll(struct file *file, struct socket *sock,
+			     poll_table *wait);
 
 DECLARE_SNMP_STAT(struct udp_mib, udp_statistics);
 #define UDP_INC_STATS(field)		SNMP_INC_STATS(udp_statistics, field)
diff -urp -X dontdiff linux-2.6.10-rc2-bk8-usb/net/ipv4/af_inet.c linux-2.6.10-rc3-usb/net/ipv4/af_inet.c
--- linux-2.6.10-rc2-bk8-usb/net/ipv4/af_inet.c	2004-11-23 09:54:15.000000000 -0800
+++ linux-2.6.10-rc3-usb/net/ipv4/af_inet.c	2004-12-15 02:01:21.000000000 -0800
@@ -809,7 +809,7 @@ struct proto_ops inet_dgram_ops = {
 	.socketpair =	sock_no_socketpair,
 	.accept =	sock_no_accept,
 	.getname =	inet_getname,
-	.poll =		datagram_poll,
+	.poll =		udp_poll,
 	.ioctl =	inet_ioctl,
 	.listen =	sock_no_listen,
 	.shutdown =	inet_shutdown,
diff -urp -X dontdiff linux-2.6.10-rc2-bk8-usb/net/ipv4/udp.c linux-2.6.10-rc3-usb/net/ipv4/udp.c
--- linux-2.6.10-rc2-bk8-usb/net/ipv4/udp.c	2004-11-23 09:54:15.000000000 -0800
+++ linux-2.6.10-rc3-usb/net/ipv4/udp.c	2004-12-15 02:01:21.000000000 -0800
@@ -1303,6 +1303,52 @@ static int udp_getsockopt(struct sock *s
   	return 0;
 }
 
+/**
+ * 	udp_poll - wait for a UDP event.
+ *	@file - file struct
+ *	@sock - socket
+ *	@wait - poll table
+ *
+ *	This is same as datagram poll, except for the special case of 
+ *	blocking sockets. If application is using a blocking fd
+ *	and a packet with checksum error is in the queue;
+ *	then it could get return from select indicating data available
+ *	but then block when reading it. Add special case code
+ *	to work around these arguably broken applications.
+ */
+unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
+{
+	unsigned int mask = datagram_poll(file, sock, wait);
+	struct sock *sk = sock->sk;
+	
+	/* Check for false positives due to checksum errors */
+	if ( (mask & POLLRDNORM) &&
+	     !(file->f_flags & O_NONBLOCK) &&
+	     !(sk->sk_shutdown & RCV_SHUTDOWN)){
+		struct sk_buff_head *rcvq = &sk->sk_receive_queue;
+		struct sk_buff *skb;
+
+		spin_lock_irq(&rcvq->lock);
+		while ((skb = skb_peek(rcvq)) != NULL) {
+			if (udp_checksum_complete(skb)) {
+				UDP_INC_STATS_BH(UDP_MIB_INERRORS);
+				__skb_unlink(skb, rcvq);
+				kfree_skb(skb);
+			} else {
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+				break;
+			}
+		}
+		spin_unlock_irq(&rcvq->lock);
+
+		/* nothing to see, move along */
+		if (skb == NULL)
+			mask &= ~(POLLIN | POLLRDNORM);
+	}
+
+	return mask;
+	
+}
 
 struct proto udp_prot = {
  	.name =		"UDP",
@@ -1517,6 +1563,7 @@ EXPORT_SYMBOL(udp_ioctl);
 EXPORT_SYMBOL(udp_port_rover);
 EXPORT_SYMBOL(udp_prot);
 EXPORT_SYMBOL(udp_sendmsg);
+EXPORT_SYMBOL(udp_poll);
 
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(udp_proc_register);
diff -urp -X dontdiff linux-2.6.10-rc2-bk8-usb/net/ipv6/af_inet6.c linux-2.6.10-rc3-usb/net/ipv6/af_inet6.c
--- linux-2.6.10-rc2-bk8-usb/net/ipv6/af_inet6.c	2004-11-23 09:54:15.000000000 -0800
+++ linux-2.6.10-rc3-usb/net/ipv6/af_inet6.c	2004-12-15 02:01:21.000000000 -0800
@@ -501,7 +501,7 @@ struct proto_ops inet6_dgram_ops = {
 	.socketpair =	sock_no_socketpair,		/* a do nothing	*/
 	.accept =	sock_no_accept,			/* a do nothing	*/
 	.getname =	inet6_getname, 
-	.poll =		datagram_poll,			/* ok		*/
+	.poll =		udp_poll,			/* ok		*/
 	.ioctl =	inet6_ioctl,			/* must change  */
 	.listen =	sock_no_listen,			/* ok		*/
 	.shutdown =	inet_shutdown,			/* ok		*/

Re: udp_poll breaks vpnc

From: "David S. Miller" <davem@davemloft.net>
Date: 2004-12-15 21:19:02

On Wed, 15 Dec 2004 13:13:42 -0800
Pete Zaitcev [off-list ref] wrote:
I found that the attached patch breaks VPNC. By looking at strace, it never
gets any poll events about arriving encrypted data. It may be a bug in VPNC,
but this is a rather old binary which I used even on 2.4...
Fixed by a followon patch which is in BK as of 2 weeks ago.
Basically, we were using UDP poll for RAW sockets by accident.

Re: udp_poll breaks vpnc

From: Phil Oester <hidden>
Date: 2004-12-15 21:22:04

On Wed, Dec 15, 2004 at 01:13:42PM -0800, Pete Zaitcev wrote:
Hi, Guys:

I found that the attached patch breaks VPNC. By looking at strace, it never
gets any poll events about arriving encrypted data. It may be a bug in VPNC,
but this is a rather old binary which I used even on 2.4...
This was fixed post-rc3.

Phil
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help