I've now managed to get this actually passing packets, albeit sporadically. Nikos, I wonder if GnuTLS should be accepting EWOULDBLOCK on a read from a non-blocking socket and treating it the same as EAGAIN? See http://git.infradead.org/users/dwmw2/openconnect.git/commitdiff/b5df97e74b I've committed the code to find and open the tun device (using the latest one from OpenVPN, which does actually support tun mode). What I haven't committed is anything to actually read/write the tun device. That's in the patch below, but it's only barely function. The problem is that Windows is crap and you can't just open the tun device, get a file descriptor for it, and select() on that. We're probably going to have to do the reads from the tun device in a thread and then wake the main thread (perhaps via a socketpair). The alternative is to revamp the whole of the event processing to allow us to make it work with real Windows events, and I think that's just a step too far. So this patch works, except that it keeps blocking on reading from the tun device when there isn't a packet to be read. I've only tested it with Legacy IP, not IPv6. The other issue is that I haven't worked out how to configure the device. The 'netsh' command lines that vpnc and openvpn attempt to use are failing here with a confusing 'Element not found' error. I went through the GUI to *manually* configure the device with the IP addresses for my test connection, but we need to find a correct fix. diff --git a/tun.c b/tun.c index 1fcb19f..5ad0a96 100644 --- a/tun.c +++ b/tun.c @@ -723,8 +723,8 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout) prefix_size = sizeof(int); #endif - if (FD_ISSET(vpninfo->tun_fd, &vpninfo->select_rfds)) { - while (1) { + if (1 || FD_ISSET(vpninfo->tun_fd, &vpninfo->select_rfds)) { + while (!work_done) { int len = vpninfo->ip_info.mtu; if (!out_pkt) { @@ -734,8 +734,23 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout) break; } } - +#ifdef _WIN32 + { DWORD got; + printf("reading...\n"); + if (!ReadFile(vpninfo->tun_fh, out_pkt->data - prefix_size, len + prefix_size, &got, NULL)) { + DWORD err = GetLastError(); + vpn_progress(vpninfo, PRG_ERR, + _("Failed to read from to TAP device: %lx\n"), err); + break; + } + else printf("got %d: %02x %02x %02x %02x %02x %02x %02x %02x\n", got, + out_pkt->data[0], out_pkt->data[1], out_pkt->data[2], out_pkt->data[3], + out_pkt->data[4], out_pkt->data[5], out_pkt->data[6], out_pkt->data[7]); + len = got; + } +#else len = read(vpninfo->tun_fd, out_pkt->data - prefix_size, len + prefix_size); +#endif if (len <= prefix_size) break; out_pkt->len = len - prefix_size; @@ -794,7 +809,19 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout) } #endif vpninfo->incoming_queue = this->next; +#ifdef _WIN32 + { + DWORD wrote; + if (!WriteFile(vpninfo->tun_fh, data, len, &wrote, NULL)) { + DWORD err = GetLastError(); + + vpn_progress(vpninfo, PRG_ERR, + _("Failed to write to TAP device: %lx\n"), err); + } + else printf("wrote %d\n", wrote); + } +#else if (write(vpninfo->tun_fd, data, len) < 0) { /* Handle death of "script" socket */ if (vpninfo->script_tun && errno == ENOTCONN) { @@ -805,6 +832,7 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout) _("Failed to write incoming packet: %s\n"), strerror(errno)); } +#endif free(this); } /* Work is not done if we just got rid of packets off the queue */ -- dwmw2 -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/x-pkcs7-signature Size: 5745 bytes Desc: not available URL: <http://lists.infradead.org/pipermail/openconnect-devel/attachments/20140210/2674fb05/attachment.bin>