/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show 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 /*
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