2 device.c -- Interaction with Linux ethertap and tun/tap device
3 Copyright (C) 2001-2005 Ivo Timmermans,
4 2001-2014 Guus Sliepen <guus@tinc-vpn.org>
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.
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.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "../system.h"
23 #include <linux/if_tun.h>
24 #define DEFAULT_DEVICE "/dev/net/tun"
27 #include "../device.h"
28 #include "../logger.h"
33 #include "../xalloc.h"
34 #include "../device.h"
36 typedef enum device_type_t
{
42 static device_type_t device_type
;
45 static char *type
= NULL
;
46 static char ifrname
[IFNAMSIZ
];
47 static char *device_info
;
49 static bool setup_device(void) {
50 if(!get_config_string(lookup_config(config_tree
, "Device"), &device
))
51 device
= xstrdup(DEFAULT_DEVICE
);
53 if(!get_config_string(lookup_config(config_tree
, "Interface"), &iface
))
55 iface
= xstrdup(netname
);
57 device_fd
= open(device
, O_RDWR
| O_NONBLOCK
);
60 logger(DEBUG_ALWAYS
, LOG_ERR
, "Could not open %s: %s", device
, strerror(errno
));
65 fcntl(device_fd
, F_SETFD
, FD_CLOEXEC
);
68 struct ifreq ifr
= {{{0}}};
70 get_config_string(lookup_config(config_tree
, "DeviceType"), &type
);
72 if(type
&& strcasecmp(type
, "tun") && strcasecmp(type
, "tap")) {
73 logger(DEBUG_ALWAYS
, LOG_ERR
, "Unknown device type %s!", type
);
77 if((type
&& !strcasecmp(type
, "tun")) || (!type
&& routing_mode
== RMODE_ROUTER
)) {
78 ifr
.ifr_flags
= IFF_TUN
;
79 device_type
= DEVICE_TYPE_TUN
;
80 device_info
= "Linux tun/tap device (tun mode)";
82 if (routing_mode
== RMODE_ROUTER
)
84 ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
;
85 device_type
= DEVICE_TYPE_TAP
;
86 device_info
= "Linux tun/tap device (tap mode)";
90 /* Set IFF_ONE_QUEUE flag... */
93 if(get_config_bool(lookup_config(config_tree
, "IffOneQueue"), &t1q
) && t1q
)
94 ifr
.ifr_flags
|= IFF_ONE_QUEUE
;
98 strncpy(ifr
.ifr_name
, iface
, IFNAMSIZ
);
100 if(!ioctl(device_fd
, TUNSETIFF
, &ifr
)) {
101 strncpy(ifrname
, ifr
.ifr_name
, IFNAMSIZ
);
103 iface
= xstrdup(ifrname
);
106 logger(DEBUG_ALWAYS
, LOG_INFO
, "%s is a %s", device
, device_info
);
108 if(ifr
.ifr_flags
& IFF_TAP
) {
109 struct ifreq ifr_mac
= {};
110 if(!ioctl(device_fd
, SIOCGIFHWADDR
, &ifr_mac
))
111 memcpy(mymac
.x
, ifr_mac
.ifr_hwaddr
.sa_data
, ETH_ALEN
);
113 logger(DEBUG_ALWAYS
, LOG_WARNING
, "Could not get MAC address of %s: %s", device
, strerror(errno
));
119 static void close_device(void) {
123 free(type
); type
= NULL
;
124 free(device
); device
= NULL
;
125 free(iface
); iface
= NULL
;
129 static bool read_packet(vpn_packet_t
*packet
) {
132 switch(device_type
) {
133 case DEVICE_TYPE_TUN
:
134 inlen
= read(device_fd
, DATA(packet
) + 10, MTU
- 10);
137 logger(DEBUG_ALWAYS
, LOG_ERR
, "Error while reading from %s %s: %s",
138 device_info
, device
, strerror(errno
));
142 memset(DATA(packet
), 0, 12);
143 packet
->len
= inlen
+ 10;
145 case DEVICE_TYPE_TAP
:
146 inlen
= read(device_fd
, DATA(packet
), MTU
);
149 logger(DEBUG_ALWAYS
, LOG_ERR
, "Error while reading from %s %s: %s",
150 device_info
, device
, strerror(errno
));
160 logger(DEBUG_TRAFFIC
, LOG_DEBUG
, "Read packet of %d bytes from %s", packet
->len
,
166 static bool write_packet(vpn_packet_t
*packet
) {
167 logger(DEBUG_TRAFFIC
, LOG_DEBUG
, "Writing packet of %d bytes to %s",
168 packet
->len
, device_info
);
170 switch(device_type
) {
171 case DEVICE_TYPE_TUN
:
172 DATA(packet
)[10] = DATA(packet
)[11] = 0;
173 if(write(device_fd
, DATA(packet
) + 10, packet
->len
- 10) < 0) {
174 logger(DEBUG_ALWAYS
, LOG_ERR
, "Can't write to %s %s: %s", device_info
, device
,
179 case DEVICE_TYPE_TAP
:
180 if(write(device_fd
, DATA(packet
), packet
->len
) < 0) {
181 logger(DEBUG_ALWAYS
, LOG_ERR
, "Can't write to %s %s: %s", device_info
, device
,
193 const devops_t os_devops
= {
194 .setup
= setup_device
,
195 .close
= close_device
,
197 .write
= write_packet
,