iwd: Track IWD Known Networks

Keep a list of IWD's Known Networks which are networks that have their
configurations stored by IWD including the secrets, either because they
have been connected to before or because they were preprovisioned on the
machine.
This commit is contained in:
Andrew Zaborowski 2017-12-15 15:30:18 +01:00 committed by Thomas Haller
parent ab8fc07640
commit b2ee8e8704
3 changed files with 203 additions and 17 deletions

View file

@ -399,6 +399,29 @@ deactivate (NMDevice *device)
cleanup_association_attempt (NM_DEVICE_IWD (device), TRUE);
}
static NMIwdNetworkSecurity
get_connection_iwd_security (NMConnection *connection)
{
NMSettingWirelessSecurity *s_wireless_sec;
const char *key_mgmt = NULL;
s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
if (!s_wireless_sec)
return NM_IWD_NETWORK_SECURITY_NONE;
key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec);
nm_assert (key_mgmt);
if (!strcmp (key_mgmt, "none") || !strcmp (key_mgmt, "ieee8021x"))
return NM_IWD_NETWORK_SECURITY_WEP;
if (!strcmp (key_mgmt, "wpa-psk"))
return NM_IWD_NETWORK_SECURITY_PSK;
nm_assert (!strcmp (key_mgmt, "wpa-eap"));
return NM_IWD_NETWORK_SECURITY_8021X;
}
static gboolean
check_connection_compatible (NMDevice *device, NMConnection *connection)
{
@ -1029,6 +1052,7 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data)
NMConnection *connection;
NMSettingWireless *s_wifi;
GBytes *ssid;
gs_free gchar *str_ssid = NULL;
if (!_nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res,
G_VARIANT_TYPE ("()"),
@ -1083,11 +1107,17 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data)
if (!ssid)
goto failed;
str_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL),
g_bytes_get_size (ssid));
_LOGI (LOGD_DEVICE | LOGD_WIFI,
"Activation: (wifi) Stage 2 of 5 (Device Configure) successful. Connected to '%s'.",
ssid ? nm_utils_escape_ssid (g_bytes_get_data (ssid, NULL),
g_bytes_get_size (ssid)) : "(none)");
str_ssid);
nm_device_activate_schedule_stage3_ip_config_start (device);
nm_iwd_manager_network_connected (nm_iwd_manager_get (), str_ssid,
get_connection_iwd_security (connection));
return;
failed:

View file

