Simplify logging, update copyrights and some minor cleanups.
[oweals/tinc.git] / src / linux / device.c
1 /*
2     device.c -- Interaction with Linux ethertap and tun/tap device
3     Copyright (C) 2001-2003 Ivo Timmermans <ivo@o2w.nl>,
4                   2001-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.17 2003/07/12 17:41:48 guus Exp $
21 */
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <net/if.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <sys/ioctl.h>
34
35 #ifdef HAVE_TUNTAP
36 #ifdef LINUX_IF_TUN_H
37 #include LINUX_IF_TUN_H
38 #else
39 #include <linux/if_tun.h>
40 #endif
41 #define DEFAULT_DEVICE "/dev/net/tun"
42 #else
43 #define DEFAULT_DEVICE "/dev/tap0"
44 #endif
45
46 #include <utils.h>
47 #include "conf.h"
48 #include "net.h"
49 #include "route.h"
50 #include "logger.h"
51
52 #include "system.h"
53
54 enum {
55         DEVICE_TYPE_ETHERTAP,
56         DEVICE_TYPE_TUN,
57         DEVICE_TYPE_TAP,
58 };
59
60 int device_fd = -1;
61 int device_type;
62 char *device;
63 char *interface;
64 char ifrname[IFNAMSIZ];
65 char *device_info;
66
67 int device_total_in = 0;
68 int device_total_out = 0;
69
70 int setup_device(void)
71 {
72         struct ifreq ifr;
73
74         cp();
75
76         if(!get_config_string(lookup_config(config_tree, "Device"), &device))
77                 device = DEFAULT_DEVICE;
78
79         if(!get_config_string(lookup_config(config_tree, "Interface"), &interface))
80 #ifdef HAVE_TUNTAP
81                 interface = netname;
82 #else
83                 interface = rindex(device, '/') ? rindex(device, '/') + 1 : device;
84 #endif
85         device_fd = open(device, O_RDWR | O_NONBLOCK);
86
87         if(device_fd < 0) {
88                 logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
89                 return -1;
90         }
91
92 #ifdef HAVE_TUNTAP
93         /* Ok now check if this is an old ethertap or a new tun/tap thingie */
94
95         memset(&ifr, 0, sizeof(ifr));
96         if(routing_mode == RMODE_ROUTER) {
97                 ifr.ifr_flags = IFF_TUN;
98                 device_type = DEVICE_TYPE_TUN;
99                 device_info = _("Linux tun/tap device (tun mode)");
100         } else {
101                 ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
102                 device_type = DEVICE_TYPE_TAP;
103                 device_info = _("Linux tun/tap device (tap mode)");
104         }
105
106         if(interface)
107                 strncpy(ifr.ifr_name, interface, IFNAMSIZ);
108
109         if(!ioctl(device_fd, TUNSETIFF, (void *) &ifr)) {
110                 strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
111                 interface = ifrname;
112         } else if(!ioctl(device_fd, (('T' << 8) | 202), (void *) &ifr)) {
113                 logger(LOG_WARNING, _("Old ioctl() request was needed for %s"), device);
114                 strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
115                 interface = ifrname;
116         } else
117 #endif
118         {
119                 if(routing_mode == RMODE_ROUTER)
120                         overwrite_mac = 1;
121                 device_info = _("Linux ethertap device");
122                 device_type = DEVICE_TYPE_ETHERTAP;
123                 interface = rindex(device, '/') ? rindex(device, '/') + 1 : device;
124         }
125
126         logger(LOG_INFO, _("%s is a %s"), device, device_info);
127
128         return 0;
129 }
130
131 void close_device(void)
132 {
133         cp();
134         
135         close(device_fd);
136 }
137
138 int read_packet(vpn_packet_t *packet)
139 {
140         int lenin;
141         
142         cp();
143
144         switch(device_type) {
145                 case DEVICE_TYPE_TUN:
146                         lenin = read(device_fd, packet->data + 10, MTU - 10);
147
148                         if(lenin <= 0) {
149                                 logger(LOG_ERR, _("Error while reading from %s %s: %s"),
150                                            device_info, device, strerror(errno));
151                                 return -1;
152                         }
153
154                         packet->len = lenin + 10;
155                         break;
156                 case DEVICE_TYPE_TAP:
157                         lenin = read(device_fd, packet->data, MTU);
158
159                         if(lenin <= 0) {
160                                 logger(LOG_ERR, _("Error while reading from %s %s: %s"),
161                                            device_info, device, strerror(errno));
162                                 return -1;
163                         }
164
165                         packet->len = lenin;
166                         break;
167                 case DEVICE_TYPE_ETHERTAP:
168                         lenin = read(device_fd, packet->data - 2, MTU + 2);
169
170                         if(lenin <= 0) {
171                                 logger(LOG_ERR, _("Error while reading from %s %s: %s"),
172                                            device_info, device, strerror(errno));
173                                 return -1;
174                         }
175
176                         packet->len = lenin - 2;
177                         break;
178         }
179
180         device_total_in += packet->len;
181
182         ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
183                            device_info);
184
185         return 0;
186 }
187
188 int write_packet(vpn_packet_t *packet)
189 {
190         cp();
191
192         ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
193                            packet->len, device_info);
194
195         switch(device_type) {
196                 case DEVICE_TYPE_TUN:
197                         packet->data[10] = packet->data[11] = 0;
198                         if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
199                                 logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
200                                            strerror(errno));
201                                 return -1;
202                         }
203                         break;
204                 case DEVICE_TYPE_TAP:
205                         if(write(device_fd, packet->data, packet->len) < 0) {
206                                 logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
207                                            strerror(errno));
208                                 return -1;
209                         }
210                         break;
211                 case DEVICE_TYPE_ETHERTAP:
212                         *(short int *)(packet->data - 2) = packet->len;
213
214                         if(write(device_fd, packet->data - 2, packet->len + 2) < 0) {
215                                 logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
216                                            strerror(errno));
217                                 return -1;
218                         }
219                         break;
220         }
221
222         device_total_out += packet->len;
223
224         return 0;
225 }
226
227 void dump_device_stats(void)
228 {
229         cp();
230
231         logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
232         logger(LOG_DEBUG, _(" total bytes in:  %10d"), device_total_in);
233         logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
234 }