[PATCH v2 1/4] knownnetworks: network: support updating known network settings

James Prestwood
2023-12-18T14:12:54Z

Currently if a known network is modified on disk the settings are not
reloaded by network. Only disconnecting/reconnecting to the network
would update the settings. This poses an issue to DPP since its
creating or updating a known network after configuration then trying
to connect. The connection itself works fine since the PSK/passphrase
is set to the network object directly, but any additional settings
are not updated.

To fix this add a new UPDATED known network event. This is then
handled from within network and all settings read from disk are
applied to the network object.
---
src/knownnetworks.c | 4 ++++
src/knownnetworks.h | 1 +
src/network.c | 27 ++++++++++++++++++++++++---
3 files changed, 29 insertions(+), 3 deletions(-)

v2:
* Instead of bothering with individual settings we can just use the
new l_settings object. This would still prefer agent-obtained creds
set into the network object but also honor any new settings written
to the profile if there is an ongoing connection. This is a much
simpler approach (unless I'm missing something). Only questionable
piece is what to do with the Security group. I hesitate to skip it
because its what we have on disk, but it could mean the network
object isn't synced with its settings. But I'm not sure this is
any different than what we have today, if a profile is modified
during an ongoing connection its settings (including security)
won't get updated until a disconnect/reconnect.

* Remove frequency sync on UPDATED event

diff --git a/src/knownnetworks.c b/src/knownnetworks.c
index d4d50a6f..04ce74ec 100644
--- a/src/knownnetworks.c
+++ b/src/knownnetworks.c
@@ -468,6 +468,10 @@ void known_network_update(struct network_info *network,
known_network_set_autoconnect(network, new->is_autoconnectable);

memcpy(&network->config, new, sizeof(struct network_config));
+
+ WATCHLIST_NOTIFY(&known_network_watches,
+ known_networks_watch_func_t,
+ KNOWN_NETWORKS_EVENT_UPDATED, network);
}

bool known_networks_foreach(known_networks_foreach_func_t function,
diff --git a/src/knownnetworks.h b/src/knownnetworks.h
index 0a5c9e25..e8ffac0b 100644
--- a/src/knownnetworks.h
+++ b/src/knownnetworks.h
@@ -35,6 +35,7 @@ struct network_info;
enum known_networks_event {
KNOWN_NETWORKS_EVENT_ADDED,
KNOWN_NETWORKS_EVENT_REMOVED,
+ KNOWN_NETWORKS_EVENT_UPDATED,
};

struct network_info_ops {
diff --git a/src/network.c b/src/network.c
index 3918ae08..f19482d8 100644
--- a/src/network.c
+++ b/src/network.c
@@ -2001,7 +2001,8 @@ static void network_update_hotspot(struct network *network, void *user_data)
match_hotspot_network(info, network);
}

-static void match_known_network(struct station *station, void *user_data)
+static void match_known_network(struct station *station, void *user_data,
+ bool new)
{
struct network_info *info = user_data;
struct network *network;
@@ -2011,7 +2012,14 @@ static void match_known_network(struct station *station, void *user_data)
if (!network)
return;

- network_set_info(network, info);
+ if (new)
+ network_set_info(network, info);
+
+ if (network->settings)
+ l_settings_free(network->settings);
+
+ network->settings = network_info_open_settings(info);
+
return;
}

@@ -2019,17 +2027,30 @@ static void match_known_network(struct station *station, void *user_data)
station_network_foreach(station, network_update_hotspot, info);
}

+static void add_known_network(struct station *station, void *user_data)
+{
+ match_known_network(station, (struct network_info *)user_data, true);
+}
+
+static void update_known_network(struct station *station, void *user_data)
+{
+ match_known_network(station, (struct network_info *)user_data, false);
+}
+
static void known_networks_changed(enum known_networks_event event,
const struct network_info *info,
void *user_data)
{
switch (event) {
case KNOWN_NETWORKS_EVENT_ADDED:
- station_foreach(match_known_network, (void *) info);
+ station_foreach(add_known_network, (void *) info);

/* Syncs frequencies of newly known network */
known_network_frequency_sync((struct network_info *)info);
break;
+ case KNOWN_NETWORKS_EVENT_UPDATED:
+ station_foreach(update_known_network, (void *) info);
+ break;
case KNOWN_NETWORKS_EVENT_REMOVED:
station_foreach(emit_known_network_removed, (void *) info);
break;
--
2.34.1