Send connman mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
https://lists.01.org/mailman/listinfo/connman
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of connman digest..."
Today's Topics:
1. [PATCH 1/2] Fast-reconnect and Band-steering support
([email protected])
2. [PATCH 2/2] Connectable network in wpa_s should not be marked
unavailable ([email protected])
----------------------------------------------------------------------
Message: 1
Date: Fri, 8 Apr 2016 00:29:47 -0700
From: [email protected]
To: [email protected]
Cc: Naveen Singh <[email protected]>
Subject: [PATCH 1/2] Fast-reconnect and Band-steering support
Message-ID: <[email protected]>
From: Naveen Singh <[email protected]>
This patch contains new implementations for following:
1. Band Steering and Load balancing Support: Enterprise AP sometimes
denies association with assoc status code 17. The reason AP sends
this code, is to steer to some other AP (in a different band) or for
doing load balancing (in case this AP is heavily loaded). This will not
work with current connman as connman would take this disconnect
notification as normal disconnect and disable the network. This act
would cause wpa_s search for the next BSSID stop. The next time connect
attempt is issued from connman, the story would repeat again. The idea
of this patch is to not interfere with BSSID selection logic of wpa_s.
wpa_s was sending disconnect reason code on DBUS as a part of
PropertyChanged signal but there was no notification for assoc status
code.
In this commit id of hostapd (c7fb678f3109e62af1ef39be9b12bf8370c35bde)
wpa_s is also sending assoc status code as a part of DBUS
PropertyChanged signal. Idea here is that on a disconnect notification
from wpa_s connman would look into the assoc status code and if it is
set to 17, it would not proceed. This will let wpa_s continue with its
own BSSID selection logic.
2. Optimize DBUS call - In case network path is Not NULL (means a
profile is already plumbed in wpa_s), network_remove should only
be called if the new network is different from what is sitting in
wpa_s. The notion of new network here is SSID, security type and
passphrase. If the new network is same as the one in wpa_s, no need
to do remove, add and select. This would save 3 DBUS calls to wpa_s.
3. Fast Reconnect: On receiving a deauth with reason code 6, 7 or 4
wpa_supplicant will immediately try to connect back. Now with current
implementation of connman, a disconnect notification will cause network
to get disabled and connection procedure would stop. This also impacts
the roaming time in case disconnect is because of any other reason code.
The act of disabling network severly affects wpa_s connection state
machine as it would generate a deauth to current network when half way
the connection was done. The idea here is that we do not disable network
on disconnect and let wpa_s keep trying to find out that network. Only
when connman has another network this network would be removed and new
network would be added.
---
gsupplicant/gsupplicant.h | 2 +
gsupplicant/supplicant.c | 126 ++++++++++++++++++++++++++++++++++++++++++++--
plugins/wifi.c | 51 ++++++++++++++++---
3 files changed, 170 insertions(+), 9 deletions(-)
diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index a2a7605..2f9806e 100644
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -353,6 +353,8 @@ struct _GSupplicantCallbacks {
GSupplicantPeerState state);
void (*peer_request) (GSupplicantPeer *peer);
void (*debug) (const char *str);
+ void (*update_disconnect_reasoncode)(GSupplicantInterface *interface,
int reasoncode);
+ void (*update_assoc_status_code)(GSupplicantInterface *interface, int
reasoncode);
};
typedef struct _GSupplicantCallbacks GSupplicantCallbacks;
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index c8fbef6..32cbc14 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -150,6 +150,13 @@ struct _GSupplicantWpsCredentials {
char *key;
};
+struct added_network_information {
+ char * ssid;
+ GSupplicantSecurity security;
+ char * passphrase;
+ char * private_passphrase;
+};
+
struct _GSupplicantInterface {
char *path;
char *network_path;
@@ -181,6 +188,7 @@ struct _GSupplicantInterface {
GHashTable *bss_mapping;
void *data;
const char *pending_peer_path;
+ struct added_network_information network_info;
};
struct g_supplicant_bss {
@@ -387,6 +395,63 @@ static GSupplicantState string2state(const char *state)
return G_SUPPLICANT_STATE_UNKNOWN;
}
+static bool compare_network_parameters(GSupplicantInterface *interface,
GSupplicantSSID *ssid)
+{
+ if (memcmp(interface->network_info.ssid, ssid->ssid, ssid->ssid_len))
+ return FALSE;
+
+ if (interface->network_info.security != ssid->security)
+ return FALSE;
+
+ if (interface->network_info.passphrase &&
+ g_strcmp0(interface->network_info.passphrase, ssid->passphrase)
!= 0) {
+ return FALSE;
+ }
+
+ if (interface->network_info.private_passphrase &&
+ g_strcmp0(interface->network_info.private_passphrase,
ssid->private_key_passphrase) != 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void remove_network_information(GSupplicantInterface * interface)
+{
+ g_free(interface->network_info.ssid);
+ g_free(interface->network_info.passphrase);
+ g_free(interface->network_info.private_passphrase);
+ interface->network_info.ssid = NULL;
+ interface->network_info.passphrase = NULL;
+ interface->network_info.private_passphrase = NULL;
+}
+
+static int store_network_information(GSupplicantInterface * interface,
GSupplicantSSID *ssid)
+{
+ interface->network_info.ssid = g_malloc(ssid->ssid_len + 1);
+ if (interface->network_info.ssid != NULL) {
+ memcpy(interface->network_info.ssid, ssid->ssid,
ssid->ssid_len);
+ interface->network_info.ssid[ssid->ssid_len] = '\0';
+ } else {
+ return -ENOMEM;
+ }
+
+ interface->network_info.security = ssid->security;
+
+ if ((ssid->security == G_SUPPLICANT_SECURITY_WEP ||
+ ssid->security == G_SUPPLICANT_SECURITY_PSK ||
+ ssid->security == G_SUPPLICANT_SECURITY_NONE) &&
+ ssid->passphrase) {
+ interface->network_info.passphrase = g_strdup(ssid->passphrase);
+ }
+
+ if (ssid->security == G_SUPPLICANT_SECURITY_IEEE8021X &&
ssid->private_key_passphrase) {
+ interface->network_info.private_passphrase =
g_strdup(ssid->private_key_passphrase);
+ }
+
+ return 0;
+}
+
static void callback_system_ready(void)
{
if (system_ready)
@@ -576,6 +641,30 @@ static void callback_peer_request(GSupplicantPeer *peer)
callbacks_pointer->peer_request(peer);
}
+static void callback_disconnect_reason_code(GSupplicantInterface *interface,
int reason_code)
+{
+ if (!callbacks_pointer)
+ return;
+
+ if (!callbacks_pointer->update_disconnect_reasoncode)
+ return;
+
+ if (reason_code != 0)
+ callbacks_pointer->update_disconnect_reasoncode(interface,
reason_code);
+}
+
+static void callback_assoc_status_code(GSupplicantInterface *interface, int
status_code)
+{
+ if (!callbacks_pointer)
+ return;
+
+ if (!callbacks_pointer->update_assoc_status_code)
+ return;
+
+ callbacks_pointer->update_assoc_status_code(interface, status_code);
+
+}
+
static void remove_group(gpointer data)
{
GSupplicantGroup *group = data;
@@ -619,6 +708,7 @@ static void remove_interface(gpointer data)
g_free(interface->ifname);
g_free(interface->driver);
g_free(interface->bridge);
+ remove_network_information(interface);
g_free(interface);
}
@@ -2135,9 +2225,22 @@ static void interface_property(const char *key,
DBusMessageIter *iter,
} else if (g_strcmp0(key, "Networks") == 0) {
supplicant_dbus_array_foreach(iter, interface_network_added,
interface);
- } else
+ } else if (g_strcmp0(key, "DisconnectReason") == 0) {
+ int reason_code;
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
+ dbus_message_iter_get_basic(iter, &reason_code);
+ callback_disconnect_reason_code(interface, reason_code);
+ }
+ } else if (g_strcmp0(key, "AssocStatusCode") == 0) {
+ int status_code;
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
+ dbus_message_iter_get_basic(iter, &status_code);
+ callback_assoc_status_code(interface, status_code);
+ }
+ } else {
SUPPLICANT_DBG("key %s type %c",
key, dbus_message_iter_get_arg_type(iter));
+ }
}
static void scan_network_update(DBusMessageIter *iter, void *user_data)
@@ -4111,6 +4214,8 @@ static void interface_add_network_result(const char
*error,
interface->network_path = g_strdup(path);
+ store_network_information(interface, data->ssid);
+
supplicant_dbus_method_call(data->interface->path,
SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
interface_select_network_params,
@@ -4708,6 +4813,19 @@ int g_supplicant_interface_connect(GSupplicantInterface
*interface,
g_free(data->path);
dbus_free(data);
+ /*
+ * If this add network is for the same network for which
+ * wpa_supplicant already has a profile then do not need
+ * to add another profile. Only if the profile that
needs
+ * to get added is different from what is there in wpa_s
+ * delete the current one. A network is identified by
its
+ * SSID, security_type and passphrase (private
passphrase
+ * in case security type is 802.11x).
+ */
+ if (compare_network_parameters(interface, ssid)) {
+ return -EALREADY;
+ }
+
intf_data = dbus_malloc0(sizeof(*intf_data));
if (!intf_data)
return -ENOMEM;
@@ -4753,8 +4871,10 @@ static void network_remove_result(const char *error,
result = -ECONNABORTED;
}
- g_free(data->interface->network_path);
- data->interface->network_path = NULL;
+ g_free(data->interface->network_path);
+ data->interface->network_path = NULL;
+
+ remove_network_information(data->interface);
if (data->network_remove_in_progress == TRUE) {
data->network_remove_in_progress = FALSE;
diff --git a/plugins/wifi.c b/plugins/wifi.c
index bb1cabc..e76423d 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -71,6 +71,8 @@
#define P2P_LISTEN_PERIOD 500
#define P2P_LISTEN_INTERVAL 2000
+#define GSUP_80211_ASSOC_STATUS_NO_ADDITIONAL_CLIENT 17
+#define WPA_SUP_LOAD_SHAPING_MAX_RETRIES 3
static struct connman_technology *wifi_technology = NULL;
static struct connman_technology *p2p_technology = NULL;
@@ -128,6 +130,7 @@ struct wifi_data {
unsigned flags;
unsigned int watch;
int retries;
+ int wpa_sup_load_shaping_retries;
struct hidden_params *hidden;
bool postpone_hidden;
struct wifi_tethering_info *tethering_param;
@@ -144,6 +147,8 @@ struct wifi_data {
bool p2p_connecting;
bool p2p_device;
int servicing;
+ int disconnect_reasoncode;
+ int assoc_statuscode;
};
static GList *iface_list = NULL;
@@ -2291,6 +2296,19 @@ static bool handle_wps_completion(GSupplicantInterface
*interface,
return true;
}
+static bool handle_assoc_status_code(GSupplicantInterface *interface,
+ struct wifi_data *wifi)
+{
+ if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
+ wifi->assoc_statuscode ==
GSUP_80211_ASSOC_STATUS_NO_ADDITIONAL_CLIENT &&
+ wifi->wpa_sup_load_shaping_retries <
WPA_SUP_LOAD_SHAPING_MAX_RETRIES) {
+ wifi->wpa_sup_load_shaping_retries ++;
+ return TRUE;
+ }
+ wifi->wpa_sup_load_shaping_retries = 0;
+ return FALSE;
+}
+
static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
struct connman_network *network,
struct wifi_data *wifi)
@@ -2382,6 +2400,10 @@ static void interface_state(GSupplicantInterface
*interface)
break;
connman_network_set_connected(network, true);
+
+ wifi->disconnect_reasoncode = 0;
+ wifi->assoc_statuscode = 0;
+ wifi->wpa_sup_load_shaping_retries = 0;
break;
case G_SUPPLICANT_STATE_DISCONNECTED:
@@ -2399,6 +2421,9 @@ static void interface_state(GSupplicantInterface
*interface)
if (is_idle(wifi))
break;
+ if (handle_assoc_status_code(interface, wifi))
+ break;
+
/* If previous state was 4way-handshake, then
* it's either: psk was incorrect and thus we retry
* or if we reach the maximum retries we declare the
@@ -2407,12 +2432,6 @@ static void interface_state(GSupplicantInterface
*interface)
network, wifi))
break;
- /* We disable the selected network, if not then
- * wpa_supplicant will loop retrying */
- if (g_supplicant_interface_enable_selected_network(interface,
- FALSE) != 0)
- DBG("Could not disable selected network");
-
connman_network_set_connected(network, false);
connman_network_set_associating(network, false);
wifi->disconnecting = false;
@@ -2935,6 +2954,24 @@ static void debug(const char *str)
connman_debug("%s", str);
}
+static void wifi_disconnect_reasoncode(GSupplicantInterface *interface, int
reasoncode)
+{
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+ if (wifi != NULL) {
+ wifi->disconnect_reasoncode = reasoncode;
+ }
+}
+
+static void wifi_assoc_status_code(GSupplicantInterface *interface, int
status_code)
+{
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+ if (wifi != NULL) {
+ wifi->assoc_statuscode = status_code;
+ }
+}
+
static const GSupplicantCallbacks callbacks = {
.system_ready = system_ready,
.system_killed = system_killed,
@@ -2953,6 +2990,8 @@ static const GSupplicantCallbacks callbacks = {
.peer_changed = peer_changed,
.peer_request = peer_request,
.debug = debug,
+ .update_disconnect_reasoncode = wifi_disconnect_reasoncode,
+ .update_assoc_status_code = wifi_assoc_status_code,
};
--
2.8.0.rc3.226.g39d4020
------------------------------
Message: 2
Date: Fri, 8 Apr 2016 00:29:48 -0700
From: [email protected]
To: [email protected]
Cc: Naveen Singh <[email protected]>
Subject: [PATCH 2/2] Connectable network in wpa_s should not be marked
unavailable
Message-ID: <[email protected]>
From: Naveen Singh <[email protected]>
If a network is added to wpa_s through AddNetwork, never mark that
network unavailable even if scan did not find this network. The reason
for this is that even if this network is not seen in scan results, wpa_s
will keep tring to connect to same network and in case this network is
found later on, wifi connection will be established but since it was
marked unavailable earlier, connman service state transition would not
happen.
---
include/network.h | 4 ++++
plugins/wifi.c | 29 +++++++++++++++++++++++++++++
src/device.c | 5 ++++-
src/network.c | 12 ++++++++++++
4 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/include/network.h b/include/network.h
index d772699..bf8d809 100644
--- a/include/network.h
+++ b/include/network.h
@@ -102,6 +102,10 @@ bool connman_network_get_connected(struct connman_network
*network);
bool connman_network_get_associating(struct connman_network *network);
+bool connman_network_get_connectable(struct connman_network *network);
+
+int connman_network_set_connectable(struct connman_network *network, bool
connectable);
+
void connman_network_clear_hidden(void *user_data);
int connman_network_connect_hidden(struct connman_network *network,
char *identity, char* passphrase, void *user_data);
diff --git a/plugins/wifi.c b/plugins/wifi.c
index e76423d..64d42d8 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -2100,7 +2100,21 @@ static int network_connect(struct connman_network
*network)
wifi->pending_network = network;
g_free(ssid);
} else {
+
+ /*
+ * This is the network that is going to get plumbed into wpa_s
+ * Mark the previous network that is plumbed in wpa_s as not
+ * connectable and then the current one as connectable. This
flag
+ * will be used to ensure that the network that is sitting in
wpa_s
+ * never gets marked unavailable even though the scan did not
find
+ * this network.
+ */
+ if (wifi->network) {
+ connman_network_set_connectable(wifi->network, false);
+ }
+
wifi->network = connman_network_ref(network);
+ connman_network_set_connectable(wifi->network, true);
wifi->retries = 0;
return g_supplicant_interface_connect(interface, ssid,
@@ -2124,6 +2138,7 @@ static void disconnect_callback(int result,
GSupplicantInterface *interface,
}
if (wifi->network) {
+ connman_network_set_connectable(wifi->network, false);
connman_network_set_connected(wifi->network, false);
wifi->network = NULL;
}
@@ -2741,6 +2756,20 @@ static void network_removed(GSupplicantNetwork *network)
if (!connman_network)
return;
+ /*
+ * wpa_s did not find this network in last scan and hence it generated
+ * this callback. In case if this is the network with which device was
connected
+ * to, even though network_removed was called, wpa_s will keep trying
to connect to
+ * the same network and once the network is back, it will proceed with
the connection.
+ * Now if connman would have removed this network from network hash
table, on a successful
+ * connection complete indication service state machine will not move.
End result would be
+ * only a L2 level connection and no IP address. This check ensures
that even if the
+ * network_removed gets called for the previously connected network do
not remove it from
+ * network hash table.
+ */
+ if (wifi->network == connman_network)
+ return;
+
wifi->networks = g_slist_remove(wifi->networks, connman_network);
connman_device_remove_network(wifi->device, connman_network);
diff --git a/src/device.c b/src/device.c
index 188106c..22d9cde 100644
--- a/src/device.c
+++ b/src/device.c
@@ -671,7 +671,7 @@ static void mark_network_unavailable(gpointer key, gpointer
value,
struct connman_network *network = value;
if (connman_network_get_connected(network) ||
- connman_network_get_connecting(network))
+ connman_network_get_connecting(network) ||
connman_network_get_connectable(network))
return;
connman_network_set_available(network, false);
@@ -688,6 +688,9 @@ static gboolean remove_unavailable_network(gpointer key,
gpointer value,
if (connman_network_get_available(network))
return FALSE;
+ if (connman_network_get_connectable(network))
+ return FALSE;
+
return TRUE;
}
diff --git a/src/network.c b/src/network.c
index db3d2f3..a24eadb 100644
--- a/src/network.c
+++ b/src/network.c
@@ -50,6 +50,7 @@ struct connman_network {
bool available;
bool connected;
bool roaming;
+ bool connectable;
uint8_t strength;
uint16_t frequency;
char *identifier;
@@ -825,6 +826,17 @@ static gint compare_priority(gconstpointer a,
gconstpointer b)
return driver2->priority - driver1->priority;
}
+int connman_network_set_connectable(struct connman_network *network, bool
connectable)
+{
+ network->connectable = connectable;
+ return 0;
+}
+
+bool connman_network_get_connectable(struct connman_network *network)
+{
+ return network->connectable;
+}
+
/**
* connman_network_driver_register:
* @driver: network driver definition
--
2.8.0.rc3.226.g39d4020
------------------------------
Subject: Digest Footer
_______________________________________________
connman mailing list
[email protected]
https://lists.01.org/mailman/listinfo/connman
------------------------------
End of connman Digest, Vol 6, Issue 4
*************************************