In a big network, for example at Ubuntu Developer Summit which has >10 APs,
connman and wpasupplicant got out of sync very easily. connman claimed it
was connected even though wpasupplicant (and the kernel driver) was actually
connected to the AP.

The problem is that while roaming between APs inside ESS wpasupplicant states
go like this:

COMPLETED -> DISCONNECTED -> SCANNING -> AUTHENTICATING ... -> COMPLETED

So what happens is that connman unnecessarily marks the network disconnected
even though wpasupplicant is just roaming to a different AP within ESS.

To fix this add a timer which waits 10 seconds after a disconnected state.
If wpasupplicant hasn't connected to a network at time only then set the
network disconnected.
---
 plugins/wifi.c |   71 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/plugins/wifi.c b/plugins/wifi.c
index 37f6e32..d036a92 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -61,6 +61,7 @@ struct wifi_data {
        int index;
        unsigned flags;
        unsigned int watch;
+       guint disconnect_timer;
 };
 
 static int get_bssid(struct connman_device *device,
@@ -309,6 +310,61 @@ static const gchar *state2str(GSupplicantState state)
        return "UNKNOWN";
 }
 
+static gboolean disconnected_timeout(gpointer user_data)
+{
+       GSupplicantInterface *interface;
+       struct connman_network *network;
+       struct wifi_data *wifi;
+
+       DBG("");
+
+       interface = user_data;
+
+       wifi = g_supplicant_interface_get_data(interface);
+
+       if (wifi == NULL)
+               return FALSE;
+
+       network = wifi->network;
+
+       connman_network_set_associating(network, FALSE);
+       connman_network_set_connected(network, FALSE);
+
+       connman_network_unref(wifi->network);
+       wifi->network = NULL;
+
+       return FALSE;
+}
+
+static void start_disconnected_timer(GSupplicantInterface *interface)
+{
+       struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+       if (wifi == NULL)
+               return;
+
+       if (wifi->disconnect_timer != 0)
+               return;
+
+       wifi->disconnect_timer = g_timeout_add(10000, disconnected_timeout,
+                                       interface);
+}
+
+static void stop_disconnected_timer(GSupplicantInterface *interface)
+{
+       struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+       if (wifi == NULL)
+               return;
+
+       if (wifi->disconnect_timer == 0)
+               return;
+
+       g_source_remove(wifi->disconnect_timer);
+       wifi->disconnect_timer = 0;
+}
+
+
 static void interface_state(GSupplicantInterface *interface)
 {
        struct connman_network *network;
@@ -328,8 +384,10 @@ static void interface_state(GSupplicantInterface 
*interface)
        network = wifi->network;
        device = wifi->device;
 
-       if (device == NULL || network == NULL)
+       if (device == NULL || network == NULL) {
+               stop_disconnected_timer(interface);
                return;
+       }
 
        switch (state) {
        case G_SUPPLICANT_STATE_SCANNING:
@@ -345,6 +403,8 @@ static void interface_state(GSupplicantInterface *interface)
                /* reset scan trigger and schedule background scan */
                connman_device_schedule_scan(device);
 
+               stop_disconnected_timer(interface);
+
                if (get_bssid(device, bssid, &bssid_len) == 0)
                        connman_network_set_address(network,
                                                        bssid, bssid_len);
@@ -352,12 +412,7 @@ static void interface_state(GSupplicantInterface 
*interface)
                break;
 
        case G_SUPPLICANT_STATE_DISCONNECTED:
-               connman_network_set_associating(network, FALSE);
-               connman_network_set_connected(network, FALSE);
-
-               connman_network_unref(wifi->network);
-               wifi->network = NULL;
-
+               start_disconnected_timer(interface);
                break;
 
        case G_SUPPLICANT_STATE_INACTIVE:
@@ -640,6 +695,8 @@ static int network_disconnect(struct connman_network 
*network)
 
        connman_network_set_associating(network, FALSE);
 
+       stop_disconnected_timer(wifi->interface);
+
        return g_supplicant_interface_disconnect(wifi->interface,
                                                disconnect_callback, wifi);
 }
-- 
1.7.1

_______________________________________________
connman mailing list
connman@connman.net
http://lists.connman.net/listinfo/connman

Reply via email to