mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-05 07:38:20 +02:00
core: fix auto-connect to hidden SSIDs (rh #707406)
Previously (in NM 0.8.x) most WiFi connection were from user settings service. And the service updated 'seen-bssids' property when got connected. But the settings service in 0.9 don't do that. That inhibits auto-connecting to hidden networks. This commit takes care of updating 'seen-bssids'. However, we don't want to write out the conection each time it's activated (touching /etc). So, seen BSSIDs are kept separately from the connection in a look-aside file. Signed-off-by: Jiří Klimeš <jklimes@redhat.com>
This commit is contained in:
parent
060e865ecd
commit
9549c70d94
5 changed files with 256 additions and 46 deletions
|
|
@ -55,6 +55,7 @@
|
|||
#include "nm-setting-ip4-config.h"
|
||||
#include "nm-setting-ip6-config.h"
|
||||
#include "nm-system.h"
|
||||
#include "nm-settings-connection.h"
|
||||
|
||||
static gboolean impl_device_get_access_points (NMDeviceWifi *device,
|
||||
GPtrArray **aps,
|
||||
|
|
@ -977,6 +978,28 @@ get_active_ap (NMDeviceWifi *self,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
update_seen_bssids_cache (NMDeviceWifi *self, NMAccessPoint *ap)
|
||||
{
|
||||
NMActRequest *req;
|
||||
NMConnection *connection;
|
||||
|
||||
g_return_if_fail (ap != NULL);
|
||||
|
||||
/* Don't cache the BSSID for Ad-Hoc APs */
|
||||
if (nm_ap_get_mode (ap) != NM_802_11_MODE_INFRA)
|
||||
return;
|
||||
|
||||
if (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED) {
|
||||
req = nm_device_get_act_request (NM_DEVICE (self));
|
||||
if (req) {
|
||||
connection = nm_act_request_get_connection (req);
|
||||
nm_settings_connection_add_seen_bssid (NM_SETTINGS_CONNECTION (connection),
|
||||
nm_ap_get_address (ap));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_current_ap (NMDeviceWifi *self, NMAccessPoint *new_ap)
|
||||
{
|
||||
|
|
@ -1003,6 +1026,9 @@ set_current_ap (NMDeviceWifi *self, NMAccessPoint *new_ap)
|
|||
*/
|
||||
priv->ap_list = g_slist_remove (priv->ap_list, new_ap);
|
||||
priv->ap_list = g_slist_prepend (priv->ap_list, new_ap);
|
||||
|
||||
/* Update seen BSSIDs cache */
|
||||
update_seen_bssids_cache (self, priv->current_ap);
|
||||
}
|
||||
|
||||
/* Unref old AP here to ensure object lives if new_ap == old_ap */
|
||||
|
|
@ -3436,11 +3462,13 @@ activation_success_handler (NMDevice *dev)
|
|||
done:
|
||||
periodic_update (self);
|
||||
|
||||
/* Update seen BSSIDs cache with the connected AP */
|
||||
update_seen_bssids_cache (self, priv->current_ap);
|
||||
|
||||
/* Reset scan interval to something reasonable */
|
||||
priv->scan_interval = SCAN_INTERVAL_MIN + (SCAN_INTERVAL_STEP * 2);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
activation_failure_handler (NMDevice *dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
#include "nm-settings-connection.h"
|
||||
#include "nm-manager-auth.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-utils.h"
|
||||
|
||||
#define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
|
||||
#define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd"
|
||||
|
|
@ -1040,52 +1041,27 @@ manager_hidden_ap_found (NMDeviceInterface *device,
|
|||
{
|
||||
NMManager *manager = NM_MANAGER (user_data);
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
||||
const struct ether_addr *ap_addr;
|
||||
const GByteArray *ap_ssid;
|
||||
const struct ether_addr *bssid;
|
||||
GSList *iter;
|
||||
GSList *connections;
|
||||
gboolean done = FALSE;
|
||||
|
||||
ap_ssid = nm_ap_get_ssid (ap);
|
||||
if (ap_ssid && ap_ssid->len)
|
||||
return;
|
||||
g_return_if_fail (nm_ap_get_ssid (ap) == NULL);
|
||||
|
||||
ap_addr = nm_ap_get_address (ap);
|
||||
g_assert (ap_addr);
|
||||
bssid = nm_ap_get_address (ap);
|
||||
g_assert (bssid);
|
||||
|
||||
/* Look for this AP's BSSID in the seen-bssids list of a connection,
|
||||
* and if a match is found, copy over the SSID */
|
||||
connections = nm_settings_get_connections (priv->settings);
|
||||
|
||||
for (iter = connections; iter && !done; iter = g_slist_next (iter)) {
|
||||
NMConnection *connection = NM_CONNECTION (iter->data);
|
||||
NMSettingWireless *s_wireless;
|
||||
const GByteArray *ssid;
|
||||
guint32 num_bssids;
|
||||
guint32 i;
|
||||
NMSettingWireless *s_wifi;
|
||||
|
||||
s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
|
||||
if (!s_wireless)
|
||||
continue;
|
||||
|
||||
num_bssids = nm_setting_wireless_get_num_seen_bssids (s_wireless);
|
||||
if (num_bssids < 1)
|
||||
continue;
|
||||
|
||||
ssid = nm_setting_wireless_get_ssid (s_wireless);
|
||||
g_assert (ssid);
|
||||
|
||||
for (i = 0; i < num_bssids && !done; i++) {
|
||||
const char *seen_bssid = nm_setting_wireless_get_seen_bssid (s_wireless, i);
|
||||
struct ether_addr seen_addr;
|
||||
|
||||
if (ether_aton_r (seen_bssid, &seen_addr)) {
|
||||
if (memcmp (ap_addr, &seen_addr, sizeof (struct ether_addr)) == 0) {
|
||||
/* Copy the SSID from the connection to the AP */
|
||||
nm_ap_set_ssid (ap, ssid);
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
s_wifi = nm_connection_get_setting_wireless (connection);
|
||||
if (s_wifi) {
|
||||
if (nm_settings_connection_has_seen_bssid (NM_SETTINGS_CONNECTION (connection), bssid))
|
||||
nm_ap_set_ssid (ap, nm_setting_wireless_get_ssid (s_wifi));
|
||||
}
|
||||
}
|
||||
g_slist_free (connections);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <netinet/ether.h>
|
||||
|
||||
#include <NetworkManager.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
|
@ -38,8 +39,10 @@
|
|||
#include "nm-manager-auth.h"
|
||||
#include "nm-marshal.h"
|
||||
#include "nm-agent-manager.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
#define SETTINGS_TIMESTAMPS_FILE LOCALSTATEDIR"/lib/NetworkManager/timestamps"
|
||||
#define SETTINGS_SEEN_BSSIDS_FILE LOCALSTATEDIR"/lib/NetworkManager/seen-bssids"
|
||||
|
||||
static void impl_settings_connection_get_settings (NMSettingsConnection *connection,
|
||||
DBusGMethodInvocation *context);
|
||||
|
|
@ -91,7 +94,8 @@ typedef struct {
|
|||
NMSessionMonitor *session_monitor;
|
||||
guint session_changed_id;
|
||||
|
||||
guint64 timestamp; /* Up-to-date timestamp of connection use */
|
||||
guint64 timestamp; /* Up-to-date timestamp of connection use */
|
||||
GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */
|
||||
} NMSettingsConnectionPrivate;
|
||||
|
||||
/**************************************************************/
|
||||
|
|
@ -455,12 +459,20 @@ commit_changes (NMSettingsConnection *connection,
|
|||
}
|
||||
|
||||
static void
|
||||
remove_timestamp_from_db (NMSettingsConnection *connection)
|
||||
remove_entry_from_db (NMSettingsConnection *connection, const char* db_name)
|
||||
{
|
||||
GKeyFile *timestamps_file;
|
||||
GKeyFile *key_file;
|
||||
const char *db_file;
|
||||
|
||||
timestamps_file = g_key_file_new ();
|
||||
if (g_key_file_load_from_file (timestamps_file, SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL)) {
|
||||
if (strcmp (db_name, "timestamps") == 0)
|
||||
db_file = SETTINGS_TIMESTAMPS_FILE;
|
||||
else if (strcmp (db_name, "seen-bssids") == 0)
|
||||
db_file = SETTINGS_SEEN_BSSIDS_FILE;
|
||||
else
|
||||
return;
|
||||
|
||||
key_file = g_key_file_new ();
|
||||
if (g_key_file_load_from_file (key_file, db_file, G_KEY_FILE_KEEP_COMMENTS, NULL)) {
|
||||
const char *connection_uuid;
|
||||
char *data;
|
||||
gsize len;
|
||||
|
|
@ -468,18 +480,18 @@ remove_timestamp_from_db (NMSettingsConnection *connection)
|
|||
|
||||
connection_uuid = nm_connection_get_uuid (NM_CONNECTION (connection));
|
||||
|
||||
g_key_file_remove_key (timestamps_file, "timestamps", connection_uuid, NULL);
|
||||
data = g_key_file_to_data (timestamps_file, &len, &error);
|
||||
g_key_file_remove_key (key_file, db_name, connection_uuid, NULL);
|
||||
data = g_key_file_to_data (key_file, &len, &error);
|
||||
if (data) {
|
||||
g_file_set_contents (SETTINGS_TIMESTAMPS_FILE, data, len, &error);
|
||||
g_file_set_contents (db_file, data, len, &error);
|
||||
g_free (data);
|
||||
}
|
||||
if (error) {
|
||||
nm_log_warn (LOGD_SETTINGS, "error writing timestamps file '%s': %s", SETTINGS_TIMESTAMPS_FILE, error->message);
|
||||
nm_log_warn (LOGD_SETTINGS, "error writing %s file '%s': %s", db_name, db_file, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
g_key_file_free (timestamps_file);
|
||||
g_key_file_free (key_file);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -499,7 +511,10 @@ do_delete (NMSettingsConnection *connection,
|
|||
nm_agent_manager_delete_secrets (priv->agent_mgr, for_agents, FALSE, 0);
|
||||
|
||||
/* Remove timestamp from timestamps database file */
|
||||
remove_timestamp_from_db (connection);
|
||||
remove_entry_from_db (connection, "timestamps");
|
||||
|
||||
/* Remove connection from seen-bssids database file */
|
||||
remove_entry_from_db (connection, "seen-bssids");
|
||||
|
||||
/* Signal the connection is removed and deleted */
|
||||
g_signal_emit (connection, signals[REMOVED], 0);
|
||||
|
|
@ -1440,6 +1455,181 @@ nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *connection
|
|||
g_key_file_free (timestamps_file);
|
||||
}
|
||||
|
||||
static guint
|
||||
mac_hash (gconstpointer v)
|
||||
{
|
||||
const guint8 *p = v;
|
||||
guint32 i, h = 5381;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
h = (h << 5) + h + p[i];
|
||||
return h;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
mac_equal (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
return memcmp (a, b, ETH_ALEN) == 0;
|
||||
}
|
||||
|
||||
static guint8 *
|
||||
mac_dup (const struct ether_addr *old)
|
||||
{
|
||||
guint8 *new;
|
||||
|
||||
g_return_val_if_fail (old != NULL, NULL);
|
||||
|
||||
new = g_malloc0 (ETH_ALEN);
|
||||
memcpy (new, old, ETH_ALEN);
|
||||
return new;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_settings_connection_has_seen_bssid:
|
||||
* @connection: the #NMSettingsConnection
|
||||
* @bssid: the BSSID to check the seen BSSID list for
|
||||
*
|
||||
* Returns: TRUE if the given @bssid is in the seen BSSIDs list
|
||||
**/
|
||||
gboolean
|
||||
nm_settings_connection_has_seen_bssid (NMSettingsConnection *connection,
|
||||
const struct ether_addr *bssid)
|
||||
{
|
||||
g_return_val_if_fail (connection != NULL, FALSE);
|
||||
g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), FALSE);
|
||||
g_return_val_if_fail (bssid != NULL, FALSE);
|
||||
|
||||
return !!g_hash_table_lookup (NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->seen_bssids, bssid);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_settings_connection_add_seen_bssid:
|
||||
* @connection: the #NMSettingsConnection
|
||||
* @seen_bssid: BSSID to set into the connection and to store into
|
||||
* the seen-bssids database
|
||||
*
|
||||
* Updates the connection and seen-bssids database with the provided BSSID.
|
||||
**/
|
||||
void
|
||||
nm_settings_connection_add_seen_bssid (NMSettingsConnection *connection,
|
||||
const struct ether_addr *seen_bssid)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
|
||||
const char *connection_uuid;
|
||||
GKeyFile *seen_bssids_file;
|
||||
char *data, *bssid_str;
|
||||
const char **list;
|
||||
gsize len;
|
||||
GError *error = NULL;
|
||||
GHashTableIter iter;
|
||||
guint n;
|
||||
|
||||
g_return_if_fail (seen_bssid != NULL);
|
||||
|
||||
if (g_hash_table_lookup (priv->seen_bssids, seen_bssid))
|
||||
return; /* Already in the list */
|
||||
|
||||
/* Add the new BSSID; let the hash take ownership of the allocated BSSID string */
|
||||
bssid_str = nm_ether_ntop (seen_bssid);
|
||||
g_return_if_fail (bssid_str != NULL);
|
||||
g_hash_table_insert (priv->seen_bssids, mac_dup (seen_bssid), bssid_str);
|
||||
|
||||
/* Build up a list of all the BSSIDs in string form */
|
||||
n = 0;
|
||||
list = g_malloc0 (g_hash_table_size (priv->seen_bssids) * sizeof (char *));
|
||||
g_hash_table_iter_init (&iter, priv->seen_bssids);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &bssid_str))
|
||||
list[n++] = bssid_str;
|
||||
|
||||
/* Save BSSID to seen-bssids file */
|
||||
seen_bssids_file = g_key_file_new ();
|
||||
g_key_file_set_list_separator (seen_bssids_file, ',');
|
||||
if (!g_key_file_load_from_file (seen_bssids_file, SETTINGS_SEEN_BSSIDS_FILE, G_KEY_FILE_KEEP_COMMENTS, &error)) {
|
||||
if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
|
||||
nm_log_warn (LOGD_SETTINGS, "error parsing seen-bssids file '%s': %s",
|
||||
SETTINGS_SEEN_BSSIDS_FILE, error->message);
|
||||
}
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
connection_uuid = nm_connection_get_uuid (NM_CONNECTION (connection));
|
||||
g_key_file_set_string_list (seen_bssids_file, "seen-bssids", connection_uuid, list, n);
|
||||
g_free (list);
|
||||
|
||||
data = g_key_file_to_data (seen_bssids_file, &len, &error);
|
||||
if (data) {
|
||||
g_file_set_contents (SETTINGS_SEEN_BSSIDS_FILE, data, len, &error);
|
||||
g_free (data);
|
||||
}
|
||||
g_key_file_free (seen_bssids_file);
|
||||
|
||||
if (error) {
|
||||
nm_log_warn (LOGD_SETTINGS, "error saving seen-bssids to file '%s': %s",
|
||||
SETTINGS_SEEN_BSSIDS_FILE, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_seen_bssid_string (NMSettingsConnection *self, const char *bssid)
|
||||
{
|
||||
struct ether_addr mac;
|
||||
|
||||
g_return_if_fail (bssid != NULL);
|
||||
if (ether_aton_r (bssid, &mac)) {
|
||||
g_hash_table_insert (NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->seen_bssids,
|
||||
mac_dup (&mac),
|
||||
g_strdup (bssid));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_settings_connection_read_and_fill_seen_bssids:
|
||||
* @connection: the #NMSettingsConnection
|
||||
*
|
||||
* Retrieves seen BSSIDs of the connection from database file and stores then into the
|
||||
* connection private data.
|
||||
**/
|
||||
void
|
||||
nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *connection)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
|
||||
const char *connection_uuid;
|
||||
GKeyFile *seen_bssids_file;
|
||||
char **tmp_strv = NULL;
|
||||
gsize i, len = 0;
|
||||
NMSettingWireless *s_wifi;
|
||||
|
||||
/* Get seen BSSIDs from database file */
|
||||
seen_bssids_file = g_key_file_new ();
|
||||
g_key_file_set_list_separator (seen_bssids_file, ',');
|
||||
if (g_key_file_load_from_file (seen_bssids_file, SETTINGS_SEEN_BSSIDS_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL)) {
|
||||
connection_uuid = nm_connection_get_uuid (NM_CONNECTION (connection));
|
||||
tmp_strv = g_key_file_get_string_list (seen_bssids_file, "seen-bssids", connection_uuid, &len, NULL);
|
||||
}
|
||||
g_key_file_free (seen_bssids_file);
|
||||
|
||||
/* Update connection's seen-bssids */
|
||||
if (tmp_strv) {
|
||||
g_hash_table_remove_all (priv->seen_bssids);
|
||||
for (i = 0; i < len; i++)
|
||||
add_seen_bssid_string (connection, tmp_strv[i]);
|
||||
g_strfreev (tmp_strv);
|
||||
} else {
|
||||
/* 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_CONNECTION (connection));
|
||||
if (s_wifi) {
|
||||
len = nm_setting_wireless_get_num_seen_bssids (s_wifi);
|
||||
for (i = 0; i < len; i++)
|
||||
add_seen_bssid_string (connection, nm_setting_wireless_get_seen_bssid (s_wifi, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
static void
|
||||
|
|
@ -1463,6 +1653,8 @@ nm_settings_connection_init (NMSettingsConnection *self)
|
|||
self);
|
||||
|
||||
priv->agent_mgr = nm_agent_manager_get ();
|
||||
|
||||
priv->seen_bssids = g_hash_table_new_full (mac_hash, mac_equal, g_free, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1490,6 +1682,8 @@ dispose (GObject *object)
|
|||
nm_agent_manager_cancel_secrets (priv->agent_mgr, GPOINTER_TO_UINT (iter->data));
|
||||
g_slist_free (priv->reqs);
|
||||
|
||||
g_hash_table_destroy (priv->seen_bssids);
|
||||
|
||||
set_visible (self, FALSE);
|
||||
|
||||
if (priv->session_changed_id)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <nm-connection.h>
|
||||
#include "nm-settings-flags.h"
|
||||
#include <net/ethernet.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
|
@ -124,6 +125,14 @@ void nm_settings_connection_update_timestamp (NMSettingsConnection *connection,
|
|||
|
||||
void nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *connection);
|
||||
|
||||
gboolean nm_settings_connection_has_seen_bssid (NMSettingsConnection *connection,
|
||||
const struct ether_addr *bssid);
|
||||
|
||||
void nm_settings_connection_add_seen_bssid (NMSettingsConnection *connection,
|
||||
const struct ether_addr *seen_bssid);
|
||||
|
||||
void nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *connection);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* NM_SETTINGS_CONNECTION_H */
|
||||
|
|
|
|||
|
|
@ -773,6 +773,9 @@ claim_connection (NMSettings *self,
|
|||
/* Read timestamp from look-aside file and put it into the connection's data */
|
||||
nm_settings_connection_read_and_fill_timestamp (connection);
|
||||
|
||||
/* Read seen-bssids from look-aside file and put it into the connection's data */
|
||||
nm_settings_connection_read_and_fill_seen_bssids (connection);
|
||||
|
||||
/* Ensure it's initial visibility is up-to-date */
|
||||
nm_settings_connection_recheck_visibility (connection);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue