c67f2007fb584c9628be2cd712790aed9440dc86
[framework/connectivity/connman.git] / src / tethering.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
6  *  Copyright (C) 2011  ProFUSION embedded systems
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <sys/ioctl.h>
33 #include <net/if.h>
34 #include <linux/sockios.h>
35 #include <string.h>
36 #include <fcntl.h>
37 #include <linux/if_tun.h>
38
39 #include "connman.h"
40
41 #include <gdhcp/gdhcp.h>
42
43 #include <gdbus.h>
44
45 #ifndef DBUS_TYPE_UNIX_FD
46 #define DBUS_TYPE_UNIX_FD -1
47 #endif
48
49 #define BRIDGE_PROC_DIR "/proc/sys/net/bridge"
50
51 #define BRIDGE_NAME "tether"
52 #define BRIDGE_DNS "8.8.8.8"
53
54 #define DEFAULT_MTU     1500
55
56 #define PRIVATE_NETWORK_PRIMARY_DNS BRIDGE_DNS
57 #define PRIVATE_NETWORK_SECONDARY_DNS "8.8.4.4"
58
59 static volatile int tethering_enabled;
60 static GDHCPServer *tethering_dhcp_server = NULL;
61 static struct connman_ippool *dhcp_ippool = NULL;
62 static DBusConnection *connection;
63 static GHashTable *pn_hash;
64
65 struct connman_private_network {
66         char *owner;
67         char *path;
68         guint watch;
69         DBusMessage *msg;
70         DBusMessage *reply;
71         int fd;
72         char *interface;
73         int index;
74         guint iface_watch;
75         struct connman_ippool *pool;
76         const char *primary_dns;
77         const char *secondary_dns;
78 };
79
80 const char *__connman_tethering_get_bridge(void)
81 {
82         struct stat st;
83
84         if (stat(BRIDGE_PROC_DIR, &st) < 0) {
85                 connman_error("Missing support for 802.1d ethernet bridging");
86                 return NULL;
87         }
88
89         return BRIDGE_NAME;
90 }
91
92 static void dhcp_server_debug(const char *str, void *data)
93 {
94         connman_info("%s: %s\n", (const char *) data, str);
95 }
96
97 static void dhcp_server_error(GDHCPServerError error)
98 {
99         switch (error) {
100         case G_DHCP_SERVER_ERROR_NONE:
101                 connman_error("OK");
102                 break;
103         case G_DHCP_SERVER_ERROR_INTERFACE_UNAVAILABLE:
104                 connman_error("Interface unavailable");
105                 break;
106         case G_DHCP_SERVER_ERROR_INTERFACE_IN_USE:
107                 connman_error("Interface in use");
108                 break;
109         case G_DHCP_SERVER_ERROR_INTERFACE_DOWN:
110                 connman_error("Interface down");
111                 break;
112         case G_DHCP_SERVER_ERROR_NOMEM:
113                 connman_error("No memory");
114                 break;
115         case G_DHCP_SERVER_ERROR_INVALID_INDEX:
116                 connman_error("Invalid index");
117                 break;
118         case G_DHCP_SERVER_ERROR_INVALID_OPTION:
119                 connman_error("Invalid option");
120                 break;
121         case G_DHCP_SERVER_ERROR_IP_ADDRESS_INVALID:
122                 connman_error("Invalid address");
123                 break;
124         }
125 }
126
127 static GDHCPServer *dhcp_server_start(const char *bridge,
128                                 const char *router, const char* subnet,
129                                 const char *start_ip, const char *end_ip,
130                                 unsigned int lease_time, const char *dns)
131 {
132         GDHCPServerError error;
133         GDHCPServer *dhcp_server;
134         int index;
135
136         DBG("");
137
138         index = connman_inet_ifindex(bridge);
139         if (index < 0)
140                 return NULL;
141
142         dhcp_server = g_dhcp_server_new(G_DHCP_IPV4, index, &error);
143         if (dhcp_server == NULL) {
144                 dhcp_server_error(error);
145                 return NULL;
146         }
147
148         g_dhcp_server_set_debug(dhcp_server, dhcp_server_debug, "DHCP server");
149
150         g_dhcp_server_set_lease_time(dhcp_server, lease_time);
151         g_dhcp_server_set_option(dhcp_server, G_DHCP_SUBNET, subnet);
152         g_dhcp_server_set_option(dhcp_server, G_DHCP_ROUTER, router);
153         g_dhcp_server_set_option(dhcp_server, G_DHCP_DNS_SERVER, dns);
154         g_dhcp_server_set_ip_range(dhcp_server, start_ip, end_ip);
155
156         g_dhcp_server_start(dhcp_server);
157
158         return dhcp_server;
159 }
160
161 static void dhcp_server_stop(GDHCPServer *server)
162 {
163         if (server == NULL)
164                 return;
165
166         g_dhcp_server_unref(server);
167 }
168
169 static void tethering_restart(struct connman_ippool *pool, void *user_data)
170 {
171         __connman_tethering_set_disabled();
172         __connman_tethering_set_enabled();
173 }
174
175 void __connman_tethering_set_enabled(void)
176 {
177         int index;
178         int err;
179         const char *gateway;
180         const char *broadcast;
181         const char *subnet_mask;
182         const char *start_ip;
183         const char *end_ip;
184         const char *dns;
185         unsigned char prefixlen;
186
187         DBG("enabled %d", tethering_enabled + 1);
188
189         if (__sync_fetch_and_add(&tethering_enabled, 1) != 0)
190                 return;
191
192         err = __connman_bridge_create(BRIDGE_NAME);
193         if (err < 0)
194                 return;
195
196         index = connman_inet_ifindex(BRIDGE_NAME);
197         dhcp_ippool = __connman_ippool_create(index, 2, 252,
198                                                 tethering_restart, NULL);
199         if (dhcp_ippool == NULL) {
200                 connman_error("Fail to create IP pool");
201                 return;
202         }
203
204         gateway = __connman_ippool_get_gateway(dhcp_ippool);
205         broadcast = __connman_ippool_get_broadcast(dhcp_ippool);
206         subnet_mask = __connman_ippool_get_subnet_mask(dhcp_ippool);
207         start_ip = __connman_ippool_get_start_ip(dhcp_ippool);
208         end_ip = __connman_ippool_get_end_ip(dhcp_ippool);
209
210         err = __connman_bridge_enable(BRIDGE_NAME, gateway, broadcast);
211         if (err < 0 && err != -EALREADY) {
212                 __connman_bridge_remove(BRIDGE_NAME);
213                 return;
214         }
215
216         dns = gateway;
217         if (__connman_dnsproxy_add_listener(BRIDGE_NAME) < 0) {
218                 connman_error("Can't add listener %s to DNS proxy",
219                                                                 BRIDGE_NAME);
220                 dns = BRIDGE_DNS;
221         }
222
223         tethering_dhcp_server = dhcp_server_start(BRIDGE_NAME,
224                                                 gateway, subnet_mask,
225                                                 start_ip, end_ip,
226                                                 24 * 3600, dns);
227         if (tethering_dhcp_server == NULL) {
228                 __connman_bridge_disable(BRIDGE_NAME);
229                 __connman_bridge_remove(BRIDGE_NAME);
230                 return;
231         }
232
233         prefixlen =
234                 __connman_ipconfig_netmask_prefix_len(subnet_mask);
235         __connman_nat_enable(BRIDGE_NAME, start_ip, prefixlen);
236
237         DBG("tethering started");
238 }
239
240 void __connman_tethering_set_disabled(void)
241 {
242         DBG("enabled %d", tethering_enabled - 1);
243
244         __connman_dnsproxy_remove_listener(BRIDGE_NAME);
245
246         if (__sync_fetch_and_sub(&tethering_enabled, 1) != 1)
247                 return;
248
249         __connman_nat_disable(BRIDGE_NAME);
250
251         dhcp_server_stop(tethering_dhcp_server);
252
253         tethering_dhcp_server = NULL;
254
255         __connman_bridge_disable(BRIDGE_NAME);
256
257         __connman_ippool_unref(dhcp_ippool);
258
259         __connman_bridge_remove(BRIDGE_NAME);
260
261         DBG("tethering stopped");
262 }
263
264 static void setup_tun_interface(unsigned int flags, unsigned change,
265                 void *data)
266 {
267         struct connman_private_network *pn = data;
268         unsigned char prefixlen;
269         DBusMessageIter array, dict;
270         const char *server_ip;
271         const char *peer_ip;
272         const char *subnet_mask;
273         int err;
274
275         DBG("index %d flags %d change %d", pn->index,  flags, change);
276
277         if (flags & IFF_UP)
278                 return;
279
280         subnet_mask = __connman_ippool_get_subnet_mask(pn->pool);
281         server_ip = __connman_ippool_get_start_ip(pn->pool);
282         peer_ip = __connman_ippool_get_end_ip(pn->pool);
283         prefixlen =
284                 __connman_ipconfig_netmask_prefix_len(subnet_mask);
285
286         if ((__connman_inet_modify_address(RTM_NEWADDR,
287                                 NLM_F_REPLACE | NLM_F_ACK, pn->index, AF_INET,
288                                 server_ip, peer_ip, prefixlen, NULL)) < 0) {
289                 DBG("address setting failed");
290                 return;
291         }
292
293         connman_inet_ifup(pn->index);
294
295         err = __connman_nat_enable(BRIDGE_NAME, server_ip, prefixlen);
296         if (err < 0) {
297                 connman_error("failed to enable NAT");
298                 goto error;
299         }
300
301         dbus_message_iter_init_append(pn->reply, &array);
302
303         dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
304                                                 &pn->path);
305
306         connman_dbus_dict_open(&array, &dict);
307
308         connman_dbus_dict_append_basic(&dict, "ServerIPv4",
309                                         DBUS_TYPE_STRING, &server_ip);
310         connman_dbus_dict_append_basic(&dict, "PeerIPv4",
311                                         DBUS_TYPE_STRING, &peer_ip);
312         connman_dbus_dict_append_basic(&dict, "PrimaryDNS",
313                                         DBUS_TYPE_STRING, &pn->primary_dns);
314         connman_dbus_dict_append_basic(&dict, "SecondaryDNS",
315                                         DBUS_TYPE_STRING, &pn->secondary_dns);
316
317         connman_dbus_dict_close(&array, &dict);
318
319         dbus_message_iter_append_basic(&array, DBUS_TYPE_UNIX_FD, &pn->fd);
320
321         g_dbus_send_message(connection, pn->reply);
322
323         return;
324
325 error:
326         pn->reply = __connman_error_failed(pn->msg, -err);
327         g_dbus_send_message(connection, pn->reply);
328
329         g_hash_table_remove(pn_hash, pn->path);
330 }
331
332 static void remove_private_network(gpointer user_data)
333 {
334         struct connman_private_network *pn = user_data;
335
336         __connman_nat_disable(BRIDGE_NAME);
337         connman_rtnl_remove_watch(pn->iface_watch);
338         __connman_ippool_unref(pn->pool);
339
340         if (pn->watch > 0) {
341                 g_dbus_remove_watch(connection, pn->watch);
342                 pn->watch = 0;
343         }
344
345         close(pn->fd);
346
347         g_free(pn->interface);
348         g_free(pn->owner);
349         g_free(pn->path);
350         g_free(pn);
351 }
352
353 static void owner_disconnect(DBusConnection *connection, void *user_data)
354 {
355         struct connman_private_network *pn = user_data;
356
357         DBG("%s died", pn->owner);
358
359         pn->watch = 0;
360
361         g_hash_table_remove(pn_hash, pn->path);
362 }
363
364 static void ippool_disconnect(struct connman_ippool *pool, void *user_data)
365 {
366         struct connman_private_network *pn = user_data;
367
368         DBG("block used externally");
369
370         g_hash_table_remove(pn_hash, pn->path);
371 }
372
373 int __connman_private_network_request(DBusMessage *msg, const char *owner)
374 {
375         struct connman_private_network *pn;
376         char *iface = NULL;
377         char *path = NULL;
378         int index, fd, err;
379
380         if (DBUS_TYPE_UNIX_FD < 0)
381                 return -EINVAL;
382
383         fd = connman_inet_create_tunnel(&iface);
384         if (fd < 0)
385                 return fd;
386
387         path = g_strdup_printf("/tethering/%s", iface);
388
389         pn = g_hash_table_lookup(pn_hash, path);
390         if (pn) {
391                 g_free(path);
392                 g_free(iface);
393                 close(fd);
394                 return -EEXIST;
395         }
396
397         index = connman_inet_ifindex(iface);
398         if (index < 0) {
399                 err = -ENODEV;
400                 goto error;
401         }
402         DBG("interface %s", iface);
403
404         err = connman_inet_set_mtu(index, DEFAULT_MTU);
405
406         pn = g_try_new0(struct connman_private_network, 1);
407         if (pn == NULL) {
408                 err = -ENOMEM;
409                 goto error;
410         }
411
412         pn->owner = g_strdup(owner);
413         pn->path = path;
414         pn->watch = g_dbus_add_disconnect_watch(connection, pn->owner,
415                                         owner_disconnect, pn, NULL);
416         pn->msg = msg;
417         pn->reply = dbus_message_new_method_return(pn->msg);
418         if (pn->reply == NULL)
419                 goto error;
420
421         pn->fd = fd;
422         pn->interface = iface;
423         pn->index = index;
424         pn->pool = __connman_ippool_create(pn->fd, 1, 1, ippool_disconnect, pn);
425         if (pn->pool == NULL) {
426                 errno = -ENOMEM;
427                 goto error;
428         }
429
430         pn->primary_dns = PRIVATE_NETWORK_PRIMARY_DNS;
431         pn->secondary_dns = PRIVATE_NETWORK_SECONDARY_DNS;
432
433         pn->iface_watch = connman_rtnl_add_newlink_watch(index,
434                                                 setup_tun_interface, pn);
435
436         g_hash_table_insert(pn_hash, pn->path, pn);
437
438         return 0;
439
440 error:
441         close(fd);
442         g_free(iface);
443         g_free(path);
444         g_free(pn);
445         return err;
446 }
447
448 int __connman_private_network_release(const char *path)
449 {
450         struct connman_private_network *pn;
451
452         pn = g_hash_table_lookup(pn_hash, path);
453         if (pn == NULL)
454                 return -EACCES;
455
456         g_hash_table_remove(pn_hash, path);
457         return 0;
458 }
459
460 int __connman_tethering_init(void)
461 {
462         DBG("");
463
464         tethering_enabled = 0;
465
466         connection = connman_dbus_get_connection();
467         if (connection == NULL)
468                 return -EFAULT;
469
470         pn_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
471                                                 NULL, remove_private_network);
472
473         return 0;
474 }
475
476 void __connman_tethering_cleanup(void)
477 {
478         DBG("");
479
480         __sync_synchronize();
481         if (tethering_enabled == 0) {
482                 if (tethering_dhcp_server)
483                         dhcp_server_stop(tethering_dhcp_server);
484                 __connman_bridge_disable(BRIDGE_NAME);
485                 __connman_bridge_remove(BRIDGE_NAME);
486                 __connman_nat_disable(BRIDGE_NAME);
487         }
488
489         if (connection == NULL)
490                 return;
491
492         g_hash_table_destroy(pn_hash);
493         dbus_connection_unref(connection);
494 }