@ -26,18 +26,25 @@
#include <net/if.h>
#include "nm-logging.h"
#include "nm-core-internal.h"
#include "nm-manager.h"
#include "nm-device-iwd.h"
#include "nm-utils/nm-random-utils.h"
/*****************************************************************************/
typedef struct {
gchar *name;
NMIwdNetworkSecurity security;
} KnownNetworkData;
typedef struct {
GCancellable *cancellable;
gboolean running;
GDBusObjectManager *object_manager;
guint agent_id;
gchar *agent_path;
GSList *known_networks;
} NMIwdManagerPrivate;
struct _NMIwdManager {
@ -232,6 +239,26 @@ psk_agent_export (GDBusConnection *connection, gpointer user_data,
return id;
}
static void
register_agent (NMIwdManager *self)
{
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
GDBusInterface *agent_manager;
agent_manager = g_dbus_object_manager_get_interface (priv->object_manager,
"/",
NM_IWD_AGENT_MANAGER_INTERFACE);
/* Register our agent */
g_dbus_proxy_call (G_DBUS_PROXY (agent_manager),
"RegisterAgent",
g_variant_new ("(o)", priv->agent_path),
G_DBUS_CALL_FLAGS_NONE, -1,
NULL, NULL, NULL);
g_object_unref (agent_manager);
}
/*****************************************************************************/
static void
@ -336,6 +363,99 @@ object_added (NMIwdManager *self, GDBusObject *object)
g_list_free_full (interfaces, g_object_unref);
}
static void
known_network_free (KnownNetworkData *network)
{
g_free (network->name);
g_free (network);
}
static void
list_known_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data)
{
NMIwdManager *self = user_data;
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *variant = NULL;
GVariantIter *networks, *props;
variant = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res,
G_VARIANT_TYPE ("(aa{sv})"),
&error);
if (!variant) {
_LOGE ("ListKnownNetworks() failed: %s", error->message);
return;
}
g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free);
priv->known_networks = NULL;
g_variant_get (variant, "(aa{sv})", &networks);
while (g_variant_iter_next (networks, "a{sv}", &props)) {
const gchar *key;
const gchar *name = NULL;
const gchar *type = NULL;
GVariant *val;
KnownNetworkData *network_data;
while (g_variant_iter_next (props, "{&sv}", &key, &val)) {
if (!strcmp (key, "Name"))
name = g_variant_get_string (val, NULL);
if (!strcmp (key, "Type"))
type = g_variant_get_string (val, NULL);
g_variant_unref (val);
}
if (!name || !type)
goto next;
network_data = g_new (KnownNetworkData, 1);
network_data->name = g_strdup (name);
if (!strcmp (type, "open"))
network_data->security = NM_IWD_NETWORK_SECURITY_NONE;
else if (!strcmp (type, "psk"))
network_data->security = NM_IWD_NETWORK_SECURITY_PSK;
else if (!strcmp (type, "8021x"))
network_data->security = NM_IWD_NETWORK_SECURITY_8021X;
priv->known_networks = g_slist_append (priv->known_networks,
network_data);
next:
g_variant_iter_free (props);
}
g_variant_iter_free (networks);
/* For completness we may want to call nm_device_emit_recheck_auto_activate
* and nm_device_recheck_available_connections for all affected devices
* now but the ListKnownNetworks call should have been really fast,
* faster than any scan on any newly created devices could have happened.
*/
}
static void
update_known_networks (NMIwdManager *self)
{
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
GDBusInterface *known_networks_if;
known_networks_if = g_dbus_object_manager_get_interface (priv->object_manager,
"/",
NM_IWD_KNOWN_NETWORKS_INTERFACE);
g_dbus_proxy_call (G_DBUS_PROXY (known_networks_if),
"ListKnownNetworks",
g_variant_new ("()"),
G_DBUS_CALL_FLAGS_NONE, -1,
priv->cancellable, list_known_networks_cb, self);
g_object_unref (known_networks_if);
}
static void
name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
{
@ -356,22 +476,10 @@ name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
g_list_free_full (objects, g_object_unref);
if (priv->agent_id) {
GDBusInterface *agent_manager;
if (priv->agent_id)
register_agent (self);
agent_manager = g_dbus_object_manager_get_interface (object_manager,
"/",
NM_IWD_AGENT_MANAGER_INTERFACE);
/* Register our agent */
g_dbus_proxy_call (G_DBUS_PROXY (agent_manager),
"RegisterAgent",
g_variant_new ("(o)", priv->agent_path),
G_DBUS_CALL_FLAGS_NONE, -1,
NULL, NULL, NULL);
g_object_unref (agent_manager);
}
update_known_networks (self);
} else {
NMManager *manager = nm_manager_get ();
const GSList *devices, *iter;
@ -498,6 +606,39 @@ prepare_object_manager (NMIwdManager *self)
got_object_manager, self);
}
gboolean
nm_iwd_manager_is_known_network (NMIwdManager *self, const gchar *name,
NMIwdNetworkSecurity security)
{
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
const GSList *iter;
for (iter = priv->known_networks; iter; iter = g_slist_next (iter)) {
const KnownNetworkData *network = iter->data;
if (!strcmp (network->name, name) && network->security == security)
return true;
}
return false;
}
void
nm_iwd_manager_network_connected (NMIwdManager *self, const gchar *name,
NMIwdNetworkSecurity security)
{
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
KnownNetworkData *network_data;
if (nm_iwd_manager_is_known_network (self, name, security))
return;
network_data = g_new (KnownNetworkData, 1);
network_data->name = g_strdup (name);
network_data->security = security;
priv->known_networks = g_slist_append (priv->known_networks, network_data);
}
/*****************************************************************************/
NM_DEFINE_SINGLETON_GETTER (NMIwdManager, nm_iwd_manager_get,
@ -540,6 +681,9 @@ dispose (GObject *object)
nm_clear_g_cancellable (&priv->cancellable);
g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free);
priv->known_networks = NULL;
G_OBJECT_CLASS (nm_iwd_manager_parent_class)->dispose (object);
}

View file

@ -36,6 +36,13 @@
#define NM_IWD_KNOWN_NETWORKS_INTERFACE "net.connman.iwd.KnownNetworks"
#define NM_IWD_SIGNAL_AGENT_INTERFACE "net.connman.iwd.SignalLevelAgent"
typedef enum {
NM_IWD_NETWORK_SECURITY_NONE,
NM_IWD_NETWORK_SECURITY_WEP,
NM_IWD_NETWORK_SECURITY_PSK,
NM_IWD_NETWORK_SECURITY_8021X,
} NMIwdNetworkSecurity;
#define NM_TYPE_IWD_MANAGER (nm_iwd_manager_get_type ())
#define NM_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IWD_MANAGER, NMIwdManager))
#define NM_IWD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IWD_MANAGER, NMIwdManagerClass))
@ -50,4 +57,9 @@ GType nm_iwd_manager_get_type (void);
NMIwdManager *nm_iwd_manager_get (void);
gboolean nm_iwd_manager_is_known_network (NMIwdManager *self, const gchar *name,
NMIwdNetworkSecurity security);
void nm_iwd_manager_network_connected (NMIwdManager *self, const gchar *name,
NMIwdNetworkSecurity security);
#endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */