Update routing table when default address is reset
[platform/upstream/connman.git] / src / connection.c
old mode 100644 (file)
new mode 100755 (executable)
index 712a4be..c18701a
@@ -2,8 +2,8 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
- *  Copyright (C) 2011  BMW Car IT GmbH. All rights reserved.
+ *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2011-2014  BMW Car IT GmbH.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
 #include "connman.h"
 
 struct gateway_config {
-       gboolean active;
+       bool active;
        char *gateway;
 
        /* VPN extra data */
-       gboolean vpn;
+       bool vpn;
        char *vpn_ip;
        int vpn_phy_index;
        char *vpn_phy_ip;
@@ -46,10 +46,9 @@ struct gateway_config {
 struct gateway_data {
        int index;
        struct connman_service *service;
-       unsigned int order;
        struct gateway_config *ipv4_gateway;
        struct gateway_config *ipv6_gateway;
-       connman_bool_t default_checked;
+       bool default_checked;
 };
 
 static GHashTable *gateway_hash = NULL;
@@ -59,22 +58,22 @@ static struct gateway_config *find_gateway(int index, const char *gateway)
        GHashTableIter iter;
        gpointer value, key;
 
-       if (gateway == NULL)
+       if (!gateway)
                return NULL;
 
        g_hash_table_iter_init(&iter, gateway_hash);
 
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct gateway_data *data = value;
 
-               if (data->ipv4_gateway != NULL && data->index == index &&
+               if (data->ipv4_gateway && data->index == index &&
                                g_str_equal(data->ipv4_gateway->gateway,
-                                       gateway) == TRUE)
+                                       gateway))
                        return data->ipv4_gateway;
 
-               if (data->ipv6_gateway != NULL && data->index == index &&
+               if (data->ipv6_gateway && data->index == index &&
                                g_str_equal(data->ipv6_gateway->gateway,
-                                       gateway) == TRUE)
+                                       gateway))
                        return data->ipv6_gateway;
        }
 
@@ -86,19 +85,19 @@ static struct gateway_data *lookup_gateway_data(struct gateway_config *config)
        GHashTableIter iter;
        gpointer value, key;
 
-       if (config == NULL)
+       if (!config)
                return NULL;
 
        g_hash_table_iter_init(&iter, gateway_hash);
 
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct gateway_data *data = value;
 
-               if (data->ipv4_gateway != NULL &&
+               if (data->ipv4_gateway &&
                                data->ipv4_gateway == config)
                        return data;
 
-               if (data->ipv6_gateway != NULL &&
+               if (data->ipv6_gateway &&
                                data->ipv6_gateway == config)
                        return data;
        }
@@ -106,105 +105,192 @@ static struct gateway_data *lookup_gateway_data(struct gateway_config *config)
        return NULL;
 }
 
-/*
- * Find the gateway that is serving the VPN link
- */
-static struct gateway_data *find_phy_gateway(int index, const char *gateway)
+static struct gateway_data *find_vpn_gateway(int index, const char *gateway)
 {
        GHashTableIter iter;
        gpointer value, key;
 
-       if (gateway == NULL)
+       if (!gateway)
                return NULL;
 
        g_hash_table_iter_init(&iter, gateway_hash);
 
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct gateway_data *data = value;
 
-               if (data->ipv4_gateway != NULL && data->index != index &&
+               if (data->ipv4_gateway && data->index == index &&
                                g_str_equal(data->ipv4_gateway->gateway,
-                                       gateway) == TRUE)
+                                       gateway))
                        return data;
 
-               if (data->ipv6_gateway != NULL && data->index != index &&
+               if (data->ipv6_gateway && data->index == index &&
                                g_str_equal(data->ipv6_gateway->gateway,
-                                       gateway) == TRUE)
+                                       gateway))
                        return data;
        }
 
        return NULL;
 }
 
-static void set_vpn_routes(struct gateway_config *config,
+struct get_gateway_params {
+       char *vpn_gateway;
+       int vpn_index;
+};
+
+static void get_gateway_cb(const char *gateway, int index, void *user_data)
+{
+       struct gateway_config *config;
+       struct gateway_data *data;
+       struct get_gateway_params *params = user_data;
+       int family;
+
+       if (index < 0)
+               goto out;
+
+       DBG("phy index %d phy gw %s vpn index %d vpn gw %s", index, gateway,
+               params->vpn_index, params->vpn_gateway);
+
+       data = find_vpn_gateway(params->vpn_index, params->vpn_gateway);
+       if (!data) {
+               DBG("Cannot find VPN link route, index %d addr %s",
+                       params->vpn_index, params->vpn_gateway);
+               goto out;
+       }
+
+       family = connman_inet_check_ipaddress(params->vpn_gateway);
+
+       if (family == AF_INET)
+               config = data->ipv4_gateway;
+       else if (family == AF_INET6)
+               config = data->ipv6_gateway;
+       else
+               goto out;
+
+       config->vpn_phy_index = index;
+
+       DBG("vpn %s phy index %d", config->vpn_ip, config->vpn_phy_index);
+
+out:
+       g_free(params->vpn_gateway);
+       g_free(params);
+}
+
+static void set_vpn_routes(struct gateway_data *new_gateway,
                        struct connman_service *service,
                        const char *gateway,
                        enum connman_ipconfig_type type,
-                       const char *peer)
+                       const char *peer,
+                       struct gateway_data *active_gateway)
 {
-       struct gateway_data *data;
+       struct gateway_config *config;
        struct connman_ipconfig *ipconfig;
-       int index;
+       char *dest;
 
-       config->vpn = TRUE;
-       if (peer != NULL)
-               config->vpn_ip = g_strdup(peer);
-       else if (gateway != NULL)
-               config->vpn_ip = g_strdup(gateway);
+       DBG("new %p service %p gw %s type %d peer %s active %p",
+               new_gateway, service, gateway, type, peer, active_gateway);
 
-       if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+       if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
                ipconfig = __connman_service_get_ip4config(service);
-       else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+               config = new_gateway->ipv4_gateway;
+       } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
                ipconfig = __connman_service_get_ip6config(service);
-       else
+               config = new_gateway->ipv6_gateway;
+       } else
+               return;
+
+       if (config) {
+               int index = __connman_ipconfig_get_index(ipconfig);
+               struct get_gateway_params *params;
+
+               config->vpn = true;
+               if (peer)
+                       config->vpn_ip = g_strdup(peer);
+               else if (gateway)
+                       config->vpn_ip = g_strdup(gateway);
+
+               params = g_try_malloc(sizeof(struct get_gateway_params));
+               if (!params)
+                       return;
+
+               params->vpn_index = index;
+               params->vpn_gateway = g_strdup(gateway);
+
+               /*
+                * Find the gateway that is serving the VPN link
+                */
+               __connman_inet_get_route(gateway, get_gateway_cb, params);
+       }
+
+       if (!active_gateway)
                return;
 
-       index = __connman_ipconfig_get_index(ipconfig);
-       data = find_phy_gateway(index, gateway);
+       if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
+               /*
+                * Special route to VPN server via gateway. This
+                * is needed so that we can access hosts behind
+                * the VPN. The route might already exist depending
+                * on network topology.
+                */
+               if (!active_gateway->ipv4_gateway)
+                       return;
+
 
-       if (data != NULL) {
                /*
-                * data->service points now to original
-                * service that is serving the VPN link
+                * If VPN server is on same subnet as we are, skip adding
+                * route.
                 */
-               if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
-                       ipconfig =
-                               __connman_service_get_ip4config(data->service);
-               else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
-                       ipconfig =
-                               __connman_service_get_ip6config(data->service);
+               if (connman_inet_compare_subnet(active_gateway->index,
+                                                               gateway))
+                       return;
+
+               DBG("active gw %s", active_gateway->ipv4_gateway->gateway);
+
+               if (g_strcmp0(active_gateway->ipv4_gateway->gateway,
+                                                       "0.0.0.0") != 0)
+                       dest = active_gateway->ipv4_gateway->gateway;
                else
+                       dest = NULL;
+
+               connman_inet_add_host_route(active_gateway->index, gateway,
+                                                                       dest);
+
+       } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
+
+               if (!active_gateway->ipv6_gateway)
                        return;
 
-               if (ipconfig != NULL) {
-                       const char *address;
+               if (connman_inet_compare_ipv6_subnet(active_gateway->index,
+                                                               gateway))
+                       return;
 
-                       address = __connman_ipconfig_get_local(ipconfig);
-                       config->vpn_phy_ip = g_strdup(address);
-               }
+               DBG("active gw %s", active_gateway->ipv6_gateway->gateway);
 
-               config->vpn_phy_index = data->index;
-       }
+               if (g_strcmp0(active_gateway->ipv6_gateway->gateway,
+                                                               "::") != 0)
+                       dest = active_gateway->ipv6_gateway->gateway;
+               else
+                       dest = NULL;
 
-       DBG("vpn %s phy %s index %d", config->vpn_ip,
-               config->vpn_phy_ip, config->vpn_phy_index);
+               connman_inet_add_ipv6_host_route(active_gateway->index,
+                                                               gateway, dest);
+       }
 }
 
 static int del_routes(struct gateway_data *data,
                        enum connman_ipconfig_type type)
 {
        int status4 = 0, status6 = 0;
-       int do_ipv4 = FALSE, do_ipv6 = FALSE;
+       bool do_ipv4 = false, do_ipv6 = false;
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
-               do_ipv4 = TRUE;
+               do_ipv4 = true;
        else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
-               do_ipv6 = TRUE;
+               do_ipv6 = true;
        else
-               do_ipv4 = do_ipv6 = TRUE;
+               do_ipv4 = do_ipv6 = true;
 
-       if (do_ipv4 == TRUE && data->ipv4_gateway != NULL) {
-               if (data->ipv4_gateway->vpn == TRUE) {
+       if (do_ipv4 && data->ipv4_gateway) {
+               if (data->ipv4_gateway->vpn) {
                        status4 = connman_inet_clear_gateway_address(
                                                data->index,
                                                data->ipv4_gateway->vpn_ip);
@@ -222,8 +308,8 @@ static int del_routes(struct gateway_data *data,
                }
        }
 
-       if (do_ipv6 == TRUE && data->ipv6_gateway != NULL) {
-               if (data->ipv6_gateway->vpn == TRUE) {
+       if (do_ipv6 && data->ipv6_gateway) {
+               if (data->ipv6_gateway->vpn) {
                        status6 = connman_inet_clear_ipv6_gateway_address(
                                                data->index,
                                                data->ipv6_gateway->vpn_ip);
@@ -246,20 +332,20 @@ static int del_routes(struct gateway_data *data,
 static int disable_gateway(struct gateway_data *data,
                        enum connman_ipconfig_type type)
 {
-       gboolean active = FALSE;
+       bool active = false;
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
-               if (data->ipv4_gateway != NULL)
+               if (data->ipv4_gateway)
                        active = data->ipv4_gateway->active;
        } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
-               if (data->ipv6_gateway != NULL)
+               if (data->ipv6_gateway)
                        active = data->ipv6_gateway->active;
        } else
-               active = TRUE;
+               active = true;
 
        DBG("type %d active %d", type, active);
 
-       if (active == TRUE)
+       if (active)
                return del_routes(data, type);
 
        return 0;
@@ -272,17 +358,17 @@ static struct gateway_data *add_gateway(struct connman_service *service,
        struct gateway_data *data, *old;
        struct gateway_config *config;
 
-       if (gateway == NULL || strlen(gateway) == 0)
+       if (!gateway || strlen(gateway) == 0)
                return NULL;
 
        data = g_try_new0(struct gateway_data, 1);
-       if (data == NULL)
+       if (!data)
                return NULL;
 
        data->index = index;
 
        config = g_try_new0(struct gateway_config, 1);
-       if (config == NULL) {
+       if (!config) {
                g_free(data);
                return NULL;
        }
@@ -290,9 +376,9 @@ static struct gateway_data *add_gateway(struct connman_service *service,
        config->gateway = g_strdup(gateway);
        config->vpn_ip = NULL;
        config->vpn_phy_ip = NULL;
-       config->vpn = FALSE;
+       config->vpn = false;
        config->vpn_phy_index = -1;
-       config->active = FALSE;
+       config->active = false;
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
                data->ipv4_gateway = config;
@@ -307,8 +393,6 @@ static struct gateway_data *add_gateway(struct connman_service *service,
 
        data->service = service;
 
-       data->order = __connman_service_get_order(service);
-
        /*
         * If the service is already in the hash, then we
         * must not replace it blindly but disable the gateway
@@ -316,7 +400,7 @@ static struct gateway_data *add_gateway(struct connman_service *service,
         * from old gateway settings.
         */
        old = g_hash_table_lookup(gateway_hash, service);
-       if (old != NULL) {
+       if (old) {
                DBG("Replacing gw %p ipv4 %p ipv6 %p", old,
                        old->ipv4_gateway, old->ipv6_gateway);
                disable_gateway(old, type);
@@ -327,13 +411,9 @@ static struct gateway_data *add_gateway(struct connman_service *service,
                        data->ipv4_gateway = old->ipv4_gateway;
                        old->ipv4_gateway = NULL;
                }
-       } else {
-               /*
-                * Only take a ref if we are adding new stuff to hash.
-                */
-               connman_service_ref(service);
        }
 
+       connman_service_ref(data->service);
        g_hash_table_replace(gateway_hash, service, data);
 
        return data;
@@ -344,25 +424,22 @@ static void set_default_gateway(struct gateway_data *data,
 {
        int index;
        int status4 = 0, status6 = 0;
-       int do_ipv4 = FALSE, do_ipv6 = FALSE;
+       bool do_ipv4 = false, do_ipv6 = false;
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
-               do_ipv4 = TRUE;
+               do_ipv4 = true;
        else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
-               do_ipv6 = TRUE;
+               do_ipv6 = true;
        else
-               do_ipv4 = do_ipv6 = TRUE;
+               do_ipv4 = do_ipv6 = true;
 
        DBG("type %d gateway ipv4 %p ipv6 %p", type, data->ipv4_gateway,
                                                data->ipv6_gateway);
 
-       if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
-                                       data->ipv4_gateway->vpn == TRUE) {
-               connman_inet_set_gateway_address(data->index,
-                                               data->ipv4_gateway->vpn_ip);
-               connman_inet_add_host_route(data->index,
-                                       data->ipv4_gateway->vpn_ip, NULL);
-               data->ipv4_gateway->active = TRUE;
+       if (do_ipv4 && data->ipv4_gateway &&
+                                       data->ipv4_gateway->vpn) {
+               connman_inet_set_gateway_interface(data->index);
+               data->ipv4_gateway->active = true;
 
                DBG("set %p index %d vpn %s index %d phy %s",
                        data, data->index, data->ipv4_gateway->vpn_ip,
@@ -374,13 +451,10 @@ static void set_default_gateway(struct gateway_data *data,
                return;
        }
 
-       if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
-                                       data->ipv6_gateway->vpn == TRUE) {
-               connman_inet_set_ipv6_gateway_address(data->index,
-                                               data->ipv6_gateway->vpn_ip);
-               connman_inet_add_ipv6_host_route(data->index,
-                                       data->ipv6_gateway->vpn_ip, NULL);
-               data->ipv6_gateway->active = TRUE;
+       if (do_ipv6 && data->ipv6_gateway &&
+                                       data->ipv6_gateway->vpn) {
+               connman_inet_set_ipv6_gateway_interface(data->index);
+               data->ipv6_gateway->active = true;
 
                DBG("set %p index %d vpn %s index %d phy %s",
                        data, data->index, data->ipv6_gateway->vpn_ip,
@@ -394,29 +468,31 @@ static void set_default_gateway(struct gateway_data *data,
 
        index = __connman_service_get_index(data->service);
 
-       if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
+       if (do_ipv4 && data->ipv4_gateway &&
                        g_strcmp0(data->ipv4_gateway->gateway,
                                                        "0.0.0.0") == 0) {
                if (connman_inet_set_gateway_interface(index) < 0)
                        return;
+               data->ipv4_gateway->active = true;
                goto done;
        }
 
-       if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
+       if (do_ipv6 && data->ipv6_gateway &&
                        g_strcmp0(data->ipv6_gateway->gateway,
                                                        "::") == 0) {
                if (connman_inet_set_ipv6_gateway_interface(index) < 0)
                        return;
+               data->ipv6_gateway->active = true;
                goto done;
        }
 
-       if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
-               status6 = connman_inet_set_ipv6_gateway_address(index,
-                                               data->ipv6_gateway->gateway);
+       if (do_ipv6 && data->ipv6_gateway)
+               status6 = __connman_inet_add_default_to_table(RT_TABLE_MAIN,
+                                       index, data->ipv6_gateway->gateway);
 
-       if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
-               status4 = connman_inet_set_gateway_address(index,
-                                               data->ipv4_gateway->gateway);
+       if (do_ipv4 && data->ipv4_gateway)
+               status4 = __connman_inet_add_default_to_table(RT_TABLE_MAIN,
+                                       index, data->ipv4_gateway->gateway);
 
        if (status4 < 0 || status6 < 0)
                return;
@@ -429,25 +505,22 @@ static void unset_default_gateway(struct gateway_data *data,
                                enum connman_ipconfig_type type)
 {
        int index;
-       int do_ipv4 = FALSE, do_ipv6 = FALSE;
+       bool do_ipv4 = false, do_ipv6 = false;
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
-               do_ipv4 = TRUE;
+               do_ipv4 = true;
        else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
-               do_ipv6 = TRUE;
+               do_ipv6 = true;
        else
-               do_ipv4 = do_ipv6 = TRUE;
+               do_ipv4 = do_ipv6 = true;
 
        DBG("type %d gateway ipv4 %p ipv6 %p", type, data->ipv4_gateway,
                                                data->ipv6_gateway);
 
-       if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
-                                       data->ipv4_gateway->vpn == TRUE) {
-               connman_inet_del_host_route(data->index,
-                                               data->ipv4_gateway->vpn_ip);
-               connman_inet_clear_gateway_address(data->index,
-                                               data->ipv4_gateway->vpn_ip);
-               data->ipv4_gateway->active = FALSE;
+       if (do_ipv4 && data->ipv4_gateway &&
+                                       data->ipv4_gateway->vpn) {
+               connman_inet_clear_gateway_interface(data->index);
+               data->ipv4_gateway->active = false;
 
                DBG("unset %p index %d vpn %s index %d phy %s",
                        data, data->index, data->ipv4_gateway->vpn_ip,
@@ -457,13 +530,10 @@ static void unset_default_gateway(struct gateway_data *data,
                return;
        }
 
-       if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
-                                       data->ipv6_gateway->vpn == TRUE) {
-               connman_inet_del_ipv6_host_route(data->index,
-                                               data->ipv6_gateway->vpn_ip);
-               connman_inet_clear_ipv6_gateway_address(data->index,
-                                               data->ipv6_gateway->vpn_ip);
-               data->ipv6_gateway->active = FALSE;
+       if (do_ipv6 && data->ipv6_gateway &&
+                                       data->ipv6_gateway->vpn) {
+               connman_inet_clear_ipv6_gateway_interface(data->index);
+               data->ipv6_gateway->active = false;
 
                DBG("unset %p index %d vpn %s index %d phy %s",
                        data, data->index, data->ipv6_gateway->vpn_ip,
@@ -475,94 +545,82 @@ static void unset_default_gateway(struct gateway_data *data,
 
        index = __connman_service_get_index(data->service);
 
-       if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
+       if (do_ipv4 && data->ipv4_gateway &&
                        g_strcmp0(data->ipv4_gateway->gateway,
                                                        "0.0.0.0") == 0) {
                connman_inet_clear_gateway_interface(index);
+               data->ipv4_gateway->active = false;
                return;
        }
 
-       if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
+       if (do_ipv6 && data->ipv6_gateway &&
                        g_strcmp0(data->ipv6_gateway->gateway,
                                                        "::") == 0) {
                connman_inet_clear_ipv6_gateway_interface(index);
+               data->ipv6_gateway->active = false;
                return;
        }
 
-       if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
+       if (do_ipv6 && data->ipv6_gateway)
                connman_inet_clear_ipv6_gateway_address(index,
                                                data->ipv6_gateway->gateway);
 
-       if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
+       if (do_ipv4 && data->ipv4_gateway)
                connman_inet_clear_gateway_address(index,
                                                data->ipv4_gateway->gateway);
 }
 
 static struct gateway_data *find_default_gateway(void)
 {
-       struct gateway_data *found = NULL;
-       unsigned int order = 0;
-       GHashTableIter iter;
-       gpointer value, key;
-
-       g_hash_table_iter_init(&iter, gateway_hash);
-
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
-               struct gateway_data *data = value;
-
-               if (found == NULL || data->order > order) {
-                       found = data;
-                       order = data->order;
+       struct connman_service *service;
 
-                       DBG("default %p order %d", found, order);
-               }
-       }
+       service = connman_service_get_default();
+       if (!service)
+               return NULL;
 
-       return found;
+       return g_hash_table_lookup(gateway_hash, service);
 }
 
-static gboolean choose_default_gateway(struct gateway_data *data,
+static bool choose_default_gateway(struct gateway_data *data,
                                        struct gateway_data *candidate)
 {
-       gboolean downgraded = FALSE;
+       bool downgraded = false;
 
        /*
         * If the current default is not active, then we mark
         * this one as default. If the other one is already active
         * we mark this one as non default.
         */
-       if (data->ipv4_gateway != NULL) {
-               if (candidate->ipv4_gateway != NULL &&
-                               candidate->ipv4_gateway->active == FALSE) {
+       if (data->ipv4_gateway && candidate->ipv4_gateway) {
+
+               if (!candidate->ipv4_gateway->active) {
                        DBG("ipv4 downgrading %p", candidate);
                        unset_default_gateway(candidate,
                                                CONNMAN_IPCONFIG_TYPE_IPV4);
                }
-               if (candidate->ipv4_gateway != NULL &&
-                               candidate->ipv4_gateway->active == TRUE &&
-                               candidate->order > data->order) {
+
+               if (candidate->ipv4_gateway->active &&
+                               __connman_service_compare(candidate->service,
+                                                       data->service) < 0) {
                        DBG("ipv4 downgrading this %p", data);
-                       unset_default_gateway(data,
-                                               CONNMAN_IPCONFIG_TYPE_IPV4);
-                       downgraded = TRUE;
+                       unset_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV4);
+                       downgraded = true;
                }
        }
 
-       if (data->ipv6_gateway != NULL) {
-               if (candidate->ipv6_gateway != NULL &&
-                               candidate->ipv6_gateway->active == FALSE) {
+       if (data->ipv6_gateway && candidate->ipv6_gateway) {
+               if (!candidate->ipv6_gateway->active) {
                        DBG("ipv6 downgrading %p", candidate);
                        unset_default_gateway(candidate,
                                                CONNMAN_IPCONFIG_TYPE_IPV6);
                }
 
-               if (candidate->ipv6_gateway != NULL &&
-                               candidate->ipv6_gateway->active == TRUE &&
-                               candidate->order > data->order) {
+               if (candidate->ipv6_gateway->active &&
+                       __connman_service_compare(candidate->service,
+                                               data->service) < 0) {
                        DBG("ipv6 downgrading this %p", data);
-                       unset_default_gateway(data,
-                                               CONNMAN_IPCONFIG_TYPE_IPV6);
-                       downgraded = TRUE;
+                       unset_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV6);
+                       downgraded = true;
                }
        }
 
@@ -575,15 +633,15 @@ static void connection_newgateway(int index, const char *gateway)
        struct gateway_data *data;
        GHashTableIter iter;
        gpointer value, key;
-       gboolean found = FALSE;
+       bool found = false;
 
        DBG("index %d gateway %s", index, gateway);
 
        config = find_gateway(index, gateway);
-       if (config == NULL)
+       if (!config)
                return;
 
-       config->active = TRUE;
+       config->active = true;
 
        /*
         * It is possible that we have two default routes atm
@@ -591,10 +649,10 @@ static void connection_newgateway(int index, const char *gateway)
         * same time.
         */
        data = lookup_gateway_data(config);
-       if (data == NULL)
+       if (!data)
                return;
 
-       if (data->default_checked == TRUE)
+       if (data->default_checked)
                return;
 
        /*
@@ -604,26 +662,33 @@ static void connection_newgateway(int index, const char *gateway)
 
        g_hash_table_iter_init(&iter, gateway_hash);
 
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct gateway_data *candidate = value;
 
                if (candidate == data)
                        continue;
 
                found = choose_default_gateway(data, candidate);
-               if (found == TRUE)
+               if (found)
                        break;
        }
 
-       if (found == FALSE) {
-               if (data->ipv4_gateway != NULL)
+       if (!found) {
+#if defined TIZEN_EXT
+               if (data->ipv4_gateway != NULL){
+                       set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV4);
+                       connman_check_proxy_setup_and_wispr_start(data->service);
+               }
+#else
+               if (data->ipv4_gateway)
                        set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV4);
+#endif
 
-               if (data->ipv6_gateway != NULL)
+               if (data->ipv6_gateway)
                        set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV6);
        }
 
-       data->default_checked = TRUE;
+       data->default_checked = true;
 }
 
 static void remove_gateway(gpointer user_data)
@@ -632,20 +697,22 @@ static void remove_gateway(gpointer user_data)
 
        DBG("gateway ipv4 %p ipv6 %p", data->ipv4_gateway, data->ipv6_gateway);
 
-       if (data->ipv4_gateway != NULL) {
+       if (data->ipv4_gateway) {
                g_free(data->ipv4_gateway->gateway);
                g_free(data->ipv4_gateway->vpn_ip);
                g_free(data->ipv4_gateway->vpn_phy_ip);
                g_free(data->ipv4_gateway);
        }
 
-       if (data->ipv6_gateway != NULL) {
+       if (data->ipv6_gateway) {
                g_free(data->ipv6_gateway->gateway);
                g_free(data->ipv6_gateway->vpn_ip);
                g_free(data->ipv6_gateway->vpn_phy_ip);
                g_free(data->ipv6_gateway);
        }
 
+       connman_service_unref(data->service);
+
        g_free(data);
 }
 
@@ -657,11 +724,11 @@ static void connection_delgateway(int index, const char *gateway)
        DBG("index %d gateway %s", index, gateway);
 
        config = find_gateway(index, gateway);
-       if (config != NULL)
-               config->active = FALSE;
+       if (config)
+               config->active = false;
 
        data = find_default_gateway();
-       if (data != NULL)
+       if (data)
                set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
 }
 
@@ -680,55 +747,21 @@ static struct gateway_data *find_active_gateway(void)
 
        g_hash_table_iter_init(&iter, gateway_hash);
 
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct gateway_data *data = value;
 
-               if (data->ipv4_gateway != NULL &&
-                               data->ipv4_gateway->active == TRUE)
+               if (data->ipv4_gateway &&
+                               data->ipv4_gateway->active)
                        return data;
 
-               if (data->ipv6_gateway != NULL &&
-                               data->ipv6_gateway->active == TRUE)
+               if (data->ipv6_gateway &&
+                               data->ipv6_gateway->active)
                        return data;
        }
 
        return NULL;
 }
 
-static void update_order(void)
-{
-       GHashTableIter iter;
-       gpointer value, key;
-
-       DBG("");
-
-       g_hash_table_iter_init(&iter, gateway_hash);
-
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
-               struct gateway_data *data = value;
-
-               data->order = __connman_service_get_order(data->service);
-       }
-}
-
-void __connman_connection_gateway_activate(struct connman_service *service,
-                                       enum connman_ipconfig_type type)
-{
-       struct gateway_data *data = NULL;
-
-       data = g_hash_table_lookup(gateway_hash, service);
-       if (data == NULL)
-               return;
-
-       DBG("gateway %p/%p type %d", data->ipv4_gateway,
-                                       data->ipv6_gateway, type);
-
-       if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
-               data->ipv4_gateway->active = TRUE;
-       else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
-               data->ipv6_gateway->active = TRUE;
-}
-
 static void add_host_route(int family, int index, const char *gateway,
                        enum connman_service_type service_type)
 {
@@ -777,6 +810,32 @@ static void add_host_route(int family, int index, const char *gateway,
        }
 }
 
+#if defined TIZEN_EXT
+static bool __connman_service_is_not_cellular_internet_profile(
+               struct connman_service *cellular)
+{
+       char *suffix;
+       const char *path;
+       const char internet_suffix[] = "_1";
+       const char prepaid_internet_suffix[] = "_3";
+
+       if (connman_service_get_type(cellular) != CONNMAN_SERVICE_TYPE_CELLULAR)
+               return FALSE;
+
+       path = __connman_service_get_path(cellular);
+
+       suffix = strrchr(path, '_');
+
+       if (g_strcmp0(suffix, internet_suffix) != 0 &&
+                       g_strcmp0(suffix, prepaid_internet_suffix) != 0) {
+               DBG("not internet service profile: %s", path);
+               return TRUE;
+       }
+
+       return FALSE;
+}
+#endif
+
 int __connman_connection_gateway_add(struct connman_service *service,
                                        const char *gateway,
                                        enum connman_ipconfig_type type,
@@ -797,17 +856,39 @@ int __connman_connection_gateway_add(struct connman_service *service,
         * gateway for ipv4 is 0.0.0.0 and for ipv6 is ::, meaning the
         * interface
         */
-       if (gateway == NULL && type == CONNMAN_IPCONFIG_TYPE_IPV4)
+       if (!gateway && type == CONNMAN_IPCONFIG_TYPE_IPV4)
                gateway = "0.0.0.0";
 
-       if (gateway == NULL && type == CONNMAN_IPCONFIG_TYPE_IPV6)
+       if (!gateway && type == CONNMAN_IPCONFIG_TYPE_IPV6)
                gateway = "::";
 
+#if defined TIZEN_EXT
+       if (__connman_service_is_not_cellular_internet_profile(service) == TRUE) {
+               /* not internet service should not be default gateway */
+
+               DBG("no internet service %p index %d gateway %s vpn ip %s type %d",
+                       service, index, gateway, peer, type);
+
+               if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
+                       add_host_route(AF_INET, index, gateway, service_type);
+                       __connman_service_nameserver_add_routes(service, gateway);
+                       type4 = CONNMAN_IPCONFIG_TYPE_IPV4;
+               }
+
+               if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
+                       add_host_route(AF_INET6, index, gateway, service_type);
+                       __connman_service_nameserver_add_routes(service, gateway);
+                       type6 = CONNMAN_IPCONFIG_TYPE_IPV6;
+               }
+
+               goto done;
+       }
+#endif
        DBG("service %p index %d gateway %s vpn ip %s type %d",
                service, index, gateway, peer, type);
 
        new_gateway = add_gateway(service, index, gateway, type);
-       if (new_gateway == NULL)
+       if (!new_gateway)
                return -EINVAL;
 
        active_gateway = find_active_gateway();
@@ -816,7 +897,7 @@ int __connman_connection_gateway_add(struct connman_service *service,
                active_gateway ? active_gateway->index : -1, new_gateway);
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
-                               new_gateway->ipv4_gateway != NULL) {
+                               new_gateway->ipv4_gateway) {
                add_host_route(AF_INET, index, gateway, service_type);
                __connman_service_nameserver_add_routes(service,
                                        new_gateway->ipv4_gateway->gateway);
@@ -824,7 +905,7 @@ int __connman_connection_gateway_add(struct connman_service *service,
        }
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
-                               new_gateway->ipv6_gateway != NULL) {
+                               new_gateway->ipv6_gateway) {
                add_host_route(AF_INET6, index, gateway, service_type);
                __connman_service_nameserver_add_routes(service,
                                        new_gateway->ipv6_gateway->gateway);
@@ -832,73 +913,44 @@ int __connman_connection_gateway_add(struct connman_service *service,
        }
 
        if (service_type == CONNMAN_SERVICE_TYPE_VPN) {
-               char *dest;
-
-               if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
-                       if (new_gateway->ipv4_gateway != NULL)
-                               set_vpn_routes(new_gateway->ipv4_gateway,
-                                       service, gateway, type, peer);
-
-                       /*
-                        * Special route to VPN server via gateway. This
-                        * is needed so that we can access hosts behind
-                        * the VPN. The route might already exist depending
-                        * on network topology.
-                        */
-                       if (g_strcmp0(active_gateway->ipv4_gateway->gateway, "0.0.0.0") != 0)
-                               dest = active_gateway->ipv4_gateway->gateway;
-                       else
-                               dest = NULL;
-
-                       connman_inet_add_host_route(active_gateway->index,
-                                       gateway,
-                                       dest);
 
-               } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
-                       if (new_gateway->ipv6_gateway != NULL)
-                               set_vpn_routes(new_gateway->ipv6_gateway,
-                                       service, gateway, type, peer);
-
-                       if (g_strcmp0(active_gateway->ipv6_gateway->gateway, "::") != 0)
-                               dest = active_gateway->ipv6_gateway->gateway;
-                       else
-                               dest = NULL;
-
-                       connman_inet_add_ipv6_host_route(active_gateway->index,
-                                       gateway,
-                                       dest);
-               }
+               set_vpn_routes(new_gateway, service, gateway, type, peer,
+                                                       active_gateway);
 
        } else {
                if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
-                                       new_gateway->ipv4_gateway != NULL)
-                       new_gateway->ipv4_gateway->vpn = FALSE;
+                                       new_gateway->ipv4_gateway)
+                       new_gateway->ipv4_gateway->vpn = false;
 
                if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
-                                       new_gateway->ipv6_gateway != NULL)
-                       new_gateway->ipv6_gateway->vpn = FALSE;
+                                       new_gateway->ipv6_gateway)
+                       new_gateway->ipv6_gateway->vpn = false;
        }
 
-       if (active_gateway == NULL) {
+       if (!active_gateway) {
+#if defined TIZEN_EXT
+               if(new_gateway->ipv4_gateway)
+                       DBG("ConnMan, Set default gateway[%s], active[%d]",
+                               new_gateway->ipv4_gateway->gateway,
+                               new_gateway->ipv4_gateway->active);
+#endif
                set_default_gateway(new_gateway, type);
                goto done;
        }
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
-                               new_gateway->ipv4_gateway != NULL &&
-                               new_gateway->ipv4_gateway->vpn == TRUE) {
-               if (__connman_service_is_split_routing(new_gateway->service) ==
-                                                                       FALSE)
+                               new_gateway->ipv4_gateway &&
+                               new_gateway->ipv4_gateway->vpn) {
+               if (!__connman_service_is_split_routing(new_gateway->service))
                        connman_inet_clear_gateway_address(
                                        active_gateway->index,
                                        active_gateway->ipv4_gateway->gateway);
        }
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
-                               new_gateway->ipv6_gateway != NULL &&
-                               new_gateway->ipv6_gateway->vpn == TRUE) {
-               if (__connman_service_is_split_routing(new_gateway->service) ==
-                                                                       FALSE)
+                               new_gateway->ipv6_gateway &&
+                               new_gateway->ipv6_gateway->vpn) {
+               if (!__connman_service_is_split_routing(new_gateway->service))
                        connman_inet_clear_ipv6_gateway_address(
                                        active_gateway->index,
                                        active_gateway->ipv6_gateway->gateway);
@@ -921,29 +973,29 @@ void __connman_connection_gateway_remove(struct connman_service *service,
                                        enum connman_ipconfig_type type)
 {
        struct gateway_data *data = NULL;
-       gboolean set_default4 = FALSE, set_default6 = FALSE;
-       int do_ipv4 = FALSE, do_ipv6 = FALSE;
+       bool set_default4 = false, set_default6 = false;
+        bool do_ipv4 = false, do_ipv6 = false;
        int err;
 
        DBG("service %p type %d", service, type);
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
-               do_ipv4 = TRUE;
+               do_ipv4 = true;
        else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
-               do_ipv6 = TRUE;
+               do_ipv6 = true;
        else
-               do_ipv4 = do_ipv6 = TRUE;
+               do_ipv4 = do_ipv6 = true;
 
        __connman_service_nameserver_del_routes(service, type);
 
        data = g_hash_table_lookup(gateway_hash, service);
-       if (data == NULL)
+       if (!data)
                return;
 
-       if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
+       if (do_ipv4 && data->ipv4_gateway)
                set_default4 = data->ipv4_gateway->vpn;
 
-       if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
+       if (do_ipv6 && data->ipv6_gateway)
                set_default6 = data->ipv6_gateway->vpn;
 
        DBG("ipv4 gateway %s ipv6 gateway %s vpn %d/%d",
@@ -951,14 +1003,15 @@ void __connman_connection_gateway_remove(struct connman_service *service,
                data->ipv6_gateway ? data->ipv6_gateway->gateway : "<null>",
                set_default4, set_default6);
 
-       if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
-                       data->ipv4_gateway->vpn == TRUE && data->index >= 0)
-               connman_inet_del_host_route(data->index,
+       if (do_ipv4 && data->ipv4_gateway &&
+                       data->ipv4_gateway->vpn && data->index >= 0)
+               connman_inet_del_host_route(data->ipv4_gateway->vpn_phy_index,
                                                data->ipv4_gateway->gateway);
 
-       if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
-                       data->ipv6_gateway->vpn == TRUE && data->index >= 0)
-               connman_inet_del_ipv6_host_route(data->index,
+       if (do_ipv6 && data->ipv6_gateway &&
+                       data->ipv6_gateway->vpn && data->index >= 0)
+               connman_inet_del_ipv6_host_route(
+                                       data->ipv6_gateway->vpn_phy_index,
                                                data->ipv6_gateway->gateway);
 
        err = disable_gateway(data, type);
@@ -968,12 +1021,10 @@ void __connman_connection_gateway_remove(struct connman_service *service,
         * settings are to be removed.
         */
        if (do_ipv4 == do_ipv6 ||
-               (data->ipv4_gateway != NULL && data->ipv6_gateway == NULL
-                       && do_ipv4 == TRUE) ||
-               (data->ipv6_gateway != NULL && data->ipv4_gateway == NULL
-                       && do_ipv6 == TRUE)
-               ) {
-               connman_service_unref(service);
+               (data->ipv4_gateway && !data->ipv6_gateway
+                       && do_ipv4) ||
+               (data->ipv6_gateway && !data->ipv4_gateway
+                       && do_ipv6)) {
                g_hash_table_remove(gateway_hash, service);
        } else
                DBG("Not yet removing gw ipv4 %p/%d ipv6 %p/%d",
@@ -981,33 +1032,32 @@ void __connman_connection_gateway_remove(struct connman_service *service,
                        data->ipv6_gateway, do_ipv6);
 
        /* with vpn this will be called after the network was deleted,
-        * we need to call set_default here because we will not recieve any
+        * we need to call set_default here because we will not receive any
         * gateway delete notification.
         * We hit the same issue if remove_gateway() fails.
         */
        if (set_default4 || set_default6 || err < 0) {
                data = find_default_gateway();
-               if (data != NULL)
+               if (data)
                        set_default_gateway(data, type);
        }
 }
 
-gboolean __connman_connection_update_gateway(void)
+bool __connman_connection_update_gateway(void)
 {
        struct gateway_data *default_gateway;
-       gboolean updated = FALSE;
+       bool updated = false;
        GHashTableIter iter;
        gpointer value, key;
+#if defined TIZEN_EXT
+       static struct gateway_data *old_default = NULL;
+#endif
 
-       if (gateway_hash == NULL)
+       if (!gateway_hash)
                return updated;
 
-       update_order();
-
        default_gateway = find_default_gateway();
 
-       __connman_service_update_ordering();
-
        DBG("default %p", default_gateway);
 
        /*
@@ -1016,35 +1066,47 @@ gboolean __connman_connection_update_gateway(void)
         */
        g_hash_table_iter_init(&iter, gateway_hash);
 
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct gateway_data *active_gateway = value;
 
                if (active_gateway == default_gateway)
                        continue;
 
-               if (active_gateway->ipv4_gateway != NULL &&
-                               active_gateway->ipv4_gateway->active == TRUE) {
+               if (active_gateway->ipv4_gateway &&
+                               active_gateway->ipv4_gateway->active) {
 
                        unset_default_gateway(active_gateway,
                                                CONNMAN_IPCONFIG_TYPE_IPV4);
-                       updated = TRUE;
+                       updated = true;
                }
 
-               if (active_gateway->ipv6_gateway != NULL &&
-                               active_gateway->ipv6_gateway->active == TRUE) {
+               if (active_gateway->ipv6_gateway &&
+                               active_gateway->ipv6_gateway->active) {
 
                        unset_default_gateway(active_gateway,
                                                CONNMAN_IPCONFIG_TYPE_IPV6);
-                       updated = TRUE;
+                       updated = true;
                }
        }
 
-       if (updated && default_gateway != NULL) {
-               if (default_gateway->ipv4_gateway)
+#if defined TIZEN_EXT
+       if (updated == false && old_default != default_gateway) {
+               updated = true;
+               old_default = default_gateway;
+       }
+#endif
+       /*
+        * Set default gateway if it has been updated or if it has not been
+        * set as active yet.
+        */
+       if (default_gateway) {
+               if (default_gateway->ipv4_gateway &&
+                       (updated || !default_gateway->ipv4_gateway->active))
                        set_default_gateway(default_gateway,
                                        CONNMAN_IPCONFIG_TYPE_IPV4);
 
-               if (default_gateway->ipv6_gateway)
+               if (default_gateway->ipv6_gateway &&
+                       (updated || !default_gateway->ipv6_gateway->active))
                        set_default_gateway(default_gateway,
                                        CONNMAN_IPCONFIG_TYPE_IPV6);
        }
@@ -1052,6 +1114,23 @@ gboolean __connman_connection_update_gateway(void)
        return updated;
 }
 
+#if defined TIZEN_EXT
+void __connman_connection_update_default_gateway(void)
+{
+       struct gateway_data *default_gateway;
+
+       default_gateway = find_default_gateway();
+       DBG("default %p", default_gateway);
+
+       if (!default_gateway)
+               return;
+
+       if (default_gateway->ipv4_gateway)
+               set_default_gateway(default_gateway,
+                               CONNMAN_IPCONFIG_TYPE_IPV4);
+}
+#endif
+
 int __connman_connection_get_vpn_index(int phy_index)
 {
        GHashTableIter iter;
@@ -1059,14 +1138,14 @@ int __connman_connection_get_vpn_index(int phy_index)
 
        g_hash_table_iter_init(&iter, gateway_hash);
 
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct gateway_data *data = value;
 
-               if (data->ipv4_gateway != NULL &&
+               if (data->ipv4_gateway &&
                                data->ipv4_gateway->vpn_phy_index == phy_index)
                        return data->index;
 
-               if (data->ipv6_gateway != NULL &&
+               if (data->ipv6_gateway &&
                                data->ipv6_gateway->vpn_phy_index == phy_index)
                        return data->index;
        }
@@ -1101,7 +1180,7 @@ void __connman_connection_cleanup(void)
 
        g_hash_table_iter_init(&iter, gateway_hash);
 
-       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
                struct gateway_data *data = value;
 
                disable_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);