summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2011-06-22 13:37:44 +0300
committerSamuel Ortiz <sameo@linux.intel.com>2011-06-27 16:15:08 +0200
commit84a739d0082b89efa8cfbf376abe17937e4bc843 (patch)
treedde143bee8440f3e3f5022dd9ce3bc4ac50aa613
parent83b40034d10f7da8840fa2ee5f4698317c0315a4 (diff)
downloadconnman-84a739d0082b89efa8cfbf376abe17937e4bc843.tar.gz
connman-84a739d0082b89efa8cfbf376abe17937e4bc843.tar.bz2
connman-84a739d0082b89efa8cfbf376abe17937e4bc843.zip
connection: Separate IPv4 and IPv6 gateway and routing handling.
-rw-r--r--include/ipconfig.h1
-rw-r--r--src/connection.c495
-rw-r--r--src/connman.h9
-rw-r--r--src/ipconfig.c18
-rw-r--r--src/network.c3
5 files changed, 393 insertions, 133 deletions
diff --git a/include/ipconfig.h b/include/ipconfig.h
index a0673afc..8980a78a 100644
--- a/include/ipconfig.h
+++ b/include/ipconfig.h
@@ -58,6 +58,7 @@ void connman_ipaddress_copy(struct connman_ipaddress *ipaddress,
enum connman_ipconfig_type {
CONNMAN_IPCONFIG_TYPE_UNKNOWN = 0,
+ CONNMAN_IPCONFIG_TYPE_ALL = 0,
CONNMAN_IPCONFIG_TYPE_IPV4 = 1,
CONNMAN_IPCONFIG_TYPE_IPV6 = 2,
};
diff --git a/src/connection.c b/src/connection.c
index 10ef04a3..a4025883 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -31,22 +31,27 @@
#include "connman.h"
-struct gateway_data {
- int index;
- struct connman_service *service;
- char *ipv4_gateway;
- char *ipv6_gateway;
- unsigned int order;
+struct gateway_config {
gboolean active;
+ char *gateway;
+
/* VPN extra data */
gboolean vpn;
char *vpn_ip;
int vpn_phy_index;
};
+struct gateway_data {
+ int index;
+ struct connman_service *service;
+ unsigned int order;
+ struct gateway_config *ipv4_gateway;
+ struct gateway_config *ipv6_gateway;
+};
+
static GHashTable *gateway_hash = NULL;
-static struct gateway_data *find_gateway(int index, const char *gateway)
+static struct gateway_config *find_gateway(int index, const char *gateway)
{
GHashTableIter iter;
gpointer value, key;
@@ -59,46 +64,113 @@ static struct gateway_data *find_gateway(int index, const char *gateway)
while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
struct gateway_data *data = value;
- if (data->ipv4_gateway == NULL)
- continue;
+ if (data->ipv4_gateway != NULL && data->index == index &&
+ g_str_equal(data->ipv4_gateway->gateway,
+ gateway) == TRUE)
+ return data->ipv4_gateway;
- if (data->index == index &&
- g_str_equal(data->ipv4_gateway, gateway)
- == TRUE)
- return data;
+ if (data->ipv6_gateway != NULL && data->index == index &&
+ g_str_equal(data->ipv6_gateway->gateway,
+ gateway) == TRUE)
+ return data->ipv6_gateway;
}
return NULL;
}
-static int del_routes(struct gateway_data *data)
+static int del_routes(struct gateway_data *data,
+ enum connman_ipconfig_type type)
{
- if (data->vpn) {
- if (data->vpn_phy_index >= 0)
- connman_inet_del_host_route(data->vpn_phy_index,
- data->ipv4_gateway);
- return connman_inet_clear_gateway_address(data->index,
- data->vpn_ip);
- } else if (g_strcmp0(data->ipv4_gateway, "0.0.0.0") == 0) {
- return connman_inet_clear_gateway_interface(data->index);
- } else {
- connman_inet_del_ipv6_host_route(data->index,
- data->ipv6_gateway);
- connman_inet_clear_ipv6_gateway_address(data->index,
- data->ipv6_gateway);
- connman_inet_del_host_route(data->index, data->ipv4_gateway);
- return connman_inet_clear_gateway_address(data->index,
- data->ipv4_gateway);
+ int status4 = 0, status6 = 0;
+ int do_ipv4 = FALSE, do_ipv6 = FALSE;
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ do_ipv4 = TRUE;
+ else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+ do_ipv6 = TRUE;
+ else
+ do_ipv4 = do_ipv6 = TRUE;
+
+ if (do_ipv4 == TRUE && data->ipv4_gateway != NULL) {
+ if (data->ipv4_gateway->vpn == TRUE) {
+ if (data->ipv4_gateway->vpn_phy_index >= 0)
+ connman_inet_del_host_route(
+ data->ipv4_gateway->vpn_phy_index,
+ data->ipv4_gateway->gateway);
+
+ status4 = connman_inet_clear_gateway_address(
+ data->index,
+ data->ipv4_gateway->vpn_ip);
+
+ } else if (g_strcmp0(data->ipv4_gateway->gateway,
+ "0.0.0.0") == 0) {
+ status4 = connman_inet_clear_gateway_interface(
+ data->index);
+ } else {
+ connman_inet_del_host_route(data->index,
+ data->ipv4_gateway->gateway);
+ status4 = connman_inet_clear_gateway_address(
+ data->index,
+ data->ipv4_gateway->gateway);
+ }
+ }
+
+ if (do_ipv6 == TRUE && data->ipv6_gateway != NULL) {
+ if (data->ipv6_gateway->vpn == TRUE) {
+ if (data->ipv6_gateway->vpn_phy_index >= 0)
+ connman_inet_del_host_route(
+ data->ipv6_gateway->vpn_phy_index,
+ data->ipv6_gateway->gateway);
+
+ status6 = connman_inet_clear_ipv6_gateway_address(
+ data->index,
+ data->ipv6_gateway->vpn_ip);
+
+ } else if (g_strcmp0(data->ipv6_gateway->gateway, "::") == 0) {
+ status6 = connman_inet_clear_ipv6_gateway_interface(
+ data->index);
+ } else {
+ connman_inet_del_ipv6_host_route(data->index,
+ data->ipv6_gateway->gateway);
+ status6 = connman_inet_clear_ipv6_gateway_address(
+ data->index,
+ data->ipv6_gateway->gateway);
+ }
}
+
+ return (status4 < 0 ? status4 : status6);
+}
+
+static int disable_gateway(struct gateway_data *data,
+ enum connman_ipconfig_type type)
+{
+ gboolean active = FALSE;
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
+ if (data->ipv4_gateway != NULL)
+ active = data->ipv4_gateway->active;
+ } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
+ if (data->ipv6_gateway != NULL)
+ active = data->ipv6_gateway->active;
+ } else
+ active = TRUE;
+
+ DBG("type %d active %d", type, active);
+
+ if (active == TRUE)
+ return del_routes(data, type);
+
+ return 0;
}
static struct gateway_data *add_gateway(struct connman_service *service,
- int index, const char *ipv4_gateway,
- const char *ipv6_gateway)
+ int index, const char *gateway,
+ enum connman_ipconfig_type type)
{
- struct gateway_data *data;
+ struct gateway_data *data, *old;
+ struct gateway_config *config;
- if (strlen(ipv4_gateway) == 0)
+ if (gateway == NULL || strlen(gateway) == 0)
return NULL;
data = g_try_new0(struct gateway_data, 1);
@@ -106,16 +178,54 @@ static struct gateway_data *add_gateway(struct connman_service *service,
return NULL;
data->index = index;
- data->ipv4_gateway = g_strdup(ipv4_gateway);
- data->ipv6_gateway = g_strdup(ipv6_gateway);
- data->active = FALSE;
- data->vpn_ip = NULL;
- data->vpn = FALSE;
- data->vpn_phy_index = -1;
+
+ config = g_try_new0(struct gateway_config, 1);
+ if (config == NULL) {
+ g_free(data);
+ return NULL;
+ }
+
+ config->gateway = g_strdup(gateway);
+ config->vpn_ip = NULL;
+ config->vpn = FALSE;
+ config->vpn_phy_index = -1;
+ config->active = FALSE;
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ data->ipv4_gateway = config;
+ else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+ data->ipv6_gateway = config;
+ else {
+ g_free(config->gateway);
+ g_free(config);
+ g_free(data);
+ return NULL;
+ }
+
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
+ * of the type we are replacing and take the other type
+ * from old gateway settings.
+ */
+ old = g_hash_table_lookup(gateway_hash, service);
+ if (old != NULL) {
+ DBG("Replacing gw %p ipv4 %p ipv6 %p", old,
+ old->ipv4_gateway, old->ipv6_gateway);
+ disable_gateway(old, type);
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
+ data->ipv6_gateway = old->ipv6_gateway;
+ old->ipv6_gateway = NULL;
+ } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
+ data->ipv4_gateway = old->ipv4_gateway;
+ old->ipv4_gateway = NULL;
+ }
+ }
+
g_hash_table_replace(gateway_hash, service, data);
return data;
@@ -123,27 +233,50 @@ static struct gateway_data *add_gateway(struct connman_service *service,
static void connection_newgateway(int index, const char *gateway)
{
- struct gateway_data *data;
+ struct gateway_config *config;
DBG("index %d gateway %s", index, gateway);
- data = find_gateway(index, gateway);
- if (data == NULL)
+ config = find_gateway(index, gateway);
+ if (config == NULL)
return;
- data->active = TRUE;
+ config->active = TRUE;
}
-static void set_default_gateway(struct gateway_data *data)
+static void set_default_gateway(struct gateway_data *data,
+ enum connman_ipconfig_type type)
{
int index;
+ int status4 = 0, status6 = 0;
+ int do_ipv4 = FALSE, do_ipv6 = FALSE;
- DBG("gateway %s", data->ipv4_gateway);
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ do_ipv4 = TRUE;
+ else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+ do_ipv6 = TRUE;
+ else
+ do_ipv4 = do_ipv6 = TRUE;
- if (data->vpn == 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->vpn_ip);
- data->active = TRUE;
+ data->ipv4_gateway->vpn_ip);
+ data->ipv4_gateway->active = TRUE;
+
+ __connman_service_indicate_default(data->service);
+
+ 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);
+ data->ipv6_gateway->active = TRUE;
__connman_service_indicate_default(data->service);
@@ -152,14 +285,31 @@ static void set_default_gateway(struct gateway_data *data)
index = __connman_service_get_index(data->service);
- if (g_strcmp0(data->ipv4_gateway, "0.0.0.0") == 0) {
+ if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
+ g_strcmp0(data->ipv4_gateway->gateway,
+ "0.0.0.0") == 0) {
if (connman_inet_set_gateway_interface(index) < 0)
return;
goto done;
}
- connman_inet_set_ipv6_gateway_address(index, data->ipv6_gateway);
- if (connman_inet_set_gateway_address(index, data->ipv4_gateway) < 0)
+ if (do_ipv6 == TRUE && data->ipv6_gateway != NULL &&
+ g_strcmp0(data->ipv6_gateway->gateway,
+ "::") == 0) {
+ if (connman_inet_set_ipv6_gateway_interface(index) < 0)
+ return;
+ goto done;
+ }
+
+ if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
+ status6 = connman_inet_set_ipv6_gateway_address(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 (status4 < 0 || status6 < 0)
return;
done:
@@ -187,39 +337,41 @@ static struct gateway_data *find_default_gateway(void)
return found;
}
-static int disable_gateway(struct gateway_data *data)
-{
- if (data->active == TRUE)
- return del_routes(data);
-
- return 0;
-}
-
static void remove_gateway(gpointer user_data)
{
struct gateway_data *data = user_data;
- DBG("gateway %s", data->ipv4_gateway);
+ DBG("gateway ipv4 %p ipv6 %p", data->ipv4_gateway, data->ipv6_gateway);
+
+ if (data->ipv4_gateway != NULL) {
+ g_free(data->ipv4_gateway->gateway);
+ g_free(data->ipv4_gateway->vpn_ip);
+ g_free(data->ipv4_gateway);
+ }
+
+ if (data->ipv6_gateway != NULL) {
+ g_free(data->ipv6_gateway->gateway);
+ g_free(data->ipv6_gateway->vpn_ip);
+ g_free(data->ipv6_gateway);
+ }
- g_free(data->ipv4_gateway);
- g_free(data->ipv6_gateway);
- g_free(data->vpn_ip);
g_free(data);
}
static void connection_delgateway(int index, const char *gateway)
{
+ struct gateway_config *config;
struct gateway_data *data;
DBG("index %d gateway %s", index, gateway);
- data = find_gateway(index, gateway);
- if (data != NULL)
- data->active = FALSE;
+ config = find_gateway(index, gateway);
+ if (config != NULL)
+ config->active = FALSE;
data = find_default_gateway();
if (data != NULL)
- set_default_gateway(data);
+ set_default_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
}
static struct connman_rtnl connection_rtnl = {
@@ -240,7 +392,12 @@ static struct gateway_data *find_active_gateway(void)
while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
struct gateway_data *data = value;
- if (data->active == TRUE)
+ if (data->ipv4_gateway != NULL &&
+ data->ipv4_gateway->active == TRUE)
+ return data;
+
+ if (data->ipv6_gateway != NULL &&
+ data->ipv6_gateway->active == TRUE)
return data;
}
@@ -263,9 +420,27 @@ static void update_order(void)
}
}
+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;
+}
+
int __connman_connection_gateway_add(struct connman_service *service,
- const char *ipv4_gateway,
- const char *ipv6_gateway,
+ const char *gateway,
+ enum connman_ipconfig_type type,
const char *peer)
{
struct gateway_data *active_gateway = NULL;
@@ -274,76 +449,127 @@ int __connman_connection_gateway_add(struct connman_service *service,
index = __connman_service_get_index(service);
- DBG("service %p index %d ipv4 gateway %s ipv6 gateway %s vpn ip %s",
- service, index, ipv4_gateway, ipv6_gateway, peer);
-
- /*
- * If gateway is NULL, it's a point to point link and the default
- * gateway is 0.0.0.0, meaning the interface.
- */
- if (ipv4_gateway == NULL)
- ipv4_gateway = "0.0.0.0";
+ DBG("service %p index %d gateway %s vpn ip %s type %d",
+ service, index, gateway, peer, type);
active_gateway = find_active_gateway();
- new_gateway = add_gateway(service, index, ipv4_gateway, ipv6_gateway);
+ new_gateway = add_gateway(service, index, gateway, type);
if (new_gateway == NULL)
return 0;
- if (new_gateway->ipv6_gateway) {
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
+ new_gateway->ipv6_gateway != NULL &&
+ g_strcmp0(new_gateway->ipv6_gateway->gateway,
+ "::") != 0)
connman_inet_add_ipv6_host_route(index,
- new_gateway->ipv6_gateway,
- NULL);
- }
+ new_gateway->ipv6_gateway->gateway,
+ NULL);
- if (g_strcmp0(new_gateway->ipv4_gateway, "0.0.0.0") != 0) {
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
+ new_gateway->ipv4_gateway != NULL &&
+ g_strcmp0(new_gateway->ipv4_gateway->gateway,
+ "0.0.0.0") != 0)
connman_inet_add_host_route(index,
- new_gateway->ipv4_gateway,
- NULL);
+ new_gateway->ipv4_gateway->gateway,
+ NULL);
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
+ new_gateway->ipv4_gateway != NULL) {
+ __connman_service_nameserver_add_routes(service,
+ new_gateway->ipv4_gateway->gateway);
+ __connman_service_set_ipconfig_ready(service,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
}
- __connman_service_nameserver_add_routes(service,
- new_gateway->ipv4_gateway);
-
- __connman_service_set_ipconfig_ready(service, CONNMAN_IPCONFIG_TYPE_IPV4);
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
+ new_gateway->ipv6_gateway != NULL) {
+ __connman_service_nameserver_add_routes(service,
+ new_gateway->ipv6_gateway->gateway);
+ __connman_service_set_ipconfig_ready(service,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
+ }
if (connman_service_get_type(service) == CONNMAN_SERVICE_TYPE_VPN) {
- new_gateway->vpn = TRUE;
- if (peer != NULL)
- new_gateway->vpn_ip = g_strdup(peer);
- else if (ipv4_gateway != NULL)
- new_gateway->vpn_ip = g_strdup(ipv4_gateway);
- else
- new_gateway->vpn_ip = g_strdup(ipv6_gateway);
-
- if (active_gateway)
- new_gateway->vpn_phy_index = active_gateway->index;
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
+ new_gateway->ipv4_gateway != NULL) {
+ new_gateway->ipv4_gateway->vpn = TRUE;
+ if (peer != NULL)
+ new_gateway->ipv4_gateway->vpn_ip =
+ g_strdup(peer);
+ else if (gateway != NULL)
+ new_gateway->ipv4_gateway->vpn_ip =
+ g_strdup(gateway);
+ if (active_gateway)
+ new_gateway->ipv4_gateway->vpn_phy_index =
+ active_gateway->index;
+
+ } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
+ new_gateway->ipv6_gateway != NULL) {
+ new_gateway->ipv6_gateway->vpn = TRUE;
+ if (peer != NULL)
+ new_gateway->ipv6_gateway->vpn_ip =
+ g_strdup(peer);
+ else if (gateway != NULL)
+ new_gateway->ipv6_gateway->vpn_ip =
+ g_strdup(gateway);
+ if (active_gateway)
+ new_gateway->ipv6_gateway->vpn_phy_index =
+ active_gateway->index;
+ }
} else {
- new_gateway->vpn = FALSE;
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
+ new_gateway->ipv4_gateway != NULL)
+ new_gateway->ipv4_gateway->vpn = FALSE;
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
+ new_gateway->ipv6_gateway != NULL)
+ new_gateway->ipv6_gateway->vpn = FALSE;
}
if (active_gateway == NULL) {
- set_default_gateway(new_gateway);
+ set_default_gateway(new_gateway, type);
return 0;
}
- if (new_gateway->vpn == TRUE) {
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
+ new_gateway->ipv4_gateway != NULL &&
+ new_gateway->ipv4_gateway->vpn == TRUE) {
connman_inet_add_host_route(active_gateway->index,
- new_gateway->ipv4_gateway,
- active_gateway->ipv4_gateway);
+ new_gateway->ipv4_gateway->gateway,
+ active_gateway->ipv4_gateway->gateway);
connman_inet_clear_gateway_address(active_gateway->index,
- active_gateway->ipv4_gateway);
+ active_gateway->ipv4_gateway->gateway);
+ }
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
+ new_gateway->ipv6_gateway != NULL &&
+ new_gateway->ipv6_gateway->vpn == TRUE) {
+ connman_inet_add_ipv6_host_route(active_gateway->index,
+ new_gateway->ipv6_gateway->gateway,
+ active_gateway->ipv6_gateway->gateway);
+ connman_inet_clear_ipv6_gateway_address(active_gateway->index,
+ active_gateway->ipv6_gateway->gateway);
}
return 0;
}
-void __connman_connection_gateway_remove(struct connman_service *service)
+void __connman_connection_gateway_remove(struct connman_service *service,
+ enum connman_ipconfig_type type)
{
struct gateway_data *data = NULL;
- gboolean set_default = FALSE;
+ gboolean set_default4 = FALSE, set_default6 = FALSE;
+ int do_ipv4 = FALSE, do_ipv6 = FALSE;
int err;
- DBG("service %p", service);
+ DBG("service %p type %d", service, type);
+
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+ do_ipv4 = TRUE;
+ else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+ do_ipv6 = TRUE;
+ else
+ do_ipv4 = do_ipv6 = TRUE;
__connman_service_nameserver_del_routes(service);
@@ -351,27 +577,56 @@ void __connman_connection_gateway_remove(struct connman_service *service)
if (data == NULL)
return;
- set_default = data->vpn;
+ if (do_ipv4 == TRUE && data->ipv4_gateway != NULL)
+ set_default4 = data->ipv4_gateway->vpn;
+
+ if (do_ipv6 == TRUE && data->ipv6_gateway != NULL)
+ set_default6 = data->ipv6_gateway->vpn;
+
+ DBG("ipv4 gateway %s ipv6 gateway %s vpn %d/%d",
+ data->ipv4_gateway ? data->ipv4_gateway->gateway : "<null>",
+ data->ipv6_gateway ? data->ipv6_gateway->gateway : "<null>",
+ set_default4, set_default6);
- if (data->vpn == TRUE && data->index >= 0) {
+ if (do_ipv4 == TRUE && data->ipv4_gateway != NULL &&
+ data->ipv4_gateway->vpn == TRUE && data->index >= 0)
connman_inet_del_host_route(data->index,
- data->ipv4_gateway);
- }
+ 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,
+ data->ipv6_gateway->gateway);
__connman_service_nameserver_del_routes(service);
- err = disable_gateway(data);
- g_hash_table_remove(gateway_hash, service);
+ err = disable_gateway(data, type);
+
+ /*
+ * We remove the service from the hash only if all the gateway
+ * 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)
+ )
+ g_hash_table_remove(gateway_hash, service);
+ else
+ DBG("Not yet removing gw ipv4 %p/%d ipv6 %p/%d",
+ data->ipv4_gateway, do_ipv4,
+ 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
* gateway delete notification.
* We hit the same issue if remove_gateway() fails.
*/
- if (set_default || err < 0) {
+ if (set_default4 || set_default6 || err < 0) {
data = find_default_gateway();
if (data != NULL)
- set_default_gateway(data);
+ set_default_gateway(data, type);
}
}
@@ -424,7 +679,7 @@ void __connman_connection_cleanup(void)
while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
struct gateway_data *data = value;
- disable_gateway(data);
+ disable_gateway(data, CONNMAN_IPCONFIG_TYPE_ALL);
}
g_hash_table_destroy(gateway_hash);
diff --git a/src/connman.h b/src/connman.h
index a6361d7f..0d6ca8b2 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -286,12 +286,15 @@ int __connman_connection_init(void);
void __connman_connection_cleanup(void);
int __connman_connection_gateway_add(struct connman_service *service,
- const char *ipv4_gateway,
- const char *ipv6_gateway,
+ const char *gateway,
+ enum connman_ipconfig_type type,
const char *peer);
-void __connman_connection_gateway_remove(struct connman_service *service);
+void __connman_connection_gateway_remove(struct connman_service *service,
+ enum connman_ipconfig_type type);
gboolean __connman_connection_update_gateway(void);
+void __connman_connection_gateway_activate(struct connman_service *service,
+ enum connman_ipconfig_type type);
int __connman_wpad_init(void);
void __connman_wpad_cleanup(void);
diff --git a/src/ipconfig.c b/src/ipconfig.c
index 700f4a6b..c8466d98 100644
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -1098,17 +1098,17 @@ int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig)
if (service == NULL)
return -EINVAL;
- __connman_connection_gateway_remove(service);
+ __connman_connection_gateway_remove(service, ipconfig->type);
- if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
- return __connman_connection_gateway_add(service, NULL,
- ipconfig->address->gateway,
- ipconfig->address->peer);
- } else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4) {
+ DBG("type %d gw %s peer %s", ipconfig->type,
+ ipconfig->address->gateway, ipconfig->address->peer);
+
+ if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6 ||
+ ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
return __connman_connection_gateway_add(service,
ipconfig->address->gateway,
- NULL, ipconfig->address->peer);
- }
+ ipconfig->type,
+ ipconfig->address->peer);
return 0;
}
@@ -1121,7 +1121,7 @@ void __connman_ipconfig_gateway_remove(struct connman_ipconfig *ipconfig)
service = __connman_service_lookup_from_index(ipconfig->index);
if (service != NULL)
- __connman_connection_gateway_remove(service);
+ __connman_connection_gateway_remove(service, ipconfig->type);
}
unsigned char __connman_ipconfig_get_prefixlen(struct connman_ipconfig *ipconfig)
diff --git a/src/network.c b/src/network.c
index 16931099..acc374f6 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1083,7 +1083,8 @@ static gboolean set_connected(gpointer user_data)
CONNMAN_SERVICE_STATE_DISCONNECT,
CONNMAN_IPCONFIG_TYPE_IPV6);
- __connman_connection_gateway_remove(service);
+ __connman_connection_gateway_remove(service,
+ CONNMAN_IPCONFIG_TYPE_ALL);
__connman_service_indicate_state(service,
CONNMAN_SERVICE_STATE_IDLE,