provider: Disconnect VPN when phy service is disconnected
authorJukka Rissanen <jukka.rissanen@linux.intel.com>
Tue, 3 Apr 2012 11:07:24 +0000 (14:07 +0300)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Thu, 12 Apr 2012 08:00:42 +0000 (11:00 +0300)
If the VPN is connected and the underlaying service is
disconnected, then we must also disconnect the VPN if it
is still connected.

src/connection.c
src/connman.h
src/provider.c

index 3747c05..8b1b689 100644 (file)
@@ -1025,6 +1025,28 @@ gboolean __connman_connection_update_gateway(void)
        return updated;
 }
 
+int __connman_connection_get_vpn_index(int phy_index)
+{
+       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 (data->ipv4_gateway != NULL &&
+                               data->ipv4_gateway->vpn_phy_index == phy_index)
+                       return data->index;
+
+               if (data->ipv6_gateway != NULL &&
+                               data->ipv6_gateway->vpn_phy_index == phy_index)
+                       return data->index;
+       }
+
+       return -1;
+}
+
 int __connman_connection_init(void)
 {
        int err;
index 306e9d6..7f42bc9 100644 (file)
@@ -402,6 +402,7 @@ int __connman_connection_gateway_add(struct connman_service *service,
                                        const char *peer);
 void __connman_connection_gateway_remove(struct connman_service *service,
                                        enum connman_ipconfig_type type);
+int __connman_connection_get_vpn_index(int phy_index);
 
 gboolean __connman_connection_update_gateway(void);
 void __connman_connection_gateway_activate(struct connman_service *service,
index 42fd112..00f3f4c 100644 (file)
@@ -1281,9 +1281,71 @@ static void provider_offline_mode(connman_bool_t enabled)
 
 }
 
+static struct connman_provider *provider_get(int index)
+{
+       GHashTableIter iter;
+       gpointer value, key;
+
+       g_hash_table_iter_init(&iter, provider_hash);
+
+       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+               struct connman_provider *provider = value;
+
+               if (provider->index == index)
+                       return provider;
+       }
+
+       return NULL;
+}
+
+static void provider_service_changed(struct connman_service *service,
+                               enum connman_service_state state)
+{
+       struct connman_provider *provider;
+       int vpn_index, service_index;
+
+       if (service == NULL)
+               return;
+
+       switch (state) {
+       case CONNMAN_SERVICE_STATE_UNKNOWN:
+       case CONNMAN_SERVICE_STATE_IDLE:
+       case CONNMAN_SERVICE_STATE_ASSOCIATION:
+       case CONNMAN_SERVICE_STATE_CONFIGURATION:
+       case CONNMAN_SERVICE_STATE_READY:
+       case CONNMAN_SERVICE_STATE_ONLINE:
+               return;
+       case CONNMAN_SERVICE_STATE_DISCONNECT:
+       case CONNMAN_SERVICE_STATE_FAILURE:
+               break;
+       }
+
+       service_index = __connman_service_get_index(service);
+
+       vpn_index = __connman_connection_get_vpn_index(service_index);
+
+       DBG("service %p %s state %d index %d/%d", service,
+               __connman_service_get_ident(service),
+               state, service_index, vpn_index);
+
+       if (vpn_index < 0)
+               return;
+
+       provider = provider_get(vpn_index);
+       if (provider == NULL)
+               return;
+
+       DBG("disconnect %p index %d", provider, vpn_index);
+
+       __connman_provider_disconnect(provider);
+
+       return;
+}
+
 static struct connman_notifier provider_notifier = {
        .name                   = "provider",
        .offline_mode           = provider_offline_mode,
+       .service_state_changed  = provider_service_changed,
 };
 
 int __connman_provider_init(void)