gsupplicant: Support empty property set responses
[framework/connectivity/connman.git] / gsupplicant / supplicant.c
index 4850b63..0e4f932 100644 (file)
@@ -24,6 +24,8 @@
 #endif
 
 #include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdint.h>
 #include <syslog.h>
@@ -31,9 +33,6 @@
 #include <glib.h>
 #include <gdbus.h>
 
-#define CONNMAN_API_SUBJECT_TO_CHANGE
-#include <connman/log.h>
-
 #include "dbus.h"
 #include "gsupplicant.h"
 
@@ -139,6 +138,7 @@ static GHashTable *bss_mapping;
 
 struct _GSupplicantInterface {
        char *path;
+       char *network_path;
        unsigned int keymgmt_capa;
        unsigned int authalg_capa;
        unsigned int proto_capa;
@@ -194,6 +194,25 @@ struct g_supplicant_bss {
        dbus_bool_t ieee8021x;
 };
 
+static inline void debug(const char *format, ...)
+{
+       char str[256];
+       va_list ap;
+
+       if (callbacks_pointer->debug == NULL)
+               return;
+
+       va_start(ap, format);
+
+       if (vsnprintf(str, sizeof(str), format, ap) > 0)
+               callbacks_pointer->debug(str);
+
+       va_end(ap);
+}
+
+#define SUPPLICANT_DBG(fmt, arg...) \
+       debug("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg);
+
 static GSupplicantMode string2mode(const char *mode)
 {
        if (mode == NULL)
@@ -213,7 +232,7 @@ static const char *mode2string(GSupplicantMode mode)
        case G_SUPPLICANT_MODE_UNKNOWN:
                break;
        case G_SUPPLICANT_MODE_INFRA:
-               return "infra";
+               return "managed";
        case G_SUPPLICANT_MODE_IBSS:
                return "adhoc";
        }
@@ -299,7 +318,7 @@ static void callback_system_killed(void)
 
 static void callback_interface_added(GSupplicantInterface *interface)
 {
-       DBG("");
+       SUPPLICANT_DBG("");
 
        if (callbacks_pointer == NULL)
                return;
@@ -423,7 +442,7 @@ static void debug_strvalmap(const char *label, struct strvalmap *map,
 
        for (i = 0; map[i].str != NULL; i++) {
                if (val & map[i].val)
-                       DBG("%s: %s", label, map[i].str);
+                       SUPPLICANT_DBG("%s: %s", label, map[i].str);
        }
 }
 
@@ -577,7 +596,7 @@ static void interface_capability(const char *key, DBusMessageIter *iter,
                supplicant_dbus_array_foreach(iter,
                                interface_capability_mode, interface);
        else
-               DBG("key %s type %c",
+               SUPPLICANT_DBG("key %s type %c",
                                key, dbus_message_iter_get_arg_type(iter));
 }
 
@@ -590,7 +609,7 @@ void g_supplicant_interface_set_data(GSupplicantInterface *interface,
        interface->data = data;
 }
 
-const void *g_supplicant_interface_get_data(GSupplicantInterface *interface)
+void *g_supplicant_interface_get_data(GSupplicantInterface *interface)
 {
        if (interface == NULL)
                return NULL;
@@ -703,7 +722,7 @@ static void merge_network(GSupplicantNetwork *network)
        mode = g_hash_table_lookup(network->config_table, "mode");
        key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt");
 
-       DBG("ssid %s mode %s", ssid, mode);
+       SUPPLICANT_DBG("ssid %s mode %s", ssid, mode);
 
        if (ssid != NULL)
                ssid_len = strlen(ssid);
@@ -718,7 +737,7 @@ static void merge_network(GSupplicantNetwork *network)
                g_string_append_printf(str, "%02x", ssid[i]);
 
        if (g_strcmp0(mode, "0") == 0)
-               g_string_append_printf(str, "_infra");
+               g_string_append_printf(str, "_managed");
        else if (g_strcmp0(mode, "1") == 0)
                g_string_append_printf(str, "_adhoc");
 
@@ -727,7 +746,7 @@ static void merge_network(GSupplicantNetwork *network)
 
        group = g_string_free(str, FALSE);
 
-       DBG("%s", group);
+       SUPPLICANT_DBG("%s", group);
 
        g_free(group);
 
@@ -763,7 +782,7 @@ static void network_property(const char *key, DBusMessageIter *iter,
                                                g_strdup(key), g_strdup(str));
                }
        } else
-               DBG("key %s type %c",
+               SUPPLICANT_DBG("key %s type %c",
                                key, dbus_message_iter_get_arg_type(iter));
 }
 
@@ -773,7 +792,7 @@ static void interface_network_added(DBusMessageIter *iter, void *user_data)
        GSupplicantNetwork *network;
        const char *path = NULL;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        dbus_message_iter_get_basic(iter, &path);
        if (path == NULL)
@@ -805,7 +824,7 @@ static void interface_network_added(DBusMessageIter *iter, void *user_data)
        }
 
        supplicant_dbus_property_get_all(path,
-                               SUPPLICANT_INTERFACE ".Interface.Network",
+                               SUPPLICANT_INTERFACE ".Network",
                                                network_property, network);
 }
 
@@ -1012,7 +1031,7 @@ static void bss_property(const char *key, DBusMessageIter *iter,
        if (bss->interface == NULL)
                return;
 
-       DBG("key %s", key);
+       SUPPLICANT_DBG("key %s", key);
 
        if (key == NULL) {
                if (bss->ieee8021x == TRUE)
@@ -1114,7 +1133,7 @@ static void bss_property(const char *key, DBusMessageIter *iter,
                                G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
                        bss->psk = TRUE;
        } else
-               DBG("key %s type %c",
+               SUPPLICANT_DBG("key %s type %c",
                                key, dbus_message_iter_get_arg_type(iter));
 }
 
@@ -1125,7 +1144,7 @@ static void interface_bss_added(DBusMessageIter *iter, void *user_data)
        struct g_supplicant_bss *bss;
        const char *path = NULL;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        dbus_message_iter_get_basic(iter, &path);
        if (path == NULL)
@@ -1134,7 +1153,7 @@ static void interface_bss_added(DBusMessageIter *iter, void *user_data)
        if (g_strcmp0(path, "/") == 0)
                return;
 
-       DBG("%s", path);
+       SUPPLICANT_DBG("%s", path);
 
        network = g_hash_table_lookup(interface->bss_mapping, path);
        if (network != NULL) {
@@ -1158,7 +1177,7 @@ static void interface_bss_added(DBusMessageIter *iter, void *user_data)
        }
 
        supplicant_dbus_property_get_all(path,
-                                       SUPPLICANT_INTERFACE ".Interface.BSS",
+                                       SUPPLICANT_INTERFACE ".BSS",
                                                        bss_property, bss);
 }
 
@@ -1193,7 +1212,7 @@ static void interface_property(const char *key, DBusMessageIter *iter,
        if (interface == NULL)
                return;
 
-       DBG("%s", key);
+       SUPPLICANT_DBG("%s", key);
 
        if (key == NULL) {
                debug_strvalmap("KeyMgmt capability", keymgmt_map,
@@ -1229,7 +1248,7 @@ static void interface_property(const char *key, DBusMessageIter *iter,
                                callback_interface_state(interface);
                        }
 
-               DBG("state %s (%d)", str, interface->state);
+               SUPPLICANT_DBG("state %s (%d)", str, interface->state);
        } else if (g_strcmp0(key, "Scanning") == 0) {
                dbus_bool_t scanning = FALSE;
 
@@ -1278,10 +1297,49 @@ static void interface_property(const char *key, DBusMessageIter *iter,
                supplicant_dbus_array_foreach(iter, interface_network_added,
                                                                interface);
        } else
-               DBG("key %s type %c",
+               SUPPLICANT_DBG("key %s type %c",
                                key, dbus_message_iter_get_arg_type(iter));
 }
 
+static void scan_network_update(DBusMessageIter *iter, void *user_data)
+{
+       GSupplicantInterface *interface = user_data;
+       GSupplicantNetwork *network;
+       char *path;
+
+       if (iter == NULL)
+               return;
+
+       dbus_message_iter_get_basic(iter, &path);
+
+       if (path == NULL)
+               return;
+
+       if (g_strcmp0(path, "/") == 0)
+               return;
+
+       /* Update the network details based on scan BSS data */
+       network = g_hash_table_lookup(interface->bss_mapping, path);
+       if (network != NULL)
+               callback_network_added(network);
+}
+
+static void scan_bss_data(const char *key, DBusMessageIter *iter,
+                               void *user_data)
+{
+       GSupplicantInterface *interface = user_data;
+
+       if (iter)
+               supplicant_dbus_array_foreach(iter, scan_network_update,
+                                               interface);
+
+       if (interface->scan_callback != NULL)
+               interface->scan_callback(0, interface, interface->scan_data);
+
+       interface->scan_callback = NULL;
+       interface->scan_data = NULL;
+}
+
 static GSupplicantInterface *interface_alloc(const char *path)
 {
        GSupplicantInterface *interface;
@@ -1310,7 +1368,7 @@ static void interface_added(DBusMessageIter *iter, void *user_data)
        GSupplicantInterface *interface;
        const char *path = NULL;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        dbus_message_iter_get_basic(iter, &path);
        if (path == NULL)
@@ -1331,9 +1389,7 @@ static void interface_added(DBusMessageIter *iter, void *user_data)
        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
                supplicant_dbus_property_foreach(iter, interface_property,
                                                                interface);
-               DBG("NULL prop");
                interface_property(NULL, NULL, interface);
-               DBG("DONE");
                return;
        }
 
@@ -1387,20 +1443,20 @@ static void service_property(const char *key, DBusMessageIter *iter,
                                debug_level = i;
                                break;
                        }
-               DBG("Debug level %d", debug_level);
+               SUPPLICANT_DBG("Debug level %d", debug_level);
        } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
                dbus_message_iter_get_basic(iter, &debug_timestamp);
-               DBG("Debug timestamp %u", debug_timestamp);
+               SUPPLICANT_DBG("Debug timestamp %u", debug_timestamp);
        } else if (g_strcmp0(key, "DebugShowKeys") == 0) {
                dbus_message_iter_get_basic(iter, &debug_showkeys);
-               DBG("Debug show keys %u", debug_showkeys);
+               SUPPLICANT_DBG("Debug show keys %u", debug_showkeys);
        } else if (g_strcmp0(key, "Interfaces") == 0) {
                supplicant_dbus_array_foreach(iter, interface_added, NULL);
        } else if (g_strcmp0(key, "EapMethods") == 0) {
                supplicant_dbus_array_foreach(iter, eap_method, NULL);
                debug_strvalmap("EAP method", eap_method_map, eap_methods);
        } else
-               DBG("key %s type %c",
+               SUPPLICANT_DBG("key %s type %c",
                                key, dbus_message_iter_get_arg_type(iter));
 }
 
@@ -1408,7 +1464,7 @@ static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
 {
        const char *name = NULL, *old = NULL, *new = NULL;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
                return;
@@ -1445,7 +1501,7 @@ static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
 
 static void signal_properties_changed(const char *path, DBusMessageIter *iter)
 {
-       DBG("");
+       SUPPLICANT_DBG("");
 
        if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
                return;
@@ -1455,7 +1511,7 @@ static void signal_properties_changed(const char *path, DBusMessageIter *iter)
 
 static void signal_interface_added(const char *path, DBusMessageIter *iter)
 {
-       DBG("path %s %s", path, SUPPLICANT_PATH);
+       SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
 
        if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
                interface_added(iter, NULL);
@@ -1463,7 +1519,7 @@ static void signal_interface_added(const char *path, DBusMessageIter *iter)
 
 static void signal_interface_removed(const char *path, DBusMessageIter *iter)
 {
-       DBG("");
+       SUPPLICANT_DBG("");
 
        if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
                interface_removed(iter, NULL);
@@ -1473,7 +1529,7 @@ static void signal_interface_changed(const char *path, DBusMessageIter *iter)
 {
        GSupplicantInterface *interface;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        interface = g_hash_table_lookup(interface_table, path);
        if (interface == NULL)
@@ -1487,7 +1543,7 @@ static void signal_scan_done(const char *path, DBusMessageIter *iter)
        GSupplicantInterface *interface;
        dbus_bool_t success = FALSE;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        interface = g_hash_table_lookup(interface_table, path);
        if (interface == NULL)
@@ -1495,25 +1551,30 @@ static void signal_scan_done(const char *path, DBusMessageIter *iter)
 
        dbus_message_iter_get_basic(iter, &success);
 
-       if (interface->scan_callback != NULL) {
-               int result = 0;
+       /*
+        * If scan is unsuccessful return -EIO else get the scanned BSSs
+        * and update the network details accordingly
+        */
+       if (success == FALSE) {
+               if (interface->scan_callback != NULL)
+                       interface->scan_callback(-EIO, interface,
+                                               interface->scan_data);
 
-               if (success == FALSE)
-                       result = -EIO;
+               interface->scan_callback = NULL;
+               interface->scan_data = NULL;
 
-               interface->scan_callback(result, interface,
-                                               interface->scan_data);
+               return;
        }
 
-       interface->scan_callback = NULL;
-       interface->scan_data = NULL;
+       supplicant_dbus_property_get(path, SUPPLICANT_INTERFACE ".Interface",
+                                       "BSSs", scan_bss_data, interface);
 }
 
 static void signal_bss_added(const char *path, DBusMessageIter *iter)
 {
        GSupplicantInterface *interface;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        interface = g_hash_table_lookup(interface_table, path);
        if (interface == NULL)
@@ -1526,7 +1587,7 @@ static void signal_bss_removed(const char *path, DBusMessageIter *iter)
 {
        GSupplicantInterface *interface;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        interface = g_hash_table_lookup(interface_table, path);
        if (interface == NULL)
@@ -1539,7 +1600,7 @@ static void signal_network_added(const char *path, DBusMessageIter *iter)
 {
        GSupplicantInterface *interface;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        interface = g_hash_table_lookup(interface_table, path);
        if (interface == NULL)
@@ -1552,7 +1613,7 @@ static void signal_network_removed(const char *path, DBusMessageIter *iter)
 {
        GSupplicantInterface *interface;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        interface = g_hash_table_lookup(interface_table, path);
        if (interface == NULL)
@@ -1567,7 +1628,7 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter)
        GSupplicantNetwork *network;
        struct g_supplicant_bss *bss;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        interface = g_hash_table_lookup(bss_mapping, path);
        if (interface == NULL)
@@ -1603,7 +1664,7 @@ static struct {
        { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added     },
        { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed   },
 
-       { SUPPLICANT_INTERFACE ".Interface.BSS", "PropertiesChanged", signal_bss_changed   },
+       { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed   },
 
        { }
 };
@@ -1682,10 +1743,10 @@ static void interface_create_result(const char *error,
        const char *path = NULL;
        int err;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        if (error != NULL) {
-               connman_error("error %s", error);
+               g_critical("error %s", error);
                err = -EIO;
                goto done;
        }
@@ -1728,7 +1789,7 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data)
        struct interface_create_data *data = user_data;
        DBusMessageIter dict;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        supplicant_dbus_dict_open(iter, &dict);
 
@@ -1750,10 +1811,10 @@ static void interface_get_result(const char *error,
        const char *path = NULL;
        int err;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        if (error != NULL) {
-               connman_error("error %s", error);
+               g_warning("error %s", error);
                err = -EIO;
                goto create;
        }
@@ -1783,7 +1844,7 @@ create:
                goto done;
        }
 
-       DBG("Creating interface");
+       SUPPLICANT_DBG("Creating interface");
 
        err = supplicant_dbus_method_call(SUPPLICANT_PATH,
                                                SUPPLICANT_INTERFACE,
@@ -1804,7 +1865,7 @@ static void interface_get_params(DBusMessageIter *iter, void *user_data)
 {
        struct interface_create_data *data = user_data;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
 }
@@ -1815,7 +1876,7 @@ int g_supplicant_interface_create(const char *ifname, const char *driver,
 {
        struct interface_create_data *data;
 
-       DBG("ifname %s", ifname);
+       SUPPLICANT_DBG("ifname %s", ifname);
 
        if (ifname == NULL)
                return -EINVAL;
@@ -1946,6 +2007,21 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface,
        if (interface->scanning == TRUE)
                return -EALREADY;
 
+       switch (interface->state) {
+       case G_SUPPLICANT_STATE_AUTHENTICATING:
+       case G_SUPPLICANT_STATE_ASSOCIATING:
+       case G_SUPPLICANT_STATE_ASSOCIATED:
+       case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
+       case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
+               return -EBUSY;
+       case G_SUPPLICANT_STATE_UNKNOWN:
+       case G_SUPPLICANT_STATE_DISCONNECTED:
+       case G_SUPPLICANT_STATE_INACTIVE:
+       case G_SUPPLICANT_STATE_SCANNING:
+       case G_SUPPLICANT_STATE_COMPLETED:
+               break;
+       }
+
        data = dbus_malloc0(sizeof(*data));
        if (data == NULL)
                return -ENOMEM;
@@ -1962,39 +2038,244 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface,
 static void interface_select_network_result(const char *error,
                                DBusMessageIter *iter, void *user_data)
 {
-       DBG("");
+       struct interface_connect_data *data = user_data;
+
+       SUPPLICANT_DBG("");
+
+       dbus_free(data);
 }
 
 static void interface_select_network_params(DBusMessageIter *iter,
                                                        void *user_data)
 {
-       char *path = user_data;
+       struct interface_connect_data *data = user_data;
+       GSupplicantInterface *interface = data->interface;
 
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+                                       &interface->network_path);
 }
 
 static void interface_add_network_result(const char *error,
                                DBusMessageIter *iter, void *user_data)
 {
        struct interface_connect_data *data = user_data;
-       char *path = NULL;
+       GSupplicantInterface *interface = data->interface;
+       const char *path;
 
        if (error != NULL)
-               goto done;
+               goto error;
 
        dbus_message_iter_get_basic(iter, &path);
        if (path == NULL)
-               goto done;
+               goto error;
+
+       SUPPLICANT_DBG("PATH: %s", path);
 
-       DBG("PATH: %s", path);
+       g_free(interface->network_path);
+       interface->network_path = g_strdup(path);
 
        supplicant_dbus_method_call(data->interface->path,
                        SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
                        interface_select_network_params,
-                       interface_select_network_result, path);
+                       interface_select_network_result, data);
 
-done:
-       dbus_free(data);
+       return;
+
+error:
+       g_free(interface->network_path);
+       interface->network_path = NULL;
+       g_free(data);
+}
+
+static void add_network_security_wep(DBusMessageIter *dict,
+                                       GSupplicantSSID *ssid)
+{
+       const char *auth_alg = "OPEN SHARED";
+       const char *key_index = "0";
+
+       supplicant_dbus_dict_append_basic(dict, "auth_alg",
+                                       DBUS_TYPE_STRING, &auth_alg);
+
+       if (ssid->passphrase) {
+               int size = strlen(ssid->passphrase);
+               if (size == 10 || size == 26) {
+                       unsigned char *key = g_try_malloc(13);
+                       char tmp[3];
+                       int i;
+
+                       memset(tmp, 0, sizeof(tmp));
+                       if (key == NULL)
+                               size = 0;
+
+                       for (i = 0; i < size / 2; i++) {
+                               memcpy(tmp, ssid->passphrase + (i * 2), 2);
+                               key[i] = (unsigned char) strtol(tmp, NULL, 16);
+                       }
+
+                       supplicant_dbus_dict_append_fixed_array(dict,
+                                                       "wep_key0",
+                                                       DBUS_TYPE_BYTE,
+                                                       &key, size / 2);
+                       g_free(key);
+               } else if (size == 5 || size == 13) {
+                       unsigned char *key = g_try_malloc(13);
+                       int i;
+
+                       if (key == NULL)
+                               size = 0;
+
+                       for (i = 0; i < size; i++)
+                               key[i] = (unsigned char) ssid->passphrase[i];
+
+                       supplicant_dbus_dict_append_fixed_array(dict,
+                                                               "wep_key0",
+                                                               DBUS_TYPE_BYTE,
+                                                               &key, size);
+                       g_free(key);
+               } else
+                       supplicant_dbus_dict_append_basic(dict,
+                                                       "wep_key0",
+                                                       DBUS_TYPE_STRING,
+                                                       &ssid->passphrase);
+
+               supplicant_dbus_dict_append_basic(dict, "wep_tx_keyidx",
+                                       DBUS_TYPE_STRING, &key_index);
+       }
+}
+
+static void add_network_security_psk(DBusMessageIter *dict,
+                                       GSupplicantSSID *ssid)
+{
+       if (ssid->passphrase && strlen(ssid->passphrase) > 0)
+                       supplicant_dbus_dict_append_basic(dict, "psk",
+                                               DBUS_TYPE_STRING,
+                                                       &ssid->passphrase);
+}
+
+static void add_network_security_tls(DBusMessageIter *dict,
+                                       GSupplicantSSID *ssid)
+{
+       /*
+        * For TLS, we at least need:
+        *              The client certificate
+        *              The client private key file
+        *              The client private key file password
+        *
+        * The Authority certificate is optional.
+        */
+       if (ssid->client_cert_path == NULL)
+               return;
+
+       if (ssid->private_key_path == NULL)
+               return;
+
+       if (ssid->private_key_passphrase == NULL)
+               return;
+
+       if (ssid->ca_cert_path)
+               supplicant_dbus_dict_append_basic(dict, "ca_cert",
+                                       DBUS_TYPE_STRING, &ssid->ca_cert_path);
+
+       supplicant_dbus_dict_append_basic(dict, "private_key",
+                                               DBUS_TYPE_STRING,
+                                               &ssid->private_key_path);
+       supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
+                                               DBUS_TYPE_STRING,
+                                               &ssid->private_key_passphrase);
+       supplicant_dbus_dict_append_basic(dict, "client_cert",
+                                               DBUS_TYPE_STRING,
+                                               &ssid->client_cert_path);
+}
+
+static void add_network_security_peap(DBusMessageIter *dict,
+                                       GSupplicantSSID *ssid)
+{
+       char *phase2_auth;
+
+       /*
+        * For PEAP/TTLS, we at least need
+        *              The authority certificate
+        *              The 2nd phase authentication method
+        *              The 2nd phase passphrase
+        *
+        * The Client certificate is optional although strongly required
+        * When setting it, we need in addition
+        *              The Client private key file
+        *              The Client private key file password
+        */
+       if (ssid->passphrase == NULL)
+               return;
+
+       if (ssid->ca_cert_path == NULL)
+               return;
+
+       if (ssid->phase2_auth == NULL)
+               return;
+
+       if (ssid->client_cert_path) {
+               if (ssid->private_key_path == NULL)
+                       return;
+
+               if (ssid->private_key_passphrase == NULL)
+                       return;
+
+               supplicant_dbus_dict_append_basic(dict, "client_cert",
+                                               DBUS_TYPE_STRING,
+                                               &ssid->client_cert_path);
+
+               supplicant_dbus_dict_append_basic(dict, "private_key",
+                                               DBUS_TYPE_STRING,
+                                               &ssid->private_key_path);
+
+               supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
+                                               DBUS_TYPE_STRING,
+                                               &ssid->private_key_passphrase);
+
+       }
+
+       phase2_auth = g_strdup_printf("\"auth=%s\"", ssid->phase2_auth);
+
+       supplicant_dbus_dict_append_basic(dict, "password",
+                                               DBUS_TYPE_STRING,
+                                               &ssid->passphrase);
+
+       supplicant_dbus_dict_append_basic(dict, "ca_cert",
+                                               DBUS_TYPE_STRING,
+                                               &ssid->ca_cert_path);
+
+       supplicant_dbus_dict_append_basic(dict, "phase2",
+                                               DBUS_TYPE_STRING,
+                                               &ssid->phase2_auth);
+
+       g_free(phase2_auth);
+}
+
+static void add_network_security_eap(DBusMessageIter *dict,
+                                       GSupplicantSSID *ssid)
+{
+       char *eap_value;
+
+       if (ssid->eap == NULL || ssid->identity == NULL)
+               return;
+
+       if (g_strcmp0(ssid->eap, "tls") == 0) {
+               add_network_security_tls(dict, ssid);
+       } else if (g_strcmp0(ssid->eap, "peap") == 0 ||
+                               g_strcmp0(ssid->eap, "ttls") == 0) {
+               add_network_security_peap(dict, ssid);
+       } else
+               return;
+
+       eap_value = g_ascii_strup(ssid->eap, -1);
+
+       supplicant_dbus_dict_append_basic(dict, "eap",
+                                               DBUS_TYPE_STRING,
+                                               &eap_value);
+       supplicant_dbus_dict_append_basic(dict, "identity",
+                                               DBUS_TYPE_STRING,
+                                               &ssid->identity);
+
+       g_free(eap_value);
 }
 
 static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
@@ -2006,12 +2287,15 @@ static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
        case G_SUPPLICANT_SECURITY_NONE:
        case G_SUPPLICANT_SECURITY_WEP:
                key_mgmt = "NONE";
+               add_network_security_wep(dict, ssid);
                break;
        case G_SUPPLICANT_SECURITY_PSK:
                key_mgmt = "WPA-PSK";
+               add_network_security_psk(dict, ssid);
                break;
        case G_SUPPLICANT_SECURITY_IEEE8021X:
                key_mgmt = "WPA-EAP";
+               add_network_security_eap(dict, ssid);
                break;
        }
 
@@ -2075,13 +2359,13 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface,
        return -EINPROGRESS;
 }
 
-static void interface_disconnect_result(const char *error,
+static void network_remove_result(const char *error,
                                DBusMessageIter *iter, void *user_data)
 {
        struct interface_data *data = user_data;
        int result = 0;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        if (error != NULL)
                result = -EIO;
@@ -2092,13 +2376,49 @@ static void interface_disconnect_result(const char *error,
        dbus_free(data);
 }
 
+static void network_remove_params(DBusMessageIter *iter, void *user_data)
+{
+       struct interface_data *data = user_data;
+       const char *path = data->interface->network_path;
+
+       SUPPLICANT_DBG("path %s", path);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static int network_remove(struct interface_data *data)
+{
+       GSupplicantInterface *interface = data->interface;
+
+       SUPPLICANT_DBG("");
+
+       return supplicant_dbus_method_call(interface->path,
+                       SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork",
+                       network_remove_params, network_remove_result, data);
+}
+
+static void interface_disconnect_result(const char *error,
+                               DBusMessageIter *iter, void *user_data)
+{
+       struct interface_data *data = user_data;
+
+       SUPPLICANT_DBG("");
+
+       if (error != NULL && data->callback != NULL) {
+               data->callback(-EIO, data->interface, data->user_data);
+               return;
+       }
+
+       network_remove(data);
+}
+
 int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
                                        GSupplicantInterfaceCallback callback,
                                                        void *user_data)
 {
        struct interface_data *data;
 
-       DBG("");
+       SUPPLICANT_DBG("");
 
        if (interface == NULL)
                return -EINVAL;
@@ -2133,16 +2453,29 @@ static const char *g_supplicant_rule2 = "type=signal,"
 static const char *g_supplicant_rule3 = "type=signal,"
                        "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
 static const char *g_supplicant_rule4 = "type=signal,"
-                       "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
+                       "interface=" SUPPLICANT_INTERFACE ".BSS";
 static const char *g_supplicant_rule5 = "type=signal,"
-                       "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
-static const char *g_supplicant_rule6 = "type=signal,"
-                       "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
+                       "interface=" SUPPLICANT_INTERFACE ".Network";
 
-int g_supplicant_register(const GSupplicantCallbacks *callbacks)
+static void invoke_introspect_method(void)
 {
-       DBG("");
+       DBusMessage *message;
 
+       message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
+                                       SUPPLICANT_PATH,
+                                       DBUS_INTERFACE_INTROSPECTABLE,
+                                       "Introspect");
+
+       if (message == NULL)
+               return;
+
+       dbus_message_set_no_reply(message, TRUE);
+       dbus_connection_send(connection, message, NULL);
+       dbus_message_unref(message);
+}
+
+int g_supplicant_register(const GSupplicantCallbacks *callbacks)
+{
        connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
        if (connection == NULL)
                return -EIO;
@@ -2171,7 +2504,6 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks)
        dbus_bus_add_match(connection, g_supplicant_rule3, NULL);
        dbus_bus_add_match(connection, g_supplicant_rule4, NULL);
        dbus_bus_add_match(connection, g_supplicant_rule5, NULL);
-       dbus_bus_add_match(connection, g_supplicant_rule6, NULL);
        dbus_connection_flush(connection);
 
        if (dbus_bus_name_has_owner(connection,
@@ -2180,7 +2512,8 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks)
                supplicant_dbus_property_get_all(SUPPLICANT_PATH,
                                                SUPPLICANT_INTERFACE,
                                                service_property, NULL);
-       }
+       } else
+               invoke_introspect_method();
 
        return 0;
 }
@@ -2209,10 +2542,9 @@ static void unregister_remove_interface(gpointer key, gpointer value,
 
 void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
 {
-       DBG("");
+       SUPPLICANT_DBG("");
 
        if (connection != NULL) {
-               dbus_bus_remove_match(connection, g_supplicant_rule6, NULL);
                dbus_bus_remove_match(connection, g_supplicant_rule5, NULL);
                dbus_bus_remove_match(connection, g_supplicant_rule4, NULL);
                dbus_bus_remove_match(connection, g_supplicant_rule3, NULL);