Merge "Fix SIGSEV on freeing server domains list" into tizen
[platform/upstream/connman.git] / src / tethering.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  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 <string.h>
35 #include <fcntl.h>
36 #include <netinet/in.h>
37 #include <linux/sockios.h>
38 #include <linux/if_tun.h>
39 #include <linux/if_bridge.h>
40
41 #include "connman.h"
42
43 #include <gdhcp/gdhcp.h>
44
45 #include <gdbus.h>
46
47 #ifndef DBUS_TYPE_UNIX_FD
48 #define DBUS_TYPE_UNIX_FD -1
49 #endif
50
51 #define BRIDGE_NAME "tether"
52
53 #define DEFAULT_MTU     1500
54
55 static char *private_network_primary_dns = NULL;
56 static char *private_network_secondary_dns = NULL;
57
58 static volatile int tethering_enabled;
59 static GDHCPServer *tethering_dhcp_server = NULL;
60 static struct connman_ippool *dhcp_ippool = NULL;
61 static DBusConnection *connection;
62 static GHashTable *pn_hash;
63
64 static GHashTable *clients_table;
65
66 struct _clients_notify {
67         int id;
68         GHashTable *remove;
69 } *clients_notify;
70
71 struct connman_private_network {
72         char *owner;
73         char *path;
74         guint watch;
75         DBusMessage *msg;
76         DBusMessage *reply;
77         int fd;
78         char *interface;
79         int index;
80         guint iface_watch;
81         struct connman_ippool *pool;
82         char *primary_dns;
83         char *secondary_dns;
84 };
85
86 const char *__connman_tethering_get_bridge(void)
87 {
88         int sk, err;
89         unsigned long args[3];
90
91         sk = socket(AF_INET, SOCK_STREAM, 0);
92         if (sk < 0)
93                 return NULL;
94
95         args[0] = BRCTL_GET_VERSION;
96         args[1] = args[2] = 0;
97         err = ioctl(sk, SIOCGIFBR, &args);
98         close(sk);
99         if (err == -1) {
100                 connman_error("Missing support for 802.1d ethernet bridging");
101                 return NULL;
102         }
103
104         return BRIDGE_NAME;
105 }
106
107 static void dhcp_server_debug(const char *str, void *data)
108 {
109         connman_info("%s: %s\n", (const char *) data, str);
110 }
111
112 static void dhcp_server_error(GDHCPServerError error)
113 {
114         switch (error) {
115         case G_DHCP_SERVER_ERROR_NONE:
116                 connman_error("OK");
117                 break;
118         case G_DHCP_SERVER_ERROR_INTERFACE_UNAVAILABLE:
119                 connman_error("Interface unavailable");
120                 break;
121         case G_DHCP_SERVER_ERROR_INTERFACE_IN_USE:
122                 connman_error("Interface in use");
123                 break;
124         case G_DHCP_SERVER_ERROR_INTERFACE_DOWN:
125                 connman_error("Interface down");
126                 break;
127         case G_DHCP_SERVER_ERROR_NOMEM:
128                 connman_error("No memory");
129                 break;
130         case G_DHCP_SERVER_ERROR_INVALID_INDEX:
131                 connman_error("Invalid index");
132                 break;
133         case G_DHCP_SERVER_ERROR_INVALID_OPTION:
134                 connman_error("Invalid option");
135                 break;
136         case G_DHCP_SERVER_ERROR_IP_ADDRESS_INVALID:
137                 connman_error("Invalid address");
138                 break;
139         }
140 }
141
142 static GDHCPServer *dhcp_server_start(const char *bridge,
143                                 const char *router, const char *subnet,
144                                 const char *start_ip, const char *end_ip,
145                                 unsigned int lease_time, const char *dns)
146 {
147         GDHCPServerError error;
148         GDHCPServer *dhcp_server;
149         int index;
150
151         DBG("");
152
153         index = connman_inet_ifindex(bridge);
154         if (index < 0)
155                 return NULL;
156
157         dhcp_server = g_dhcp_server_new(G_DHCP_IPV4, index, &error);
158         if (!dhcp_server) {
159                 dhcp_server_error(error);
160                 return NULL;
161         }
162
163         g_dhcp_server_set_debug(dhcp_server, dhcp_server_debug, "DHCP server");
164
165         g_dhcp_server_set_lease_time(dhcp_server, lease_time);
166         g_dhcp_server_set_option(dhcp_server, G_DHCP_SUBNET, subnet);
167         g_dhcp_server_set_option(dhcp_server, G_DHCP_ROUTER, router);
168         g_dhcp_server_set_option(dhcp_server, G_DHCP_DNS_SERVER, dns);
169         g_dhcp_server_set_ip_range(dhcp_server, start_ip, end_ip);
170
171         g_dhcp_server_start(dhcp_server);
172
173         return dhcp_server;
174 }
175
176 static void dhcp_server_stop(GDHCPServer *server)
177 {
178         if (!server)
179                 return;
180
181         g_dhcp_server_unref(server);
182 }
183
184 static void tethering_restart(struct connman_ippool *pool, void *user_data)
185 {
186         DBG("pool %p", pool);
187         __connman_tethering_set_disabled();
188         __connman_tethering_set_enabled();
189 }
190
191 static void unregister_client(gpointer key,
192                                         gpointer value, gpointer user_data)
193 {
194         const char *addr = key;
195         __connman_tethering_client_unregister(addr);
196 }
197
198 static void unregister_all_clients(void)
199 {
200         g_hash_table_foreach(clients_table, unregister_client, NULL);
201 }
202
203 int __connman_tethering_set_enabled(void)
204 {
205         int index;
206         int err;
207         const char *gateway;
208         const char *broadcast;
209         const char *subnet_mask;
210         const char *start_ip;
211         const char *end_ip;
212         const char *dns;
213         unsigned char prefixlen;
214         char **ns;
215
216         DBG("enabled %d", tethering_enabled + 1);
217
218         if (__sync_fetch_and_add(&tethering_enabled, 1) != 0)
219                 return 0;
220
221         err = __connman_bridge_create(BRIDGE_NAME);
222         if (err < 0) {
223                 __sync_fetch_and_sub(&tethering_enabled, 1);
224                 return -EOPNOTSUPP;
225         }
226
227         index = connman_inet_ifindex(BRIDGE_NAME);
228         dhcp_ippool = __connman_ippool_create(index, 2, 252,
229                                                 tethering_restart, NULL);
230         if (!dhcp_ippool) {
231                 connman_error("Fail to create IP pool");
232                 __connman_bridge_remove(BRIDGE_NAME);
233                 __sync_fetch_and_sub(&tethering_enabled, 1);
234                 return -EADDRNOTAVAIL;
235         }
236
237         gateway = __connman_ippool_get_gateway(dhcp_ippool);
238         broadcast = __connman_ippool_get_broadcast(dhcp_ippool);
239         subnet_mask = __connman_ippool_get_subnet_mask(dhcp_ippool);
240         start_ip = __connman_ippool_get_start_ip(dhcp_ippool);
241         end_ip = __connman_ippool_get_end_ip(dhcp_ippool);
242
243         err = __connman_bridge_enable(BRIDGE_NAME, gateway,
244                         connman_ipaddress_calc_netmask_len(subnet_mask),
245                         broadcast);
246         if (err < 0 && err != -EALREADY) {
247                 __connman_ippool_free(dhcp_ippool);
248                 dhcp_ippool = NULL;
249                 __connman_bridge_remove(BRIDGE_NAME);
250                 __sync_fetch_and_sub(&tethering_enabled, 1);
251                 return -EADDRNOTAVAIL;
252         }
253
254         ns = connman_setting_get_string_list("FallbackNameservers");
255         if (ns) {
256                 if (ns[0]) {
257                         g_free(private_network_primary_dns);
258                         private_network_primary_dns = g_strdup(ns[0]);
259                 }
260                 if (ns[1]) {
261                         g_free(private_network_secondary_dns);
262                         private_network_secondary_dns = g_strdup(ns[1]);
263                 }
264
265                 DBG("Fallback ns primary %s secondary %s",
266                         private_network_primary_dns,
267                         private_network_secondary_dns);
268         }
269
270         dns = gateway;
271         if (__connman_dnsproxy_add_listener(index) < 0) {
272                 connman_error("Can't add listener %s to DNS proxy",
273                                                                 BRIDGE_NAME);
274                 dns = private_network_primary_dns;
275                 DBG("Serving %s nameserver to clients", dns);
276         }
277
278         tethering_dhcp_server = dhcp_server_start(BRIDGE_NAME,
279                                                 gateway, subnet_mask,
280                                                 start_ip, end_ip,
281                                                 24 * 3600, dns);
282         if (!tethering_dhcp_server) {
283                 __connman_bridge_disable(BRIDGE_NAME);
284                 __connman_ippool_free(dhcp_ippool);
285                 dhcp_ippool = NULL;
286                 __connman_bridge_remove(BRIDGE_NAME);
287                 __sync_fetch_and_sub(&tethering_enabled, 1);
288                 return -EOPNOTSUPP;
289         }
290
291         prefixlen = connman_ipaddress_calc_netmask_len(subnet_mask);
292         err = __connman_nat_enable(BRIDGE_NAME, start_ip, prefixlen);
293         if (err < 0) {
294                 connman_error("Cannot enable NAT %d/%s", err, strerror(-err));
295                 dhcp_server_stop(tethering_dhcp_server);
296                 __connman_bridge_disable(BRIDGE_NAME);
297                 __connman_ippool_free(dhcp_ippool);
298                 dhcp_ippool = NULL;
299                 __connman_bridge_remove(BRIDGE_NAME);
300                 __sync_fetch_and_sub(&tethering_enabled, 1);
301                 return -EOPNOTSUPP;
302         }
303
304         err = __connman_ipv6pd_setup(BRIDGE_NAME);
305         if (err < 0 && err != -EINPROGRESS)
306                 DBG("Cannot setup IPv6 prefix delegation %d/%s", err,
307                         strerror(-err));
308
309         DBG("tethering started");
310
311         return 0;
312 }
313
314 void __connman_tethering_set_disabled(void)
315 {
316         int index;
317
318         DBG("enabled %d", tethering_enabled - 1);
319
320         if (__sync_fetch_and_sub(&tethering_enabled, 1) != 1)
321                 return;
322
323         unregister_all_clients();
324
325         __connman_ipv6pd_cleanup();
326
327         index = connman_inet_ifindex(BRIDGE_NAME);
328         __connman_dnsproxy_remove_listener(index);
329
330         __connman_nat_disable(BRIDGE_NAME);
331
332         dhcp_server_stop(tethering_dhcp_server);
333
334         tethering_dhcp_server = NULL;
335
336         __connman_bridge_disable(BRIDGE_NAME);
337
338         __connman_ippool_free(dhcp_ippool);
339         dhcp_ippool = NULL;
340
341         __connman_bridge_remove(BRIDGE_NAME);
342
343         g_free(private_network_primary_dns);
344         private_network_primary_dns = NULL;
345         g_free(private_network_secondary_dns);
346         private_network_secondary_dns = NULL;
347
348         DBG("tethering stopped");
349 }
350
351 static void append_client(gpointer key, gpointer value,
352                                                 gpointer user_data)
353 {
354         const char *addr = key;
355         DBusMessageIter *array = user_data;
356
357         dbus_message_iter_append_basic(array, DBUS_TYPE_STRING,
358                                                         &addr);
359 }
360
361 void __connman_tethering_list_clients(DBusMessageIter *array)
362 {
363         g_hash_table_foreach(clients_table, append_client, array);
364 }
365
366 static void setup_tun_interface(unsigned int flags, unsigned change,
367                 void *data)
368 {
369         struct connman_private_network *pn = data;
370         unsigned char prefixlen;
371         DBusMessageIter array, dict;
372         const char *server_ip;
373         const char *peer_ip;
374         const char *subnet_mask;
375         int err;
376
377         DBG("index %d flags %d change %d", pn->index,  flags, change);
378
379         if (flags & IFF_UP)
380                 return;
381
382         subnet_mask = __connman_ippool_get_subnet_mask(pn->pool);
383         server_ip = __connman_ippool_get_start_ip(pn->pool);
384         peer_ip = __connman_ippool_get_end_ip(pn->pool);
385         prefixlen = connman_ipaddress_calc_netmask_len(subnet_mask);
386
387         if ((__connman_inet_modify_address(RTM_NEWADDR,
388                                 NLM_F_REPLACE | NLM_F_ACK, pn->index, AF_INET,
389                                 server_ip, peer_ip, prefixlen, NULL, true))
390                                 < 0) {
391                 DBG("address setting failed");
392                 return;
393         }
394
395         connman_inet_ifup(pn->index);
396
397         err = __connman_nat_enable(BRIDGE_NAME, server_ip, prefixlen);
398         if (err < 0) {
399                 connman_error("failed to enable NAT");
400                 goto error;
401         }
402
403         dbus_message_iter_init_append(pn->reply, &array);
404
405         dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
406                                                 &pn->path);
407
408         connman_dbus_dict_open(&array, &dict);
409
410         connman_dbus_dict_append_basic(&dict, "ServerIPv4",
411                                         DBUS_TYPE_STRING, &server_ip);
412         connman_dbus_dict_append_basic(&dict, "PeerIPv4",
413                                         DBUS_TYPE_STRING, &peer_ip);
414         if (pn->primary_dns)
415                 connman_dbus_dict_append_basic(&dict, "PrimaryDNS",
416                                         DBUS_TYPE_STRING, &pn->primary_dns);
417
418         if (pn->secondary_dns)
419                 connman_dbus_dict_append_basic(&dict, "SecondaryDNS",
420                                         DBUS_TYPE_STRING, &pn->secondary_dns);
421
422         connman_dbus_dict_close(&array, &dict);
423
424         dbus_message_iter_append_basic(&array, DBUS_TYPE_UNIX_FD, &pn->fd);
425
426         g_dbus_send_message(connection, pn->reply);
427
428         return;
429
430 error:
431         pn->reply = __connman_error_failed(pn->msg, -err);
432         g_dbus_send_message(connection, pn->reply);
433
434         g_hash_table_remove(pn_hash, pn->path);
435 }
436
437 static void remove_private_network(gpointer user_data)
438 {
439         struct connman_private_network *pn = user_data;
440
441         __connman_nat_disable(BRIDGE_NAME);
442         connman_rtnl_remove_watch(pn->iface_watch);
443         __connman_ippool_free(pn->pool);
444
445         if (pn->watch > 0) {
446                 g_dbus_remove_watch(connection, pn->watch);
447                 pn->watch = 0;
448         }
449
450         close(pn->fd);
451
452         g_free(pn->interface);
453         g_free(pn->owner);
454         g_free(pn->path);
455         g_free(pn->primary_dns);
456         g_free(pn->secondary_dns);
457         g_free(pn);
458 }
459
460 static void owner_disconnect(DBusConnection *conn, void *user_data)
461 {
462         struct connman_private_network *pn = user_data;
463
464         DBG("%s died", pn->owner);
465
466         pn->watch = 0;
467
468         g_hash_table_remove(pn_hash, pn->path);
469 }
470
471 static void ippool_disconnect(struct connman_ippool *pool, void *user_data)
472 {
473         struct connman_private_network *pn = user_data;
474
475         DBG("block used externally");
476
477         g_hash_table_remove(pn_hash, pn->path);
478 }
479
480 static gboolean client_send_changed(gpointer data)
481 {
482         DBusMessage *signal;
483         DBusMessageIter iter, array;
484
485         DBG("");
486
487         clients_notify->id = 0;
488
489         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
490                                 CONNMAN_MANAGER_INTERFACE, "TetheringClientsChanged");
491         if (!signal)
492                 return FALSE;
493
494         dbus_message_iter_init_append(signal, &iter);
495         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
496                                 DBUS_TYPE_STRING_AS_STRING, &array);
497
498         g_hash_table_foreach(clients_table, append_client, &array);
499
500         dbus_message_iter_close_container(&iter, &array);
501
502         dbus_message_iter_init_append(signal, &iter);
503         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
504                                 DBUS_TYPE_STRING_AS_STRING, &array);
505
506         g_hash_table_foreach(clients_notify->remove, append_client, &array);
507
508         dbus_message_iter_close_container(&iter, &array);
509
510         dbus_connection_send(connection, signal, NULL);
511         dbus_message_unref(signal);
512
513         g_hash_table_remove_all(clients_notify->remove);
514
515         return FALSE;
516 }
517
518 static void client_schedule_changed(void)
519 {
520         if (clients_notify->id != 0)
521                 return;
522
523         clients_notify->id = g_timeout_add(100, client_send_changed, NULL);
524 }
525
526 static void client_added(const char *addr)
527 {
528         DBG("client %s", addr);
529
530         g_hash_table_remove(clients_notify->remove, addr);
531
532         client_schedule_changed();
533 }
534
535 static void client_removed(const char *addr)
536 {
537         DBG("client %s", addr);
538
539         g_hash_table_replace(clients_notify->remove, g_strdup(addr), NULL);
540
541         client_schedule_changed();
542 }
543
544 int __connman_private_network_request(DBusMessage *msg, const char *owner)
545 {
546         struct connman_private_network *pn;
547         char *iface = NULL;
548         char *path = NULL;
549         int index, fd, err;
550
551         if (DBUS_TYPE_UNIX_FD < 0)
552                 return -EINVAL;
553
554         fd = connman_inet_create_tunnel(&iface);
555         if (fd < 0)
556                 return fd;
557
558         path = g_strdup_printf("/tethering/%s", iface);
559
560         pn = g_hash_table_lookup(pn_hash, path);
561         if (pn) {
562                 g_free(path);
563                 g_free(iface);
564                 close(fd);
565                 return -EEXIST;
566         }
567
568         index = connman_inet_ifindex(iface);
569         if (index < 0) {
570                 err = -ENODEV;
571                 goto error;
572         }
573         DBG("interface %s", iface);
574
575         err = connman_inet_set_mtu(index, DEFAULT_MTU);
576
577         pn = g_try_new0(struct connman_private_network, 1);
578         if (!pn) {
579                 err = -ENOMEM;
580                 goto error;
581         }
582
583         pn->owner = g_strdup(owner);
584         pn->path = path;
585         pn->watch = g_dbus_add_disconnect_watch(connection, pn->owner,
586                                         owner_disconnect, pn, NULL);
587         pn->msg = msg;
588         pn->reply = dbus_message_new_method_return(pn->msg);
589         if (!pn->reply)
590                 goto error;
591
592         pn->fd = fd;
593         pn->interface = iface;
594         pn->index = index;
595         pn->pool = __connman_ippool_create(pn->index, 1, 1, ippool_disconnect, pn);
596         if (!pn->pool) {
597                 errno = -ENOMEM;
598                 goto error;
599         }
600
601         pn->primary_dns = g_strdup(private_network_primary_dns);
602         pn->secondary_dns = g_strdup(private_network_secondary_dns);
603
604         pn->iface_watch = connman_rtnl_add_newlink_watch(index,
605                                                 setup_tun_interface, pn);
606
607         g_hash_table_insert(pn_hash, pn->path, pn);
608
609         return 0;
610
611 error:
612         close(fd);
613         g_free(iface);
614         g_free(path);
615         if (pn)
616                 g_free(pn->owner);
617         g_free(pn);
618         return err;
619 }
620
621 int __connman_private_network_release(const char *path)
622 {
623         struct connman_private_network *pn;
624
625         pn = g_hash_table_lookup(pn_hash, path);
626         if (!pn)
627                 return -EACCES;
628
629         g_hash_table_remove(pn_hash, path);
630         return 0;
631 }
632
633 void __connman_tethering_client_register(const char *addr)
634 {
635         g_hash_table_insert(clients_table, g_strdup(addr), NULL);
636         client_added(addr);
637 }
638
639 void __connman_tethering_client_unregister(const char *addr)
640 {
641         client_removed(addr);
642         g_hash_table_remove(clients_table, addr);
643 }
644
645 int __connman_tethering_init(void)
646 {
647         DBG("");
648
649         tethering_enabled = 0;
650
651         connection = connman_dbus_get_connection();
652         if (!connection)
653                 return -EFAULT;
654
655         pn_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
656                                                 NULL, remove_private_network);
657
658         clients_table = g_hash_table_new_full(g_str_hash, g_str_equal,
659                                                         g_free, NULL);
660
661         clients_notify = g_new0(struct _clients_notify, 1);
662         clients_notify->remove = g_hash_table_new_full(g_str_hash, g_str_equal,
663                                                         g_free, NULL);
664         return 0;
665 }
666
667 void __connman_tethering_cleanup(void)
668 {
669         DBG("enabled %d", tethering_enabled);
670
671         __sync_synchronize();
672         if (tethering_enabled > 0) {
673                 if (tethering_dhcp_server)
674                         dhcp_server_stop(tethering_dhcp_server);
675                 __connman_bridge_disable(BRIDGE_NAME);
676                 __connman_bridge_remove(BRIDGE_NAME);
677                 __connman_nat_disable(BRIDGE_NAME);
678         }
679
680         if (!connection)
681                 return;
682
683         g_hash_table_destroy(pn_hash);
684
685         g_hash_table_destroy(clients_notify->remove);
686         g_free(clients_notify);
687         clients_notify = NULL;
688
689         g_hash_table_destroy(clients_table);
690         clients_table = NULL;
691
692         dbus_connection_unref(connection);
693 }