~lopin/openconnect/lopin-gp-deb-2

1392 by David Woodhouse
Add basic support for opening Windows TAP driver
1
/*
2
 * OpenConnect (SSL + DTLS) VPN client
3
 *
2054 by David Woodhouse
Update copyright year
4
 * Copyright © 2008-2015 Intel Corporation.
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
5
 *
6
 * Author: David Woodhouse <dwmw2@infradead.org>
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * version 2.1, as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 */
17
1636 by David Woodhouse
Use autoheader. Ick. But the command lines were getting silly
18
#include <config.h>
19
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
20
#define WIN32_LEAN_AND_MEAN
21
#include <windows.h>
22
#include <winioctl.h>
2479 by David Woodhouse
Add TUNIDX for Windows vpnc-script
23
#include <iphlpapi.h>
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
24
25
#include <errno.h>
26
#include <stdio.h>
27
28
#include <openconnect-internal.h>
29
30
/*
31
 * TAP-Windows support inspired by http://i3.cs.berkeley.edu/ with
32
 * permission.
33
 */
34
#define _TAP_IOCTL(nr) CTL_CODE(FILE_DEVICE_UNKNOWN, nr, METHOD_BUFFERED, \
35
				FILE_ANY_ACCESS)
36
37
#define TAP_IOCTL_GET_MAC               _TAP_IOCTL(1)
38
#define TAP_IOCTL_GET_VERSION           _TAP_IOCTL(2)
39
#define TAP_IOCTL_GET_MTU               _TAP_IOCTL(3)
40
#define TAP_IOCTL_GET_INFO              _TAP_IOCTL(4)
41
#define TAP_IOCTL_CONFIG_POINT_TO_POINT _TAP_IOCTL(5)
42
#define TAP_IOCTL_SET_MEDIA_STATUS      _TAP_IOCTL(6)
43
#define TAP_IOCTL_CONFIG_DHCP_MASQ      _TAP_IOCTL(7)
44
#define TAP_IOCTL_GET_LOG_LINE          _TAP_IOCTL(8)
45
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT   _TAP_IOCTL(9)
46
#define TAP_IOCTL_CONFIG_TUN            _TAP_IOCTL(10)
47
48
#define TAP_COMPONENT_ID "tap0901"
49
50
#define DEVTEMPLATE "\\\\.\\Global\\%s.tap"
51
52
#define NETDEV_GUID "{4D36E972-E325-11CE-BFC1-08002BE10318}"
53
#define CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control\\"
54
55
#define ADAPTERS_KEY CONTROL_KEY "Class\\" NETDEV_GUID
56
#define CONNECTIONS_KEY CONTROL_KEY "Network\\" NETDEV_GUID
57
1433 by David Woodhouse
Clean up search_taps() function
58
typedef intptr_t (tap_callback)(struct openconnect_info *vpninfo, char *idx, char *name);
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
59
1433 by David Woodhouse
Clean up search_taps() function
60
static intptr_t search_taps(struct openconnect_info *vpninfo, tap_callback *cb, int all)
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
61
{
62
	LONG status;
1678 by David Woodhouse
Use RegQueryValueEx() instead of RegGetValue() to support 32-bit Windows XP
63
	HKEY adapters_key, hkey;
64
	DWORD len, type;
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
65
	char buf[40];
66
	wchar_t name[40];
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
67
	char keyname[strlen(CONNECTIONS_KEY) + sizeof(buf) + 1 + strlen("\\Connection")];
1433 by David Woodhouse
Clean up search_taps() function
68
	int i = 0, found = 0;
1709 by David Woodhouse
Fix tun device matching with --interface on Windows
69
	intptr_t ret = -1;
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
70
	struct oc_text_buf *namebuf = buf_alloc();
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
71
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
72
	status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, ADAPTERS_KEY, 0,
73
			       KEY_READ, &adapters_key);
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
74
	if (status) {
1415 by David Woodhouse
Fix error printing when registry open fails
75
		vpn_progress(vpninfo, PRG_ERR,
76
			     _("Error accessing registry key for network adapters\n"));
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
77
		return -EIO;
78
	}
1433 by David Woodhouse
Clean up search_taps() function
79
	while (1) {
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
80
		len = sizeof(buf);
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
81
		status = RegEnumKeyExA(adapters_key, i++, buf, &len,
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
82
				       NULL, NULL, NULL, NULL);
83
		if (status) {
84
			if (status != ERROR_NO_MORE_ITEMS)
1433 by David Woodhouse
Clean up search_taps() function
85
				ret = -1;
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
86
			break;
87
		}
88
89
		snprintf(keyname, sizeof(keyname), "%s\\%s",
90
			 ADAPTERS_KEY, buf);
91
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
92
		status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyname, 0,
93
				       KEY_QUERY_VALUE, &hkey);
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
94
		if (status)
