ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/device-cygwin.C
Revision: 1.12
Committed: Thu Aug 7 17:54:26 2008 UTC (15 years, 9 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-3_0, rel-2_2, rel-2_21, rel-2_22, rel-2_25, HEAD
Changes since 1.11: +24 -14 lines
Log Message:
update to gplv3, finally

File Contents

# Content
1 /*
2 device-cygwin.C -- Stub for Cygwin environment
3 Copyright (C) 2003-2008 Marc Lehmann <ocg@goof.com>
4 Copyright (C) 2002-2003 Ivo Timmermans <ivo@o2w.nl>,
5 2002-2003 Guus Sliepen <guus@sliepen.eu.org>
6
7 This file is part of GVPE.
8
9 GVPE is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17 Public License for more details.
18
19 You should have received a copy of the GNU General Public License along
20 with this program; if not, see <http://www.gnu.org/licenses/>.
21
22 Additional permission under GNU GPL version 3 section 7
23
24 If you modify this Program, or any covered work, by linking or
25 combining it with the OpenSSL project's OpenSSL library (or a modified
26 version of that library), containing parts covered by the terms of the
27 OpenSSL or SSLeay licenses, the licensors of this Program grant you
28 additional permission to convey the resulting work. Corresponding
29 Source for a non-source form of such a combination shall include the
30 source code for the parts of OpenSSL used as well as that of the
31 covered work.
32 */
33
34 // unfortunately, there is be no way to set MAC addresses under windows,
35 // and the default cipedrvr uses a different MAC address than we do,
36 // so this module tries to fix mac addresses in packets and arp packets.
37 // this is probably not very fast, but neither is cygwin nor poll.
38 //
39 // http://cipe-win32.sourceforge.net/
40 // a newer driver is available as part of the openvpn package:
41 // http://openvpn.sf.net/
42
43 #include "config.h"
44
45 #include <cstdio>
46 #include <cstring>
47 #include <cstdlib>
48 #include <errno.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52 #include <unistd.h>
53
54 #include "conf.h"
55 #include "util.h"
56
57 #include <io.h>
58 #include <w32api/windows.h>
59 #include <w32api/winioctl.h>
60
61 #define REG_CONTROL_NET "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
62
63 #define USERMODEDEVICEDIR "\\\\.\\"
64 #define USERDEVICEDIR "\\??\\"
65 #define TAPSUFFIX ".tap"
66
67 #define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS)
68
69 #define TAP_IOCTL_GET_LASTMAC TAP_CONTROL_CODE(0, METHOD_BUFFERED)
70 #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE(1, METHOD_BUFFERED)
71 #define TAP_IOCTL_SET_STATISTICS TAP_CONTROL_CODE(2, METHOD_BUFFERED)
72 #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(7, METHOD_BUFFERED)
73
74 static const char *
75 wstrerror (int err)
76 {
77 static char buf[1024];
78
79 if (!FormatMessage
80 (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
81 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof (buf), NULL))
82 {
83 strncpy (buf, _("(unable to format errormessage)"), sizeof (buf));
84 };
85
86 char *nl;
87 if ((nl = strchr (buf, '\r')))
88 *nl = '\0';
89
90 return buf;
91 }
92
93 static HANDLE device_handle = INVALID_HANDLE_VALUE;
94 static mac local_mac;
95 static tap_packet *rcv_pkt;
96 static int iopipe[2];
97 static HANDLE pipe_handle, send_event, thread;
98
99 static DWORD WINAPI
100 read_thread(void *)
101 {
102 static OVERLAPPED overlapped;
103 static DWORD dlen;
104 static u32 len;
105 static u8 data[MAX_MTU];
106
107 overlapped.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
108
109 for (;;)
110 {
111 if (!ReadFile (device_handle, data, MAX_MTU, &dlen, &overlapped))
112 {
113 if (GetLastError () == ERROR_IO_PENDING)
114 GetOverlappedResult (device_handle, &overlapped, &dlen, TRUE);
115 else
116 {
117 slog (L_ERR, "WIN32 TAP: ReadFile returned error: %s", wstrerror (GetLastError ()));
118 exit (EXIT_FAILURE);
119 }
120 }
121
122 if (dlen > 0)
123 {
124 len = dlen;
125 WriteFile (pipe_handle, &len, sizeof (len), &dlen, NULL);
126 WriteFile (pipe_handle, data, len, &dlen, NULL);
127 }
128 }
129 }
130
131 const char *
132 tap_device::info ()
133 {
134 return _("cygwin cipe/openvpn tap device");
135 }
136
137 const char *
138 tap_device::if_up ()
139 {
140 return "";
141 }
142
143 tap_device::tap_device ()
144 {
145 HKEY key, key2;
146 int i;
147
148 char regpath[1024];
149 char adapterid[1024];
150 BYTE adaptername[1024];
151 char tapname[1024];
152 DWORD len;
153
154 bool found = false;
155
156 int sock, err;
157
158 /* Open registry and look for network adapters */
159
160 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_CONTROL_NET, 0, KEY_READ, &key))
161 {
162 slog (L_ERR, _("WIN32 TAP: unable to read registry: %s"),
163 wstrerror (GetLastError ()));
164 exit (EXIT_FAILURE);
165 }
166
167 for (i = 0;; i++)
168 {
169 len = sizeof (adapterid);
170 if (RegEnumKeyEx (key, i, adapterid, &len, 0, 0, 0, NULL))
171 break;
172
173 /* Find out more about this adapter */
174
175 snprintf (regpath, sizeof (regpath), "%s\\%s\\Connection",
176 REG_CONTROL_NET, adapterid);
177
178 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2))
179 continue;
180
181 len = sizeof (adaptername);
182 err = RegQueryValueEx (key2, "Name", 0, 0, adaptername, &len);
183
184 RegCloseKey (key2);
185
186 if (err)
187 continue;
188
189 if (conf.ifname)
190 {
191 if (strcmp (conf.ifname, adapterid))
192 continue;
193 }
194 else
195 {
196 found = true;
197 break;
198 }
199
200 snprintf (tapname, sizeof (tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
201 device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0,
202 OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
203 if (device_handle != INVALID_HANDLE_VALUE)
204 {
205 found = true;
206 break;
207 }
208 }
209
210 RegCloseKey (key);
211
212 if (!found)
213 {
214 slog (L_ERR, _("WIN32 TAP: no windows tap device found!"));
215 exit (EXIT_FAILURE);
216 }
217
218 /* Try to open the corresponding tap device */
219
220 if (device_handle == INVALID_HANDLE_VALUE)
221 {
222 snprintf (tapname, sizeof (tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
223 device_handle =
224 CreateFile (tapname, GENERIC_WRITE | GENERIC_READ, 0, 0,
225 OPEN_EXISTING,
226 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
227 }
228
229 if (device_handle == INVALID_HANDLE_VALUE)
230 {
231 slog (L_ERR, _("WIN32 TAP: %s is not a usable windows tap device %s: %s"),
232 adaptername, tapname, wstrerror (GetLastError ()));
233 exit (EXIT_FAILURE);
234 }
235
236 strcpy (ifrname, (char *)tapname);
237
238 /* Get MAC address from tap device */
239
240 if (!DeviceIoControl (device_handle, TAP_IOCTL_GET_MAC,
241 &local_mac, sizeof (local_mac), &local_mac, sizeof (local_mac),
242 &len, 0))
243 {
244 slog (L_ERR,
245 _("WIN32 TAP: could not get MAC address from windows tap device %s: %s"),
246 adaptername, wstrerror (GetLastError ()));
247 exit (EXIT_FAILURE);
248 }
249
250 pipe (iopipe);
251 fd = iopipe[0];
252 pipe_handle = (HANDLE) get_osfhandle (iopipe[1]);
253
254 send_event = CreateEvent (NULL, FALSE, FALSE, NULL);
255
256 thread = CreateThread (NULL, 0, read_thread, NULL, 0, NULL);
257
258 /* try to set driver media status to 'connected' */
259 ULONG status = TRUE;
260 DeviceIoControl (device_handle, TAP_IOCTL_SET_MEDIA_STATUS,
261 &status, sizeof (status),
262 &status, sizeof (status), &len, NULL);
263 // ignore error here on purpose
264 }
265
266 tap_device::~tap_device ()
267 {
268 close (iopipe[0]);
269 close (iopipe[1]);
270 CloseHandle (device_handle);
271 CloseHandle (send_event);
272 }
273
274 tap_packet *
275 tap_device::recv ()
276 {
277 tap_packet *pkt = new tap_packet;
278
279 if (sizeof (u32) != read (iopipe[0], &pkt->len, sizeof (u32)))
280 {
281 slog (L_ERR, _("WIN32 TAP: i/o thread delivered incomplete pkt length"));
282 delete pkt;
283 return 0;
284 }
285
286 if (pkt->len != read (iopipe[0], &((*pkt)[0]), pkt->len))
287 {
288 slog (L_ERR, _("WIN32 TAP: i/o thread delivered incomplete pkt"));
289 delete pkt;
290 return 0;
291 }
292
293 id2mac (THISNODE->id, &((*pkt)[6]));
294
295 if (pkt->is_arp ())
296 {
297 if (!memcmp (&(*pkt)[22], &local_mac, sizeof (mac))) id2mac (THISNODE->id, &((*pkt)[22]));
298 if (!memcmp (&(*pkt)[32], &local_mac, sizeof (mac))) id2mac (THISNODE->id, &((*pkt)[32]));
299 }
300
301 return pkt;
302 }
303
304 void
305 tap_device::send (tap_packet * pkt)
306 {
307 memcpy (&(*pkt)[6], &local_mac, sizeof (mac));
308
309 if (pkt->is_arp ())
310 {
311 if ((*pkt)[22] == 0xfe && (*pkt)[27] == THISNODE->id)
312 memcpy (&(*pkt)[22], &local_mac, sizeof (mac));
313
314 if ((*pkt)[32] == 0xfe && (*pkt)[37] == THISNODE->id)
315 memcpy (&(*pkt)[32], &local_mac, sizeof (mac));
316 }
317
318 DWORD dlen;
319 OVERLAPPED overlapped;
320 overlapped.hEvent = send_event;
321
322 if (!WriteFile (device_handle, &((*pkt)[0]), pkt->len, &dlen, &overlapped))
323 {
324 if (GetLastError () == ERROR_IO_PENDING)
325 GetOverlappedResult (device_handle, &overlapped, &dlen, TRUE);
326 else
327 slog (L_ERR, _("WIN32 TAP: can't write to %s %s: %s"), info (), conf.ifname,
328 wstrerror (GetLastError ()));
329 }
330 }