Update routing table when default address is reset
[platform/upstream/connman.git] / src / connection.c
old mode 100644 (file)
new mode 100755 (executable)
index e98ccb5..c18701a
@@ -3,7 +3,7 @@
  *  Connection Manager
  *
  *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
- *  Copyright (C) 2011-2013  BMW Car IT GmbH. 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
@@ -46,7 +46,6 @@ 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;
        bool default_checked;
@@ -235,6 +234,15 @@ static void set_vpn_routes(struct gateway_data *new_gateway,
                if (!active_gateway->ipv4_gateway)
                        return;
 
+
+               /*
+                * If VPN server is on same subnet as we are, skip adding
+                * route.
+                */
+               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,
@@ -251,6 +259,10 @@ static void set_vpn_routes(struct gateway_data *new_gateway,
                if (!active_gateway->ipv6_gateway)
                        return;
 
+               if (connman_inet_compare_ipv6_subnet(active_gateway->index,
+                                                               gateway))
+                       return;
+
                DBG("active gw %s", active_gateway->ipv6_gateway->gateway);
 
                if (g_strcmp0(active_gateway->ipv6_gateway->gateway,
@@ -381,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
@@ -401,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;
@@ -467,6 +473,7 @@ static void set_default_gateway(struct gateway_data *data,
                                                        "0.0.0.0") == 0) {
                if (connman_inet_set_gateway_interface(index) < 0)
                        return;
+               data->ipv4_gateway->active = true;
                goto done;
        }
 
@@ -475,6 +482,7 @@ static void set_default_gateway(struct gateway_data *data,
                                                        "::") == 0) {
                if (connman_inet_set_ipv6_gateway_interface(index) < 0)
                        return;
+               data->ipv6_gateway->active = true;
                goto done;
        }
 
@@ -541,6 +549,7 @@ static void unset_default_gateway(struct gateway_data *data,
                        g_strcmp0(data->ipv4_gateway->gateway,
                                                        "0.0.0.0") == 0) {
                connman_inet_clear_gateway_interface(index);
+               data->ipv4_gateway->active = false;
                return;
        }
 
@@ -548,6 +557,7 @@ static void unset_default_gateway(struct gateway_data *data,
                        g_strcmp0(data->ipv6_gateway->gateway,
                                                        "::") == 0) {
                connman_inet_clear_ipv6_gateway_interface(index);
+               data->ipv6_gateway->active = false;
                return;
        }
 
@@ -562,25 +572,13 @@ static void unset_default_gateway(struct gateway_data *data,
 
 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)) {
-               struct gateway_data *data = value;
-
-               if (!found || 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 bool choose_default_gateway(struct gateway_data *data,
@@ -593,37 +591,35 @@ static bool choose_default_gateway(struct gateway_data *data,
         * this one as default. If the other one is already active
         * we mark this one as non default.
         */
-       if (data->ipv4_gateway) {
-               if (candidate->ipv4_gateway &&
-                               !candidate->ipv4_gateway->active) {
+       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 &&
-                               candidate->ipv4_gateway->active &&
-                               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);
+                       unset_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV4);
                        downgraded = true;
                }
        }
 
-       if (data->ipv6_gateway) {
-               if (candidate->ipv6_gateway &&
-                               !candidate->ipv6_gateway->active) {
+       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 &&
-                               candidate->ipv6_gateway->active &&
-                               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);
+                       unset_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV6);
                        downgraded = true;
                }
        }
@@ -678,8 +674,15 @@ static void connection_newgateway(int index, const char *gateway)
        }
 
        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)
                        set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_IPV6);
@@ -708,6 +711,8 @@ static void remove_gateway(gpointer user_data)
                g_free(data->ipv6_gateway);
        }
 
+       connman_service_unref(data->service);
+
        g_free(data);
 }
 
@@ -757,40 +762,6 @@ static struct gateway_data *find_active_gateway(void)
        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)) {
-               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)
-               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)
 {
@@ -839,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,
@@ -865,6 +862,28 @@ int __connman_connection_gateway_add(struct connman_service *service,
        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);
 
@@ -909,6 +928,12 @@ int __connman_connection_gateway_add(struct connman_service *service,
        }
 
        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;
        }
@@ -999,9 +1024,7 @@ void __connman_connection_gateway_remove(struct connman_service *service,
                (data->ipv4_gateway && !data->ipv6_gateway
                        && do_ipv4) ||
                (data->ipv6_gateway && !data->ipv4_gateway
-                       && do_ipv6)
-               ) {
-               connman_service_unref(service);
+                       && do_ipv6)) {
                g_hash_table_remove(gateway_hash, service);
        } else
                DBG("Not yet removing gw ipv4 %p/%d ipv6 %p/%d",
@@ -1009,7 +1032,7 @@ 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.
         */
@@ -1026,16 +1049,15 @@ bool __connman_connection_update_gateway(void)
        bool updated = false;
        GHashTableIter iter;
        gpointer value, key;
+#if defined TIZEN_EXT
+       static struct gateway_data *old_default = NULL;
+#endif
 
        if (!gateway_hash)
                return updated;
 
-       update_order();
-
        default_gateway = find_default_gateway();
 
-       __connman_service_update_ordering();
-
        DBG("default %p", default_gateway);
 
        /*
@@ -1067,12 +1089,24 @@ bool __connman_connection_update_gateway(void)
                }
        }
 
-       if (updated && default_gateway) {
-               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);
        }
@@ -1080,6 +1114,23 @@ bool __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;