Added support to enable clatd service 94/212194/2
authorJaehyun Kim <jeik01.kim@samsung.com>
Fri, 16 Aug 2019 13:13:16 +0000 (22:13 +0900)
committerJaehyun Kim <jeik01.kim@samsung.com>
Tue, 20 Aug 2019 09:59:46 +0000 (18:59 +0900)
Change-Id: I943f9e5be057a1dc9959f7a36e00397777b6bd45
Signed-off-by: Jaehyun Kim <jeik01.kim@samsung.com>
CMakeLists.txt
include/network-state.h
src/clatd-handler.c
src/network-state.c
src/signal-handler.c

index b210f77..71d17c9 100755 (executable)
@@ -44,6 +44,7 @@ SET(SRCS
        src/wifi-config.c
        src/wifi-extension.c
        src/ip-conflict-detect.c
+       src/clatd-handler.c
        )
 
 IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
index a38b1af..ee624d4 100755 (executable)
@@ -43,6 +43,12 @@ char *netconfig_get_ifname(const char *profile);
 void state_object_create_and_init(void);
 void state_object_deinit(void);
 
+#define MAX_DNS 2
+struct clatd_ctrl_hint {
+       char *nameserver[MAX_DNS];
+};
+char *netconfig_get_connected_cellular_internet_ipv6only_profile(struct clatd_ctrl_hint *hint);
+
 #ifdef __cplusplus
 }
 #endif
index b953eed..4d442f4 100755 (executable)
 #include "log.h"
 #include "util.h"
 #include "network-state.h"
+#include "netdbus.h"
 #include "clatd-handler.h"
 
-#define CLAT_EXEC_PATH "/usr/sbin/clatd"
-#define ROUTE_EXEC_PATH "/sbin/route"
-#define KILLALL_EXEC_PATH "/usr/bin/killall"
-#define IFCONFIG_EXEC_PATH "/sbin/ifconfig"
+#define CLATD_SERVICE  "com.samsung.clatd"
+#define CLATD_PATH             "/com/samsung/clatd"
+#define CLATD_INTERFACE        "com.samsung.clatd.Control"
 
-char g_ifname[32] = {0, };
+static gboolean g_is_running = FALSE;
 
-int netconfig_clatd_enable(void)
+static void __netconfig_clatd_async_callback(GObject *source_object,
+               GAsyncResult *res, gpointer user_data)
 {
-       int rv = 0;
+       GDBusConnection *conn = NULL;
+       GVariant *reply = NULL;
+       GError *error = NULL;
+       DBG("__netconfig_clatd_async_callback");
+
+       conn = G_DBUS_CONNECTION(source_object);
+       reply = g_dbus_connection_call_finish(conn, res, &error);
+       if (error) {
+               ERR("Dbus error : %s", error->message);
+               g_error_free(error);
+       } else {
+               int is_clat_enabled = -1;
+               g_variant_get(reply, "(i)", &is_clat_enabled);
+
+               if (is_clat_enabled == 0) {
+                       DBG("OK");
+               } else if (is_clat_enabled == 1) {
+                       INFO("already on going");
+                       g_is_running = TRUE;
+               } else {
+                       ERR("Failed to clat enable, %d", is_clat_enabled);
+               }
+       }
 
-       if (g_ifname[0] != '\0') {
-               rv = netconfig_clatd_disable();
+       if (reply)
+               g_variant_unref(reply);
+}
 
-               if (rv < 0) {
-                       DBG("Failed to disable existing clatd process");
-                       return -1;
-               }
+int netconfig_clatd_enable(void)
+{
+       DBG("");
+       GVariant *params = NULL;
+       GVariantBuilder *builder = NULL;
+       gboolean rv = FALSE;
+       struct clatd_ctrl_hint hint = {0 ,};
+       char ns_buff[256] = {0, };
+
+       if (g_is_running) {
+               INFO("clatd is already ENABLED");
+               return 0;
        }
 
        const char *if_name = netconfig_get_default_ifname();
-
        if (if_name == NULL) {
-               DBG("There is no interface name");
+               int idx;
+               for (idx = 0; idx < MAX_DNS; idx++)
+                       g_free(hint.nameserver[idx]);
+
+               ERR("There is no interface name");
                return -1;
+       } else {
+               DBG("if_name : %s", if_name);
        }
 
-       memset(g_ifname, 0, sizeof(g_ifname));
-       g_strlcat(g_ifname, if_name, 32);
+       builder = g_variant_builder_new(G_VARIANT_TYPE ("a{is}"));
 
-       const char *path = CLAT_EXEC_PATH;
-       char *const args[] = { "/usr/sbin/clatd", "-i", g_ifname, NULL };
+       g_variant_builder_add(builder, "{is}", 'i', if_name);
 
-       rv = netconfig_execute_clatd(path, args);
+       // nameserver addresses
+       if (hint.nameserver[0] != NULL || hint.nameserver[1] != NULL) {
+               g_snprintf(ns_buff, 256, "%s;%s",
+                                       ((hint.nameserver[0] != NULL) ? hint.nameserver[0] : "NULL"),
+                                       ((hint.nameserver[1] != NULL) ? hint.nameserver[1] : "NULL"));
+       }
+       g_variant_builder_add(builder, "{is}", 'd', ns_buff);
+
+       params = g_variant_builder_end(builder);
+       g_variant_builder_unref(builder);
+
+       rv = netconfig_invoke_dbus_method_nonblock(CLATD_SERVICE, CLATD_PATH,
+                       CLATD_INTERFACE, "Start", g_variant_new("(@a{is})", params), __netconfig_clatd_async_callback);
+
+       if (!rv) {
+               DBG("Failed to dbus call");
+               g_variant_unref(params);
 
-       if (rv < 0) {
-               DBG("Failed to enable clatd process %d", rv);
+               int idx;
+               for (idx = 0; idx < MAX_DNS; idx++)
+                       g_free(hint.nameserver[idx]);
                return -1;
        }
 
-       DBG("Successfully enabled clatd process with %s interface", g_ifname);
+       g_is_running = TRUE;
+       DBG("clatd enabled[%d]", g_is_running);
+       int idx;
+       for (idx = 0; idx < MAX_DNS; idx++)
+               g_free(hint.nameserver[idx]);
        return 0;
 }
 
 int netconfig_clatd_disable(void)
 {
-       int rv = 0;
+       DBG("");
+       gboolean rv = FALSE;
 
-       const char *path = KILLALL_EXEC_PATH;
-       char *const args[] = { "/usr/bin/kill -15", "clatd", NULL };
-       char *const envs[] = { NULL };
-
-       if (g_ifname[0] == '\0') {
-               DBG("There is no clatd process");
-               return -1;
+       if (!g_is_running) {
+               ERR("clatd is already DISABLED");
+               return 0;
        }
 
-       memset(g_ifname, 0, sizeof(g_ifname));
-
-       rv = netconfig_execute_file(path, args, envs);
-
-       if (rv < 0) {
-               DBG("Failed to disable clatd process %d", rv);
+       rv = netconfig_invoke_dbus_method_nonblock(CLATD_SERVICE, CLATD_PATH,
+                       CLATD_INTERFACE, "Stop", NULL, NULL);
+       g_is_running = FALSE;
+       DBG("clatd disabled[%d]", g_is_running);
+       if (!rv) {
+               DBG("Failed to dbus call");
                return -1;
        }
 
-       DBG("Successfully disable clatd process");;
        return 0;
 }
index 428550c..84de50a 100755 (executable)
@@ -38,6 +38,7 @@
 #include "network-dpm.h"
 #include "network-monitor.h"
 #include "netsupplicant.h"
+#include "clatd-handler.h"
 #if defined TIZEN_DEBUG_ENABLE
 #include "network-dump.h"
 #endif
@@ -792,6 +793,9 @@ static void __netconfig_update_default_connection_info(void)
 
                DBG("Successfully clear IP and PROXY up");
 
+               /* Try to disable CLATD if it was enabled */
+               DBG("Disable clatd");
+               netconfig_clatd_disable();
        } else if (profile != NULL) {
                char *old_ip = vconf_get_str(VCONFKEY_NETWORK_IP);
                char *old_ip6 = vconf_get_str(VCONFKEY_NETWORK_IP6);
@@ -828,6 +832,11 @@ static void __netconfig_update_default_connection_info(void)
 
                        netconfig_set_system_event(SYS_EVT_NETWORK_STATUS,
                                EKEY_NETWORK_STATUS, EVAL_NETWORK_CELLULAR);
+                       /* Enable clatd if IPv6 is set and no IPv4 address */
+                       if (!ip_addr && ip_addr6) {
+                               DBG("Enable clatd");
+                               netconfig_clatd_enable();
+                       }
                } else if (netconfig_is_ethernet_profile(profile) == TRUE) {
                        netconfig_set_vconf_int(VCONFKEY_NETWORK_STATUS,
                                                                        VCONFKEY_NETWORK_ETHERNET);
@@ -1571,3 +1580,118 @@ void state_object_deinit(void)
        g_object_unref(tcpdump_object);
 #endif
 }
+
+static gboolean __netconfig_check_ipv6_address(const char *address)
+{
+       unsigned char buf[sizeof(struct in6_addr)];
+       int err;
+
+       if (!address)
+               return FALSE;
+
+       err = inet_pton(AF_INET6, address, buf);
+       if (err > 0)
+               return TRUE;
+
+       return FALSE;
+}
+
+char *netconfig_get_connected_cellular_internet_ipv6only_profile(struct clatd_ctrl_hint *hint)
+{
+       GVariant *message = NULL;
+       GVariantIter *iter = NULL;
+       GVariantIter *next = NULL;
+       gchar *cellular_internet_profile = NULL;
+       gchar *object_path = NULL;
+
+       message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
+                       CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
+                       "GetServices", NULL);
+       if (message == NULL) {
+               ERR("Failed to get profiles");
+               return NULL;
+       }
+
+       g_variant_get(message, "(a(oa{sv}))", &iter);
+       while (g_variant_iter_loop(iter, "(oa{sv})", &object_path, &next)) {
+               if (object_path == NULL)
+                       continue;
+
+               if (netconfig_is_cellular_profile(object_path) == FALSE)
+                       continue;
+
+               if (netconfig_is_cellular_internet_profile(object_path) == FALSE)
+                       continue;
+
+               if (__netconfig_is_connected(next) == TRUE) {
+                       DBG("found connected profiles");
+                       gchar *key = NULL;
+                       gboolean has_v4 = FALSE, has_v6 = FALSE;
+
+                       GVariant *variant = NULL;
+                       while (g_variant_iter_loop(next, "{sv}", &key, &variant)) {
+                               if (g_strcmp0(key, "IPv4") == 0) {
+                                       GVariantIter *ipv4_iter = NULL;
+                                       GVariant *ipv4_variant = NULL;
+                                       gchar *ipv4_key = NULL;
+                                       const gchar *ipv4_value = NULL;
+                                       g_variant_get(variant, "a{sv}", &ipv4_iter);
+                                       while (g_variant_iter_loop(ipv4_iter, "{sv}",
+                                               &ipv4_key, &ipv4_variant)) {
+                                               if (g_strcmp0(ipv4_key, "Address") == 0) {
+                                                       ipv4_value = g_variant_get_string(ipv4_variant, NULL);
+                                                       DBG("ipv4: %s", ipv4_value);
+                                                       has_v4 = TRUE;
+                                               }
+                                       }
+                                       g_variant_iter_free (ipv4_iter);
+                               } else if (g_strcmp0(key, "IPv6") == 0) {
+                                       GVariantIter *ipv6_iter = NULL;
+                                       GVariant *ipv6_variant = NULL;
+                                       gchar *ipv6_key = NULL;
+                                       const gchar *ipv6_value = NULL;
+                                       g_variant_get(variant, "a{sv}", &ipv6_iter);
+                                       while (g_variant_iter_loop(ipv6_iter, "{sv}",
+                                               &ipv6_key, &ipv6_variant)) {
+                                               if (g_strcmp0(ipv6_key, "Address") == 0) {
+                                                       ipv6_value = g_variant_get_string(ipv6_variant, NULL);
+                                                       DBG("ipv6: %s", ipv6_value);
+                                                       has_v6 = TRUE;
+                                               }
+                                       }
+                                       g_variant_iter_free (ipv6_iter);
+                               } else if (hint && g_strcmp0(key, "Nameservers") == 0) {
+                                       int idx = 0;
+                                       GVariantIter *ns_iter = NULL;
+                                       gchar *nameserver = NULL;
+                                       g_variant_get(variant, "as", &ns_iter);
+                                       while(g_variant_iter_loop(ns_iter, "s", &nameserver)) {
+                                               INFO("nameserver[%d]: %s", idx, nameserver);
+                                               if (idx >= MAX_DNS) {
+                                                       INFO("index exceeded %d -- skip", idx);
+                                                       continue;
+                                               }
+                                               if (__netconfig_check_ipv6_address(nameserver) == TRUE) {
+                                                       hint->nameserver[idx] = g_strdup(nameserver);
+                                                       idx++;
+                                               } else {
+                                                       INFO("malformed address %s -- skip", nameserver);
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (!has_v4 && has_v6) {
+                               DBG("found 'ipv6-only/connected/internet cellular profile'");
+                               cellular_internet_profile = g_strdup(object_path);
+                               g_free(object_path);
+                               g_variant_iter_free(next);
+                               break;
+                       }
+               }
+       }
+       g_variant_iter_free(iter);
+       g_variant_unref(message);
+
+       return cellular_internet_profile;
+}
index d653171..9a57730 100755 (executable)
@@ -41,6 +41,7 @@
 #include "wifi-tdls.h"
 #include "ip-conflict-detect.h"
 #include "wifi-key-encryption.h"
+#include "clatd-handler.h"
 #if defined TIZEN_DEBUG_ENABLE
 #include "network-dump.h"
 #define NETWORK_LOG_DUMP_SCRIPT  "/opt/var/lib/net-config/network_log_dump.sh"
@@ -310,6 +311,7 @@ static void _service_signal_cb(GDBusConnection *conn,
        GVariantIter *iter;
        const gchar *value = NULL;
        struct sock_data *sd = NULL;
+       gchar *pf = NULL;
        int idx = 0;
 
        if (path == NULL || param == NULL)
@@ -403,6 +405,16 @@ static void _service_signal_cb(GDBusConnection *conn,
                                                if (netconfig_is_cellular_internet_profile(path))
                                                        netconfig_update_default_profile(path);
                                        }
+                               } else {
+                                       pf = netconfig_get_connected_cellular_internet_ipv6only_profile(NULL);
+                                       if (pf)
+                                       {
+                                               g_free(pf);
+
+                                               /* Enable clatd if it is not in running state */
+                                               DBG("Connected to ipv6 only cellular, enable clatd");
+                                               netconfig_clatd_enable();
+                                       }
                                }
 
                                if (netconfig_is_cellular_profile(path) && netconfig_is_cellular_internet_profile(path))
@@ -414,9 +426,14 @@ static void _service_signal_cb(GDBusConnection *conn,
                                        goto done;
                                }
 
-                               if (netconfig_is_cellular_profile(path) && netconfig_is_cellular_internet_profile(path))
+                               if (netconfig_is_cellular_profile(path) && netconfig_is_cellular_internet_profile(path)) {
                                        cellular_state_set_service_state(NETCONFIG_CELLULAR_IDLE);
 
+                                       /* Disable clatd if it is in running state */
+                                       DBG("disable clatd");
+                                       netconfig_clatd_disable();
+                               }
+
                                if (g_strcmp0(path, netconfig_get_default_profile()) != 0) {
                                        g_free(property);
                                        goto done;