ipconfig: Add function to clear ipaddress information
[platform/upstream/connman.git] / src / tethering.c
index 70c9177..f3d67df 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
  *  Copyright (C) 2011 ProFUSION embedded systems
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <fcntl.h>
 #include <linux/if_tun.h>
+#include <linux/if_bridge.h>
 
 #include "connman.h"
 
@@ -46,8 +47,6 @@
 #define DBUS_TYPE_UNIX_FD -1
 #endif
 
-#define BRIDGE_PROC_DIR "/proc/sys/net/bridge"
-
 #define BRIDGE_NAME "tether"
 #define BRIDGE_DNS "8.8.8.8"
 
@@ -56,7 +55,6 @@
 #define PRIVATE_NETWORK_PRIMARY_DNS BRIDGE_DNS
 #define PRIVATE_NETWORK_SECONDARY_DNS "8.8.4.4"
 
-static char *default_interface = NULL;
 static volatile int tethering_enabled;
 static GDHCPServer *tethering_dhcp_server = NULL;
 static struct connman_ippool *dhcp_ippool = NULL;
@@ -80,9 +78,18 @@ struct connman_private_network {
 
 const char *__connman_tethering_get_bridge(void)
 {
-       struct stat st;
+       int sk, err;
+       unsigned long args[3];
+
+       sk = socket(AF_INET, SOCK_STREAM, 0);
+       if (sk < 0)
+               return NULL;
 
-       if (stat(BRIDGE_PROC_DIR, &st) < 0) {
+       args[0] = BRCTL_GET_VERSION;
+       args[1] = args[2] = 0;
+       err = ioctl(sk, SIOCGIFBR, &args);
+       close(sk);
+       if (err == -1) {
                connman_error("Missing support for 802.1d ethernet bridging");
                return NULL;
        }
@@ -167,66 +174,6 @@ static void dhcp_server_stop(GDHCPServer *server)
        g_dhcp_server_unref(server);
 }
 
-static int enable_ip_forward(connman_bool_t enable)
-{
-
-       FILE *f;
-
-       f = fopen("/proc/sys/net/ipv4/ip_forward", "r+");
-       if (f == NULL)
-               return -errno;
-
-       if (enable == TRUE)
-               fprintf(f, "1");
-       else
-               fprintf(f, "0");
-
-       fclose(f);
-
-       return 0;
-}
-
-static int enable_nat(const char *interface)
-{
-       int err;
-
-       if (interface == NULL)
-               return 0;
-
-       /* Enable IPv4 forwarding */
-       err = enable_ip_forward(TRUE);
-       if (err < 0)
-               return err;
-
-       /* POSTROUTING flush */
-       err = __connman_iptables_command("-t nat -F POSTROUTING");
-       if (err < 0)
-               return err;
-
-       /* Enable masquerading */
-       err = __connman_iptables_command("-t nat -A POSTROUTING "
-                                       "-o %s -j MASQUERADE", interface);
-       if (err < 0)
-               return err;
-
-       return __connman_iptables_commit("nat");
-}
-
-static void disable_nat(const char *interface)
-{
-       int err;
-
-       /* Disable IPv4 forwarding */
-       enable_ip_forward(FALSE);
-
-       /* POSTROUTING flush */
-       err = __connman_iptables_command("-t nat -F POSTROUTING");
-       if (err < 0)
-               return;
-
-       __connman_iptables_commit("nat");
-}
-
 static void tethering_restart(struct connman_ippool *pool, void *user_data)
 {
        __connman_tethering_set_disabled();
@@ -243,6 +190,7 @@ void __connman_tethering_set_enabled(void)
        const char *start_ip;
        const char *end_ip;
        const char *dns;
+       unsigned char prefixlen;
 
        DBG("enabled %d", tethering_enabled + 1);
 
@@ -250,14 +198,18 @@ void __connman_tethering_set_enabled(void)
                return;
 
        err = __connman_bridge_create(BRIDGE_NAME);
-       if (err < 0)
+       if (err < 0) {
+               __sync_fetch_and_sub(&tethering_enabled, 1);
                return;
+       }
 
        index = connman_inet_ifindex(BRIDGE_NAME);
-       dhcp_ippool = __connman_ippool_create(index, 1, 253,
+       dhcp_ippool = __connman_ippool_create(index, 2, 252,
                                                tethering_restart, NULL);
        if (dhcp_ippool == NULL) {
                connman_error("Fail to create IP pool");
+               __connman_bridge_remove(BRIDGE_NAME);
+               __sync_fetch_and_sub(&tethering_enabled, 1);
                return;
        }
 
@@ -269,7 +221,9 @@ void __connman_tethering_set_enabled(void)
 
        err = __connman_bridge_enable(BRIDGE_NAME, gateway, broadcast);
        if (err < 0 && err != -EALREADY) {
+               __connman_ippool_unref(dhcp_ippool);
                __connman_bridge_remove(BRIDGE_NAME);
+               __sync_fetch_and_sub(&tethering_enabled, 1);
                return;
        }
 
@@ -286,11 +240,15 @@ void __connman_tethering_set_enabled(void)
                                                24 * 3600, dns);
        if (tethering_dhcp_server == NULL) {
                __connman_bridge_disable(BRIDGE_NAME);
+               __connman_ippool_unref(dhcp_ippool);
                __connman_bridge_remove(BRIDGE_NAME);
+               __sync_fetch_and_sub(&tethering_enabled, 1);
                return;
        }
 
-       enable_nat(default_interface);
+       prefixlen =
+               __connman_ipconfig_netmask_prefix_len(subnet_mask);
+       __connman_nat_enable(BRIDGE_NAME, start_ip, prefixlen);
 
        DBG("tethering started");
 }
@@ -304,7 +262,7 @@ void __connman_tethering_set_disabled(void)
        if (__sync_fetch_and_sub(&tethering_enabled, 1) != 1)
                return;
 
-       disable_nat(default_interface);
+       __connman_nat_disable(BRIDGE_NAME);
 
        dhcp_server_stop(tethering_dhcp_server);
 
@@ -319,35 +277,6 @@ void __connman_tethering_set_disabled(void)
        DBG("tethering stopped");
 }
 
-static void update_tethering_interface(struct connman_service *service)
-{
-       char *interface;
-
-       interface = connman_service_get_interface(service);
-
-       DBG("interface %s", interface);
-
-       g_free(default_interface);
-
-       if (interface == NULL) {
-               disable_nat(interface);
-               default_interface = NULL;
-
-               goto out;
-       }
-
-       default_interface = g_strdup(interface);
-
-       __sync_synchronize();
-       if (tethering_enabled == 0)
-               goto out;
-
-       enable_nat(interface);
-
-out:
-       g_free(interface);
-}
-
 static void setup_tun_interface(unsigned int flags, unsigned change,
                void *data)
 {
@@ -379,9 +308,9 @@ static void setup_tun_interface(unsigned int flags, unsigned change,
 
        connman_inet_ifup(pn->index);
 
-       err = enable_nat(default_interface);
+       err = __connman_nat_enable(BRIDGE_NAME, server_ip, prefixlen);
        if (err < 0) {
-               connman_error("failed to enable NAT on %s", default_interface);
+               connman_error("failed to enable NAT");
                goto error;
        }
 
@@ -420,7 +349,7 @@ static void remove_private_network(gpointer user_data)
 {
        struct connman_private_network *pn = user_data;
 
-       disable_nat(default_interface);
+       __connman_nat_disable(BRIDGE_NAME);
        connman_rtnl_remove_watch(pn->iface_watch);
        __connman_ippool_unref(pn->pool);
 
@@ -437,7 +366,7 @@ static void remove_private_network(gpointer user_data)
        g_free(pn);
 }
 
-static void owner_disconnect(DBusConnection *connection, void *user_data)
+static void owner_disconnect(DBusConnection *conn, void *user_data)
 {
        struct connman_private_network *pn = user_data;
 
@@ -508,7 +437,7 @@ int __connman_private_network_request(DBusMessage *msg, const char *owner)
        pn->fd = fd;
        pn->interface = iface;
        pn->index = index;
-       pn->pool = __connman_ippool_create(pn->fd, 1, 1, ippool_disconnect, pn);
+       pn->pool = __connman_ippool_create(pn->index, 1, 1, ippool_disconnect, pn);
        if (pn->pool == NULL) {
                errno = -ENOMEM;
                goto error;
@@ -544,15 +473,8 @@ int __connman_private_network_release(const char *path)
        return 0;
 }
 
-static struct connman_notifier tethering_notifier = {
-       .name                   = "tethering",
-       .default_changed        = update_tethering_interface,
-};
-
 int __connman_tethering_init(void)
 {
-       int err;
-
        DBG("");
 
        tethering_enabled = 0;
@@ -561,12 +483,6 @@ int __connman_tethering_init(void)
        if (connection == NULL)
                return -EFAULT;
 
-       err = connman_notifier_register(&tethering_notifier);
-       if (err < 0) {
-               dbus_connection_unref(connection);
-               return err;
-       }
-
        pn_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                NULL, remove_private_network);
 
@@ -583,10 +499,9 @@ void __connman_tethering_cleanup(void)
                        dhcp_server_stop(tethering_dhcp_server);
                __connman_bridge_disable(BRIDGE_NAME);
                __connman_bridge_remove(BRIDGE_NAME);
+               __connman_nat_disable(BRIDGE_NAME);
        }
 
-       connman_notifier_unregister(&tethering_notifier);
-
        if (connection == NULL)
                return;