5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
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.
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.
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
28 #include <sys/ioctl.h>
30 #include <linux/sockios.h>
34 #include <gdhcp/gdhcp.h>
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"
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;
49 connman_bool_t __connman_tethering_get_status(void)
51 return tethering_status;
55 static void dhcp_server_debug(const char *str, void *data)
57 connman_info("%s: %s\n", (const char *) data, str);
60 static void dhcp_server_error(GDHCPServerError error)
63 case G_DHCP_SERVER_ERROR_NONE:
66 case G_DHCP_SERVER_ERROR_INTERFACE_UNAVAILABLE:
67 connman_error("Interface unavailable");
69 case G_DHCP_SERVER_ERROR_INTERFACE_IN_USE:
70 connman_error("Interface in use");
72 case G_DHCP_SERVER_ERROR_INTERFACE_DOWN:
73 connman_error("Interface down");
75 case G_DHCP_SERVER_ERROR_NOMEM:
76 connman_error("No memory");
78 case G_DHCP_SERVER_ERROR_INVALID_INDEX:
79 connman_error("Invalid index");
81 case G_DHCP_SERVER_ERROR_INVALID_OPTION:
82 connman_error("Invalid option");
84 case G_DHCP_SERVER_ERROR_IP_ADDRESS_INVALID:
85 connman_error("Invalid address");
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)
95 GDHCPServerError error;
96 GDHCPServer *dhcp_server;
101 index = connman_inet_ifindex(bridge);
105 dhcp_server = g_dhcp_server_new(G_DHCP_IPV4, index, &error);
106 if (dhcp_server == NULL) {
107 dhcp_server_error(error);
111 g_dhcp_server_set_debug(dhcp_server, dhcp_server_debug, "DHCP server");
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);
119 g_dhcp_server_start(dhcp_server);
124 static void dhcp_server_stop(GDHCPServer *server)
129 g_dhcp_server_unref(server);
132 static int create_bridge(const char *name)
136 DBG("name %s", name);
138 sk = socket(AF_INET, SOCK_STREAM, 0);
142 err = ioctl(sk, SIOCBRADDBR, name);
152 static int remove_bridge(const char *name)
156 DBG("name %s", name);
158 sk = socket(AF_INET, SOCK_STREAM, 0);
162 err = ioctl(sk, SIOCBRDELBR, name);
172 static int enable_bridge(const char *name)
176 index = connman_inet_ifindex(name);
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);
186 return connman_inet_ifup(index);
189 static int disable_bridge(const char *name)
193 index = connman_inet_ifindex(name);
197 return connman_inet_ifdown(index);
200 static int enable_ip_forward(connman_bool_t enable)
205 f = fopen("/proc/sys/net/ipv4/ip_forward", "r+");
219 static int enable_nat(const char *interface)
223 if (interface == NULL)
226 /* Enable IPv4 forwarding */
227 err = enable_ip_forward(TRUE);
231 /* POSTROUTING flush */
232 err = __connman_iptables_command("-t nat -F POSTROUTING");
236 /* Enable masquerading */
237 err = __connman_iptables_command("-t nat -A POSTROUTING "
238 "-o %s -j MASQUERADE", interface);
242 return __connman_iptables_commit("nat");
245 static void disable_nat(const char *interface)
249 /* Disable IPv4 forwarding */
250 enable_ip_forward(FALSE);
252 /* POSTROUTING flush */
253 err = __connman_iptables_command("-t nat -F POSTROUTING");
257 __connman_iptables_commit("nat");
260 void __connman_tethering_set_enabled(void)
264 if (tethering_status == FALSE)
267 DBG("enabled %d", tethering_enabled + 1);
269 if (g_atomic_int_exchange_and_add(&tethering_enabled, 1) == 0) {
270 err = enable_bridge(BRIDGE_NAME);
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);
284 enable_nat(default_interface);
286 DBG("tethering started");
290 void __connman_tethering_set_disabled(void)
292 if (tethering_status == TRUE)
295 DBG("enabled %d", tethering_enabled - 1);
297 if (g_atomic_int_dec_and_test(&tethering_enabled) == 0) {
298 disable_nat(default_interface);
300 dhcp_server_stop(tethering_dhcp_server);
302 disable_bridge(BRIDGE_NAME);
304 DBG("tethering stopped");
308 int __connman_tethering_set_status(connman_bool_t status)
310 if (status == tethering_status)
313 if (status == TRUE) {
314 create_bridge(BRIDGE_NAME);
315 __connman_technology_enable_tethering(BRIDGE_NAME);
317 __connman_technology_disable_tethering(BRIDGE_NAME);
318 remove_bridge(BRIDGE_NAME);
321 tethering_status = status;
326 void __connman_tethering_update_interface(const char *interface)
328 DBG("interface %s", interface);
330 g_free(default_interface);
332 if (interface == NULL) {
333 disable_nat(interface);
338 default_interface = g_strdup(interface);
340 if (tethering_status == FALSE ||
341 !g_atomic_int_get(&tethering_enabled))
344 enable_nat(interface);
347 int __connman_tethering_init(void)
351 tethering_enabled = 0;
356 void __connman_tethering_cleanup(void)
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);