/[pearpc]/src/system/osapi/win32/sysethtun.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /src/system/osapi/win32/sysethtun.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 10161 byte(s)
import upstream CVS
1 dpavlin 1 /*
2     * PearPC
3     * sysethtun.cc
4     *
5     * win32-specific ethernet-tunnel access
6     *
7     * Copyright (C) 2004 John Kelley (pearpc@kelley.ca)
8     * Copyright (C) 2004 Stefan Weyergraf
9     *
10     * This program is free software; you can redistribute it and/or modify
11     * it under the terms of the GNU General Public License version 2 as
12     * published by the Free Software Foundation.
13     *
14     * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     * GNU General Public License for more details.
18     *
19     * You should have received a copy of the GNU General Public License
20     * along with this program; if not, write to the Free Software
21     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22     */
23    
24     // FIXME: What about multiple instances of Win32EthTunDevice?
25    
26     #include <errno.h>
27     #include <stdio.h>
28     #include <winsock.h>
29     #include <windows.h>
30     #include <Winioctl.h>
31    
32     #undef FASTCALL
33    
34     #ifdef HAVE_CONFIG_H
35     #include "config.h"
36     #endif
37    
38     #include "system/sysethtun.h"
39     #include "tools/except.h"
40     #include "tap_constants.h"
41     #include "tools/snprintf.h"
42    
43     //minimum version that we will work with
44     #define TAP_WIN32_MIN_MAJOR 7
45     #define TAP_WIN32_MIN_MINOR 1
46    
47     #define printm(s...) ht_printf("[TAP-WIN32]: "s)
48     #define MAX_PACKET_SIZE 16384
49     #define ERRORMSG_SIZE 1024
50    
51     //simple function to translate an error code into a string
52     static void getErrorString(char *out, int maxSize, DWORD error)
53     {
54     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
55     NULL,
56     error,
57     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
58     (LPTSTR) out,
59     maxSize,
60     NULL);
61     }
62     //checks to see if a given NIC GUID is a TAP-WIN32 device
63     static bool is_tap_win32_dev(const char *guid)
64     {
65     HKEY netcard_key;
66     LONG status;
67     DWORD len;
68     int i = 0;
69    
70     status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ, &netcard_key);
71    
72     if (status != ERROR_SUCCESS) {
73     printm("Error opening registry key: %s\n", ADAPTER_KEY);
74     return false;
75     }
76    
77     while (true) {
78     char enum_name[256];
79     char unit_string[256];
80     HKEY unit_key;
81     char component_id_string[] = "ComponentId";
82     char component_id[256];
83     char net_cfg_instance_id_string[] = "NetCfgInstanceId";
84     char net_cfg_instance_id[256];
85     DWORD data_type;
86    
87     len = sizeof (enum_name);
88     status = RegEnumKeyEx(netcard_key, i, enum_name, &len, NULL, NULL, NULL, NULL);
89     if (status == ERROR_NO_MORE_ITEMS)
90     break;
91     else if (status != ERROR_SUCCESS) {
92     printm("Error enumerating registry subkeys of key: %s\n",
93     ADAPTER_KEY);
94     return false;
95     }
96    
97     ht_snprintf(unit_string, sizeof(unit_string), "%s\\%s", ADAPTER_KEY, enum_name);
98    
99     status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit_string, 0, KEY_READ, &unit_key);
100    
101     if (status != ERROR_SUCCESS) {
102     printm("Error opening registry key: %s\n", unit_string);
103     return false;
104     } else {
105     len = sizeof (component_id);
106     status = RegQueryValueEx(unit_key, component_id_string, NULL, &data_type, (BYTE *)component_id, &len);
107     if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
108     len = sizeof (net_cfg_instance_id);
109     status = RegQueryValueEx(unit_key, net_cfg_instance_id_string, NULL, &data_type, (BYTE *)net_cfg_instance_id, &len);
110    
111     if (status == ERROR_SUCCESS && data_type == REG_SZ) {
112     if (!strncmp(component_id, "tap", 3)
113     && !strcmp(net_cfg_instance_id, guid)) {
114     RegCloseKey(unit_key);
115     RegCloseKey(netcard_key);
116     return true;
117     }
118     }
119     }
120     RegCloseKey(unit_key);
121     }
122     ++i;
123     }
124     RegCloseKey(netcard_key);
125     return false;
126     }
127    
128    
129     static int get_device_guid(char *name, int name_size, char *actual_name, int actual_name_size)
130     {
131     LONG status;
132     HKEY control_net_key;
133     DWORD len;
134     int i = 0;
135     bool stop = false;
136    
137     status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &control_net_key);
138    
139     if (status != ERROR_SUCCESS) {
140     printm("Error opening registry key: %s", NETWORK_CONNECTIONS_KEY);
141     return 1;
142     }
143    
144     while (!stop) {
145     char enum_name[256];
146     char connection_string[256];
147     HKEY connection_key;
148     char name_data[256];
149     DWORD name_type;
150     const char name_string[] = "Name";
151    
152     len = sizeof (enum_name);
153     status = RegEnumKeyEx(control_net_key, i, enum_name, &len, NULL, NULL, NULL, NULL);
154    
155     if (status == ERROR_NO_MORE_ITEMS)
156     break;
157     else if (status != ERROR_SUCCESS) {
158     printm("Error enumerating registry subkeys of key: %s", NETWORK_CONNECTIONS_KEY);
159     return 1;
160     }
161    
162     ht_snprintf(connection_string, sizeof(connection_string), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, enum_name);
163     status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string, 0, KEY_READ, &connection_key);
164    
165     if (status == ERROR_SUCCESS) {
166     len = sizeof (name_data);
167     status = RegQueryValueEx(connection_key, name_string, NULL, &name_type, (BYTE *)name_data, &len);
168    
169     if (status != ERROR_SUCCESS || name_type != REG_SZ) {
170     printm("Error opening registry key: %s\\%s\\%s", NETWORK_CONNECTIONS_KEY, connection_string, name_string);
171     return 1;
172     } else {
173     if (is_tap_win32_dev(enum_name)) {
174     printm("Found TAP device named '%s'\n", name_data);
175     ht_snprintf(name, name_size, "%s", enum_name);
176     if (actual_name)
177     ht_snprintf(actual_name, actual_name_size, "%s", name_data);
178     stop = true;
179     }
180     }
181     RegCloseKey(connection_key);
182     }
183     ++i;
184     }
185     RegCloseKey(control_net_key);
186    
187     if (!stop)
188     return 1;
189    
190     return 0;
191     }
192    
193     class Win32EthTunDevice: public EthTunDevice {
194     protected:
195     HANDLE mFile;
196     unsigned char mBuf[MAX_PACKET_SIZE];
197     DWORD mBuflen;
198     OVERLAPPED mOverlapped;
199    
200     //sets the media status of the TAP device (cable connected or not)
201     bool tap_set_status(ULONG status)
202     {
203     DWORD len = 0;
204     BOOL ret = DeviceIoControl(mFile, TAP_IOCTL_SET_MEDIA_STATUS,
205     &status, sizeof (status),
206     &status, sizeof (status), &len, NULL);
207     if (!ret) {
208     char errmsg[ERRORMSG_SIZE];
209     getErrorString(errmsg, sizeof errmsg, GetLastError());
210     printm("Failed: %s\n", errmsg);
211     }
212     return ret;
213     }
214    
215     public:
216    
217     Win32EthTunDevice()
218     {
219     }
220    
221     virtual ~Win32EthTunDevice()
222     {
223     if (mFile != INVALID_HANDLE_VALUE)
224     shutdownDevice();
225     }
226    
227     int initDevice()
228     {
229     char device_path[256];
230     char device_guid[0x100];
231     int rc;
232     HANDLE handle = NULL;
233    
234     printm("Enumerating TAP devices...\n");
235     rc = get_device_guid(device_guid, sizeof device_guid, NULL, 0);
236     if (rc != 0) {
237     throw MsgException("Could not locate any installed TAP-WIN32 devices.");
238     }
239    
240     //Open Windows TAP-Win32 adapter
241     ht_snprintf(device_path, sizeof device_path, "%s%s%s",
242     USERMODEDEVICEDIR,
243     device_guid,
244     TAPSUFFIX);
245    
246     handle = CreateFile(
247     device_path,
248     GENERIC_READ | GENERIC_WRITE,
249     0,
250     0,
251     OPEN_EXISTING,
252     FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
253     0);
254    
255     if (handle == INVALID_HANDLE_VALUE || handle == NULL) {
256     throw MsgException("Opening TAP connection failed");
257     }
258    
259     mFile = handle;
260     mOverlapped.Offset = 0;
261     mOverlapped.OffsetHigh = 0;
262     mOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
263    
264     //check TAP driver version against our minimum supported version
265     {
266     ULONG info[3];
267     ULONG len;
268     info[0] = info[1] = info[2] = 0;
269     if (DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
270     &info, sizeof (info),
271     &info, sizeof (info), &len, NULL)) {
272     printm("Driver Version %d.%d\n",
273     (int) info[0],
274     (int) info[1]);
275     } else {
276     if (DeviceIoControl(handle, OLD_TAP_IOCTL_GET_VERSION,
277     &info, sizeof (info),
278     &info, sizeof (info), &len, NULL)) {
279     printm("Driver Version %d.%d %s.\n",
280     (int) info[0],
281     (int) info[1],
282     (info[2] ? "(DEBUG) " : ""));
283    
284     } else {
285     char errmsg[ERRORMSG_SIZE];
286     getErrorString(errmsg, sizeof errmsg, GetLastError());
287     throw MsgfException("Could not get driver version info: %s\n", errmsg);
288     }
289     }
290     if (!(info[0] > TAP_WIN32_MIN_MAJOR || (info[0] == TAP_WIN32_MIN_MAJOR && info[1] >= TAP_WIN32_MIN_MINOR))) {
291     throw MsgfException("ERROR: This version of PearPC requires a TAP-Win32 driver that is at least version %d.%d\n"
292     "Please install an updated version from http://prdownloads.sourceforge.net/openvpn/openvpn-2.0_beta2-install.exe\n",
293     TAP_WIN32_MIN_MAJOR,
294     TAP_WIN32_MIN_MINOR);
295     }
296     }
297    
298     //connect our virtual cat5 cable to the TAP device
299     if (!tap_set_status(TRUE)) {
300     if (CloseHandle(handle) != 1) {
301     printm("Error closing handle.\n");
302     }
303     throw MsgfException("Setting Media Status to connected failed (handle is %d)\n", handle);
304     }
305     return 0;
306     }
307    
308     int shutdownDevice()
309     {
310     printm("Setting Media Status to disconnected.\n");
311     if (!tap_set_status(false)) {
312     printm("Error disconnecting media.\n");
313     }
314     printm("Closing TAP-WIN32 handle.\n");
315     CloseHandle(mFile);
316     mFile = INVALID_HANDLE_VALUE;
317     return 0;
318     }
319    
320     virtual uint recvPacket(void *buf, uint size)
321     {
322     if (mBuflen > size) {
323     // no partial packets. drop it.
324     mBuflen = 0;
325     return 0;
326     }
327     memcpy(buf, mBuf, mBuflen);
328     uint ret = mBuflen;
329     mBuflen = 0;
330     return ret;
331     }
332    
333     virtual int waitRecvPacket()
334     {
335     BOOL status;
336     mOverlapped.Offset = 0;
337     mOverlapped.OffsetHigh = 0;
338     ResetEvent(mOverlapped.hEvent);
339     status = ReadFile(mFile, mBuf, sizeof mBuf, &mBuflen, &mOverlapped);
340     if (!status) {
341     DWORD e = GetLastError();
342     if (e == ERROR_IO_PENDING) {
343     WaitForSingleObject(mOverlapped.hEvent, INFINITE);
344     if (!GetOverlappedResult(mFile, &mOverlapped, &mBuflen, FALSE)) {
345     printm("You should never see this error\n");
346     }
347     } else {
348     char errmsg[ERRORMSG_SIZE];
349     getErrorString(errmsg, sizeof errmsg, e);
350     printm("Bad read error: %s\n", errmsg);
351    
352     return EIO;
353     }
354     }
355     return 0;
356     }
357    
358     virtual uint sendPacket(void *buf, uint size)
359     {
360     DWORD written;
361     BOOL ret;
362     OVERLAPPED wrov = {0};
363     ret = WriteFile(mFile, buf, size, &written, &wrov);
364     if (!ret) {
365     char errmsg[ERRORMSG_SIZE];
366     getErrorString(errmsg, sizeof errmsg, GetLastError());
367     printm("Sending of %d bytes failed (%d bytes sent): %s\n", size, written, errmsg);
368     }
369     return written;
370     }
371    
372     virtual uint getWriteFramePrefix()
373     {
374     return 0;
375     }
376    
377     }; // end of Win32EthTunDevice
378    
379     EthTunDevice *createEthernetTunnel()
380     {
381     return new Win32EthTunDevice();
382     }

  ViewVC Help
Powered by ViewVC 1.1.26