summaryrefslogtreecommitdiff
path: root/src/core/settings/nm-settings-connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/settings/nm-settings-connection.c')
-rw-r--r--src/core/settings/nm-settings-connection.c227
1 files changed, 152 insertions, 75 deletions
diff --git a/src/core/settings/nm-settings-connection.c b/src/core/settings/nm-settings-connection.c
index 641f3297b8..36ef6acb2f 100644
--- a/src/core/settings/nm-settings-connection.c
+++ b/src/core/settings/nm-settings-connection.c
@@ -11,6 +11,7 @@
#include "c-list/src/c-list.h"
#include "libnm-glib-aux/nm-keyfile-aux.h"
+#include "libnm-glib-aux/nm-c-list.h"
#include "libnm-core-aux-intern/nm-common-macros.h"
#include "nm-config.h"
#include "nm-config-data.h"
@@ -30,6 +31,8 @@
#define AUTOCONNECT_RETRIES_FOREVER -1
#define AUTOCONNECT_RESET_RETRIES_TIMER 300
+#define SEEN_BSSIDS_MAX 30
+
#define _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES \
((NMSettingsUpdate2Flags) (NM_SETTINGS_UPDATE2_FLAG_TO_DISK \
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY \
@@ -59,6 +62,56 @@ nm_settings_connections_array_to_connections(NMSettingsConnection *const *connec
/*****************************************************************************/
+typedef struct {
+ char bssid[sizeof(NMEtherAddr) * 3];
+ CList seen_bssids_lst;
+} SeenBssidEntry;
+
+static inline SeenBssidEntry *
+_seen_bssid_entry_init_stale(SeenBssidEntry *entry, const NMEtherAddr *bssid_bin)
+{
+ _nm_utils_hwaddr_ntoa(bssid_bin, sizeof(NMEtherAddr), TRUE, entry->bssid, sizeof(entry->bssid));
+ return entry;
+}
+
+static inline SeenBssidEntry *
+_seen_bssid_entry_new_stale_bin(const NMEtherAddr *bssid_bin)
+{
+ return _seen_bssid_entry_init_stale(g_slice_new(SeenBssidEntry), bssid_bin);
+}
+
+static inline SeenBssidEntry *
+_seen_bssid_entry_new_stale_copy(const SeenBssidEntry *src)
+{
+ SeenBssidEntry *entry;
+
+ entry = g_slice_new(SeenBssidEntry);
+ memcpy(entry->bssid, src->bssid, sizeof(entry->bssid));
+ return entry;
+}
+
+static void
+_seen_bssid_entry_free(gpointer data)
+{
+ SeenBssidEntry *entry = data;
+
+ c_list_unlink_stale(&entry->seen_bssids_lst);
+ nm_g_slice_free(entry);
+}
+
+/*****************************************************************************/
+
+static GHashTable *
+_seen_bssids_hash_new(void)
+{
+ return g_hash_table_new_full(nm_str_hash,
+ g_str_equal,
+ (GDestroyNotify) _seen_bssid_entry_free,
+ NULL);
+}
+
+/*****************************************************************************/
+
NM_GOBJECT_PROPERTIES_DEFINE(NMSettingsConnection, PROP_UNSAVED, PROP_FLAGS, PROP_FILENAME, );
enum { UPDATED_INTERNAL, FLAGS_CHANGED, LAST_SIGNAL };
@@ -99,7 +152,8 @@ typedef struct _NMSettingsConnectionPrivate {
*/
GVariant *agent_secrets;
- GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */
+ CList seen_bssids_lst_head;
+ GHashTable *seen_bssids_hash;
guint64 timestamp; /* Up-to-date timestamp of connection use */
@@ -167,7 +221,9 @@ static const GDBusSignalInfo signal_info_updated;
static const GDBusSignalInfo signal_info_removed;
static const NMDBusInterfaceInfoExtended interface_info_settings_connection;
-static void update_agent_secrets_cache(NMSettingsConnection *self, NMConnection *new);
+static void update_agent_secrets_cache(NMSettingsConnection *self, NMConnection *new);
+static guint _get_seen_bssids(NMSettingsConnection *self,
+ const char * strv_buf[static(SEEN_BSSIDS_MAX + 1)]);
/*****************************************************************************/
@@ -246,14 +302,6 @@ nm_settings_connection_still_valid(NMSettingsConnection *self)
/*****************************************************************************/
-static GHashTable *
-_seen_bssids_hash_new(void)
-{
- return g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, NULL);
-}
-
-/*****************************************************************************/
-
static void
_getsettings_cached_clear(NMSettingsConnectionPrivate *priv)
{
@@ -1300,8 +1348,8 @@ get_settings_auth_cb(NMSettingsConnection * self,
GError * error,
gpointer data)
{
- gs_free const char ** seen_bssids = NULL;
- NMConnectionSerializationOptions options = {};
+ const char * seen_bssids_strv[SEEN_BSSIDS_MAX + 1];
+ NMConnectionSerializationOptions options = {};
if (error) {
g_dbus_method_invocation_return_gerror(context, error);
@@ -1321,8 +1369,8 @@ get_settings_auth_cb(NMSettingsConnection * self,
* from the same reason as timestamp. Thus we put it here to GetSettings()
* return settings too.
*/
- seen_bssids = nm_settings_connection_get_seen_bssids(self);
- options.seen_bssids = seen_bssids;
+ _get_seen_bssids(self, seen_bssids_strv);
+ options.seen_bssids = seen_bssids_strv;
/* Secrets should *never* be returned by the GetSettings method, they
* get returned by the GetSecrets method which can be better
@@ -2304,68 +2352,66 @@ _nm_settings_connection_register_kf_dbs(NMSettingsConnection *self,
if (priv->kf_db_seen_bssids != kf_db_seen_bssids) {
gs_strfreev char **tmp_strv = NULL;
- gsize i, len;
+ gsize len;
+ gsize i;
+ guint result_len;
nm_key_file_db_unref(priv->kf_db_seen_bssids);
priv->kf_db_seen_bssids = nm_key_file_db_ref(kf_db_seen_bssids);
tmp_strv = nm_key_file_db_get_string_list(priv->kf_db_seen_bssids, connection_uuid, &len);
- nm_clear_pointer(&priv->seen_bssids, g_hash_table_unref);
+ if (priv->seen_bssids_hash)
+ g_hash_table_remove_all(priv->seen_bssids_hash);
- if (len > 0) {
- _LOGT("read %zu seen-bssids from keyfile database \"%s\"",
- len,
- nm_key_file_db_get_filename(priv->kf_db_seen_bssids));
- priv->seen_bssids = _seen_bssids_hash_new();
- for (i = len; i > 0;)
- g_hash_table_add(priv->seen_bssids, g_steal_pointer(&tmp_strv[--i]));
- nm_clear_g_free(&tmp_strv);
- } else {
- NMSettingWireless *s_wifi;
+ for (result_len = 0, i = 0; i < len; i++) {
+ NMEtherAddr addr_bin;
+ SeenBssidEntry *entry;
- _LOGT("no seen-bssids from keyfile database \"%s\"",
- nm_key_file_db_get_filename(priv->kf_db_seen_bssids));
+ nm_assert(result_len == nm_g_hash_table_size(priv->seen_bssids_hash));
+ if (result_len >= SEEN_BSSIDS_MAX)
+ break;
- /* If this connection didn't have an entry in the seen-bssids database,
- * maybe this is the first time we've read it in, so populate the
- * seen-bssids list from the deprecated seen-bssids property of the
- * wifi setting.
- */
- s_wifi =
- nm_connection_get_setting_wireless(nm_settings_connection_get_connection(self));
- if (s_wifi) {
- len = nm_setting_wireless_get_num_seen_bssids(s_wifi);
- if (len > 0) {
- priv->seen_bssids = _seen_bssids_hash_new();
- for (i = 0; i < len; i++) {
- const char *bssid = nm_setting_wireless_get_seen_bssid(s_wifi, i);
-
- g_hash_table_add(priv->seen_bssids, g_strdup(bssid));
- }
- }
+ if (!_nm_utils_hwaddr_aton_exact(tmp_strv[i], &addr_bin, sizeof(addr_bin)))
+ continue;
+
+ if (!priv->seen_bssids_hash)
+ priv->seen_bssids_hash = _seen_bssids_hash_new();
+
+ entry = _seen_bssid_entry_new_stale_bin(&addr_bin);
+ if (!g_hash_table_insert(priv->seen_bssids_hash, entry, entry)) {
+ /* duplicate detected! The @entry key was freed by g_hash_table_insert(). */
+ continue;
}
+ c_list_link_tail(&priv->seen_bssids_lst_head, &entry->seen_bssids_lst);
+ result_len++;
}
+ if (result_len > 0) {
+ _LOGT("read %u seen-bssids from keyfile database \"%s\"",
+ result_len,
+ nm_key_file_db_get_filename(priv->kf_db_seen_bssids));
+ } else
+ nm_clear_pointer(&priv->seen_bssids_hash, g_hash_table_destroy);
+
+ nm_assert(nm_g_hash_table_size(priv->seen_bssids_hash) == result_len);
+ nm_assert(result_len <= SEEN_BSSIDS_MAX);
}
}
-/**
- * nm_settings_connection_get_seen_bssids:
- * @self: the #NMSettingsConnection
- *
- * Returns current list of seen BSSIDs for the connection.
- *
- * Returns: (transfer container) list of seen BSSIDs (in the standard hex-digits-and-colons notation).
- * The caller is responsible for freeing the list, but not the content.
- **/
-const char **
-nm_settings_connection_get_seen_bssids(NMSettingsConnection *self)
+static guint
+_get_seen_bssids(NMSettingsConnection *self, const char *strv_buf[static(SEEN_BSSIDS_MAX + 1)])
{
- g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(self), NULL);
+ NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self);
+ SeenBssidEntry * entry;
+ guint i;
- return nm_utils_strdict_get_keys(NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->seen_bssids,
- TRUE,
- NULL);
+ i = 0;
+ c_list_for_each_entry (entry, &priv->seen_bssids_lst_head, seen_bssids_lst) {
+ nm_assert(i <= SEEN_BSSIDS_MAX);
+ strv_buf[i++] = entry->bssid;
+ }
+ strv_buf[i] = NULL;
+ return i;
}
/**
@@ -2379,14 +2425,17 @@ gboolean
nm_settings_connection_has_seen_bssid(NMSettingsConnection *self, const char *bssid)
{
NMSettingsConnectionPrivate *priv;
+ NMEtherAddr addr_bin;
g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(self), FALSE);
g_return_val_if_fail(bssid, FALSE);
+ nm_assert(_nm_utils_hwaddr_aton_exact(bssid, &addr_bin, sizeof(addr_bin)));
priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self);
- return priv->seen_bssids
- && g_hash_table_contains(NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->seen_bssids, bssid);
+ return priv->seen_bssids_hash
+ && g_hash_table_contains(NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->seen_bssids_hash,
+ bssid);
}
/**
@@ -2401,15 +2450,47 @@ void
nm_settings_connection_add_seen_bssid(NMSettingsConnection *self, const char *seen_bssid)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self);
- gs_free const char ** strv = NULL;
+ const char * seen_bssids_strv[SEEN_BSSIDS_MAX + 1];
+ NMEtherAddr addr_bin;
const char * connection_uuid;
+ SeenBssidEntry entry_stack;
+ SeenBssidEntry * entry;
+ guint i;
+
+ g_return_if_fail(seen_bssid);
- g_return_if_fail(seen_bssid != NULL);
+ if (!_nm_utils_hwaddr_aton_exact(seen_bssid, &addr_bin, sizeof(addr_bin)))
+ g_return_if_reached();
- if (!priv->seen_bssids)
- priv->seen_bssids = _seen_bssids_hash_new();
+ _seen_bssid_entry_init_stale(&entry_stack, &addr_bin);
- g_hash_table_add(priv->seen_bssids, g_strdup(seen_bssid));
+ if (!priv->seen_bssids_hash) {
+ priv->seen_bssids_hash = _seen_bssids_hash_new();
+ entry = NULL;
+ } else
+ entry = g_hash_table_lookup(priv->seen_bssids_hash, &entry_stack);
+
+ if (entry) {
+ if (!nm_c_list_move_front(&priv->seen_bssids_lst_head, &entry->seen_bssids_lst)) {
+ /* no change. */
+ return;
+ }
+ } else {
+ entry = _seen_bssid_entry_new_stale_copy(&entry_stack);
+ c_list_link_front(&priv->seen_bssids_lst_head, &entry->seen_bssids_lst);
+ if (!g_hash_table_add(priv->seen_bssids_hash, entry))
+ nm_assert_not_reached();
+
+ if (g_hash_table_size(priv->seen_bssids_hash) > SEEN_BSSIDS_MAX) {
+ g_hash_table_remove(
+ priv->seen_bssids_hash,
+ c_list_last_entry(&priv->seen_bssids_lst_head, SeenBssidEntry, seen_bssids_lst));
+ }
+ }
+
+ nm_assert(g_hash_table_size(priv->seen_bssids_hash) <= SEEN_BSSIDS_MAX);
+ nm_assert(g_hash_table_size(priv->seen_bssids_hash)
+ == c_list_length(&priv->seen_bssids_lst_head));
if (!priv->kf_db_seen_bssids)
return;
@@ -2418,12 +2499,8 @@ nm_settings_connection_add_seen_bssid(NMSettingsConnection *self, const char *se
if (!connection_uuid)
return;
- strv = nm_utils_strdict_get_keys(priv->seen_bssids, TRUE, NULL);
-
- nm_key_file_db_set_string_list(priv->kf_db_seen_bssids,
- connection_uuid,
- strv ?: NM_PTRARRAY_EMPTY(const char *),
- -1);
+ i = _get_seen_bssids(self, seen_bssids_strv);
+ nm_key_file_db_set_string_list(priv->kf_db_seen_bssids, connection_uuid, seen_bssids_strv, i);
}
/*****************************************************************************/
@@ -2634,7 +2711,7 @@ nm_settings_connection_init(NMSettingsConnection *self)
self->_priv = priv;
c_list_init(&self->_connections_lst);
-
+ c_list_init(&priv->seen_bssids_lst_head);
c_list_init(&priv->call_ids_lst_head);
c_list_init(&priv->auth_lst_head);
@@ -2672,7 +2749,7 @@ dispose(GObject *object)
nm_clear_pointer(&priv->agent_secrets, g_variant_unref);
- nm_clear_pointer(&priv->seen_bssids, g_hash_table_destroy);
+ nm_clear_pointer(&priv->seen_bssids_hash, g_hash_table_destroy);
g_clear_object(&priv->agent_mgr);