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

# User Rev Content
1 pcg 1.1 /*
2     device-cygwin.C -- Stub for Cygwin environment
3 pcg 1.12 Copyright (C) 2003-2008 Marc Lehmann <ocg@goof.com>
4 pcg 1.3 Copyright (C) 2002-2003 Ivo Timmermans <ivo@o2w.nl>,
5     2002-2003 Guus Sliepen <guus@sliepen.eu.org>
6 pcg 1.1
7 pcg 1.9 This file is part of GVPE.
8    
9 pcg 1.12 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 pcg 1.1 */
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 pcg 1.3 // a newer driver is available as part of the openvpn package:
41     // http://openvpn.sf.net/
42 pcg 1.1
43     #include "config.h"
44    
45 pcg 1.8 #include <cstdio>
46     #include <cstring>
47     #include <cstdlib>
48 pcg 1.1 #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 pcg 1.6 #include <io.h>
58 pcg 1.3 #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 pcg 1.6 #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 pcg 1.3
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 pcg 1.6 char *nl;
87     if ((nl = strchr (buf, '\r')))
88     *nl = '\0';
89 pcg 1.3
90     return buf;
91     }
92    
93 pcg 1.6 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 pcg 1.8 exit (EXIT_FAILURE);
119 pcg 1.6 }
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 pcg 1.2 const char *
132     tap_device::info ()
133     {
134 pcg 1.3 return _("cygwin cipe/openvpn tap device");
135 pcg 1.2 }
136    
137 pcg 1.10 const char *
138     tap_device::if_up ()
139     {
140     return "";
141     }
142    
143 pcg 1.1 tap_device::tap_device ()
144     {
145 pcg 1.3 HKEY key, key2;
146     int i;
147    
148     char regpath[1024];
149     char adapterid[1024];
150 pcg 1.6 BYTE adaptername[1024];
151 pcg 1.3 char tapname[1024];
152 pcg 1.6 DWORD len;
153 pcg 1.3
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 pcg 1.6 slog (L_ERR, _("WIN32 TAP: unable to read registry: %s"),
163 pcg 1.3 wstrerror (GetLastError ()));
164 pcg 1.8 exit (EXIT_FAILURE);
165 pcg 1.3 }
166    
167     for (i = 0;; i++)
168 pcg 1.1 {
169 pcg 1.3 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 pcg 1.4 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 pcg 1.3 if (device_handle != INVALID_HANDLE_VALUE)
204     {
205     found = true;
206     break;
207     }
208 pcg 1.1 }
209 pcg 1.3
210     RegCloseKey (key);
211    
212     if (!found)
213     {
214 pcg 1.6 slog (L_ERR, _("WIN32 TAP: no windows tap device found!"));
215 pcg 1.8 exit (EXIT_FAILURE);
216 pcg 1.3 }
217    
218     /* Try to open the corresponding tap device */
219    
220     if (device_handle == INVALID_HANDLE_VALUE)
221     {
222 pcg 1.6 snprintf (tapname, sizeof (tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
223 pcg 1.3 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 pcg 1.6 slog (L_ERR, _("WIN32 TAP: %s is not a usable windows tap device %s: %s"),
232     adaptername, tapname, wstrerror (GetLastError ()));
233 pcg 1.8 exit (EXIT_FAILURE);
234 pcg 1.3 }
235    
236 pcg 1.6 strcpy (ifrname, (char *)tapname);
237 pcg 1.4
238 pcg 1.3 /* Get MAC address from tap device */
239    
240 pcg 1.6 if (!DeviceIoControl (device_handle, TAP_IOCTL_GET_MAC,
241     &local_mac, sizeof (local_mac), &local_mac, sizeof (local_mac),
242     &len, 0))
243 pcg 1.3 {
244     slog (L_ERR,
245 pcg 1.6 _("WIN32 TAP: could not get MAC address from windows tap device %s: %s"),
246 pcg 1.5 adaptername, wstrerror (GetLastError ()));
247 pcg 1.8 exit (EXIT_FAILURE);
248 pcg 1.3 }
249 pcg 1.6
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 pcg 1.1 }
265    
266     tap_device::~tap_device ()
267     {
268 pcg 1.6 close (iopipe[0]);
269     close (iopipe[1]);
270     CloseHandle (device_handle);
271     CloseHandle (send_event);
272 pcg 1.1 }
273    
274     tap_packet *
275     tap_device::recv ()
276     {
277     tap_packet *pkt = new tap_packet;
278    
279 pcg 1.6 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 pcg 1.1 {
288 pcg 1.6 slog (L_ERR, _("WIN32 TAP: i/o thread delivered incomplete pkt"));
289     delete pkt;
290 pcg 1.1 return 0;
291     }
292 pcg 1.6
293 pcg 1.1 id2mac (THISNODE->id, &((*pkt)[6]));
294    
295     if (pkt->is_arp ())
296     {
297 pcg 1.6 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 pcg 1.1 }
300    
301     return pkt;
302     }
303    
304     void
305 pcg 1.3 tap_device::send (tap_packet * pkt)
306 pcg 1.1 {
307 pcg 1.6 memcpy (&(*pkt)[6], &local_mac, sizeof (mac));
308 pcg 1.1
309     if (pkt->is_arp ())
310     {
311 pcg 1.3 if ((*pkt)[22] == 0xfe && (*pkt)[27] == THISNODE->id)
312 pcg 1.6 memcpy (&(*pkt)[22], &local_mac, sizeof (mac));
313 pcg 1.1
314 pcg 1.3 if ((*pkt)[32] == 0xfe && (*pkt)[37] == THISNODE->id)
315 pcg 1.6 memcpy (&(*pkt)[32], &local_mac, sizeof (mac));
316 pcg 1.1 }
317    
318 pcg 1.6 DWORD dlen;
319     OVERLAPPED overlapped;
320     overlapped.hEvent = send_event;
321 pcg 1.3
322 pcg 1.6 if (!WriteFile (device_handle, &((*pkt)[0]), pkt->len, &dlen, &overlapped))
323 pcg 1.3 {
324     if (GetLastError () == ERROR_IO_PENDING)
325 pcg 1.6 GetOverlappedResult (device_handle, &overlapped, &dlen, TRUE);
326 pcg 1.3 else
327 pcg 1.6 slog (L_ERR, _("WIN32 TAP: can't write to %s %s: %s"), info (), conf.ifname,
328     wstrerror (GetLastError ()));
329 pcg 1.3 }
330 pcg 1.1 }