Commit 63edf11b authored by David Woodhouse's avatar David Woodhouse

Fix Windows tun read handling

It's too fragile to depend on the 'new_pkt' check, and only do the ReadFile()
call when we allocate a new packet buffer. Keep track of the pending state
directly in the Windows-specific code, instead.

This should fix the fact that it gets out of sync when we get an error.
Such as the ERROR_MORE_DATA errors we get because vpnc-script-win.js
doesn't set the MTU properly yet...
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 616deb64
......@@ -56,10 +56,8 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout)
if (read_fd_monitored(vpninfo, tun)) {
while (1) {
int len = vpninfo->ip_info.mtu;
int new_pkt = 0;
if (!out_pkt) {
new_pkt = 1;
out_pkt = malloc(sizeof(struct pkt) + len);
if (!out_pkt) {
vpn_progress(vpninfo, PRG_ERR, "Allocation failed\n");
......@@ -68,7 +66,7 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout)
out_pkt->len = len;
}
if (os_read_tun(vpninfo, out_pkt, new_pkt))
if (os_read_tun(vpninfo, out_pkt))
break;
vpninfo->stats.tx_pkts++;
......
......@@ -294,6 +294,7 @@ struct openconnect_info {
#ifdef _WIN32
HANDLE tun_fh;
OVERLAPPED tun_rd_overlap, tun_wr_overlap;
int tun_rd_pending;
#else
int tun_fd;
#endif
......@@ -453,7 +454,7 @@ int script_config_tun(struct openconnect_info *vpninfo, const char *reason);
/* tun.c / tun-win32.c */
void os_shutdown_tun(struct openconnect_info *vpninfo);
int os_read_tun(struct openconnect_info *vpninfo, struct pkt *pkt, int new_pkt);
int os_read_tun(struct openconnect_info *vpninfo, struct pkt *pkt);
int os_write_tun(struct openconnect_info *vpninfo, struct pkt *pkt);
intptr_t os_setup_tun(struct openconnect_info *vpninfo);
......
......@@ -200,33 +200,41 @@ intptr_t os_setup_tun(struct openconnect_info *vpninfo)
return search_taps(vpninfo, open_tun, 0);
}
int os_read_tun(struct openconnect_info *vpninfo, struct pkt *pkt, int new_pkt)
int os_read_tun(struct openconnect_info *vpninfo, struct pkt *pkt)
{
DWORD pkt_size;
/* For newly-allocated packets we have to trigger the read. */
if (new_pkt) {
if (!ReadFile(vpninfo->tun_fh, pkt->data, pkt->len, &pkt_size, &vpninfo->tun_rd_overlap)) {
DWORD err = GetLastError();
if (err != ERROR_IO_PENDING)
vpn_progress(vpninfo, PRG_ERR,
_("Failed to read from TAP device: %lx\n"),
err);
return -1;
}
} else {
/* IF it isn't a new packet, then there was already a pending read on it. */
if (!GetOverlappedResult(vpninfo->tun_fh, &vpninfo->tun_rd_overlap, &pkt_size, FALSE)) {
DWORD err = GetLastError();
if (err != ERROR_IO_INCOMPLETE)
vpn_progress(vpninfo, PRG_ERR,
_("Failed to complete read from TAP device: %lx\n"),
err);
return -1;
reread:
if (!vpninfo->tun_rd_pending &&
!ReadFile(vpninfo->tun_fh, pkt->data, pkt->len, &pkt_size,
&vpninfo->tun_rd_overlap)) {
DWORD err = GetLastError();
if (err == ERROR_IO_PENDING)
vpninfo->tun_rd_pending = 1;
else
vpn_progress(vpninfo, PRG_ERR,
_("Failed to read from TAP device: %lx\n"),
err);
return -1;
} else if (!GetOverlappedResult(vpninfo->tun_fh,
&vpninfo->tun_rd_overlap, &pkt_size,
FALSE)) {
DWORD err = GetLastError();
if (err != ERROR_IO_INCOMPLETE) {
vpninfo->tun_rd_pending = 0;
vpn_progress(vpninfo, PRG_ERR,
_("Failed to complete read from TAP device: %lx\n"),
err);
goto reread;
}
return -1;
}
/* Either a straight ReadFile() or a subsequent GetOverlappedResult()
succeeded... */
vpninfo->tun_rd_pending = 0;
pkt->len = pkt_size;
return 0;
}
......
......@@ -376,7 +376,7 @@ int openconnect_setup_tun_script(struct openconnect_info *vpninfo, char *tun_scr
return openconnect_setup_tun_fd(vpninfo, fds[0]);
}
int os_read_tun(struct openconnect_info *vpninfo, struct pkt *pkt, int new_pkt)
int os_read_tun(struct openconnect_info *vpninfo, struct pkt *pkt)
{
int prefix_size = 0;
int len;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment