]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-netdev-tuntap.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / network / networkd-netdev-tuntap.c
CommitLineData
30ae9dfd
SS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Susant Sahani <susant@redhat.com>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <sys/ioctl.h>
23#include <net/if.h>
24#include <linux/if_tun.h>
25
3be1d7e0 26#include "networkd-netdev-tuntap.h"
30ae9dfd
SS
27
28#define TUN_DEV "/dev/net/tun"
29
30ae9dfd 30static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
aa9f1140 31 TunTap *t;
30ae9dfd
SS
32
33 assert(netdev);
aa9f1140 34 assert(netdev->ifname);
30ae9dfd
SS
35 assert(ifr);
36
aa9f1140
TG
37 if (netdev->kind == NETDEV_KIND_TAP) {
38 t = TAP(netdev);
30ae9dfd 39 ifr->ifr_flags |= IFF_TAP;
aa9f1140
TG
40 } else {
41 t = TUN(netdev);
63dadd90 42 ifr->ifr_flags |= IFF_TUN;
aa9f1140 43 }
63dadd90 44
aa9f1140 45 if (!t->packet_info)
30ae9dfd
SS
46 ifr->ifr_flags |= IFF_NO_PI;
47
aa9f1140 48 if (t->one_queue)
30ae9dfd
SS
49 ifr->ifr_flags |= IFF_ONE_QUEUE;
50
aa9f1140 51 if (t->multi_queue)
30ae9dfd
SS
52 ifr->ifr_flags |= IFF_MULTI_QUEUE;
53
54 strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
55
56 return 0;
57}
58
59static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
60 _cleanup_close_ int fd;
aa9f1140 61 TunTap *t = NULL;
30ae9dfd
SS
62 const char *user;
63 const char *group;
64 uid_t uid;
65 gid_t gid;
6f44acfb 66 int r;
30ae9dfd 67
aa9f1140
TG
68 assert(netdev);
69 assert(ifr);
70
30ae9dfd
SS
71 fd = open(TUN_DEV, O_RDWR);
72 if (fd < 0) {
79008bdd 73 log_netdev_error(netdev, "Failed to open tun dev: %m");
6f44acfb 74 return -errno;
30ae9dfd
SS
75 }
76
77 r = ioctl(fd, TUNSETIFF, ifr);
78 if (r < 0) {
79008bdd 79 log_netdev_error(netdev,
30ae9dfd
SS
80 "TUNSETIFF failed on tun dev: %s",
81 strerror(-r));
82 return r;
83 }
84
aa9f1140
TG
85 if (netdev->kind == NETDEV_KIND_TAP)
86 t = TAP(netdev);
87 else
88 t = TUN(netdev);
89
90 assert(t);
30ae9dfd 91
aa9f1140
TG
92 if(t->user_name) {
93
94 user = t->user_name;
30ae9dfd
SS
95
96 r = get_user_creds(&user, &uid, NULL, NULL, NULL);
97 if (r < 0) {
c33b3297
MS
98 log_error_errno(r, "Cannot resolve user name %s: %m",
99 t->user_name);
30ae9dfd
SS
100 return 0;
101 }
102
103 r = ioctl(fd, TUNSETOWNER, uid);
104 if ( r < 0) {
79008bdd 105 log_netdev_error(netdev,
30ae9dfd
SS
106 "TUNSETOWNER failed on tun dev: %s",
107 strerror(-r));
108 }
109 }
110
aa9f1140 111 if(t->group_name) {
30ae9dfd 112
aa9f1140 113 group = t->group_name;
30ae9dfd
SS
114
115 r = get_group_creds(&group, &gid);
116 if (r < 0) {
c33b3297
MS
117 log_error_errno(r, "Cannot resolve group name %s: %m",
118 t->group_name);
30ae9dfd
SS
119 return 0;
120 }
121
122 r = ioctl(fd, TUNSETGROUP, gid);
123 if( r < 0) {
79008bdd 124 log_netdev_error(netdev,
30ae9dfd
SS
125 "TUNSETGROUP failed on tun dev: %s",
126 strerror(-r));
127 return r;
128 }
129
130 }
131
132 r = ioctl(fd, TUNSETPERSIST, 1);
133 if (r < 0) {
79008bdd 134 log_netdev_error(netdev,
30ae9dfd
SS
135 "TUNSETPERSIST failed on tun dev: %s",
136 strerror(-r));
137 return r;
138 }
139
6f44acfb 140 return 0;
30ae9dfd
SS
141}
142
3be1d7e0 143static int netdev_create_tuntap(NetDev *netdev) {
aa9f1140 144 struct ifreq ifr = {};
30ae9dfd
SS
145 int r;
146
30ae9dfd
SS
147 r = netdev_fill_tuntap_message(netdev, &ifr);
148 if(r < 0)
149 return r;
150
30ae9dfd
SS
151 return netdev_tuntap_add(netdev, &ifr);
152}
3be1d7e0 153
aa9f1140
TG
154static void tuntap_done(NetDev *netdev) {
155 TunTap *t = NULL;
156
157 assert(netdev);
158
159 if (netdev->kind == NETDEV_KIND_TUN)
160 t = TUN(netdev);
161 else
162 t = TAP(netdev);
163
164 assert(t);
165
166 free(t->user_name);
167 t->user_name = NULL;
168
169 free(t->group_name);
170 t->group_name = NULL;
171}
172
e0fbf1fc
TG
173static int tuntap_verify(NetDev *netdev, const char *filename) {
174 TunTap *t = NULL;
175
176 assert(netdev);
177
178 if (netdev->kind == NETDEV_KIND_TUN)
179 t = TUN(netdev);
180 else
181 t = TAP(netdev);
182
183 assert(t);
184
185 if (netdev->mtu) {
186 log_warning_netdev(netdev, "MTU configured for %s, ignoring",
187 netdev_kind_to_string(netdev->kind));
188 }
189
190 if (netdev->mac) {
191 log_warning_netdev(netdev, "MAC configured for %s, ignoring",
192 netdev_kind_to_string(netdev->kind));
193 }
194
195 return 0;
196}
197
3be1d7e0 198const NetDevVTable tun_vtable = {
aa9f1140
TG
199 .object_size = sizeof(TunTap),
200 .sections = "Match\0NetDev\0Tun\0",
e0fbf1fc 201 .config_verify = tuntap_verify,
aa9f1140 202 .done = tuntap_done,
3be1d7e0 203 .create = netdev_create_tuntap,
aa9f1140 204 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0
TG
205};
206
207const NetDevVTable tap_vtable = {
aa9f1140
TG
208 .object_size = sizeof(TunTap),
209 .sections = "Match\0NetDev\0Tap\0",
e0fbf1fc 210 .config_verify = tuntap_verify,
aa9f1140 211 .done = tuntap_done,
3be1d7e0 212 .create = netdev_create_tuntap,
aa9f1140 213 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0 214};