Support alternative tun/tap driver from http://www-user.rhrk.uni-kl.de/~nissler/tuntap/
[tinc] / src / darwin / device.c
1 /*
2     device.c -- Interaction with MacOS/X tun device
3     Copyright (C) 2001-2004 Ivo Timmermans <ivo@tinc-vpn.org>,
4                   2001-2004 Guus Sliepen <guus@tinc-vpn.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$
21 */
22
23 #include "system.h"
24
25 #include "conf.h"
26 #include "logger.h"
27 #include "net.h"
28 #include "route.h"
29 #include "utils.h"
30
31 #define DEFAULT_DEVICE "/dev/tun0"
32
33 typedef enum device_type {
34         DEVICE_TYPE_TUN,
35         DEVICE_TYPE_TAP,
36 } device_type_t;
37
38 int device_fd = -1;
39 char *device;
40 char *iface;
41 char *device_info;
42 int device_total_in = 0;
43 int device_total_out = 0;
44 static device_type_t device_type = DEVICE_TYPE_TUN;
45
46 bool setup_device(void)
47 {
48         char *type;
49
50         cp();
51
52         if(!get_config_string(lookup_config(config_tree, "Device"), &device))
53                 device = DEFAULT_DEVICE;
54
55         if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
56                 iface = rindex(device, '/') ? rindex(device, '/') + 1 : device;
57
58         if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0) {
59                 logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
60                 return false;
61         }
62
63         if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
64                 if(!strcasecmp(type, "tun"))
65                         device_type = DEVICE_TYPE_TUN;
66                 else if(!strcasecmp(type, "tap"))
67                         device_type = DEVICE_TYPE_TAP;
68                 else {
69                         logger(LOG_ERR, _("Unknown device type %s!"), type);
70                         return false;
71                 }
72         } else {
73                 if(strstr(device, "tap"))
74                         device_type = DEVICE_TYPE_TAP;
75         }
76
77         switch(device_type) {
78                 default:
79                         device_type = DEVICE_TYPE_TUN;
80                 case DEVICE_TYPE_TUN:
81                         device_info = _("MacOS/X tun device");
82                         break;
83                 case DEVICE_TYPE_TAP:
84                         if(routing_mode == RMODE_ROUTER)
85                                 overwrite_mac = true;
86                         device_info = _("MacOS/X tap device");
87                         break;
88         }
89
90         logger(LOG_INFO, _("%s is a %s"), device, device_info);
91
92         return true;
93 }
94
95 void close_device(void)
96 {
97         cp();
98
99         close(device_fd);
100 }
101
102 bool read_packet(vpn_packet_t *packet)
103 {
104         int lenin;
105
106         cp();
107
108         switch(device_type) {
109                 case DEVICE_TYPE_TUN:
110                         if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
111                                 logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
112                                            device, strerror(errno));
113                                 return false;
114                         }
115
116                         switch(packet->data[14] >> 4) {
117                                 case 4:
118                                         packet->data[12] = 0x08;
119                                         packet->data[13] = 0x00;
120                                         break;
121                                 case 6:
122                                         packet->data[12] = 0x86;
123                                         packet->data[13] = 0xDD;
124                                         break;
125                                 default:
126                                         ifdebug(TRAFFIC) logger(LOG_ERR,
127                                                            _ ("Unknown IP type %d while reading packet from %s %s"),
128                                                            packet->data[14] >> 4, device_info, device);
129                                         return false;
130                         }
131
132                         packet->len = lenin + 14;
133                         break;
134                 case DEVICE_TYPE_TAP:
135                         if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
136                                 logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
137                                            device, strerror(errno));
138                                 return false;
139                         }
140
141                         packet->len = lenin;
142                         break;
143                 default:
144                         return false;
145         }
146                 
147         device_total_in += packet->len;
148
149         ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"),
150                            packet->len, device_info);
151
152         return true;
153 }
154
155 bool write_packet(vpn_packet_t *packet)
156 {
157         cp();
158
159         ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
160                            packet->len, device_info);
161
162         switch(device_type) {
163                 case DEVICE_TYPE_TUN:
164                         if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
165                                 logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
166                                            device, strerror(errno));
167                                 return false;
168                         }
169                         break;
170                 case DEVICE_TYPE_TAP:
171                         if(write(device_fd, packet->data, packet->len) < 0) {
172                                 logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
173                                            device, strerror(errno));
174                                 return false;
175                         }
176                         break;
177                 default:
178                         return false;
179         }
180
181         device_total_out += packet->len;
182
183         return true;
184 }
185
186 void dump_device_stats(void)
187 {
188         cp();
189
190         logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
191         logger(LOG_DEBUG, _(" total bytes in:  %10d"), device_total_in);
192         logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
193 }