ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/tincd/mingw/device.c
Revision: 1.2
Committed: Thu Mar 17 23:59:38 2005 UTC (19 years, 3 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_9, rel-1_8, rel-2_01, rel-3_0, rel-2_2, rel-2_0, rel-2_21, rel-2_22, rel-2_25, HEAD
Changes since 1.1: +16 -20 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 device.c -- Interaction with Windows tap driver in a MinGW environment
3 Copyright (C) 2002-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
4 2002-2004 Guus Sliepen <guus@tinc-vpn.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 $Id: device.c 1400 2004-11-01 17:02:19Z guus $
21 */
22
23 #include "system.h"
24
25 #include <windows.h>
26 #include <winioctl.h>
27
28 #include "tincd/mingw/common.h"
29
30 int device_fd = 0;
31 static HANDLE device_handle = INVALID_HANDLE_VALUE;
32 char *device = NULL;
33 char *iface = NULL;
34 char *device_info = NULL;
35
36 static int device_total_in = 0;
37 static int device_total_out = 0;
38
39 extern char *myport;
40
41 DWORD WINAPI tapreader(void *bla) {
42 int sock, err, status;
43 struct addrinfo *ai;
44 struct addrinfo hint = {
45 .ai_family = AF_UNSPEC,
46 .ai_socktype = SOCK_DGRAM,
47 .ai_protocol = IPPROTO_UDP,
48 .ai_flags = 0,
49 };
50 char buf[MTU];
51 long len;
52 OVERLAPPED overlapped;
53
54 /* Open a socket to the parent process */
55
56 err = getaddrinfo(NULL, myport, &hint, &ai);
57
58 if(err || !ai) {
59 logger(LOG_ERR, _("System call `%s' failed: %s"), "getaddrinfo", gai_strerror(errno));
60 return -1;
61 }
62
63 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
64
65 freeaddrinfo(ai);
66
67 if(sock < 0) {
68 logger(LOG_ERR, _("System call `%s' failed: %s"), "socket", strerror(errno));
69 return -1;
70 }
71
72 if(connect(sock, ai->ai_addr, ai->ai_addrlen)) {
73 logger(LOG_ERR, _("System call `%s' failed: %s"), "connect", strerror(errno));
74 return -1;
75 }
76
77 logger(LOG_DEBUG, _("Tap reader running"));
78
79 /* Read from tap device and send to parent */
80
81 overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
82
83 for(;;) {
84 overlapped.Offset = 0;
85 overlapped.OffsetHigh = 0;
86 ResetEvent(overlapped.hEvent);
87
88 status = ReadFile(device_handle, buf, sizeof(buf), &len, &overlapped);
89
90 if(!status) {
91 if(GetLastError() == ERROR_IO_PENDING) {
92 WaitForSingleObject(overlapped.hEvent, INFINITE);
93 if(!GetOverlappedResult(device_handle, &overlapped, &len, FALSE))
94 continue;
95 } else {
96 logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
97 device, strerror(errno));
98 return -1;
99 }
100 }
101
102 if(send(sock, buf, len, 0) <= 0)
103 return -1;
104 }
105 }
106
107 bool setup_device(void)
108 {
109 HKEY key, key2;
110 int i;
111
112 char regpath[1024];
113 char adapterid[1024];
114 char adaptername[1024];
115 char tapname[1024];
116 long len;
117 unsigned long status;
118
119 bool found = false;
120
121 int sock, err;
122 HANDLE thread;
123
124 struct addrinfo *ai;
125 struct addrinfo hint = {
126 .ai_family = AF_UNSPEC,
127 .ai_socktype = SOCK_DGRAM,
128 .ai_protocol = IPPROTO_UDP,
129 .ai_flags = 0,
130 };
131
132 cp();
133
134 get_config_string(lookup_config(config_tree, "Device"), &device);
135 get_config_string(lookup_config(config_tree, "Interface"), &iface);
136
137 /* Open registry and look for network adapters */
138
139 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
140 logger(LOG_ERR, _("Unable to read registry: %s"), winerror(GetLastError()));
141 return false;
142 }
143
144 for (i = 0; ; i++) {
145 len = sizeof(adapterid);
146 if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL))
147 break;
148
149 /* Find out more about this adapter */
150
151 snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
152
153 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2))
154 continue;
155
156 len = sizeof(adaptername);
157 err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
158
159 RegCloseKey(key2);
160
161 if(err)
162 continue;
163
164 if(device) {
165 if(!strcmp(device, adapterid)) {
166 found = true;
167 break;
168 } else
169 continue;
170 }
171
172 if(iface) {
173 if(!strcmp(iface, adaptername)) {
174 found = true;
175 break;
176 } else
177 continue;
178 }
179
180 snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
181 device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
182 if(device_handle != INVALID_HANDLE_VALUE) {
183 found = true;
184 break;
185 }
186 }
187
188 RegCloseKey(key);
189
190 if(!found) {
191 logger(LOG_ERR, _("No Windows tap device found!"));
192 return false;
193 }
194
195 if(!device)
196 device = xstrdup(adapterid);
197
198 if(!iface)
199 iface = xstrdup(adaptername);
200
201 /* Try to open the corresponding tap device */
202
203 if(device_handle == INVALID_HANDLE_VALUE) {
204 snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
205 device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
206 }
207
208 if(device_handle == INVALID_HANDLE_VALUE) {
209 logger(LOG_ERR, _("%s (%s) is not a usable Windows tap device: %s"), device, iface, winerror(GetLastError()));
210 return false;
211 }
212
213 /* Get MAC address from tap device */
214
215 if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
216 logger(LOG_ERR, _("Could not get MAC address from Windows tap device %s (%s): %s"), device, iface, winerror(GetLastError()));
217 return false;
218 }
219
220 if(routing_mode == RMODE_ROUTER) {
221 overwrite_mac = 1;
222 }
223
224 /* Create a listening socket */
225
226 err = getaddrinfo(NULL, myport, &hint, &ai);
227
228 if(err || !ai) {
229 logger(LOG_ERR, _("System call `%s' failed: %s"), "getaddrinfo", gai_strerror(errno));
230 return false;
231 }
232
233 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
234
235 if(sock < 0) {
236 logger(LOG_ERR, _("System call `%s' failed: %s"), "socket", strerror(errno));
237 return false;
238 }
239
240 if(bind(sock, ai->ai_addr, ai->ai_addrlen)) {
241 logger(LOG_ERR, _("System call `%s' failed: %s"), "bind", strerror(errno));
242 return false;
243 }
244
245 freeaddrinfo(ai);
246
247 if(listen(sock, 1)) {
248 logger(LOG_ERR, _("System call `%s' failed: %s"), "listen", strerror(errno));
249 return false;
250 }
251
252 /* Start the tap reader */
253
254 thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
255
256 if(!thread) {
257 logger(LOG_ERR, _("System call `%s' failed: %s"), "CreateThread", winerror(GetLastError()));
258 return false;
259 }
260
261 /* Wait for the tap reader to connect back to us */
262
263 if((device_fd = accept(sock, NULL, 0)) == -1) {
264 logger(LOG_ERR, _("System call `%s' failed: %s"), "accept", strerror(errno));
265 return false;
266 }
267
268 closesocket(sock);
269
270 /* Set media status for newer TAP-Win32 devices */
271
272 status = true;
273 DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
274
275 device_info = _("Windows tap device");
276
277 logger(LOG_INFO, _("%s (%s) is a %s"), device, iface, device_info);
278
279 return true;
280 }
281
282 void close_device(void)
283 {
284 cp();
285
286 CloseHandle(device_handle);
287 }
288
289 bool read_packet(vpn_packet_t *packet)
290 {
291 int lenin;
292
293 cp();
294
295 if((lenin = recv(device_fd, packet->data, MTU, 0)) <= 0) {
296 logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
297 device, strerror(errno));
298 return false;
299 }
300
301 packet->len = lenin;
302
303 device_total_in += packet->len;
304
305 ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
306 device_info);
307
308 return true;
309 }
310
311 bool write_packet(vpn_packet_t *packet)
312 {
313 long lenout;
314 OVERLAPPED overlapped = {0};
315
316 cp();
317
318 ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
319 packet->len, device_info);
320
321 if(!WriteFile(device_handle, packet->data, packet->len, &lenout, &overlapped)) {
322 logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info, device, winerror(GetLastError()));
323 return false;
324 }
325
326 device_total_out += packet->len;
327
328 return true;
329 }
330
331 void dump_device_stats(void)
332 {
333 cp();
334
335 logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
336 logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
337 logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
338 }