Discussion:
[PATCH 0/2] wifi disconnect timer
Kalle Valo
2010-10-26 16:30:51 UTC
Permalink
I'm at UDS right now and I have been debugging gsupplicant extensively and
I have had quite a lot of problems. I noticed a problem how the wifi
plugin handles the wpasupplicant disconnect state. Here are two patches
how I propose to fix the issues. At least in my case the patches
helped a lot.

Kalle Valo (2):
wifi: add a disconnected timer
wifi: don't set associating state when roaming between APs

plugins/wifi.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 66 insertions(+), 8 deletions(-)
Kalle Valo
2010-10-26 16:30:54 UTC
Permalink
When wpasupplicant is roaming between APs it exposes all states to connman.
After the wifi network is connected, we should not set associating state
anymore. Otherwise we just end up into weird states.
---
plugins/wifi.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/plugins/wifi.c b/plugins/wifi.c
index d036a92..dc19b79 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -396,7 +396,8 @@ static void interface_state(GSupplicantInterface *interface)

case G_SUPPLICANT_STATE_AUTHENTICATING:
case G_SUPPLICANT_STATE_ASSOCIATING:
- connman_network_set_associating(network, TRUE);
+ if (!connman_network_get_connected(network))
+ connman_network_set_associating(network, TRUE);
break;

case G_SUPPLICANT_STATE_COMPLETED:
--
1.7.1
Kalle Valo
2010-10-26 16:30:52 UTC
Permalink
*** BLURB HERE ***

Kalle Valo (2):
wifi: add a disconnected timer
wifi: don't set associating state when roaming between APs

plugins/wifi.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 66 insertions(+), 8 deletions(-)
Kalle Valo
2010-10-26 16:30:53 UTC
Permalink
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
Samuel Ortiz
2010-10-26 23:11:46 UTC
Permalink
This post might be inappropriate. Click to display it.
Kalle Valo
2010-10-27 14:08:05 UTC
Permalink
Post by Samuel Ortiz
Hi Kalle,
Hi Samuel,
Post by Samuel Ortiz
Post by Kalle Valo
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.
Did you mean connman claimed it was _disconnected_ ?
Yes, that's what I mean. Sorry for the confusion.

Just to be clear: connman claimed that wifi connection was disconnected,
but 'iw wlan0 link' showed that I was connected to Ubuntu network.
Post by Samuel Ortiz
Post by Kalle Valo
The problem is that while roaming between APs inside ESS
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.
Well it really got disconnected from the AP, so ConnMan should just track
that.
Well, it depends how we want to handle intra-ESS roaming. I see two
choises:

1) wpasupplicant manages roaming, connman just provides SSID and other settings
2) connman manages roaming

We should definitely go with option 1, it's faster and wpasupplicant has
the best information to choose which AP to connect to. So roaming between
APs on an ESS would be transparent from connman point of view.
Post by Samuel Ortiz
I'm really not a big fan of trying to be smarter than wpa_supplicant. In my
experience, it's the shortest paths to new bugs
The problem here is that when wpasupplicant is roaming between APs it
goes to the disconnected state and then immediately to the scanning
state. The connman wifi plugin doesn't handle this properly.
Post by Samuel Ortiz
Post by Kalle Valo
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.
It looks a bit like a hack to me, the fundamental issue (ConnMan not tracking
the wpa_supplicant states properly, it seems) is not fixed.
I agree my patch is a bit hackish, but it makes a huge difference here
at UDS. Without these two patches (and Mohamed's busy loop fix) connman
is unusable with a large wifi network.

Currently wifi plugin makes wrong assumptions how wpasupplicant works
and what the different wpasupplicant states mean. The proper fix would
be to change wpasupplicant to not use disconnected state when roaming.
The disconnected state should be used only when wpasupplicant is certain
that it cannot connect to the ESS anymore, for example after scanning
two times and not finding any suitable APs.

I think I can work on changing wpasupplicant at some point, but it will
take few months before I can find the time. My short term goal is to
make connman wifi reliable enough for the users.

Thank you for the comments.
--
Kalle Valo
Kalle Valo
2010-10-26 16:35:03 UTC
Permalink
Post by Kalle Valo
*** BLURB HERE ***
Heh, sorry about this. git send-email also sent an emacs backup file :)
--
Kalle Valo
Kalle Valo
2010-10-26 16:43:10 UTC
Permalink
Post by Kalle Valo
I'm at UDS right now and I have been debugging gsupplicant extensively and
I have had quite a lot of problems. I noticed a problem how the wifi
plugin handles the wpasupplicant disconnect state. Here are two patches
how I propose to fix the issues. At least in my case the patches
helped a lot.
Sorry, I forgot to mention that these patches are on top of pile of
other patches. For example, Mohamed's " Fix deadlock when disassociate
while associating." patch. But please take a look and comment.
--
Kalle Valo
Loading...