tethering: Add support to create private networks TUN interface
[platform/upstream/connman.git] / src / tethering.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <sys/ioctl.h>
31 #include <net/if.h>
32 #include <linux/sockios.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <linux/if_tun.h>
36
37 #include "connman.h"
38
39 #include <gdhcp/gdhcp.h>
40
41 #include <gdbus.h>
42
43 #define BRIDGE_PROC_DIR "/proc/sys/net/bridge"
44
45 #define BRIDGE_NAME "tether"
46 #define BRIDGE_IP "192.168.218.1"
47 #define BRIDGE_BCAST "192.168.218.255"
48 #define BRIDGE_SUBNET "255.255.255.0"
49 #define BRIDGE_IP_START "192.168.218.100"
50 #define BRIDGE_IP_END "192.168.218.200"
51 #define BRIDGE_DNS "8.8.8.8"
52
53 #define DEFAULT_MTU     1500
54
55 static char *default_interface = NULL;
56 static volatile gint tethering_enabled;
57 static GDHCPServer *tethering_dhcp_server = NULL;
58 static DBusConnection *connection;
59 static GHashTable *pn_hash;
60
61 struct connman_private_network {
62         char *owner;
63         guint watch;
64         DBusMessage *msg;
65         int fd;
66         char *interface;
67         int index;
68         guint iface_watch;
69 };
70
71 const char *__connman_tethering_get_bridge(void)
72 {
73         struct stat st;
74
75         if (stat(BRIDGE_PROC_DIR, &st) < 0) {
76                 connman_error("Missing support for 802.1d ethernet bridging");
77                 return NULL;
78         }
79
80         return BRIDGE_NAME;
81 }
82
83 static void dhcp_server_debug(const char *str, void *data)
84 {
85         connman_info("%s: %s\n", (const char *) data, str);
86 }
87
88 static void dhcp_server_error(GDHCPServerError error)
89 {
90         switch (error) {
91         case G_DHCP_SERVER_ERROR_NONE:
92                 connman_error("OK");
93                 break;
94         case G_DHCP_SERVER_ERROR_INTERFACE_UNAVAILABLE:
95                 connman_error("Interface unavailable");
96                 break;
97         case G_DHCP_SERVER_ERROR_INTERFACE_IN_USE:
98                 connman_error("Interface in use");
99                 break;
100         case G_DHCP_SERVER_ERROR_INTERFACE_DOWN:
101                 connman_error("Interface down");
102                 break;
103         case G_DHCP_SERVER_ERROR_NOMEM:
104                 connman_error("No memory");
105                 break;
106         case G_DHCP_SERVER_ERROR_INVALID_INDEX:
107                 connman_error("Invalid index");
108                 break;
109         case G_DHCP_SERVER_ERROR_INVALID_OPTION:
110                 connman_error("Invalid option");
111                 break;
112         case G_DHCP_SERVER_ERROR_IP_ADDRESS_INVALID:
113                 connman_error("Invalid address");
114                 break;
115         }
116 }
117
118 static GDHCPServer *dhcp_server_start(const char *bridge,
119                                 const char *router, const char* subnet,
120                                 const char *start_ip, const char *end_ip,
121                                 unsigned int lease_time, const char *dns)
122 {
123         GDHCPServerError error;
124         GDHCPServer *dhcp_server;
125         int index;
126
127         DBG("");
128
129         index = connman_inet_ifindex(bridge);
130         if (index < 0)
131                 return NULL;
132
133         dhcp_server = g_dhcp_server_new(G_DHCP_IPV4, index, &error);
134         if (dhcp_server == NULL) {
135                 dhcp_server_error(error);
136                 return NULL;
137         }
138
139         g_dhcp_server_set_debug(dhcp_server, dhcp_server_debug, "DHCP server");
140
141         g_dhcp_server_set_lease_time(dhcp_server, lease_time);
142         g_dhcp_server_set_option(dhcp_server, G_DHCP_SUBNET, subnet);
143         g_dhcp_server_set_option(dhcp_server, G_DHCP_ROUTER, router);
144         g_dhcp_server_set_option(dhcp_server, G_DHCP_DNS_SERVER, dns);
145         g_dhcp_server_set_ip_range(dhcp_server, start_ip, end_ip);
146
147         g_dhcp_server_start(dhcp_server);
148
149         return dhcp_server;
150 }
151
152 static void dhcp_server_stop(GDHCPServer *server)
153 {
154         if (server == NULL)
155                 return;
156
157         g_dhcp_server_unref(server);
158 }
159
160 static int set_forward_delay(const char *name, unsigned int delay)
161 {
162         FILE *f;
163         char *forward_delay_path;
164
165         forward_delay_path =
166                 g_strdup_printf("/sys/class/net/%s/bridge/forward_delay", name);
167
168         if (forward_delay_path == NULL)
169                 return -ENOMEM;
170
171         f = fopen(forward_delay_path, "r+");
172
173         g_free(forward_delay_path);
174
175         if (f == NULL)
176                 return -errno;
177
178         fprintf(f, "%d", delay);
179
180         fclose(f);
181
182         return 0;
183 }
184
185 static int create_bridge(const char *name)
186 {
187         int sk, err;
188
189         DBG("name %s", name);
190
191         sk = socket(AF_INET, SOCK_STREAM, 0);
192         if (sk < 0)
193                 return -EOPNOTSUPP;
194
195         err = ioctl(sk, SIOCBRADDBR, name);
196
197         if (err < 0)
198                 return -EOPNOTSUPP;
199
200         err = set_forward_delay(name, 0);
201
202         if (err < 0)
203                 ioctl(sk, SIOCBRDELBR, name);
204
205         close(sk);
206
207         return err;
208 }
209
210 static int remove_bridge(const char *name)
211 {
212         int sk, err;
213
214         DBG("name %s", name);
215
216         sk = socket(AF_INET, SOCK_STREAM, 0);
217         if (sk < 0)
218                 return -EOPNOTSUPP;
219
220         err = ioctl(sk, SIOCBRDELBR, name);
221
222         close(sk);
223
224         if (err < 0)
225                 return -EOPNOTSUPP;
226
227         return 0;
228 }
229
230 static int enable_bridge(const char *name)
231 {
232         int err, index;
233
234         index = connman_inet_ifindex(name);
235         if (index < 0)
236                 return index;
237
238         err = __connman_inet_modify_address(RTM_NEWADDR,
239                         NLM_F_REPLACE | NLM_F_ACK, index, AF_INET,
240                                         BRIDGE_IP, NULL, 24, BRIDGE_BCAST);
241         if (err < 0)
242                 return err;
243
244         return connman_inet_ifup(index);
245 }
246
247 static int disable_bridge(const char *name)
248 {
249         int index;
250
251         index = connman_inet_ifindex(name);
252         if (index < 0)
253                 return index;
254
255         return connman_inet_ifdown(index);
256 }
257
258 static int enable_ip_forward(connman_bool_t enable)
259 {
260
261         FILE *f;
262
263         f = fopen("/proc/sys/net/ipv4/ip_forward", "r+");
264         if (f == NULL)
265                 return -errno;
266
267         if (enable == TRUE)
268                 fprintf(f, "1");
269         else
270                 fprintf(f, "0");
271
272         fclose(f);
273
274         return 0;
275 }
276
277 static int enable_nat(const char *interface)
278 {
279         int err;
280
281         if (interface == NULL)
282                 return 0;
283
284         /* Enable IPv4 forwarding */
285         err = enable_ip_forward(TRUE);
286         if (err < 0)
287                 return err;
288
289         /* POSTROUTING flush */
290         err = __connman_iptables_command("-t nat -F POSTROUTING");
291         if (err < 0)
292                 return err;
293
294         /* Enable masquerading */
295         err = __connman_iptables_command("-t nat -A POSTROUTING "
296                                         "-o %s -j MASQUERADE", interface);
297         if (err < 0)
298                 return err;
299
300         return __connman_iptables_commit("nat");
301 }
302
303 static void disable_nat(const char *interface)
304 {
305         int err;
306
307         /* Disable IPv4 forwarding */
308         enable_ip_forward(FALSE);
309
310         /* POSTROUTING flush */
311         err = __connman_iptables_command("-t nat -F POSTROUTING");
312         if (err < 0)
313                 return;
314
315         __connman_iptables_commit("nat");
316 }
317
318 void __connman_tethering_set_enabled(void)
319 {
320         int err;
321
322         DBG("enabled %d", tethering_enabled + 1);
323
324         if (g_atomic_int_exchange_and_add(&tethering_enabled, 1) == 0) {
325                 err = create_bridge(BRIDGE_NAME);
326                 if (err < 0)
327                         return;
328
329                 err = enable_bridge(BRIDGE_NAME);
330                 if (err < 0) {
331                         remove_bridge(BRIDGE_NAME);
332                         return;
333                 }
334
335                 tethering_dhcp_server =
336                         dhcp_server_start(BRIDGE_NAME,
337                                                 BRIDGE_IP, BRIDGE_SUBNET,
338                                                 BRIDGE_IP_START, BRIDGE_IP_END,
339                                                         24 * 3600, BRIDGE_DNS);
340                 if (tethering_dhcp_server == NULL) {
341                         disable_bridge(BRIDGE_NAME);
342                         remove_bridge(BRIDGE_NAME);
343                         return;
344                 }
345
346                 enable_nat(default_interface);
347
348                 DBG("tethering started");
349         }
350 }
351
352 void __connman_tethering_set_disabled(void)
353 {
354         DBG("enabled %d", tethering_enabled - 1);
355
356         if (g_atomic_int_dec_and_test(&tethering_enabled) == TRUE) {
357                 disable_nat(default_interface);
358
359                 dhcp_server_stop(tethering_dhcp_server);
360
361                 disable_bridge(BRIDGE_NAME);
362
363                 remove_bridge(BRIDGE_NAME);
364
365                 DBG("tethering stopped");
366         }
367 }
368
369 void __connman_tethering_update_interface(const char *interface)
370 {
371         DBG("interface %s", interface);
372
373         g_free(default_interface);
374
375         if (interface == NULL) {
376                 disable_nat(interface);
377                 default_interface = NULL;
378
379                 return;
380         }
381
382         default_interface = g_strdup(interface);
383
384         if (!g_atomic_int_get(&tethering_enabled))
385                 return;
386
387         enable_nat(interface);
388 }
389
390 static void setup_tun_interface(unsigned int flags, unsigned change,
391                 void *data)
392 {
393         struct connman_private_network *pn = data;
394
395         DBG("index %d flags %d change %d", pn->index,  flags, change);
396
397         g_dbus_send_reply(connection, pn->msg, DBUS_TYPE_UNIX_FD, &pn->fd,
398                                                         DBUS_TYPE_INVALID);
399 }
400
401 static void remove_private_network(gpointer user_data)
402 {
403         struct connman_private_network *pn = user_data;
404
405         close(pn->fd);
406
407         connman_rtnl_remove_watch(pn->iface_watch);
408
409         if (pn->watch > 0) {
410                 g_dbus_remove_watch(connection, pn->watch);
411                 pn->watch = 0;
412         }
413
414         g_free(pn->interface);
415         g_free(pn->owner);
416         g_free(pn);
417 }
418
419 static void owner_disconnect(DBusConnection *connection, void *user_data)
420 {
421         struct connman_private_network *pn = user_data;
422
423         DBG("%s died", pn->owner);
424
425         pn->watch = 0;
426
427         g_hash_table_remove(pn_hash, pn->owner);
428 }
429
430 int __connman_private_network_request(DBusMessage *msg, const char *owner)
431 {
432         struct connman_private_network *pn;
433         char *iface = NULL;
434         int index, fd, err;
435
436         pn = g_hash_table_lookup(pn_hash, owner);
437         if (pn != NULL)
438                 return -EEXIST;
439
440         fd = connman_inet_create_tunnel(&iface);
441         if (fd < 0)
442                 return fd;
443
444         index = connman_inet_ifindex(iface);
445         if (index < 0) {
446                 err = -ENODEV;
447                 goto error;
448         }
449         DBG("inteface %s", iface);
450
451         err = connman_inet_set_mtu(index, DEFAULT_MTU);
452
453         pn = g_try_new0(struct connman_private_network, 1);
454         if (pn == NULL) {
455                 err = -ENOMEM;
456                 goto error;
457         }
458
459         pn->owner = g_strdup(owner);
460         pn->watch = g_dbus_add_disconnect_watch(connection, pn->owner,
461                                         owner_disconnect, pn, NULL);
462         pn->msg = msg;
463         pn->fd = fd;
464         pn->interface = iface;
465         pn->index = index;
466
467         pn->iface_watch = connman_rtnl_add_newlink_watch(index,
468                                                 setup_tun_interface, pn);
469
470         g_hash_table_insert(pn_hash, pn->owner, pn);
471
472         return 0;
473
474 error:
475         close(fd);
476         g_free(iface);
477         return err;
478 }
479
480 int __connman_private_network_release(const char *owner)
481 {
482         struct connman_private_network *pn;
483
484         pn = g_hash_table_lookup(pn_hash, owner);
485         if (pn == NULL)
486                 return -EACCES;
487
488         g_hash_table_remove(pn_hash, owner);
489         return 0;
490 }
491
492 int __connman_tethering_init(void)
493 {
494         DBG("");
495
496         tethering_enabled = 0;
497
498         connection = connman_dbus_get_connection();
499         if (connection == NULL)
500                 return -EFAULT;
501
502         pn_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
503                                                 NULL, remove_private_network);
504
505         return 0;
506 }
507
508 void __connman_tethering_cleanup(void)
509 {
510         DBG("");
511
512         if (g_atomic_int_get(&tethering_enabled)) {
513                 if (tethering_dhcp_server)
514                         dhcp_server_stop(tethering_dhcp_server);
515                 disable_bridge(BRIDGE_NAME);
516                 remove_bridge(BRIDGE_NAME);
517         }
518
519         if (connection == NULL)
520                 return;
521
522         g_hash_table_destroy(pn_hash);
523         dbus_connection_unref(connection);
524 }