95
			continue;
96
1678 by David Woodhouse
Use RegQueryValueEx() instead of RegGetValue() to support 32-bit Windows XP
97
		len = sizeof(buf);
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
98
		status = RegQueryValueExA(hkey, "ComponentId", NULL, &type,
99
					  (unsigned char *)buf, &len);
1678 by David Woodhouse
Use RegQueryValueEx() instead of RegGetValue() to support 32-bit Windows XP
100
		if (status || type != REG_SZ || strcmp(buf, TAP_COMPONENT_ID)) {
101
			RegCloseKey(hkey);
102
			continue;
103
		}
104
105
		len = sizeof(buf);
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
106
		status = RegQueryValueExA(hkey, "NetCfgInstanceId", NULL,
107
					  &type, (unsigned char *)buf, &len);
1678 by David Woodhouse
Use RegQueryValueEx() instead of RegGetValue() to support 32-bit Windows XP
108
		RegCloseKey(hkey);
109
		if (status || type != REG_SZ)
110
			continue;
111
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
112
		snprintf(keyname, sizeof(keyname), "%s\\%s\\Connection",
113
			 CONNECTIONS_KEY, buf);
114
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
115
		status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyname, 0,
116
				       KEY_QUERY_VALUE, &hkey);
1678 by David Woodhouse
Use RegQueryValueEx() instead of RegGetValue() to support 32-bit Windows XP
117
		if (status)
118
			continue;
119
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
120
		len = sizeof(name);
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
121
		status = RegQueryValueExW(hkey, L"Name", NULL, &type,
1678 by David Woodhouse
Use RegQueryValueEx() instead of RegGetValue() to support 32-bit Windows XP
122
					 (unsigned char *)name, &len);
123
		RegCloseKey(hkey);
124
		if (status || type != REG_SZ)
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
125
			continue;
126
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
127
		buf_truncate(namebuf);
128
		buf_append_from_utf16le(namebuf, name);
129
		if (buf_error(namebuf)) {
130
			ret = buf_free(namebuf);
131
			namebuf = NULL;
132
			break;
133
		}
134
1416 by David Woodhouse
Print error when no TAP interfaces found
135
		found++;
136
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
137
		if (vpninfo->ifname && strcmp(namebuf->data, vpninfo->ifname)) {
1544 by Kevin Cernekee
Change most PRG_TRACE prints to PRG_DEBUG
138
			vpn_progress(vpninfo, PRG_DEBUG,
1709 by David Woodhouse
Fix tun device matching with --interface on Windows
139
				     _("Ignoring non-matching TAP interface \"%s\"\n"),
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
140
				     namebuf->data);
1432 by David Woodhouse
Move Windows interface name matching into search_taps() function
141
			continue;
142
		}
143
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
144
		ret = cb(vpninfo, buf, namebuf->data);
1433 by David Woodhouse
Clean up search_taps() function
145
		if (!all)
146
			break;
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
147
	}
148
149
	RegCloseKey(adapters_key);
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
150
	buf_free(namebuf);
1416 by David Woodhouse
Print error when no TAP interfaces found
151
152
	if (!found)
153
		vpn_progress(vpninfo, PRG_ERR,
154
			     _("No Windows-TAP adapters found. Is the driver installed?\n"));
155
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
156
	return ret;
157
}
158
2479 by David Woodhouse
Add TUNIDX for Windows vpnc-script
159
static int get_adapter_index(struct openconnect_info *vpninfo, char *guid)
160
{
161
	struct oc_text_buf *buf = buf_alloc();
162
	IP_ADAPTER_INFO *adapter;
163
	void *adapters_buf;
164
	ULONG idx;
165
	DWORD status;
166
	int ret = -EINVAL;
167
168
	vpninfo->tun_idx = -1;
169
170
	buf_append_utf16le(buf, "\\device\\tcpip_");
171
	buf_append_utf16le(buf, guid);
172
	if (buf_error(buf)) {
173
		/* If we didn't manage to malloc for this, we're never
174
		 * going to manage for GetAdaptersInfo(). Give up. */
175
		return buf_free(buf);
176
	}
177
178
	status = GetAdapterIndex((void *)buf->data, &idx);
179
	buf_free(buf);
180
	if (status == NO_ERROR) {
181
		vpninfo->tun_idx = idx;
182
		return 0;
183
	} else {
184
		char *errstr = openconnect__win32_strerror(status);
185
		vpn_progress(vpninfo, PRG_INFO,
186
			     _("GetAdapterIndex() failed: %s\nFalling back to GetAdaptersInfo()\n"),
187
			     errstr);
188
		free(errstr);
189
	}
190
	idx = 0;
191
	status = GetAdaptersInfo(NULL, &idx);
192
	if (status != ERROR_BUFFER_OVERFLOW)
193
		return -EIO;
194
	adapters_buf = malloc(idx);
195
	if (!adapters_buf)
196
		return -ENOMEM;
197
	status = GetAdaptersInfo(adapters_buf, &idx);
198
	if (status != NO_ERROR) {
199
		char *errstr = openconnect__win32_strerror(status);
200
		vpn_progress(vpninfo, PRG_ERR, _("GetAdaptersInfo() failed: %s\n"), errstr);
201
		free(errstr);
202
		free(adapters_buf);
203
		return -EIO;
204
	}
205
206
	for (adapter = adapters_buf; adapter; adapter = adapter->Next) {
207
		if (!strcmp(adapter->AdapterName, guid)) {
208
			vpninfo->tun_idx = adapter->Index;
209
			ret = 0;
210
			break;
211
		}
212
	}
213
214
	free(adapters_buf);
215
	return ret;
216
}
217
1433 by David Woodhouse
Clean up search_taps() function
218
static intptr_t open_tun(struct openconnect_info *vpninfo, char *guid, char *name)
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
219
{
220
	char devname[80];
221
	HANDLE tun_fh;
222
	ULONG data[3];
223
	DWORD len;
224
225
	snprintf(devname, sizeof(devname), DEVTEMPLATE, guid);
1697 by David Woodhouse
Handle non-ASCII tun device names under Windows
226
	tun_fh = CreateFileA(devname, GENERIC_WRITE|GENERIC_READ, 0, 0,
227
			     OPEN_EXISTING,
228
			     FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
229
			     0);
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
230
	if (tun_fh == INVALID_HANDLE_VALUE) {
231
		vpn_progress(vpninfo, PRG_ERR, _("Failed to open %s\n"),
232
			     devname);
233
		return -1;
234
235
	}
1698 by David Woodhouse
Print name of Windows tun device not devname
236
	vpn_progress(vpninfo, PRG_DEBUG, _("Opened tun device %s\n"), name);
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
237
238
	if (!DeviceIoControl(tun_fh, TAP_IOCTL_GET_VERSION,
1792 by David Woodhouse
Fix DeviceIoControl() calls to make NDIS6 TAP-Windows driver happy
239
			     data, sizeof(&data), data, sizeof(data),
240
			     &len, NULL)) {
1827 by David Woodhouse
Print error message strings on Windows
241
		char *errstr = openconnect__win32_strerror(GetLastError());
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
242
243
		vpn_progress(vpninfo, PRG_ERR,
1827 by David Woodhouse
Print error message strings on Windows
244
			     _("Failed to obtain TAP driver version: %s\n"), errstr);
245
		free(errstr);
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
246
		return -1;
247
	}
248
	if (data[0] < 9 || (data[0] == 9 && data[1] < 9)) {
249
		vpn_progress(vpninfo, PRG_ERR,
250
			     _("Error: TAP-Windows driver v9.9 or greater is required (found %ld.%ld)\n"),
251
			     data[0], data[1]);
252
		return -1;
253
	}
1544 by Kevin Cernekee
Change most PRG_TRACE prints to PRG_DEBUG
254
	vpn_progress(vpninfo, PRG_DEBUG, "TAP-Windows driver v%ld.%ld (%ld)\n",
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
255
		     data[0], data[1], data[2]);
256
257
	data[0] = inet_addr(vpninfo->ip_info.addr);
2478 by David Woodhouse
Better attempt at handling TAP-Windows tun setup
258
	/* Set network and mask both to 0.0.0.0. It's not about routing;
259
	 * it just ensures that the TAP driver fakes ARP responses for
260
	 * *everything* we throw at it, and we can just configure them
261
	 * as on-link routes. */
262
	data[1] = 0;
263
	data[2] = 0;
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
264
265
	if (!DeviceIoControl(tun_fh, TAP_IOCTL_CONFIG_TUN,
1792 by David Woodhouse
Fix DeviceIoControl() calls to make NDIS6 TAP-Windows driver happy
266
			     data, sizeof(data), data, sizeof(data),
267
			     &len, NULL)) {
1827 by David Woodhouse
Print error message strings on Windows
268
		char *errstr = openconnect__win32_strerror(GetLastError());
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
269
270
		vpn_progress(vpninfo, PRG_ERR,
1827 by David Woodhouse
Print error message strings on Windows
271
			     _("Failed to set TAP IP addresses: %s\n"), errstr);
272
		free(errstr);
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
273
		return -1;
274
	}
275
276
	data[0] = 1;
277
	if (!DeviceIoControl(tun_fh, TAP_IOCTL_SET_MEDIA_STATUS,
1792 by David Woodhouse
Fix DeviceIoControl() calls to make NDIS6 TAP-Windows driver happy
278
			     data, sizeof(data[0]), data, sizeof(data[0]),
279
			     &len, NULL)) {
1827 by David Woodhouse
Print error message strings on Windows
280
		char *errstr = openconnect__win32_strerror(GetLastError());
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
281
282
		vpn_progress(vpninfo, PRG_ERR,
1827 by David Woodhouse
Print error message strings on Windows
283
			     _("Failed to set TAP media status: %s\n"), errstr);
284
		free(errstr);
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
285
		return -1;
286
	}
287
	if (!vpninfo->ifname)
288
		vpninfo->ifname = strdup(name);
289
2479 by David Woodhouse
Add TUNIDX for Windows vpnc-script
290
	get_adapter_index(vpninfo, guid);
291
1434 by David Woodhouse
Make openconnect_setup_tun_fd() work on Windows
292
	return (intptr_t)tun_fh;
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
293
}
294
1434 by David Woodhouse
Make openconnect_setup_tun_fd() work on Windows
295
intptr_t os_setup_tun(struct openconnect_info *vpninfo)
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
296
{
1434 by David Woodhouse
Make openconnect_setup_tun_fd() work on Windows
297
	return search_taps(vpninfo, open_tun, 0);
1392 by David Woodhouse
Add basic support for opening Windows TAP driver
298
}
1423 by David Woodhouse
Factor out os_read_tun() from tun_mainloop()
299
1503 by David Woodhouse
Fix Windows tun read handling
300
int os_read_tun(struct openconnect_info *vpninfo, struct pkt *pkt)
1423 by David Woodhouse
Factor out os_read_tun() from tun_mainloop()
301
{
302
	DWORD pkt_size;
303
1503 by David Woodhouse
Fix Windows tun read handling
304
 reread:
305
	if (!vpninfo->tun_rd_pending &&
306
	    !ReadFile(vpninfo->tun_fh, pkt->data, pkt->len, &pkt_size,
307
		      &vpninfo->tun_rd_overlap)) {
308
		DWORD err = GetLastError();
309
310
		if (err == ERROR_IO_PENDING)
311
			vpninfo->tun_rd_pending = 1;
1840 by David Woodhouse
Handle ERROR_OPERATION_ABORTED on Windows TAP device
312
		else if (err == ERROR_OPERATION_ABORTED) {
313
			vpninfo->quit_reason = "TAP device aborted";
314
			vpn_progress(vpninfo, PRG_ERR,
315
				     _("TAP device aborted connectivity. Disconnecting.\n"));
316
			return -1;
317
		} else {
1827 by David Woodhouse
Print error message strings on Windows
318
			char *errstr = openconnect__win32_strerror(err);
1503 by David Woodhouse
Fix Windows tun read handling
319
			vpn_progress(vpninfo, PRG_ERR,
1827 by David Woodhouse
Print error message strings on Windows
320
				     _("Failed to read from TAP device: %s\n"),
321
				     errstr);
322
			free(errstr);
323
		}
1503 by David Woodhouse
Fix Windows tun read handling
324
		return -1;
325
	} else if (!GetOverlappedResult(vpninfo->tun_fh,
326
					&vpninfo->tun_rd_overlap, &pkt_size,
327
					FALSE)) {
328
		DWORD err = GetLastError();
329
330
		if (err != ERROR_IO_INCOMPLETE) {
1827 by David Woodhouse
Print error message strings on Windows
331
			char *errstr = openconnect__win32_strerror(err);
1503 by David Woodhouse
Fix Windows tun read handling
332
			vpninfo->tun_rd_pending = 0;
333
			vpn_progress(vpninfo, PRG_ERR,
1827 by David Woodhouse
Print error message strings on Windows
334
				     _("Failed to complete read from TAP device: %s\n"),
335
				     errstr);
336
			free(errstr);
1503 by David Woodhouse
Fix Windows tun read handling
337
			goto reread;
338
		}
339
		return -1;
1423 by David Woodhouse
Factor out os_read_tun() from tun_mainloop()
340
	}
341
1503 by David Woodhouse
Fix Windows tun read handling
342
	/* Either a straight ReadFile() or a subsequent GetOverlappedResult()
343
	   succeeded... */
344
	vpninfo->tun_rd_pending = 0;
1423 by David Woodhouse
Factor out os_read_tun() from tun_mainloop()
345
	pkt->len = pkt_size;
346
	return 0;
347
}
1424 by David Woodhouse
Factor out os_write_tun() from tun_mainloop()
348
349
int os_write_tun(struct openconnect_info *vpninfo, struct pkt *pkt)
350
{
351
	DWORD pkt_size = 0;
352
	DWORD err;
1827 by David Woodhouse
Print error message strings on Windows
353
	char *errstr;
1424 by David Woodhouse
Factor out os_write_tun() from tun_mainloop()
354
355
	if (WriteFile(vpninfo->tun_fh, pkt->data, pkt->len, &pkt_size, &vpninfo->tun_wr_overlap)) {
356
		vpn_progress(vpninfo, PRG_TRACE,
357
			     _("Wrote %ld bytes to tun\n"), pkt_size);
358
		return 0;
359
	}
360
361
	err = GetLastError();
362
	if (err == ERROR_IO_PENDING) {
363
		/* Theoretically we should let the mainloop handle this blocking,
364
		   but that's non-trivial and it doesn't ever seem to happen in
365
		   practice anyway. */
366
		vpn_progress(vpninfo, PRG_TRACE,
367
			     _("Waiting for tun write...\n"));
368
		if (GetOverlappedResult(vpninfo->tun_fh, &vpninfo->tun_wr_overlap, &pkt_size, TRUE)) {
369
			vpn_progress(vpninfo, PRG_TRACE,
370
				     _("Wrote %ld bytes to tun after waiting\n"), pkt_size);
371
			return 0;
372
		}
373
		err = GetLastError();
374
	}
1827 by David Woodhouse
Print error message strings on Windows
375
	errstr = openconnect__win32_strerror(err);
1424 by David Woodhouse
Factor out os_write_tun() from tun_mainloop()
376
	vpn_progress(vpninfo, PRG_ERR,
1827 by David Woodhouse
Print error message strings on Windows
377
		     _("Failed to write to TAP device: %s\n"), errstr);
378
	free(errstr);
1424 by David Woodhouse
Factor out os_write_tun() from tun_mainloop()
379
	return -1;
380
}
1426 by David Woodhouse
Split out os_shutdown_tun() for Windows vs. sane platforms
381
382
void os_shutdown_tun(struct openconnect_info *vpninfo)
383
{
384
	script_config_tun(vpninfo, "disconnect");
385
	CloseHandle(vpninfo->tun_fh);
386
	vpninfo->tun_fh = NULL;
387
	CloseHandle(vpninfo->tun_rd_overlap.hEvent);
388
	vpninfo->tun_rd_overlap.hEvent = NULL;
389
}
1427 by David Woodhouse
Move Windows openconnect_setup_tun_fd() to tun-win32.c
390
1434 by David Woodhouse
Make openconnect_setup_tun_fd() work on Windows
391
int openconnect_setup_tun_fd(struct openconnect_info *vpninfo, intptr_t tun_fd)
1427 by David Woodhouse
Move Windows openconnect_setup_tun_fd() to tun-win32.c
392
{
1434 by David Woodhouse
Make openconnect_setup_tun_fd() work on Windows
393
	vpninfo->tun_fh = (HANDLE)tun_fd;
394
	vpninfo->tun_rd_overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
395
	monitor_read_fd(vpninfo, tun);
396
1427 by David Woodhouse
Move Windows openconnect_setup_tun_fd() to tun-win32.c
397
	return 0;
398
}
1435 by David Woodhouse
Add openconnect_setup_tun_script() stub for Windows
399
1805 by David Woodhouse
Bump library soname and add 'const' to lots of char * arguments
400
int openconnect_setup_tun_script(struct openconnect_info *vpninfo,
401
				 const char *tun_script)
1435 by David Woodhouse
Add openconnect_setup_tun_script() stub for Windows
402
{
403
	vpn_progress(vpninfo, PRG_ERR,
404
		     _("Spawning tunnel scripts is not yet supported on Windows\n"));
405
	return -1;
406
}