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 #define BRIDGE_NAME "tether"
35 #define BRIDGE_IP "192.168.218.1"
36 #define BRIDGE_BCAST "192.168.218.255"
37 #define BRIDGE_SUBNET "255.255.255.0"
39 static connman_bool_t tethering_status = FALSE;
40 static const char *default_interface = NULL;
41 static volatile gint tethering_enabled;
43 connman_bool_t __connman_tethering_get_status(void)
45 return tethering_status;
48 static int create_bridge(const char *name)
54 sk = socket(AF_INET, SOCK_STREAM, 0);
58 err = ioctl(sk, SIOCBRADDBR, name);
68 static int remove_bridge(const char *name)
74 sk = socket(AF_INET, SOCK_STREAM, 0);
78 err = ioctl(sk, SIOCBRDELBR, name);
88 static int enable_bridge(const char *name)
92 index = connman_inet_ifindex(name);
96 err = __connman_inet_modify_address(RTM_NEWADDR,
97 NLM_F_REPLACE | NLM_F_ACK, index, AF_INET,
98 BRIDGE_IP, NULL, 24, BRIDGE_BCAST);
102 return connman_inet_ifup(index);
105 static int disable_bridge(const char *name)
109 index = connman_inet_ifindex(name);
113 return connman_inet_ifdown(index);
116 static int enable_ip_forward(connman_bool_t enable)
121 f = fopen("/proc/sys/net/ipv4/ip_forward", "r+");
135 static int enable_nat(const char *interface)
139 if (interface == NULL)
142 /* Enable IPv4 forwarding */
143 err = enable_ip_forward(TRUE);
147 /* POSTROUTING flush */
148 err = __connman_iptables_command("-t nat -F POSTROUTING");
152 /* Enable masquerading */
153 err = __connman_iptables_command("-t nat -A POSTROUTING "
154 "-o %s -j MASQUERADE", interface);
158 return __connman_iptables_commit("nat");
161 static void disable_nat(const char *interface)
165 /* Disable IPv4 forwarding */
166 enable_ip_forward(FALSE);
168 /* POSTROUTING flush */
169 err = __connman_iptables_command("-t nat -F POSTROUTING");
173 __connman_iptables_commit("nat");
176 void __connman_tethering_set_enabled(void)
180 if (tethering_status == FALSE)
183 DBG("enabled %d", tethering_enabled + 1);
185 if (g_atomic_int_exchange_and_add(&tethering_enabled, 1) == 0) {
186 err = enable_bridge(BRIDGE_NAME);
190 /* TODO Start DHCP server and DNS proxy on the bridge */
192 enable_nat(default_interface);
194 DBG("tethering started");
198 void __connman_tethering_set_disabled(void)
200 if (tethering_status == TRUE)
203 DBG("enabled %d", tethering_enabled - 1);
205 if (g_atomic_int_dec_and_test(&tethering_enabled) == 0) {
206 /* TODO Stop DHCP server and DNS proxy on the bridge */
208 disable_nat(default_interface);
210 disable_bridge(BRIDGE_NAME);
212 DBG("tethering stopped");
216 int __connman_tethering_set_status(connman_bool_t status)
218 if (status == tethering_status)
221 if (status == TRUE) {
222 create_bridge(BRIDGE_NAME);
223 __connman_technology_enable_tethering(BRIDGE_NAME);
225 __connman_technology_disable_tethering(BRIDGE_NAME);
226 remove_bridge(BRIDGE_NAME);
229 tethering_status = status;
234 void __connman_tethering_update_interface(const char *interface)
236 DBG("interface %s", interface);
238 default_interface = interface;
240 if (interface == NULL) {
241 disable_nat(interface);
246 if (tethering_status == FALSE ||
247 !g_atomic_int_get(&tethering_enabled))
250 enable_nat(interface);
253 int __connman_tethering_init(void)
257 tethering_enabled = 0;
262 void __connman_tethering_cleanup(void)
266 if (tethering_status == TRUE) {
267 disable_bridge(BRIDGE_NAME);
268 remove_bridge(BRIDGE_NAME);