wifi/iwd: merge branch 'pr/42'

https://github.com/NetworkManager/NetworkManager/pull/42
This commit is contained in:
Thomas Haller 2017-12-21 11:19:17 +01:00
commit 60d4b370ba
3 changed files with 295 additions and 31 deletions

View file

@ -399,6 +399,52 @@ 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
is_connection_known_network (NMConnection *connection)
{
NMSettingWireless *s_wireless;
GBytes *ssid;
gs_free gchar *str_ssid = NULL;
s_wireless = nm_connection_get_setting_wireless (connection);
if (!s_wireless)
return FALSE;
ssid = nm_setting_wireless_get_ssid (s_wireless);
if (!ssid)
return FALSE;
str_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL),
g_bytes_get_size (ssid));
return nm_iwd_manager_is_known_network (nm_iwd_manager_get (),
str_ssid,
get_connection_iwd_security (connection));
}
static gboolean
check_connection_compatible (NMDevice *device, NMConnection *connection)
{
@ -447,6 +493,14 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0)
return FALSE;
/* 8021x networks can only be used if they've been provisioned on the IWD side and
* thus are Known Networks.
*/
if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) {
if (!is_connection_known_network (connection))
return FALSE;
}
return TRUE;
}
@ -455,7 +509,6 @@ get_ap_by_path (NMDeviceIwd *self, const char *path)
{
g_return_val_if_fail (path != NULL, NULL);
return g_hash_table_lookup (NM_DEVICE_IWD_GET_PRIVATE (self)->aps, path);
}
static gboolean
@ -472,6 +525,23 @@ check_connection_available (NMDevice *device,
s_wifi = nm_connection_get_setting_wireless (connection);
g_return_val_if_fail (s_wifi, FALSE);
/* Only Infrastrusture mode at this time */
mode = nm_setting_wireless_get_mode (s_wifi);
if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0)
return FALSE;
/* Hidden SSIDs not supported yet */
if (nm_setting_wireless_get_hidden (s_wifi))
return FALSE;
/* 8021x networks can only be used if they've been provisioned on the IWD side and
* thus are Known Networks.
*/
if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) {
if (!is_connection_known_network (connection))
return FALSE;
}
/* a connection that is available for a certain @specific_object, MUST
* also be available in general (without @specific_object). */
@ -482,15 +552,6 @@ check_connection_available (NMDevice *device,
return ap ? nm_wifi_ap_check_compatible (ap, connection) : FALSE;
}
/* Only Infrastrusture mode at this time */
mode = nm_setting_wireless_get_mode (s_wifi);
if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0)
return FALSE;
/* Hidden SSIDs not supported yet */
if (nm_setting_wireless_get_hidden (s_wifi))
return FALSE;
if (NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP))
return TRUE;
@ -608,6 +669,19 @@ complete_connection (NMDevice *device,
if (tmp_ssid)
g_byte_array_unref (tmp_ssid);
/* 8021x networks can only be used if they've been provisioned on the IWD side and
* thus are Known Networks.
*/
if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) {
if (!is_connection_known_network (connection)) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_DEVICE_ERROR_INVALID_CONNECTION,
"This 8021x network has not been provisioned on this machine");
return FALSE;
}
}
perm_hw_addr = nm_device_get_permanent_hw_address (device);
if (perm_hw_addr) {
setting_mac = nm_setting_wireless_get_mac_address (s_wifi);
@ -682,6 +756,14 @@ can_auto_connect (NMDevice *device,
return FALSE;
}
/* 8021x networks can only be used if they've been provisioned on the IWD side and
* thus are Known Networks.
*/
if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) {
if (!is_connection_known_network (connection))
return FALSE;
}
ap = nm_wifi_aps_find_first_compatible (priv->aps, connection, FALSE);
if (ap) {
/* All good; connection is usable */
@ -997,10 +1079,25 @@ handle_8021x_or_psk_auth_fail (NMDeviceIwd *self)
NMActRequest *req;
const char *setting_name = NULL;
gboolean handled = FALSE;
NMConnection *connection;
req = nm_device_get_act_request (device);
g_return_val_if_fail (req != NULL, FALSE);
/* If this is an IWD Known Network, even if the failure was caused by bad secrets,
* IWD won't ask our agent for new secrets until we call ForgetNetwork. For 8021x
* this is not a good idea since the IWD network config file is assumed to be
* provisioned by the system admin and the admin needs to intervene anyway. For
* PSK we may want to do this here (TODO).
*/
connection = nm_act_request_get_applied_connection (req);
if (is_connection_known_network (connection)) {
_LOGI (LOGD_DEVICE | LOGD_WIFI,
"Activation: (wifi) disconnected during association to an IWD Known Network, giving up");
return FALSE;
}
if ( need_new_8021x_secrets (self, &setting_name)
|| need_new_wpa_psk (self, &setting_name)) {
nm_act_request_clear_secrets (req);
@ -1030,6 +1127,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 ("()"),
@ -1084,11 +1182,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:
@ -1206,8 +1310,14 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
s_wireless = nm_connection_get_setting_wireless (connection);
g_assert (s_wireless);
/* If we need secrets, get them */
setting_name = nm_connection_need_secrets (connection, NULL);
/* If we need secrets, get them. If a network is an IWD Known Network the secrets
* will have been stored by IWD and we don't require any secrets here.
*/
if (!is_connection_known_network (connection))
setting_name = nm_connection_need_secrets (connection, NULL);
else
setting_name = NULL;
if (setting_name) {
_LOGI (LOGD_DEVICE | LOGD_WIFI,
"Activation: (wifi) access point '%s' has security, but secrets are required.",
@ -1243,8 +1353,6 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
NM_IWD_NETWORK_INTERFACE,
NULL, &error);
if (!network_proxy) {
return FALSE;
_LOGE (LOGD_DEVICE | LOGD_WIFI,
"Activation: (wifi) could not get Network interface proxy for %s: %s",
nm_wifi_ap_get_supplicant_path (ap),

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__ */