tethering: Duplicate default interface string
[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 <unistd.h>
27 #include <stdio.h>
28 #include <sys/ioctl.h>
29 #include <net/if.h>
30 #include <linux/sockios.h>
31
32 #include "connman.h"
33
34 #include <gdhcp/gdhcp.h>
35
36 #define BRIDGE_NAME "tether"
37 #define BRIDGE_IP "192.168.218.1"
38 #define BRIDGE_BCAST "192.168.218.255"
39 #define BRIDGE_SUBNET "255.255.255.0"
40 #define BRIDGE_IP_START "192.168.218.100"
41 #define BRIDGE_IP_END "192.168.218.200"
42 #define BRIDGE_DNS "8.8.8.8"
43
44 static connman_bool_t tethering_status = FALSE;
45 static char *default_interface = NULL;
46 static volatile gint tethering_enabled;
47 static GDHCPServer *tethering_dhcp_server = NULL;
48
49 connman_bool_t __connman_tethering_get_status(void)
50 {
51         return tethering_status;
52 }
53
54
55 static void dhcp_server_debug(const char *str, void *data)
56 {
57         connman_info("%s: %s\n", (const char *) data, str);
58 }
59
60 static void dhcp_server_error(GDHCPServerError error)
61 {
62         switch (error) {
63         case G_DHCP_SERVER_ERROR_NONE:
64                 connman_error("OK");
65                 break;
66         case G_DHCP_SERVER_ERROR_INTERFACE_UNAVAILABLE:
67                 connman_error("Interface unavailable");
68                 break;
69         case G_DHCP_SERVER_ERROR_INTERFACE_IN_USE:
70                 connman_error("Interface in use");
71                 break;
72         case G_DHCP_SERVER_ERROR_INTERFACE_DOWN:
73                 connman_error("Interface down");
74                 break;
75         case G_DHCP_SERVER_ERROR_NOMEM:
76                 connman_error("No memory");
77                 break;
78         case G_DHCP_SERVER_ERROR_INVALID_INDEX:
79                 connman_error("Invalid index");
80                 break;
81         case G_DHCP_SERVER_ERROR_INVALID_OPTION:
82                 connman_error("Invalid option");
83                 break;
84         case G_DHCP_SERVER_ERROR_IP_ADDRESS_INVALID:
85                 connman_error("Invalid address");
86                 break;
87         }
88 }
89
90 static GDHCPServer *dhcp_server_start(const char *bridge,
91                                 const char *router, const char* subnet,
92                                 const char *start_ip, const char *end_ip,
93                                 unsigned int lease_time, const char *dns)
94 {
95         GDHCPServerError error;
96         GDHCPServer *dhcp_server;
97         int index;
98
99         DBG("");
100
101         index = connman_inet_ifindex(bridge);
102         if (index < 0)
103                 return NULL;
104
105         dhcp_server = g_dhcp_server_new(G_DHCP_IPV4, index, &error);
106         if (dhcp_server == NULL) {
107                 dhcp_server_error(error);
108                 return NULL;
109         }
110
111         g_dhcp_server_set_debug(dhcp_server, dhcp_server_debug, "DHCP server");
112
113         g_dhcp_server_set_lease_time(dhcp_server, lease_time);
114         g_dhcp_server_set_option(dhcp_server, G_DHCP_SUBNET, subnet);
115         g_dhcp_server_set_option(dhcp_server, G_DHCP_ROUTER, router);
116         g_dhcp_server_set_option(dhcp_server, G_DHCP_DNS_SERVER, dns);
117         g_dhcp_server_set_ip_range(dhcp_server, start_ip, end_ip);
118
119         g_dhcp_server_start(dhcp_server);
120
121         return dhcp_server;
122 }
123
124 static void dhcp_server_stop(GDHCPServer *server)
125 {
126         if (server == NULL)
127                 return;
128
129         g_dhcp_server_unref(server);
130 }
131
132 static int create_bridge(const char *name)
133 {
134         int sk, err;
135
136         DBG("name %s", name);
137
138         sk = socket(AF_INET, SOCK_STREAM, 0);
139         if (sk < 0)
140                 return -EOPNOTSUPP;
141
142         err = ioctl(sk, SIOCBRADDBR, name);
143
144         close(sk);
145
146         if (err < 0)
147                 return -EOPNOTSUPP;
148
149         return 0;
150 }
151
152 static int remove_bridge(const char *name)
153 {
154         int sk, err;
155
156         DBG("name %s", name);
157
158         sk = socket(AF_INET, SOCK_STREAM, 0);
159         if (sk < 0)
160                 return -EOPNOTSUPP;
161
162         err = ioctl(sk, SIOCBRDELBR, name);
163
164         close(sk);
165
166         if (err < 0)
167                 return -EOPNOTSUPP;
168
169         return 0;
170 }
171
172 static int enable_bridge(const char *name)
173 {
174         int err, index;
175
176         index = connman_inet_ifindex(name);
177         if (index < 0)
178                 return index;
179
180         err = __connman_inet_modify_address(RTM_NEWADDR,
181                         NLM_F_REPLACE | NLM_F_ACK, index, AF_INET,
182                                             BRIDGE_IP, NULL, 24, BRIDGE_BCAST);
183         if (err < 0)
184                 return err;
185
186         return connman_inet_ifup(index);
187 }
188
189 static int disable_bridge(const char *name)
190 {
191         int index;
192
193         index = connman_inet_ifindex(name);
194         if (index < 0)
195                 return index;
196
197         return connman_inet_ifdown(index);
198 }
199
200 static int enable_ip_forward(connman_bool_t enable)
201 {
202
203         FILE *f;
204
205         f = fopen("/proc/sys/net/ipv4/ip_forward", "r+");
206         if (f == NULL)
207                 return -errno;
208
209         if (enable == TRUE)
210                 fprintf(f, "1");
211         else
212                 fprintf(f, "0");
213
214         fclose(f);
215
216         return 0;
217 }
218
219 static int enable_nat(const char *interface)
220 {
221         int err;
222
223         if (interface == NULL)
224                 return 0;
225
226         /* Enable IPv4 forwarding */
227         err = enable_ip_forward(TRUE);
228         if (err < 0)
229                 return err;
230
231         /* POSTROUTING flush */
232         err = __connman_iptables_command("-t nat -F POSTROUTING");
233         if (err < 0)
234                 return err;
235
236         /* Enable masquerading */
237         err = __connman_iptables_command("-t nat -A POSTROUTING "
238                                         "-o %s -j MASQUERADE", interface);
239         if (err < 0)
240                 return err;
241
242         return __connman_iptables_commit("nat");
243 }
244
245 static void disable_nat(const char *interface)
246 {
247         int err;
248
249         /* Disable IPv4 forwarding */
250         enable_ip_forward(FALSE);
251
252         /* POSTROUTING flush */
253         err = __connman_iptables_command("-t nat -F POSTROUTING");
254         if (err < 0)
255                 return;
256
257         __connman_iptables_commit("nat");
258 }
259
260 void __connman_tethering_set_enabled(void)
261 {
262         int err;
263
264         if (tethering_status == FALSE)
265                 return;
266
267         DBG("enabled %d", tethering_enabled + 1);
268
269         if (g_atomic_int_exchange_and_add(&tethering_enabled, 1) == 0) {
270                 err = enable_bridge(BRIDGE_NAME);
271                 if (err < 0)
272                         return;
273
274                 tethering_dhcp_server =
275                         dhcp_server_start(BRIDGE_NAME,
276                                                 BRIDGE_IP, BRIDGE_SUBNET,
277                                                 BRIDGE_IP_START, BRIDGE_IP_END,
278                                                         24 * 3600, BRIDGE_DNS);
279                 if (tethering_dhcp_server == NULL) {
280                         disable_bridge(BRIDGE_NAME);
281                         return;
282                 }
283
284                 enable_nat(default_interface);
285
286                 DBG("tethering started");
287         }
288 }
289
290 void __connman_tethering_set_disabled(void)
291 {
292         if (tethering_status == TRUE)
293                 return;
294
295         DBG("enabled %d", tethering_enabled - 1);
296
297         if (g_atomic_int_dec_and_test(&tethering_enabled) == 0) {
298                 disable_nat(default_interface);
299
300                 dhcp_server_stop(tethering_dhcp_server);
301
302                 disable_bridge(BRIDGE_NAME);
303
304                 DBG("tethering stopped");
305         }
306 }
307
308 int __connman_tethering_set_status(connman_bool_t status)
309 {
310         if (status == tethering_status)
311                 return -EALREADY;
312
313         if (status == TRUE) {
314                 create_bridge(BRIDGE_NAME);
315                 __connman_technology_enable_tethering(BRIDGE_NAME);
316         } else {
317                 __connman_technology_disable_tethering(BRIDGE_NAME);
318                 remove_bridge(BRIDGE_NAME);
319         }
320
321         tethering_status = status;
322
323         return 0;
324 }
325
326 void __connman_tethering_update_interface(const char *interface)
327 {
328         DBG("interface %s", interface);
329
330         g_free(default_interface);
331
332         if (interface == NULL) {
333                 disable_nat(interface);
334
335                 return;
336         }
337
338         default_interface = g_strdup(interface);
339
340         if (tethering_status == FALSE ||
341                         !g_atomic_int_get(&tethering_enabled))
342                 return;
343
344         enable_nat(interface);
345 }
346
347 int __connman_tethering_init(void)
348 {
349         DBG("");
350
351         tethering_enabled = 0;
352
353         return 0;
354 }
355
356 void __connman_tethering_cleanup(void)
357 {
358         DBG("");
359
360         if (tethering_status == TRUE) {
361                 if (tethering_dhcp_server)
362                         dhcp_server_stop(tethering_dhcp_server);
363                 disable_bridge(BRIDGE_NAME);
364                 remove_bridge(BRIDGE_NAME);
365         }
366 }