--- tun-1.1/linux/2.2/tun.c 2000-10-23 22:13:08.000000000 -0700 +++ tun.new/linux/2.2/tun.c 2005-12-22 00:27:56.000000000 -0800 @@ -180,8 +180,19 @@ poll_wait(file, &tun->read_wait, wait); + /* Data written to the /dev/tunX device is immediately placed into a socket buffer, making it + * available to networking code at the tunX interface. Writes never block. + * Likewise, data flows from the network stack, through the tunX interface and into the /dev/tun* device, + * where it is queued, making it available for read(). + * Thus the character device /dev/tunX is: + * - readable if data was "transmitted" to the tunX interface and is now queued at the /dev/tunX device. + * - always writable. + * Everything written here is equally true of taps. + * The author made a mistake when implementing this routine; he forgot that the device is always writable. + * -jeff stearns 22-Dec-2005 + */ if( skb_queue_len(&tun->txq) ) - return POLLIN | POLLRDNORM; + return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; return POLLOUT | POLLWRNORM; } --- tun-1.1/linux/2.4/tun.c 2001-01-09 16:24:24.000000000 -0800 +++ tun.new/linux/2.4/tun.c 2005-12-28 12:28:46.000000000 -0800 @@ -176,9 +176,20 @@ DBG(KERN_INFO "%s: tun_chr_poll\n", tun->name); poll_wait(file, &tun->read_wait, wait); - + + /* Data written to the /dev/tunX device is immediately placed into a socket buffer, making it + * available to networking code at the tunX interface. Writes never block. + * Likewise, data flows from the network stack, through the tunX interface and into the /dev/tun* device, + * where it is queued, making it available for read(). + * Thus the character device /dev/tunX is: + * - readable if data was "transmitted" to the tunX interface and is now queued at the /dev/tunX device. + * - always writable. + * Everything written here is equally true of taps. + * The author made a mistake when implementing this routine; he forgot that the device is always writable. + * -jeff stearns 22-Dec-2005 + */ if (skb_queue_len(&tun->txq)) - return POLLIN | POLLRDNORM; + return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; return POLLOUT | POLLWRNORM; }