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