From 900751794fe7167d00e11f5f1575cc88cd0cb23c Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Wed, 21 Feb 2018 15:17:48 +0100 Subject: [PATCH 1/5] iwd: Only request secrets on request from IWD Remove the code (mostly copied from nm-device-wifi.c) that handles checking if the secrets were provided and requesting missing secrets before starting a connection attempt. Instead, request secrets when we're asked for them by IWD through its agent interface. This happens while the dbus Connect call is running. We change the NMDevice from the CONFIG state to NEED_AUTH and then change back to CONFIG once we sent the secrets back to IWD. The current code would require the secrets only based on whether a network is a KnownNetwork but IWD may need a new passwords even for KnownNetworks if the last connection attempt has failed. --- src/devices/wifi/nm-device-iwd.c | 339 ++++++++++-------------------- src/devices/wifi/nm-device-iwd.h | 3 +- src/devices/wifi/nm-iwd-manager.c | 17 +- 3 files changed, 116 insertions(+), 243 deletions(-) diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 022c37cbb8..75e9977b02 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -75,6 +75,7 @@ typedef struct { GCancellable * cancellable; NMDeviceWifiCapabilities capabilities; NMActRequestGetSecretsCallId *wifi_secrets_id; + GDBusMethodInvocation *secrets_request; guint periodic_scan_id; bool enabled:1; bool can_scan:1; @@ -386,11 +387,31 @@ send_disconnect (NMDeviceIwd *self) G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); } +static void +wifi_secrets_cancel (NMDeviceIwd *self) +{ + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + + if (priv->wifi_secrets_id) + nm_act_request_cancel_secrets (NULL, priv->wifi_secrets_id); + nm_assert (!priv->wifi_secrets_id); + + if (priv->secrets_request) { + g_dbus_method_invocation_return_error_literal (priv->secrets_request, NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "NM secrets request cancelled"); + priv->secrets_request = NULL; + } + +} + static void cleanup_association_attempt (NMDeviceIwd *self, gboolean disconnect) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + wifi_secrets_cancel (self); + set_current_ap (self, NULL, TRUE); if (disconnect && priv->dbus_obj) @@ -1020,13 +1041,15 @@ scanning_prohibited (NMDeviceIwd *self, gboolean periodic) static void wifi_secrets_cb (NMActRequest *req, NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection *connection, + NMSettingsConnection *s_connection, GError *error, gpointer user_data) { NMDevice *device = user_data; NMDeviceIwd *self = user_data; NMDeviceIwdPrivate *priv; + NMSettingWirelessSecurity *s_wireless_sec; + const gchar *psk; g_return_if_fail (NM_IS_DEVICE_IWD (self)); g_return_if_fail (NM_IS_ACT_REQUEST (req)); @@ -1040,28 +1063,50 @@ wifi_secrets_cb (NMActRequest *req, if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; + g_return_if_fail (priv->secrets_request); g_return_if_fail (req == nm_device_get_act_request (device)); - g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); - g_return_if_fail (nm_act_request_get_settings_connection (req) == connection); + g_return_if_fail (nm_act_request_get_settings_connection (req) == s_connection); + + if (nm_device_get_state (device) != NM_DEVICE_STATE_NEED_AUTH) + goto secrets_error; if (error) { _LOGW (LOGD_WIFI, "%s", error->message); + goto secrets_error; + } - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } else - nm_device_activate_schedule_stage1_device_prepare (device); -} + s_wireless_sec = nm_connection_get_setting_wireless_security (nm_act_request_get_applied_connection (req)); + if (!s_wireless_sec) + goto secrets_error; -static void -wifi_secrets_cancel (NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + psk = nm_setting_wireless_security_get_psk (s_wireless_sec); + if (!psk) + goto secrets_error; - if (priv->wifi_secrets_id) - nm_act_request_cancel_secrets (NULL, priv->wifi_secrets_id); - nm_assert (!priv->wifi_secrets_id); + _LOGD (LOGD_DEVICE | LOGD_WIFI, + "Returning a new PSK to the IWD Agent"); + + g_dbus_method_invocation_return_value (priv->secrets_request, + g_variant_new ("(s)", psk)); + priv->secrets_request = NULL; + + /* Change state back to what it was before NEED_AUTH */ + nm_device_state_changed (device, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); + return; + +secrets_error: + if (priv->secrets_request) { + g_dbus_method_invocation_return_error_literal (priv->secrets_request, NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "NM secrets request failed"); + priv->secrets_request = NULL; + } + + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); + + cleanup_association_attempt (self, TRUE); } static void @@ -1084,130 +1129,6 @@ wifi_secrets_get_secrets (NMDeviceIwd *self, NULL, wifi_secrets_cb, self); - g_return_if_fail (priv->wifi_secrets_id); -} - -static gboolean -need_new_8021x_secrets (NMDeviceIwd *self, - const char **setting_name) -{ - NMSetting8021x *s_8021x; - NMSettingWirelessSecurity *s_wsec; - NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - NMConnection *connection; - - g_assert (setting_name != NULL); - - connection = nm_device_get_applied_connection (NM_DEVICE (self)); - g_return_val_if_fail (connection != NULL, FALSE); - - /* If it's an 802.1x or LEAP connection with "always ask"/unsaved secrets - * then we need to ask again because it might be an OTP token and the PIN - * may have changed. - */ - - s_8021x = nm_connection_get_setting_802_1x (connection); - if (s_8021x) { - if (!nm_setting_get_secret_flags (NM_SETTING (s_8021x), - NM_SETTING_802_1X_PASSWORD, - &secret_flags, - NULL)) - g_assert_not_reached (); - if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) - *setting_name = NM_SETTING_802_1X_SETTING_NAME; - return *setting_name ? TRUE : FALSE; - } - - s_wsec = nm_connection_get_setting_wireless_security (connection); - if (s_wsec) { - if (!nm_setting_get_secret_flags (NM_SETTING (s_wsec), - NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, - &secret_flags, - NULL)) - g_assert_not_reached (); - if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) - *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; - return *setting_name ? TRUE : FALSE; - } - - /* Not a LEAP or 802.1x connection */ - return FALSE; -} - -static gboolean -need_new_wpa_psk (NMDeviceIwd *self, - const char **setting_name) -{ - NMSettingWirelessSecurity *s_wsec; - NMConnection *connection; - const char *key_mgmt = NULL; - - g_assert (setting_name != NULL); - - connection = nm_device_get_applied_connection (NM_DEVICE (self)); - g_return_val_if_fail (connection != NULL, FALSE); - - s_wsec = nm_connection_get_setting_wireless_security (connection); - if (s_wsec) - key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); - - if (g_strcmp0 (key_mgmt, "wpa-psk") == 0) { - /* We don't have any data from IWD about the disconnect - * reason or association state when the disconnect happened - * so just assume it was a bad password. - */ - *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; - return TRUE; - } - - /* Not a WPA-PSK connection */ - return FALSE; -} - -static gboolean -handle_8021x_or_psk_auth_fail (NMDeviceIwd *self) -{ - NMDevice *device = NM_DEVICE (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); - - _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) disconnected during association, asking for new key"); - - cleanup_association_attempt (self, FALSE); - nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - wifi_secrets_get_secrets (self, - setting_name, - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION - | NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); - handled = TRUE; - } - - return handled; } static void @@ -1235,7 +1156,7 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) error->message); connection = nm_device_get_applied_connection (device); - if (!connection || nm_connection_get_setting_wireless_security (connection)) + if (!connection) goto failed; if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) @@ -1243,13 +1164,10 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) /* If secrets were wrong, we'd be getting a net.connman.iwd.Failed */ if (nm_streq0 (dbus_error, "net.connman.iwd.Failed")) { - if (handle_8021x_or_psk_auth_fail (self)) { - _LOGW (LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) asking for new secrets"); - } else { - cleanup_association_attempt (self, FALSE); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } + nm_connection_clear_secrets (connection); + + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); } else if ( !nm_utils_error_is_cancelled (error, TRUE) && nm_device_is_activating (device)) goto failed; @@ -1293,36 +1211,6 @@ failed: NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); } -static gboolean -handle_auth_or_fail (NMDeviceIwd *self, - NMActRequest *req, - gboolean new_secrets) -{ - const char *setting_name; - NMConnection *applied_connection; - NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - - g_return_val_if_fail (NM_IS_DEVICE_IWD (self), FALSE); - - if (!nm_device_auth_retries_try_next (NM_DEVICE (self))) - return FALSE; - - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); - - nm_act_request_clear_secrets (req); - applied_connection = nm_act_request_get_applied_connection (req); - setting_name = nm_connection_need_secrets (applied_connection, NULL); - if (!setting_name) { - _LOGW (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - return FALSE; - } - - if (new_secrets) - get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - wifi_secrets_get_secrets (self, setting_name, get_secret_flags); - return TRUE; -} - /*****************************************************************************/ static NMActStageReturn @@ -1378,8 +1266,6 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NMActRequest *req; NMWifiAP *ap; NMConnection *connection; - const char *setting_name; - NMSettingWireless *s_wireless; GError *error = NULL; GDBusProxy *network_proxy; @@ -1395,42 +1281,21 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) connection = nm_act_request_get_applied_connection (req); g_assert (connection); - s_wireless = nm_connection_get_setting_wireless (connection); - g_assert (s_wireless); - - /* 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. + /* 802.1x networks that are not IWD Known Networks will definitely + * fail, for other combinations we will let the Connect call fail + * or ask us for any missing secrets through the Agent. */ - if (!is_connection_known_network (connection)) - setting_name = nm_connection_need_secrets (connection, NULL); - else - setting_name = NULL; - - if (setting_name) { + if ( !is_connection_known_network (connection) + && nm_connection_get_setting_802_1x (connection)) { _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) access point '%s' has security, but secrets are required.", + "Activation: (wifi) access point '%s' has 802.1x security, but is not configured.", nm_connection_get_id (connection)); - if (handle_auth_or_fail (self, req, FALSE)) - ret = NM_ACT_STAGE_RETURN_POSTPONE; - else { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - ret = NM_ACT_STAGE_RETURN_FAILURE; - } + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); + ret = NM_ACT_STAGE_RETURN_FAILURE; goto out; } - /* Have secrets or no secrets required */ - if (nm_connection_get_setting_wireless_security (connection)) { - _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) connection '%s' has security, and secrets exist. No new secrets needed.", - nm_connection_get_id (connection)); - } else { - _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) connection '%s' requires no security. No secrets needed.", - nm_connection_get_id (connection)); - } - /* Locate the IWD Network object */ network_proxy = g_dbus_proxy_new_for_bus_sync (NM_IWD_BUS_TYPE, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | @@ -1571,7 +1436,6 @@ device_state_changed (NMDevice *device, } break; case NM_DEVICE_STATE_NEED_AUTH: - send_disconnect (self); break; case NM_DEVICE_STATE_IP_CHECK: break; @@ -1731,8 +1595,7 @@ state_changed (NMDeviceIwd *self, const gchar *new_state) _LOGI (LOGD_DEVICE | LOGD_WIFI, "new IWD device state is %s", new_state); if ( dev_state >= NM_DEVICE_STATE_CONFIG - && dev_state <= NM_DEVICE_STATE_ACTIVATED - && dev_state != NM_DEVICE_STATE_NEED_AUTH) + && dev_state <= NM_DEVICE_STATE_ACTIVATED) iwd_connection = TRUE; /* Don't allow scanning while connecting, disconnecting or roaming */ @@ -1776,6 +1639,13 @@ state_changed (NMDeviceIwd *self, const gchar *new_state) */ send_disconnect (self); + /* + * If IWD is still handling the Connect call, let our callback + * for the dbus method handle the failure. + */ + if (dev_state == NM_DEVICE_STATE_CONFIG) + return; + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); @@ -1881,31 +1751,42 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object) send_disconnect (self); } -const gchar * -nm_device_iwd_agent_psk_query (NMDeviceIwd *self) +gboolean +nm_device_iwd_agent_psk_query (NMDeviceIwd *self, + GDBusMethodInvocation *invocation) { + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); NMActRequest *req; - NMConnection *connection; - NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; + const gchar *psk; req = nm_device_get_act_request (NM_DEVICE (self)); if (!req) - return NULL; + return FALSE; - connection = nm_act_request_get_applied_connection (req); - if (!connection) - return NULL; - - s_wireless = nm_connection_get_setting_wireless (connection); - if (!s_wireless) - return NULL; - - s_wireless_sec = nm_connection_get_setting_wireless_security (connection); + s_wireless_sec = nm_connection_get_setting_wireless_security (nm_act_request_get_applied_connection (req)); if (!s_wireless_sec) - return NULL; + return FALSE; - return nm_setting_wireless_security_get_psk (s_wireless_sec); + psk = nm_setting_wireless_security_get_psk (s_wireless_sec); + if (psk) { + _LOGD (LOGD_DEVICE | LOGD_WIFI, + "Returning the PSK to the IWD Agent"); + + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(s)", psk)); + return TRUE; + } + + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, + NM_DEVICE_STATE_REASON_NO_SECRETS); + wifi_secrets_get_secrets (self, + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION + | NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); + + priv->secrets_request = invocation; + return TRUE; } /*****************************************************************************/ @@ -1954,8 +1835,6 @@ dispose (GObject *object) nm_clear_g_source (&priv->periodic_scan_id); - wifi_secrets_cancel (self); - cleanup_association_attempt (self, TRUE); g_clear_object (&priv->dbus_proxy); diff --git a/src/devices/wifi/nm-device-iwd.h b/src/devices/wifi/nm-device-iwd.h index 332f4282c0..6619488cf7 100644 --- a/src/devices/wifi/nm-device-iwd.h +++ b/src/devices/wifi/nm-device-iwd.h @@ -55,6 +55,7 @@ NMDevice *nm_device_iwd_new (const char *iface, NMDeviceWifiCapabilities capabil void nm_device_iwd_set_dbus_object (NMDeviceIwd *device, GDBusObject *object); -const gchar *nm_device_iwd_agent_psk_query (NMDeviceIwd *device); +gboolean nm_device_iwd_agent_psk_query (NMDeviceIwd *device, + GDBusMethodInvocation *invocation); #endif /* __NETWORKMANAGER_DEVICE_IWD_H__ */ diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c index 21f0a75559..f9d0076a73 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -99,7 +99,6 @@ psk_agent_dbus_method_cb (GDBusConnection *connection, gs_unref_variant GVariant *value = NULL; gint ifindex; NMDevice *device; - const gchar *psk; /* Be paranoid and check the sender address */ if (!nm_streq0 (g_dbus_object_manager_client_get_name_owner (omc), sender)) @@ -120,8 +119,8 @@ psk_agent_dbus_method_cb (GDBusConnection *connection, } device_obj = g_dbus_object_manager_get_interface (priv->object_manager, - device_path, - NM_IWD_DEVICE_INTERFACE); + device_path, + NM_IWD_DEVICE_INTERFACE); g_variant_unref (value); value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (device_obj), "Name"); ifname = g_variant_get_string (value, NULL); @@ -146,16 +145,10 @@ psk_agent_dbus_method_cb (GDBusConnection *connection, goto return_error; } - psk = nm_device_iwd_agent_psk_query (NM_DEVICE_IWD (device)); - if (!psk) { - _LOGW ("Device %s had no PSK for the IWD Agent", ifname); - goto return_error; - } + if (nm_device_iwd_agent_psk_query (NM_DEVICE_IWD (device), invocation)) + return; - _LOGI ("Sending the PSK to the IWD Agent for device %s", ifname); - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(s)", psk)); - return; + _LOGE ("Device %s did not handle the IWD Agent request", ifname); return_error: /* IWD doesn't look at the specific error */ From f17268104872c2411963269e71f67cd5004a1121 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Wed, 21 Feb 2018 15:26:17 +0100 Subject: [PATCH 2/5] iwd: Disable timeout for iwd Device.Connect call Change from the default dbus call timeout (-1) to infinite (G_MAXINT) because the call may now include the secret requests which have their own timeout policies. --- src/devices/wifi/nm-device-iwd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 75e9977b02..447700f609 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -1323,7 +1323,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) */ g_dbus_proxy_call (network_proxy, "Connect", g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, -1, + G_DBUS_CALL_FLAGS_NONE, G_MAXINT, priv->cancellable, network_connect_cb, self); g_object_unref (network_proxy); From 6571b576c48d2134bd13dcbdc3c327f859b98672 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Thu, 1 Mar 2018 20:56:32 +0100 Subject: [PATCH 3/5] iwd: set Device.Powered during set_enable Make sure .set_enabled uses the Device.Powered property to basically bring the netdev UP and DOWN as I understand is expected by the nm_device logic. Device.Powered should generally reflect the UP state immediately but just to avoid possible race conditions .is_available() will now return a value that is an AND of the local "enabled" state and IWD's Powered property. --- src/devices/wifi/nm-device-iwd.c | 51 +++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 447700f609..39cc995ad8 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -789,17 +789,22 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + gs_unref_variant GVariant *value = NULL; - return priv->enabled && priv->dbus_obj; + if (!priv->enabled || !priv->dbus_obj) + return FALSE; + + value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "Powered"); + return g_variant_get_boolean (value); } static gboolean get_autoconnect_allowed (NMDevice *device) { - NMDeviceIwdPrivate *priv; + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (NM_DEVICE_IWD (device)); - priv = NM_DEVICE_IWD_GET_PRIVATE (NM_DEVICE_IWD (device)); - return priv->enabled && priv->dbus_obj && priv->can_connect; + return is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE) + && priv->can_connect; } static gboolean @@ -1211,6 +1216,20 @@ failed: NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); } +static void +set_powered (NMDeviceIwd *self, gboolean powered) +{ + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + + g_dbus_proxy_call (priv->dbus_proxy, + "org.freedesktop.DBus.Properties.Set", + g_variant_new ("(ssv)", NM_IWD_DEVICE_INTERFACE, + "Powered", + g_variant_new ("b", powered)), + G_DBUS_CALL_FLAGS_NONE, 2000, + NULL, NULL, NULL); +} + /*****************************************************************************/ static NMActStageReturn @@ -1479,6 +1498,9 @@ set_enabled (NMDevice *device, gboolean enabled) return; } + if (priv->dbus_proxy) + set_powered (self, enabled); + if (enabled) { if (state != NM_DEVICE_STATE_UNAVAILABLE) _LOGW (LOGD_CORE, "not in expected unavailable state!"); @@ -1677,6 +1699,14 @@ scanning_changed (NMDeviceIwd *self, gboolean new_scanning) } } +static void +powered_changed (NMDeviceIwd *self, gboolean new_powered) +{ + nm_device_queue_recheck_available (NM_DEVICE (self), + NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); +} + static void properties_changed (GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidate_properties, gpointer user_data) @@ -1694,6 +1724,9 @@ properties_changed (GDBusProxy *proxy, GVariant *changed_properties, if (!strcmp (key, "Scanning")) scanning_changed (self, g_variant_get_boolean (value)); + if (!strcmp (key, "Powered")) + powered_changed (self, g_variant_get_boolean (value)); + g_variant_unref (value); } @@ -1744,11 +1777,13 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object) g_signal_connect (priv->dbus_proxy, "g-properties-changed", G_CALLBACK (properties_changed), self); - /* Call Disconnect to make sure IWD's autoconnect is disabled. We've - * most likely just brought the device UP so it would be in - * autoconnect by default. + set_powered (self, priv->enabled); + + /* Call Disconnect to make sure IWD's autoconnect is disabled. + * Autoconnect is the default state after device is brought UP. */ - send_disconnect (self); + if (priv->enabled) + send_disconnect (self); } gboolean From 8435aa8b31964ac99b51a227f79dccf7ae135bf3 Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Fri, 2 Mar 2018 13:56:22 +0100 Subject: [PATCH 4/5] iwd: fix device-added signal handler signature This bug was not causing a crash for me because of the !IS_NM_DEVICE_IWD check and because my glib version probably had the assertion within NM_IWD_MANAGER_GET_PRIVATE disabled. While there, change the g_signal_connect line to use the macro for the signal name. --- src/devices/wifi/nm-iwd-manager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c index f9d0076a73..0007b0fff5 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -481,7 +481,7 @@ name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data) } static void -device_added (NMDevice *device, gpointer user_data) +device_added (NMManager *manager, NMDevice *device, gpointer user_data) { NMIwdManager *self = user_data; NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); @@ -641,7 +641,7 @@ nm_iwd_manager_init (NMIwdManager *self) NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); priv->nm_manager = g_object_ref (nm_manager_get ()); - g_signal_connect (priv->nm_manager, "device-added", + g_signal_connect (priv->nm_manager, NM_MANAGER_DEVICE_ADDED, G_CALLBACK (device_added), self); priv->cancellable = g_cancellable_new (); From 29e9d206aa8319c5875749cf3c3bd7b96dc0fc4e Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Mon, 5 Mar 2018 00:38:36 +0100 Subject: [PATCH 5/5] iwd: don't call nm_wifi_ap_set_ssid for empty SSID If SSID is an empty string there's no need to call nm_wifi_ap_set_ssid as it won't do anything. It also has an assert checking that NULL is passed for an empty SSID and we were passing a non-NULL pointer. --- src/devices/wifi/nm-device-iwd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 39cc995ad8..218ca80463 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -334,7 +334,8 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) props = g_variant_new ("a{sv}", &builder); ap = nm_wifi_ap_new_from_properties (path, props); - nm_wifi_ap_set_ssid (ap, (const guint8 *) name, strlen (name)); + if (name[0] != '\0') + nm_wifi_ap_set_ssid (ap, (const guint8 *) name, strlen (name)); nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (signal / 100)); nm_wifi_ap_set_freq (ap, 2417); nm_wifi_ap_set_max_bitrate (ap, 65000);