ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/device-cygwin.C
Revision: 1.6
Committed: Wed Oct 15 06:06:41 2003 UTC (20 years, 7 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: poll-based-iom, VPE_1_2
Changes since 1.5: +101 -148 lines
Log Message:
*** empty log message ***

File Contents

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