@@ -75,6 +75,7 @@ struct network {
struct l_ecc_point *sae_pt_20; /* SAE PT for Group 20 */
unsigned int agent_request;
struct l_queue *bss_list;
+ struct l_queue *old_bss_list;
struct l_settings *settings;
struct l_queue *secrets;
struct l_queue *blacklist; /* temporary blacklist for BSS's */
@@ -1129,12 +1130,97 @@ bool network_update_known_frequencies(struct network *network)
return true;
}
+const char *network_bss_get_path(const struct network *network,
+ const struct scan_bss *bss)
+{
+ static char path[256];
+
+ snprintf(path, sizeof(path), "%s/%02x%02x%02x%02x%02x%02x",
+ network->object_path, MAC_STR(bss->addr));
+
+ return path;
+}
+
+static bool network_unregister_bss(void *a, void *user_data)
+{
+ struct scan_bss *bss = a;
+ struct network *network = user_data;
+
+ l_dbus_unregister_object(dbus_get_bus(),
+ network_bss_get_path(network, bss));
+
+ return true;
+}
+
+static bool network_register_bss(struct network *network, struct scan_bss *bss)
+{
+ const char *path = network_bss_get_path(network, bss);
+ struct scan_bss *old;
+
+ /*
+ * Due to station issuing multiple scan requests we may already have
+ * this BSS data registered. Remove it from the old_bss_list
+ */
+ old = l_dbus_object_get_data(dbus_get_bus(), path, IWD_BSS_INTERFACE);
+ if (old == bss)
+ return l_queue_remove(network->old_bss_list, bss);
+ else if (old)
+ return l_dbus_object_set_data(dbus_get_bus(), path,
+ IWD_BSS_INTERFACE, bss);
+
+ if (!l_dbus_object_add_interface(dbus_get_bus(), path,
+ IWD_BSS_INTERFACE, bss))
+ return false;
+
+ if (!l_dbus_object_add_interface(dbus_get_bus(), path,
+ L_DBUS_INTERFACE_PROPERTIES, bss))
+ return false;
+
+ return true;
+}
+
+void network_bss_start_update(struct network *network)
+{
+ network->old_bss_list = network->bss_list;
+ network->bss_list = l_queue_new();
+}
+
+void network_bss_stop_update(struct network *network)
+{
+ const struct l_queue_entry *e;
+
+ /*
+ * Update has finished, clean up any BSS's from the old list that have
+ * been registered on DBus.
+ */
+ for (e = l_queue_get_entries(network->old_bss_list); e; e = e->next) {
+ const struct scan_bss *old = e->data;
+ const struct scan_bss *bss;
+ const char *path = network_bss_get_path(network, old);
+
+ bss = l_dbus_object_get_data(dbus_get_bus(), path,
+ IWD_BSS_INTERFACE);
+ /*
+ * The lookup matched the user data of an old BSS. This should
+ * be unregistered from DBus
+ */
+ if (bss && bss == old)
+ l_dbus_object_remove_interface(dbus_get_bus(), path,
+ IWD_BSS_INTERFACE);
+ }
+
+ l_queue_destroy(network->old_bss_list, NULL);
+ network->old_bss_list = NULL;
+}
+
bool network_bss_add(struct network *network, struct scan_bss *bss)
{
if (!l_queue_insert(network->bss_list, bss, scan_bss_rank_compare,
NULL))
return false;
+ network_register_bss(network, bss);
+
/* Done if BSS is not HS20 or we already have network_info set */
if (!bss->hs20_capable)
return true;
@@ -1168,6 +1254,8 @@ bool network_bss_update(struct network *network, struct scan_bss *bss)
l_queue_insert(network->bss_list, bss, scan_bss_rank_compare, NULL);
+ network_register_bss(network, bss);
+
/* Sync frequency for already known networks */
if (network->info) {
known_network_add_frequency(network->info, bss->frequency);
@@ -1190,7 +1278,12 @@ void network_bss_list_clear(struct network *network)
struct scan_bss *network_bss_list_pop(struct network *network)
{
- return l_queue_pop_head(network->bss_list);
+ struct scan_bss *bss = l_queue_pop_head(network->bss_list);
+
+ if (bss)
+ network_unregister_bss(bss, network);
+
+ return bss;
}
struct scan_bss *network_bss_find_by_addr(struct network *network,
@@ -1899,6 +1992,9 @@ static void network_unregister(struct network *network, int reason)
void network_remove(struct network *network, int reason)
{
+ l_queue_foreach_remove(network->bss_list,
+ network_unregister_bss, network);
+
if (network->object_path)
network_unregister(network, reason);
@@ -2155,6 +2251,24 @@ static void setup_network_interface(struct l_dbus_interface *interface)
network_property_get_known_network, NULL);
}
+static bool network_bss_property_get_address(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ struct l_dbus_message_builder *builder,
+ void *user_data)
+{
+ struct scan_bss *bss = user_data;
+
+ l_dbus_message_builder_append_basic(builder, 's',
+ util_address_to_string(bss->addr));
+ return true;
+}
+
+static void setup_bss_interface(struct l_dbus_interface *interface)
+{
+ l_dbus_interface_property(interface, "Address", 0, "s",
+ network_bss_property_get_address, NULL);
+}
+
static int network_init(void)
{
if (!l_dbus_register_interface(dbus_get_bus(), IWD_NETWORK_INTERFACE,
@@ -2162,6 +2276,11 @@ static int network_init(void)
l_error("Unable to register %s interface",
IWD_NETWORK_INTERFACE);
+ if (!l_dbus_register_interface(dbus_get_bus(), IWD_BSS_INTERFACE,
+ setup_bss_interface, NULL, false))
+ l_error("Unable to register %s interface",
+ IWD_BSS_INTERFACE);
+
known_networks_watch =
known_networks_watch_add(known_networks_changed, NULL, NULL);
@@ -2179,6 +2298,7 @@ static void network_exit(void)
event_watch = 0;
l_dbus_unregister_interface(dbus_get_bus(), IWD_NETWORK_INTERFACE);
+ l_dbus_unregister_interface(dbus_get_bus(), IWD_BSS_INTERFACE);
}
IWD_MODULE(network, network_init, network_exit)
@@ -67,8 +67,12 @@ int network_can_connect_bss(struct network *network,
const struct scan_bss *bss);
int network_autoconnect(struct network *network, struct scan_bss *bss);
void network_connect_failed(struct network *network, bool in_handshake);
+void network_bss_start_update(struct network *network);
+void network_bss_stop_update(struct network *network);
bool network_bss_add(struct network *network, struct scan_bss *bss);
bool network_bss_update(struct network *network, struct scan_bss *bss);
+const char *network_bss_get_path(const struct network *network,
+ const struct scan_bss *bss);
bool network_bss_list_isempty(struct network *network);
void network_bss_list_clear(struct network *network);
struct scan_bss *network_bss_list_pop(struct network *network);