Could someone kindly review this patch ?
-----Original Message-----
From: Leena S Gunda (WT01 - Innovation Group)
Sent: Wed 10/13/2010 3:28 PM
To: [email protected]
Subject: [Patch] Fix for connect-failure after kill/restart connmand
Below is the patch for connman bug filed on bugs.meego.com
http://bugs.meego.com/show_bug.cgi?id=6897
Description:
When connected to an AP, doing a `kill -9 <connmand_pid>` and restarting
connmand will fail to auto connect to the WiFi service. The
/var/lib/connman/default.profile shows a 'connect-failed' message for the
auto-connect AP.
Analysis:
connmand communicates to wpa_supplicant for WiFi using dbus messages.
wpa_supplicant is responsible to communicate with the underlying wlan driver
and add/remove/scan network based on the dbus request from connmand. When
connmand connects to an AP, wpa_supplicant will ask the wlan driver to
associate to that AP and a network object is created by wpa_supplicant. When
connmand is killed, this network is still active and the wlan is also
associated to the AP.
Now when connmand is restarted, it will get the interface, add network and ask
wpa_supplicant to select this network. wpa_supplicant will in turn ask the wlan
driver to associate to this network. The driver in turn will now dis-associate
from the old network and send a 'Disassociation notification'. On receiving
this disassociation event, wpa_supplicant will send a deauthenticate request to
the driver and set the state to disconnected. As a result connmand gets a
state_changed signal with state disconnected and hence we get a connect-failure
message.
Solution:
The new dbus interface for wpa_supplicant (fi.w1.wpa_supplicant1) provides a
properties Get method for the network objects. This dbus requests returns the
list of current network objects for the specified interface. When connmand get
a reply for getInterface, fetching this network list and removing all the old
network objects for the respective interface will fix this issue.
In order to use the new dbus interface for wpa_supplicant
(fi.w1.wpa_supplicant1), also adding functions to GetInterface and
RemoveNetwork on this interface.
Patch:
----------
plugins/supplicant.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 170 insertions(+), 0 deletions(-)
diff --git a/plugins/supplicant.c b/plugins/supplicant.c
index 469e109..d65d84b 100644
--- a/plugins/supplicant.c
+++ b/plugins/supplicant.c
@@ -56,6 +56,10 @@
#define SUPPLICANT_INTF "fi.epitest.hostap.WPASupplicant"
#define SUPPLICANT_PATH "/fi/epitest/hostap/WPASupplicant"
+#define SUPPLICANT_NEW_NAME "fi.w1.wpa_supplicant1"
+#define SUPPLICANT_NEW_INTF "fi.w1.wpa_supplicant1"
+#define SUPPLICANT_NEW_PATH "/fi/w1/wpa_supplicant1"
+
/* Taken from "WPA Supplicant - Common definitions" */
enum supplicant_state {
/**
@@ -703,6 +707,171 @@ static int add_interface(struct supplicant_task *task)
return -EINPROGRESS;
}
+static int get_interface_path (char *ifname, char **result)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+ char *path;
+
+ message = dbus_message_new_method_call(SUPPLICANT_NEW_NAME,
SUPPLICANT_NEW_PATH,
+ SUPPLICANT_NEW_INTF, "GetInterface");
+
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_set_auto_start(message, FALSE);
+
+ dbus_message_append_args(message, DBUS_TYPE_STRING, &ifname,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to get interface");
+
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for get interface");
+
+ dbus_message_unref(reply);
+ return -EIO;
+ }
+
+ *result = g_strdup(path);
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int delete_network (char *task_path, char *network_path)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ if (task_path == NULL || network_path == NULL)
+ return -EINVAL;
+
+ message = dbus_message_new_method_call(SUPPLICANT_NEW_NAME, task_path,
+ SUPPLICANT_NEW_INTF ".Interface",
"RemoveNetwork");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_set_auto_start(message, FALSE);
+
+ dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &network_path,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to remove network");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int get_networks (char *ifname)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+ char *task_path = NULL;
+ char *interface_name, *method_name;
+
+ if (get_interface_path(ifname, &task_path) != 0)
+ return -1;
+
+ message = dbus_message_new_method_call(SUPPLICANT_NEW_NAME, task_path,
+ DBUS_INTERFACE_PROPERTIES, "Get");
+
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_set_auto_start(message, FALSE);
+
+ interface_name = SUPPLICANT_NEW_INTF ".Interface";
+ method_name = "Networks";
+ dbus_message_append_args(message, DBUS_TYPE_STRING, &interface_name,
+ DBUS_TYPE_STRING, &method_name,
DBUS_TYPE_INVALID);
+
+ dbus_error_init(&error);
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ message, -1, &error);
+
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to get networks list");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ if (reply) {
+ DBusMessageIter iter;
+
+ if (dbus_message_iter_init(reply, &iter) == FALSE)
+ return -EIO;
+
+ if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT)
{
+ DBusMessageIter variant;
+
+ dbus_message_iter_recurse(&iter, &variant);
+
+ if (dbus_message_iter_get_arg_type(&variant) ==
DBUS_TYPE_ARRAY) {
+ DBusMessageIter array;
+
+ dbus_message_iter_recurse(&variant, &array);
+
+ while (dbus_message_iter_get_arg_type(&array)
!= DBUS_TYPE_INVALID) {
+ char *path;
+
+ dbus_message_iter_get_basic(&array,
&path);
+ delete_network(task_path, path);
+
+ dbus_message_iter_next(&array);
+ }
+ }
+ }
+ }
+
+ dbus_message_unref(message);
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
static void get_interface_reply(DBusPendingCall *call, void *user_data)
{
struct supplicant_task *task = user_data;
@@ -737,6 +906,7 @@ static void get_interface_reply(DBusPendingCall *call, void
*user_data)
task->created = FALSE;
connman_device_set_powered(task->device, TRUE);
+ get_networks(task->ifname);
done:
dbus_message_unref(reply);
----------
Please do not print this email unless it is absolutely necessary.
The information contained in this electronic message and any attachments to
this message are intended for the exclusive use of the addressee(s) and may
contain proprietary, confidential or privileged information. If you are not the
intended recipient, you should not disseminate, distribute or copy this e-mail.
Please notify the sender immediately and destroy all copies of this message and
any attachments.
WARNING: Computer viruses can be transmitted via email. The recipient should
check this email and any attachments for the presence of viruses. The company
accepts no liability for any damage caused by any virus transmitted by this
email.
www.wipro.com
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman