diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 44a3dee66f..29a0371805 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -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: diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c index e5ff930ca5..4eda5ebac4 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -26,18 +26,25 @@ #include #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); } diff --git a/src/devices/wifi/nm-iwd-manager.h b/src/devices/wifi/nm-iwd-manager.h index 197020bb86..8e6b66ff2d 100644 --- a/src/devices/wifi/nm-iwd-manager.h +++ b/src/devices/wifi/nm-iwd-manager.h @@ -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__ */