DA: Skip initializing failed_bssids list when eapol failure case
[platform/upstream/connman.git] / tools / supplicant.c
old mode 100644 (file)
new mode 100755 (executable)
index 26c29a3..e2e6fea
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -132,6 +132,7 @@ static struct strvalmap mode_capa_map[] = {
 };
 
 static GHashTable *interface_table;
+static GHashTable *bss_mapping;
 
 struct supplicant_interface {
        char *path;
@@ -152,15 +153,18 @@ struct supplicant_interface {
        char *driver;
        char *bridge;
        GHashTable *network_table;
+       GHashTable *net_mapping;
        GHashTable *bss_mapping;
 };
 
 struct supplicant_network {
        struct supplicant_interface *interface;
+       char *path;
        char *group;
        char *name;
        enum supplicant_mode mode;
        GHashTable *bss_table;
+       GHashTable *config_table;
 };
 
 struct supplicant_bss {
@@ -170,6 +174,7 @@ struct supplicant_bss {
        unsigned char ssid[32];
        unsigned int ssid_len;
        dbus_uint16_t frequency;
+       dbus_uint32_t maxrate;
        enum supplicant_mode mode;
        enum supplicant_security security;
        dbus_bool_t privacy;
@@ -179,12 +184,12 @@ struct supplicant_bss {
 
 static enum supplicant_mode string2mode(const char *mode)
 {
-       if (mode == NULL)
+       if (!mode)
                return SUPPLICANT_MODE_UNKNOWN;
 
-       if (g_str_equal(mode, "infrastructure") == TRUE)
+       if (g_str_equal(mode, "infrastructure"))
                return SUPPLICANT_MODE_INFRA;
-       else if (g_str_equal(mode, "ad-hoc") == TRUE)
+       else if (g_str_equal(mode, "ad-hoc"))
                return SUPPLICANT_MODE_IBSS;
 
        return SUPPLICANT_MODE_UNKNOWN;
@@ -224,28 +229,28 @@ static const char *security2string(enum supplicant_security security)
 
 static enum supplicant_state string2state(const char *state)
 {
-       if (state == NULL)
+       if (!state)
                return SUPPLICANT_STATE_UNKNOWN;
 
-       if (g_str_equal(state, "unknown") == TRUE)
+       if (g_str_equal(state, "unknown"))
                return SUPPLICANT_STATE_UNKNOWN;
-       else if (g_str_equal(state, "disconnected") == TRUE)
+       else if (g_str_equal(state, "disconnected"))
                return SUPPLICANT_STATE_DISCONNECTED;
-       else if (g_str_equal(state, "inactive") == TRUE)
+       else if (g_str_equal(state, "inactive"))
                return SUPPLICANT_STATE_INACTIVE;
-       else if (g_str_equal(state, "scanning") == TRUE)
+       else if (g_str_equal(state, "scanning"))
                return SUPPLICANT_STATE_SCANNING;
-       else if (g_str_equal(state, "authenticating") == TRUE)
+       else if (g_str_equal(state, "authenticating"))
                return SUPPLICANT_STATE_AUTHENTICATING;
-       else if (g_str_equal(state, "associating") == TRUE)
+       else if (g_str_equal(state, "associating"))
                return SUPPLICANT_STATE_ASSOCIATING;
-       else if (g_str_equal(state, "associated") == TRUE)
+       else if (g_str_equal(state, "associated"))
                return SUPPLICANT_STATE_ASSOCIATED;
-       else if (g_str_equal(state, "group_handshake") == TRUE)
+       else if (g_str_equal(state, "group_handshake"))
                return SUPPLICANT_STATE_GROUP_HANDSHAKE;
-       else if (g_str_equal(state, "4way_handshake") == TRUE)
+       else if (g_str_equal(state, "4way_handshake"))
                return SUPPLICANT_STATE_4WAY_HANDSHAKE;
-       else if (g_str_equal(state, "completed") == TRUE)
+       else if (g_str_equal(state, "completed"))
                return SUPPLICANT_STATE_COMPLETED;
 
        return SUPPLICANT_STATE_UNKNOWN;
@@ -253,15 +258,15 @@ static enum supplicant_state string2state(const char *state)
 
 static void callback_system_ready(void)
 {
-       if (system_ready == TRUE)
+       if (system_ready)
                return;
 
        system_ready = TRUE;
 
-       if (callbacks_pointer == NULL)
+       if (!callbacks_pointer)
                return;
 
-       if (callbacks_pointer->system_ready == NULL)
+       if (!callbacks_pointer->system_ready)
                return;
 
        callbacks_pointer->system_ready();
@@ -271,10 +276,10 @@ static void callback_system_killed(void)
 {
        system_ready = FALSE;
 
-       if (callbacks_pointer == NULL)
+       if (!callbacks_pointer)
                return;
 
-       if (callbacks_pointer->system_killed == NULL)
+       if (!callbacks_pointer->system_killed)
                return;
 
        callbacks_pointer->system_killed();
@@ -282,10 +287,10 @@ static void callback_system_killed(void)
 
 static void callback_interface_added(struct supplicant_interface *interface)
 {
-       if (callbacks_pointer == NULL)
+       if (!callbacks_pointer)
                return;
 
-       if (callbacks_pointer->interface_added == NULL)
+       if (!callbacks_pointer->interface_added)
                return;
 
        callbacks_pointer->interface_added(interface);
@@ -293,10 +298,10 @@ static void callback_interface_added(struct supplicant_interface *interface)
 
 static void callback_interface_removed(struct supplicant_interface *interface)
 {
-       if (callbacks_pointer == NULL)
+       if (!callbacks_pointer)
                return;
 
-       if (callbacks_pointer->interface_removed == NULL)
+       if (!callbacks_pointer->interface_removed)
                return;
 
        callbacks_pointer->interface_removed(interface);
@@ -304,10 +309,10 @@ static void callback_interface_removed(struct supplicant_interface *interface)
 
 static void callback_scan_started(struct supplicant_interface *interface)
 {
-       if (callbacks_pointer == NULL)
+       if (!callbacks_pointer)
                return;
 
-       if (callbacks_pointer->scan_started == NULL)
+       if (!callbacks_pointer->scan_started)
                return;
 
        callbacks_pointer->scan_started(interface);
@@ -315,10 +320,10 @@ static void callback_scan_started(struct supplicant_interface *interface)
 
 static void callback_scan_finished(struct supplicant_interface *interface)
 {
-       if (callbacks_pointer == NULL)
+       if (!callbacks_pointer)
                return;
 
-       if (callbacks_pointer->scan_finished == NULL)
+       if (!callbacks_pointer->scan_finished)
                return;
 
        callbacks_pointer->scan_finished(interface);
@@ -326,10 +331,10 @@ static void callback_scan_finished(struct supplicant_interface *interface)
 
 static void callback_network_added(struct supplicant_network *network)
 {
-       if (callbacks_pointer == NULL)
+       if (!callbacks_pointer)
                return;
 
-       if (callbacks_pointer->network_added == NULL)
+       if (!callbacks_pointer->network_added)
                return;
 
        callbacks_pointer->network_added(network);
@@ -337,10 +342,10 @@ static void callback_network_added(struct supplicant_network *network)
 
 static void callback_network_removed(struct supplicant_network *network)
 {
-       if (callbacks_pointer == NULL)
+       if (!callbacks_pointer)
                return;
 
-       if (callbacks_pointer->network_removed == NULL)
+       if (!callbacks_pointer->network_removed)
                return;
 
        callbacks_pointer->network_removed(network);
@@ -351,6 +356,7 @@ static void remove_interface(gpointer data)
        struct supplicant_interface *interface = data;
 
        g_hash_table_destroy(interface->bss_mapping);
+       g_hash_table_destroy(interface->net_mapping);
        g_hash_table_destroy(interface->network_table);
 
        callback_interface_removed(interface);
@@ -366,8 +372,12 @@ static void remove_network(gpointer data)
 {
        struct supplicant_network *network = data;
 
+       g_hash_table_destroy(network->bss_table);
+
        callback_network_removed(network);
 
+       g_hash_table_destroy(network->config_table);
+
        g_free(network->group);
        g_free(network->name);
        g_free(network);
@@ -386,7 +396,7 @@ static void debug_strvalmap(const char *label, struct strvalmap *map,
 {
        int i;
 
-       for (i = 0; map[i].str != NULL; i++) {
+       for (i = 0; map[i].str; i++) {
                if (val & map[i].val)
                        DBG("%s: %s", label, map[i].str);
        }
@@ -399,10 +409,10 @@ static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
        int i;
 
        dbus_message_iter_get_basic(iter, &str);
-       if (str == NULL)
+       if (!str)
                return;
 
-       for (i = 0; keymgmt_capa_map[i].str != NULL; i++)
+       for (i = 0; keymgmt_capa_map[i].str; i++)
                if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
                        interface->keymgmt_capa |= keymgmt_capa_map[i].val;
                        break;
@@ -416,10 +426,10 @@ static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
        int i;
 
        dbus_message_iter_get_basic(iter, &str);
-       if (str == NULL)
+       if (!str)
                return;
 
-       for (i = 0; authalg_capa_map[i].str != NULL; i++)
+       for (i = 0; authalg_capa_map[i].str; i++)
                if (strcmp(str, authalg_capa_map[i].str) == 0) {
                        interface->authalg_capa |= authalg_capa_map[i].val;
                        break;
@@ -433,10 +443,10 @@ static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
        int i;
 
        dbus_message_iter_get_basic(iter, &str);
-       if (str == NULL)
+       if (!str)
                return;
 
-       for (i = 0; proto_capa_map[i].str != NULL; i++)
+       for (i = 0; proto_capa_map[i].str; i++)
                if (strcmp(str, proto_capa_map[i].str) == 0) {
                        interface->proto_capa |= proto_capa_map[i].val;
                        break;
@@ -450,10 +460,10 @@ static void interface_capability_pairwise(DBusMessageIter *iter, void *user_data
        int i;
 
        dbus_message_iter_get_basic(iter, &str);
-       if (str == NULL)
+       if (!str)
                return;
 
-       for (i = 0; pairwise_capa_map[i].str != NULL; i++)
+       for (i = 0; pairwise_capa_map[i].str; i++)
                if (strcmp(str, pairwise_capa_map[i].str) == 0) {
                        interface->pairwise_capa |= pairwise_capa_map[i].val;
                        break;
@@ -467,10 +477,10 @@ static void interface_capability_group(DBusMessageIter *iter, void *user_data)
        int i;
 
        dbus_message_iter_get_basic(iter, &str);
-       if (str == NULL)
+       if (!str)
                return;
 
-       for (i = 0; group_capa_map[i].str != NULL; i++)
+       for (i = 0; group_capa_map[i].str; i++)
                if (strcmp(str, group_capa_map[i].str) == 0) {
                        interface->group_capa |= group_capa_map[i].val;
                        break;
@@ -484,10 +494,10 @@ static void interface_capability_scan(DBusMessageIter *iter, void *user_data)
        int i;
 
        dbus_message_iter_get_basic(iter, &str);
-       if (str == NULL)
+       if (!str)
                return;
 
-       for (i = 0; scan_capa_map[i].str != NULL; i++)
+       for (i = 0; scan_capa_map[i].str; i++)
                if (strcmp(str, scan_capa_map[i].str) == 0) {
                        interface->scan_capa |= scan_capa_map[i].val;
                        break;
@@ -501,10 +511,10 @@ static void interface_capability_mode(DBusMessageIter *iter, void *user_data)
        int i;
 
        dbus_message_iter_get_basic(iter, &str);
-       if (str == NULL)
+       if (!str)
                return;
 
-       for (i = 0; mode_capa_map[i].str != NULL; i++)
+       for (i = 0; mode_capa_map[i].str; i++)
                if (strcmp(str, mode_capa_map[i].str) == 0) {
                        interface->mode_capa |= mode_capa_map[i].val;
                        break;
@@ -516,7 +526,7 @@ static void interface_capability(const char *key, DBusMessageIter *iter,
 {
        struct supplicant_interface *interface = user_data;
 
-       if (key == NULL)
+       if (!key)
                return;
 
        if (g_strcmp0(key, "KeyMgmt") == 0)
@@ -547,7 +557,7 @@ static void interface_capability(const char *key, DBusMessageIter *iter,
 
 const char *supplicant_interface_get_ifname(struct supplicant_interface *interface)
 {
-       if (interface == NULL)
+       if (!interface)
                return NULL;
 
        return interface->ifname;
@@ -555,7 +565,7 @@ const char *supplicant_interface_get_ifname(struct supplicant_interface *interfa
 
 const char *supplicant_interface_get_driver(struct supplicant_interface *interface)
 {
-       if (interface == NULL)
+       if (!interface)
                return NULL;
 
        return interface->driver;
@@ -563,7 +573,7 @@ const char *supplicant_interface_get_driver(struct supplicant_interface *interfa
 
 struct supplicant_interface *supplicant_network_get_interface(struct supplicant_network *network)
 {
-       if (network == NULL)
+       if (!network)
                return NULL;
 
        return network->interface;
@@ -571,7 +581,7 @@ struct supplicant_interface *supplicant_network_get_interface(struct supplicant_
 
 const char *supplicant_network_get_name(struct supplicant_network *network)
 {
-       if (network == NULL || network->name == NULL)
+       if (!network || !network->name)
                return "";
 
        return network->name;
@@ -579,7 +589,7 @@ const char *supplicant_network_get_name(struct supplicant_network *network)
 
 const char *supplicant_network_get_identifier(struct supplicant_network *network)
 {
-       if (network == NULL || network->group == NULL)
+       if (!network || !network->group)
                return "";
 
        return network->group;
@@ -587,56 +597,141 @@ const char *supplicant_network_get_identifier(struct supplicant_network *network
 
 enum supplicant_mode supplicant_network_get_mode(struct supplicant_network *network)
 {
-       if (network == NULL)
+       if (!network)
                return SUPPLICANT_MODE_UNKNOWN;
 
        return network->mode;
 }
 
+static void merge_network(struct supplicant_network *network)
+{
+       GString *str;
+       const char *ssid, *mode, *key_mgmt;
+       unsigned int i, ssid_len;
+       char *group;
+
+       ssid = g_hash_table_lookup(network->config_table, "ssid");
+       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);
+
+       if (ssid)
+               ssid_len = strlen(ssid);
+       else
+               ssid_len = 0;
+
+       str = g_string_sized_new((ssid_len * 2) + 24);
+       if (!str)
+               return;
+
+       for (i = 0; i < ssid_len; i++)
+               g_string_append_printf(str, "%02x", ssid[i]);
+
+       if (g_strcmp0(mode, "0") == 0)
+               g_string_append_printf(str, "_infra");
+       else if (g_strcmp0(mode, "1") == 0)
+               g_string_append_printf(str, "_adhoc");
+
+       if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
+               g_string_append_printf(str, "_psk");
+
+       group = g_string_free(str, FALSE);
+
+       DBG("%s", group);
+
+       g_free(group);
+
+       g_hash_table_destroy(network->config_table);
+
+       g_free(network->path);
+       g_free(network);
+}
+
 static void network_property(const char *key, DBusMessageIter *iter,
                                                        void *user_data)
 {
-       if (key == NULL)
+       struct supplicant_network *network = user_data;
+
+       if (!network->interface)
+               return;
+
+       if (!key) {
+               merge_network(network);
                return;
+       }
+
+       if (g_strcmp0(key, "Enabled") == 0) {
+               dbus_bool_t enabled = FALSE;
 
-       //DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
+               dbus_message_iter_get_basic(iter, &enabled);
+       } else if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
+               const char *str = NULL;
+
+               dbus_message_iter_get_basic(iter, &str);
+               if (str)
+                       g_hash_table_replace(network->config_table,
+                                               g_strdup(key), g_strdup(str));
+       } else
+               DBG("key %s type %c",
+                               key, dbus_message_iter_get_arg_type(iter));
 }
 
 static void interface_network_added(DBusMessageIter *iter, void *user_data)
 {
-       //struct supplicant_interface *interface = user_data;
+       struct supplicant_interface *interface = user_data;
+       struct supplicant_network *network;
        const char *path = NULL;
 
        dbus_message_iter_get_basic(iter, &path);
-       if (path == NULL)
+       if (!path)
                return;
 
        if (g_strcmp0(path, "/") == 0)
                return;
 
+       network = g_hash_table_lookup(interface->net_mapping, path);
+       if (network)
+               return;
+
+       network = g_try_new0(struct supplicant_network, 1);
+       if (!network)
+               return;
+
+       network->interface = interface;
+       network->path = g_strdup(path);
+
+       network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                       g_free, g_free);
+
        dbus_message_iter_next(iter);
        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
-               supplicant_dbus_property_foreach(iter, network_property, NULL);
-               network_property(NULL, NULL, NULL);
+               supplicant_dbus_property_foreach(iter, network_property,
+                                                               network);
+               network_property(NULL, NULL, network);
                return;
        }
 
-       DBG("path %s", path);
-
        supplicant_dbus_property_get_all(path,
                                SUPPLICANT_INTERFACE ".Interface.Network",
-                                               network_property, NULL);
+                                               network_property, network);
 }
 
 static void interface_network_removed(DBusMessageIter *iter, void *user_data)
 {
+       struct supplicant_interface *interface = user_data;
+       struct supplicant_network *network;
        const char *path = NULL;
 
        dbus_message_iter_get_basic(iter, &path);
-       if (path == NULL)
+       if (!path)
                return;
 
-       DBG("path %s", path);
+       network = g_hash_table_lookup(interface->net_mapping, path);
+       if (!network)
+               return;
+
+       g_hash_table_remove(interface->net_mapping, path);
 }
 
 static char *create_name(unsigned char *ssid, int ssid_len)
@@ -649,7 +744,7 @@ static char *create_name(unsigned char *ssid, int ssid_len)
        else
                name = g_try_malloc0(ssid_len + 1);
 
-       if (name == NULL)
+       if (!name)
                return g_strdup("");
 
        for (i = 0; i < ssid_len; i++) {
@@ -669,7 +764,7 @@ static char *create_group(struct supplicant_bss *bss)
        const char *mode, *security;
 
        str = g_string_sized_new((bss->ssid_len * 2) + 24);
-       if (str == NULL)
+       if (!str)
                return NULL;
 
        if (bss->ssid_len > 0 && bss->ssid[0] != '\0') {
@@ -679,11 +774,11 @@ static char *create_group(struct supplicant_bss *bss)
                g_string_append_printf(str, "hidden");
 
        mode = mode2string(bss->mode);
-       if (mode != NULL)
+       if (mode)
                g_string_append_printf(str, "_%s", mode);
 
        security = security2string(bss->security);
-       if (security != NULL)
+       if (security)
                g_string_append_printf(str, "_%s", security);
 
        return g_string_free(str, FALSE);
@@ -696,17 +791,17 @@ static void add_bss_to_network(struct supplicant_bss *bss)
        char *group;
 
        group = create_group(bss);
-       if (group == NULL)
+       if (!group)
                return;
 
        network = g_hash_table_lookup(interface->network_table, group);
-       if (network != NULL) {
+       if (network) {
                g_free(group);
                goto done;
        }
 
        network = g_try_new0(struct supplicant_network, 1);
-       if (network == NULL) {
+       if (!network) {
                g_free(group);
                return;
        }
@@ -718,6 +813,9 @@ static void add_bss_to_network(struct supplicant_bss *bss)
        network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                        NULL, remove_bss);
 
+       network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                       g_free, g_free);
+
        g_hash_table_replace(interface->network_table,
                                                network->group, network);
 
@@ -726,6 +824,8 @@ static void add_bss_to_network(struct supplicant_bss *bss)
 done:
        g_hash_table_replace(interface->bss_mapping, bss->path, network);
        g_hash_table_replace(network->bss_table, bss->path, bss);
+
+       g_hash_table_replace(bss_mapping, bss->path, interface);
 }
 
 static unsigned char wifi_oui[3]      = { 0x00, 0x50, 0xf2 };
@@ -794,8 +894,19 @@ static void extract_rsn(struct supplicant_bss *bss,
                }
        }
 
-       buf += 2 + (count * 4);
-       len -= 2 + (count * 4);
+}
+
+static void bss_rates(DBusMessageIter *iter, void *user_data)
+{
+       struct supplicant_bss *bss = user_data;
+       dbus_uint32_t rate = 0;
+
+       dbus_message_iter_get_basic(iter, &rate);
+       if (rate == 0)
+               return;
+
+       if (rate > bss->maxrate)
+               bss->maxrate = rate;
 }
 
 static void bss_property(const char *key, DBusMessageIter *iter,
@@ -803,15 +914,15 @@ static void bss_property(const char *key, DBusMessageIter *iter,
 {
        struct supplicant_bss *bss = user_data;
 
-       if (bss->interface == NULL)
+       if (!bss->interface)
                return;
 
-       if (key == NULL) {
-               if (bss->ieee8021x == TRUE)
+       if (!key) {
+               if (bss->ieee8021x)
                        bss->security = SUPPLICANT_SECURITY_IEEE8021X;
-               else if (bss->psk == TRUE)
+               else if (bss->psk)
                        bss->security = SUPPLICANT_SECURITY_PSK;
-               else if (bss->privacy == TRUE)
+               else if (bss->privacy)
                        bss->security = SUPPLICANT_SECURITY_WEP;
                else
                        bss->security = SUPPLICANT_SECURITY_NONE;
@@ -875,10 +986,14 @@ static void bss_property(const char *key, DBusMessageIter *iter,
                dbus_int32_t level = 0;
 
                dbus_message_iter_get_basic(iter, &level);
+       } else if (g_strcmp0(key, "Rates") == 0) {
+               supplicant_dbus_array_foreach(iter, bss_rates, bss);
        } else if (g_strcmp0(key, "MaxRate") == 0) {
-               dbus_uint16_t maxrate = 0;
+               dbus_uint32_t maxrate = 0;
 
                dbus_message_iter_get_basic(iter, &maxrate);
+               if (maxrate != 0)
+                       bss->maxrate =maxrate;
        } else if (g_strcmp0(key, "Privacy") == 0) {
                dbus_bool_t privacy = FALSE;
 
@@ -924,21 +1039,21 @@ static void interface_bss_added(DBusMessageIter *iter, void *user_data)
        const char *path = NULL;
 
        dbus_message_iter_get_basic(iter, &path);
-       if (path == NULL)
+       if (!path)
                return;
 
        if (g_strcmp0(path, "/") == 0)
                return;
 
        network = g_hash_table_lookup(interface->bss_mapping, path);
-       if (network != NULL) {
+       if (network) {
                bss = g_hash_table_lookup(network->bss_table, path);
-               if (bss != NULL)
+               if (bss)
                        return;
        }
 
        bss = g_try_new0(struct supplicant_bss, 1);
-       if (bss == NULL)
+       if (!bss)
                return;
 
        bss->interface = interface;
@@ -963,13 +1078,15 @@ static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
        const char *path = NULL;
 
        dbus_message_iter_get_basic(iter, &path);
-       if (path == NULL)
+       if (!path)
                return;
 
        network = g_hash_table_lookup(interface->bss_mapping, path);
-       if (network == NULL)
+       if (!network)
                return;
 
+       g_hash_table_remove(bss_mapping, path);
+
        g_hash_table_remove(interface->bss_mapping, path);
        g_hash_table_remove(network->bss_table, path);
 
@@ -982,10 +1099,10 @@ static void interface_property(const char *key, DBusMessageIter *iter,
 {
        struct supplicant_interface *interface = user_data;
 
-       if (interface == NULL)
+       if (!interface)
                return;
 
-       if (key == NULL) {
+       if (!key) {
                debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
                                                interface->keymgmt_capa);
                debug_strvalmap("AuthAlg capability", authalg_capa_map,
@@ -1013,7 +1130,7 @@ static void interface_property(const char *key, DBusMessageIter *iter,
                const char *str = NULL;
 
                dbus_message_iter_get_basic(iter, &str);
-               if (str != NULL)
+               if (str)
                        interface->state = string2state(str);
 
                DBG("state %s (%d)", str, interface->state);
@@ -1023,8 +1140,8 @@ static void interface_property(const char *key, DBusMessageIter *iter,
                dbus_message_iter_get_basic(iter, &scanning);
                interface->scanning = scanning;
 
-               if (interface->ready == TRUE) {
-                       if (interface->scanning == TRUE)
+               if (interface->ready) {
+                       if (interface->scanning)
                                callback_scan_started(interface);
                        else
                                callback_scan_finished(interface);
@@ -1038,19 +1155,19 @@ static void interface_property(const char *key, DBusMessageIter *iter,
                const char *str = NULL;
 
                dbus_message_iter_get_basic(iter, &str);
-               if (str != NULL)
+               if (str)
                        interface->ifname = g_strdup(str);
        } else if (g_strcmp0(key, "Driver") == 0) {
                const char *str = NULL;
 
                dbus_message_iter_get_basic(iter, &str);
-               if (str != NULL)
+               if (str)
                        interface->driver = g_strdup(str);
        } else if (g_strcmp0(key, "BridgeIfname") == 0) {
                const char *str = NULL;
 
                dbus_message_iter_get_basic(iter, &str);
-               if (str != NULL)
+               if (str)
                        interface->bridge = g_strdup(str);
        } else if (g_strcmp0(key, "CurrentBSS") == 0) {
                interface_bss_added(iter, interface);
@@ -1073,7 +1190,7 @@ static struct supplicant_interface *interface_alloc(const char *path)
        struct supplicant_interface *interface;
 
        interface = g_try_new0(struct supplicant_interface, 1);
-       if (interface == NULL)
+       if (!interface)
                return NULL;
 
        interface->path = g_strdup(path);
@@ -1081,6 +1198,8 @@ static struct supplicant_interface *interface_alloc(const char *path)
        interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                        NULL, remove_network);
 
+       interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                               NULL, NULL);
        interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                                NULL, NULL);
 
@@ -1095,18 +1214,18 @@ static void interface_added(DBusMessageIter *iter, void *user_data)
        const char *path = NULL;
 
        dbus_message_iter_get_basic(iter, &path);
-       if (path == NULL)
+       if (!path)
                return;
 
        if (g_strcmp0(path, "/") == 0)
                return;
 
        interface = g_hash_table_lookup(interface_table, path);
-       if (interface != NULL)
+       if (interface)
                return;
 
        interface = interface_alloc(path);
-       if (interface == NULL)
+       if (!interface)
                return;
 
        dbus_message_iter_next(iter);
@@ -1127,7 +1246,7 @@ static void interface_removed(DBusMessageIter *iter, void *user_data)
        const char *path = NULL;
 
        dbus_message_iter_get_basic(iter, &path);
-       if (path == NULL)
+       if (!path)
                return;
 
        g_hash_table_remove(interface_table, path);
@@ -1139,10 +1258,10 @@ static void eap_method(DBusMessageIter *iter, void *user_data)
        int i;
 
        dbus_message_iter_get_basic(iter, &str);
-       if (str == NULL)
+       if (!str)
                return;
 
-       for (i = 0; eap_method_map[i].str != NULL; i++)
+       for (i = 0; eap_method_map[i].str; i++)
                if (strcmp(str, eap_method_map[i].str) == 0) {
                        eap_methods |= eap_method_map[i].val;
                        break;
@@ -1152,7 +1271,7 @@ static void eap_method(DBusMessageIter *iter, void *user_data)
 static void service_property(const char *key, DBusMessageIter *iter,
                                                        void *user_data)
 {
-       if (key == NULL) {
+       if (!key) {
                callback_system_ready();
                return;
        }
@@ -1162,7 +1281,7 @@ static void service_property(const char *key, DBusMessageIter *iter,
                int i;
 
                dbus_message_iter_get_basic(iter, &str);
-               for (i = 0; debug_strings[i] != NULL; i++)
+               for (i = 0; debug_strings[i]; i++)
                        if (g_strcmp0(debug_strings[i], str) == 0) {
                                debug_level = i;
                                break;
@@ -1199,7 +1318,7 @@ static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
                return;
 
        dbus_message_iter_get_basic(iter, &name);
-       if (name == NULL)
+       if (!name)
                return;
 
        if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0)
@@ -1210,11 +1329,12 @@ static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
        dbus_message_iter_next(iter);
        dbus_message_iter_get_basic(iter, &new);
 
-       if (old == NULL || new == NULL)
+       if (!old || !new)
                return;
 
        if (strlen(old) > 0 && strlen(new) == 0) {
                system_available = FALSE;
+               g_hash_table_remove_all(bss_mapping);
                g_hash_table_remove_all(interface_table);
                callback_system_killed();
        }
@@ -1245,12 +1365,12 @@ static void signal_interface_removed(const char *path, DBusMessageIter *iter)
                interface_removed(iter, NULL);
 }
 
-static void signal_properties(const char *path, DBusMessageIter *iter)
+static void signal_interface_changed(const char *path, DBusMessageIter *iter)
 {
        struct supplicant_interface *interface;
 
        interface = g_hash_table_lookup(interface_table, path);
-       if (interface == NULL)
+       if (!interface)
                return;
 
        supplicant_dbus_property_foreach(iter, interface_property, interface);
@@ -1262,15 +1382,15 @@ static void signal_scan_done(const char *path, DBusMessageIter *iter)
        dbus_bool_t success = FALSE;
 
        interface = g_hash_table_lookup(interface_table, path);
-       if (interface == NULL)
+       if (!interface)
                return;
 
        dbus_message_iter_get_basic(iter, &success);
 
-       if (interface->scan_callback != NULL) {
+       if (interface->scan_callback) {
                int result = 0;
 
-               if (success == FALSE)
+               if (!success)
                        result = -EIO;
 
                interface->scan_callback(result, interface->scan_data);
@@ -1285,7 +1405,7 @@ static void signal_bss_added(const char *path, DBusMessageIter *iter)
        struct supplicant_interface *interface;
 
        interface = g_hash_table_lookup(interface_table, path);
-       if (interface == NULL)
+       if (!interface)
                return;
 
        interface_bss_added(iter, interface);
@@ -1296,7 +1416,7 @@ static void signal_bss_removed(const char *path, DBusMessageIter *iter)
        struct supplicant_interface *interface;
 
        interface = g_hash_table_lookup(interface_table, path);
-       if (interface == NULL)
+       if (!interface)
                return;
 
        interface_bss_removed(iter, interface);
@@ -1307,7 +1427,7 @@ static void signal_network_added(const char *path, DBusMessageIter *iter)
        struct supplicant_interface *interface;
 
        interface = g_hash_table_lookup(interface_table, path);
-       if (interface == NULL)
+       if (!interface)
                return;
 
        interface_network_added(iter, interface);
@@ -1318,12 +1438,33 @@ static void signal_network_removed(const char *path, DBusMessageIter *iter)
        struct supplicant_interface *interface;
 
        interface = g_hash_table_lookup(interface_table, path);
-       if (interface == NULL)
+       if (!interface)
                return;
 
        interface_network_removed(iter, interface);
 }
 
+static void signal_bss_changed(const char *path, DBusMessageIter *iter)
+{
+       struct supplicant_interface *interface;
+       struct supplicant_network *network;
+       struct supplicant_bss *bss;
+
+       interface = g_hash_table_lookup(bss_mapping, path);
+       if (!interface)
+               return;
+
+       network = g_hash_table_lookup(interface->bss_mapping, path);
+       if (!network)
+               return;
+
+       bss = g_hash_table_lookup(network->bss_table, path);
+       if (!bss)
+               return;
+
+       supplicant_dbus_property_foreach(iter, bss_property, bss);
+}
+
 static struct {
        const char *interface;
        const char *member;
@@ -1336,12 +1477,14 @@ static struct {
        { SUPPLICANT_INTERFACE, "InterfaceCreated",  signal_interface_added    },
        { SUPPLICANT_INTERFACE, "InterfaceRemoved",  signal_interface_removed  },
 
-       { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_properties      },
-       { SUPPLICANT_INTERFACE ".Interface", "ScanDone",          signal_scan_done       },
-       { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",          signal_bss_added       },
-       { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",        signal_bss_removed     },
-       { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added   },
-       { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed },
+       { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed },
+       { SUPPLICANT_INTERFACE ".Interface", "ScanDone",          signal_scan_done         },
+       { SUPPLICANT_INTERFACE ".Interface", "BSSAdded",          signal_bss_added         },
+       { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved",        signal_bss_removed       },
+       { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added     },
+       { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed   },
+
+       { SUPPLICANT_INTERFACE ".Interface.BSS", "PropertiesChanged", signal_bss_changed   },
 
        { }
 };
@@ -1354,19 +1497,17 @@ static DBusHandlerResult supplicant_filter(DBusConnection *conn,
        int i;
 
        path = dbus_message_get_path(message);
-       if (path == NULL)
+       if (!path)
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-       if (dbus_message_iter_init(message, &iter) == FALSE)
+       if (!dbus_message_iter_init(message, &iter))
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-       for (i = 0; signal_map[i].interface != NULL; i++) {
-               if (dbus_message_has_interface(message,
-                                       signal_map[i].interface) == FALSE)
+       for (i = 0; signal_map[i].interface; i++) {
+               if (!dbus_message_has_interface(message, signal_map[i].interface))
                        continue;
 
-               if (dbus_message_has_member(message,
-                                       signal_map[i].member) == FALSE)
+               if (!dbus_message_has_member(message, signal_map[i].member))
                        continue;
 
                signal_map[i].function(path, &iter);
@@ -1398,11 +1539,10 @@ static const char *supplicant_rule6 = "type=signal,"
 int supplicant_register(const struct supplicant_callbacks *callbacks)
 {
        connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (connection == NULL)
+       if (!connection)
                return -EIO;
 
-       if (dbus_connection_add_filter(connection,
-                               supplicant_filter, NULL, NULL) == FALSE) {
+       if (!dbus_connection_add_filter(connection, supplicant_filter, NULL, NULL)) {
                dbus_connection_unref(connection);
                connection = NULL;
                return -EIO;
@@ -1414,6 +1554,9 @@ int supplicant_register(const struct supplicant_callbacks *callbacks)
        interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                NULL, remove_interface);
 
+       bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                               NULL, NULL);
+
        supplicant_dbus_setup(connection);
 
        dbus_bus_add_match(connection, supplicant_rule0, NULL);
@@ -1426,7 +1569,7 @@ int supplicant_register(const struct supplicant_callbacks *callbacks)
        dbus_connection_flush(connection);
 
        if (dbus_bus_name_has_owner(connection,
-                                       SUPPLICANT_SERVICE, NULL) == TRUE) {
+                                       SUPPLICANT_SERVICE, NULL)) {
                system_available = TRUE;
                supplicant_bootstrap();
        }
@@ -1436,7 +1579,7 @@ int supplicant_register(const struct supplicant_callbacks *callbacks)
 
 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
 {
-       if (connection != NULL) {
+       if (connection) {
                dbus_bus_remove_match(connection, supplicant_rule6, NULL);
                dbus_bus_remove_match(connection, supplicant_rule5, NULL);
                dbus_bus_remove_match(connection, supplicant_rule4, NULL);
@@ -1450,15 +1593,20 @@ void supplicant_unregister(const struct supplicant_callbacks *callbacks)
                                                supplicant_filter, NULL);
        }
 
-       if (interface_table != NULL) {
+       if (bss_mapping) {
+               g_hash_table_destroy(bss_mapping);
+               bss_mapping = NULL;
+       }
+
+       if (interface_table) {
                g_hash_table_destroy(interface_table);
                interface_table = NULL;
        }
 
-       if (system_available == TRUE)
+       if (system_available)
                callback_system_killed();
 
-       if (connection != NULL) {
+       if (connection) {
                dbus_connection_unref(connection);
                connection = NULL;
        }
@@ -1470,7 +1618,7 @@ void supplicant_unregister(const struct supplicant_callbacks *callbacks)
 static void debug_level_result(const char *error,
                                DBusMessageIter *iter, void *user_data)
 {
-       if (error != NULL)
+       if (error)
                DBG("debug level failure: %s", error);
 }
 
@@ -1489,7 +1637,7 @@ static void debug_level_params(DBusMessageIter *iter, void *user_data)
 
 void supplicant_set_debug_level(unsigned int level)
 {
-       if (system_available == FALSE)
+       if (!system_available)
                return;
 
        supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
@@ -1512,8 +1660,8 @@ static void interface_create_property(const char *key, DBusMessageIter *iter,
        struct interface_create_data *data = user_data;
        struct supplicant_interface *interface = data->interface;
 
-       if (key == NULL) {
-               if (data->callback != NULL)
+       if (!key) {
+               if (data->callback)
                        data->callback(0, data->interface, data->user_data);
 
                dbus_free(data);
@@ -1529,26 +1677,26 @@ static void interface_create_result(const char *error,
        const char *path = NULL;
        int err;
 
-       if (error != NULL) {
+       if (error) {
                err = -EIO;
                goto done;
        }
 
        dbus_message_iter_get_basic(iter, &path);
-       if (path == NULL) {
+       if (!path) {
                err = -EINVAL;
                goto done;
        }
 
-       if (system_available == FALSE) {
+       if (!system_available) {
                err = -EFAULT;
                goto done;
        }
 
        data->interface = g_hash_table_lookup(interface_table, path);
-       if (data->interface == NULL) {
+       if (!data->interface) {
                data->interface = interface_alloc(path);
-               if (data->interface == NULL) {
+               if (!data->interface) {
                        err = -ENOMEM;
                        goto done;
                }
@@ -1561,7 +1709,7 @@ static void interface_create_result(const char *error,
                return;
 
 done:
-       if (data->callback != NULL)
+       if (data->callback)
                data->callback(err, NULL, data->user_data);
 
        dbus_free(data);
@@ -1577,7 +1725,7 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data)
        supplicant_dbus_dict_append_basic(&dict, "Ifname",
                                        DBUS_TYPE_STRING, &data->ifname);
 
-       if (data->driver != NULL)
+       if (data->driver)
                supplicant_dbus_dict_append_basic(&dict, "Driver",
                                        DBUS_TYPE_STRING, &data->driver);
 
@@ -1592,24 +1740,22 @@ static void interface_get_result(const char *error,
        const char *path = NULL;
        int err;
 
-       if (error != NULL) {
-               err = -EIO;
+       if (error)
                goto create;
-       }
 
        dbus_message_iter_get_basic(iter, &path);
-       if (path == NULL) {
+       if (!path) {
                err = -EINVAL;
                goto done;
        }
 
        interface = g_hash_table_lookup(interface_table, path);
-       if (interface == NULL) {
+       if (!interface) {
                err = -ENOENT;
                goto done;
        }
 
-       if (data->callback != NULL)
+       if (data->callback)
                data->callback(0, interface, data->user_data);
 
        dbus_free(data);
@@ -1617,7 +1763,7 @@ static void interface_get_result(const char *error,
        return;
 
 create:
-       if (system_available == FALSE) {
+       if (!system_available) {
                err = -EFAULT;
                goto done;
        }
@@ -1631,7 +1777,7 @@ create:
                return;
 
 done:
-       if (data->callback != NULL)
+       if (data->callback)
                data->callback(err, NULL, data->user_data);
 
        dbus_free(data);
@@ -1650,14 +1796,14 @@ int supplicant_interface_create(const char *ifname, const char *driver,
 {
        struct interface_create_data *data;
 
-       if (ifname == NULL)
+       if (!ifname)
                return -EINVAL;
 
-       if (system_available == FALSE)
+       if (!system_available)
                return -EFAULT;
 
        data = dbus_malloc0(sizeof(*data));
-       if (data == NULL)
+       if (!data)
                return -ENOMEM;
 
        data->ifname = ifname;
@@ -1676,10 +1822,10 @@ int supplicant_interface_remove(struct supplicant_interface *interface,
                        supplicant_interface_remove_callback callback,
                                                        void *user_data)
 {
-       if (interface == NULL)
+       if (!interface)
                return -EINVAL;
 
-       if (system_available == FALSE)
+       if (!system_available)
                return -EFAULT;
 
        return 0;
@@ -1696,8 +1842,8 @@ static void interface_scan_result(const char *error,
 {
        struct interface_scan_data *data = user_data;
 
-       if (error != NULL) {
-               if (data->callback != NULL)
+       if (error) {
+               if (data->callback)
                        data->callback(-EIO, data->user_data);
        } else {
                data->interface->scan_callback = data->callback;
@@ -1726,17 +1872,17 @@ int supplicant_interface_scan(struct supplicant_interface *interface,
 {
        struct interface_scan_data *data;
 
-       if (interface == NULL)
+       if (!interface)
                return -EINVAL;
 
-       if (system_available == FALSE)
+       if (!system_available)
                return -EFAULT;
 
-       if (interface->scanning == TRUE)
+       if (interface->scanning)
                return -EALREADY;
 
        data = dbus_malloc0(sizeof(*data));
-       if (data == NULL)
+       if (!data)
                return -ENOMEM;
 
        data->interface = interface;
@@ -1759,10 +1905,10 @@ static void interface_disconnect_result(const char *error,
        struct interface_disconnect_data *data = user_data;
        int result = 0;
 
-       if (error != NULL)
+       if (error)
                result = -EIO;
 
-       if (data->callback != NULL)
+       if (data->callback)
                data->callback(result, data->user_data);
 
        dbus_free(data);
@@ -1774,14 +1920,14 @@ int supplicant_interface_disconnect(struct supplicant_interface *interface,
 {
        struct interface_disconnect_data *data;
 
-       if (interface == NULL)
+       if (!interface)
                return -EINVAL;
 
-       if (system_available == FALSE)
+       if (!system_available)
                return -EFAULT;
 
        data = dbus_malloc0(sizeof(*data));
-       if (data == NULL)
+       if (!data)
                return -ENOMEM;
 
        data->callback = callback;