ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/tincd/cygwin/device.c
Revision: 1.1
Committed: Tue Oct 14 03:22:09 2003 UTC (20 years, 8 months ago) by pcg
Content type: text/plain
Branch: MAIN
CVS Tags: poll-based-iom, VPE_1_2, VPE_1_4, VPE_1_6, rel-1_7, VPE-1_6_1
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*
2     device.c -- Interaction with Windows tap driver in a Cygwin environment
3     Copyright (C) 2002-2003 Ivo Timmermans <ivo@o2w.nl>,
4     2002-2003 Guus Sliepen <guus@sliepen.eu.org>
5    
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10    
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     GNU General Public License for more details.
15    
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19    
20     $Id: device.c,v 1.1.2.16 2003/08/08 19:49:47 guus Exp $
21     */
22    
23    
24     #include <w32api/windows.h>
25     #include <w32api/winioctl.h>
26    
27    
28     #define REG_CONTROL_NET "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
29    
30     #define USERMODEDEVICEDIR "\\\\.\\"
31     #define USERDEVICEDIR "\\??\\"
32     #define TAPSUFFIX ".tap"
33    
34     #define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS)
35    
36     #define TAP_IOCTL_GET_LASTMAC TAP_CONTROL_CODE(0, METHOD_BUFFERED)
37     #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE(1, METHOD_BUFFERED)
38     #define TAP_IOCTL_SET_STATISTICS TAP_CONTROL_CODE(2, METHOD_BUFFERED)
39    
40     int device_fd = -1;
41     static HANDLE device_handle = INVALID_HANDLE_VALUE;
42     char *device = NULL;
43     char *iface = NULL;
44     char *device_info = NULL;
45    
46     int device_total_in = 0;
47     int device_total_out = 0;
48    
49     pid_t reader_pid;
50     int sp[2];
51    
52     bool setup_device(void)
53     {
54     HKEY key, key2;
55     int i;
56    
57     char regpath[1024];
58     char adapterid[1024];
59     char adaptername[1024];
60     char tapname[1024];
61     char gelukt = 0;
62     long len;
63    
64     bool found = false;
65    
66     cp();
67    
68     get_config_string(lookup_config(config_tree, "Device"), &device);
69     get_config_string(lookup_config(config_tree, "Interface"), &iface);
70    
71     /* Open registry and look for network adapters */
72    
73     if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CONTROL_NET, 0, KEY_READ, &key)) {
74     logger(LOG_ERR, _("Unable to read registry: %s"), winerror(GetLastError()));
75     return false;
76     }
77    
78     for (i = 0; ; i++) {
79     len = sizeof(adapterid);
80     if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL))
81     break;
82    
83     /* Find out more about this adapter */
84    
85     snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", REG_CONTROL_NET, adapterid);
86    
87     if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2))
88     continue;
89    
90     len = sizeof(adaptername);
91     err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
92    
93     RegCloseKey(key2);
94    
95     if(err)
96     continue;
97    
98     if(device) {
99     if(!strcmp(device, adapterid)) {
100     found = true;
101     break;
102     } else
103     continue;
104     }
105    
106     if(iface) {
107     if(!strcmp(iface, adaptername)) {
108     found = true;
109     break;
110     } else
111     continue;
112     }
113    
114     snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
115     device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
116     if(device_handle != INVALID_HANDLE_VALUE) {
117     CloseHandle(device_handle);
118     found = true;
119     break;
120     }
121     }
122    
123     RegCloseKey(key);
124    
125     if(!found) {
126     logger(LOG_ERR, _("No Windows tap device found!"));
127     return false;
128     }
129    
130     if(!device)
131     device = xstrdup(adapterid);
132    
133     if(!iface)
134     iface = xstrdup(adaptername);
135    
136     snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
137    
138     /* Now we are going to open this device twice: once for reading and once for writing.
139     We do this because apparently it isn't possible to check for activity in the select() loop.
140     Furthermore I don't really know how to do it the "Windows" way. */
141    
142     if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
143     logger(LOG_DEBUG, _("System call `%s' failed: %s"), "socketpair", strerror(errno));
144     return false;
145     }
146    
147     /* The parent opens the tap device for writing. */
148    
149     device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0);
150    
151     if(device_handle == INVALID_HANDLE_VALUE) {
152     logger(LOG_ERR, _("Could not open Windows tap device %s (%s) for writing: %s"), device, iface, winerror(GetLastError()));
153     return false;
154     }
155    
156     device_fd = sp[0];
157    
158     /* Get MAC address from tap device */
159    
160     if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
161     logger(LOG_ERR, _("Could not get MAC address from Windows tap device %s (%s): %s"), device, iface, winerror(GetLastError()));
162     return false;
163     }
164    
165     if(routing_mode == RMODE_ROUTER) {
166     overwrite_mac = 1;
167     }
168    
169     /* Now we start the child */
170    
171     reader_pid = fork();
172    
173     if(reader_pid == -1) {
174     logger(LOG_DEBUG, _("System call `%s' failed: %s"), "fork", strerror(errno));
175     return false;
176     }
177    
178     if(!reader_pid) {
179     /* The child opens the tap device for reading, blocking.
180     It passes everything it reads to the socket. */
181    
182     char buf[MTU];
183     long lenin;
184    
185     CloseHandle(device_handle);
186    
187     device_handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
188    
189     if(device_handle == INVALID_HANDLE_VALUE) {
190     logger(LOG_ERR, _("Could not open Windows tap device %s (%s) for reading: %s"), device, iface, winerror(GetLastError()));
191     buf[0] = 0;
192     write(sp[1], buf, 1);
193     exit(1);
194     }
195    
196     logger(LOG_DEBUG, _("Tap reader forked and running."));
197    
198     /* Notify success */
199    
200     buf[0] = 1;
201     write(sp[1], buf, 1);
202    
203     /* Pass packets */
204    
205     for(;;) {
206     ReadFile(device_handle, buf, MTU, &lenin, NULL);
207     write(sp[1], buf, lenin);
208     }
209     }
210    
211     read(device_fd, &gelukt, 1);
212     if(gelukt != 1) {
213     logger(LOG_DEBUG, _("Tap reader failed!"));
214     return false;
215     }
216    
217     device_info = _("Windows tap device");
218    
219     logger(LOG_INFO, _("%s (%s) is a %s"), device, iface, device_info);
220    
221     return true;
222     }
223    
224     void close_device(void)
225     {
226     cp();
227    
228     close(sp[0]);
229     close(sp[1]);
230     CloseHandle(device_handle);
231    
232     kill(reader_pid, SIGKILL);
233     }
234    
235     bool read_packet(vpn_packet_t *packet)
236     {
237     int lenin;
238    
239     cp();
240    
241     if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
242     logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
243     device, strerror(errno));
244     return false;
245     }
246    
247     packet->len = lenin;
248    
249     device_total_in += packet->len;
250    
251     ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
252     device_info);
253    
254     return true;
255     }
256    
257     bool write_packet(vpn_packet_t *packet)
258     {
259     long lenout;
260    
261     cp();
262    
263     ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
264     packet->len, device_info);
265    
266     if(!WriteFile (device_handle, packet->data, packet->len, &lenout, NULL)) {
267     logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info, device, winerror(GetLastError()));
268     return false;
269     }
270    
271     device_total_out += packet->len;
272    
273     return true;
274     }
275    
276     void dump_device_stats(void)
277     {
278     cp();
279    
280     logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
281     logger(LOG_DEBUG, _(" total bytes in: %10d"), device_total_in);
282     logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
283     }