diff options
author | Thomas Haller <thaller@redhat.com> | 2020-04-24 19:34:44 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-04-24 19:34:44 +0200 |
commit | fe84237cf09b29a99d70580044694c1aa7ff1a16 (patch) | |
tree | 8067197fbb8246324f884e38f24472ef2aed6f10 | |
parent | 93b634f1a23c43dd71c3b7668ae738c3ab6c970e (diff) | |
parent | 16c1869476106859b684151eb1b101c24cff3451 (diff) | |
download | NetworkManager-fe84237cf09b29a99d70580044694c1aa7ff1a16.tar.gz |
wifi: merge branch 'th/cli-trigger-scan-retry'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/476
-rw-r--r-- | clients/cli/devices.c | 57 | ||||
-rw-r--r-- | shared/nm-glib-aux/nm-shared-utils.c | 103 | ||||
-rw-r--r-- | shared/nm-glib-aux/nm-shared-utils.h | 13 | ||||
-rw-r--r-- | src/devices/bluetooth/nm-bluez-manager.c | 6 | ||||
-rw-r--r-- | src/devices/ovs/nm-device-ovs-interface.c | 2 | ||||
-rw-r--r-- | src/devices/wifi/nm-device-iwd.c | 2 | ||||
-rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 8 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem-broadband.c | 6 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem-ofono.c | 6 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 8 | ||||
-rw-r--r-- | src/supplicant/nm-supplicant-interface.c | 109 | ||||
-rw-r--r-- | src/supplicant/nm-supplicant-interface.h | 9 |
12 files changed, 253 insertions, 76 deletions
diff --git a/clients/cli/devices.c b/clients/cli/devices.c index 4ea4e772e4..7031b43756 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -2978,6 +2978,24 @@ wifi_last_scan_updated (GObject *gobject, GParamSpec *pspec, gpointer user_data) wifi_list_finish (user_data, FALSE); } +static void wifi_list_rescan_cb (GObject *source_object, GAsyncResult *res, gpointer user_data); + +static void +wifi_list_rescan_retry_cb (gpointer user_data, + GCancellable *cancellable) +{ + WifiListData *wifi_list_data; + + if (g_cancellable_is_cancelled (cancellable)) + return; + + wifi_list_data = user_data; + nm_device_wifi_request_scan_async (wifi_list_data->wifi, + wifi_list_data->scan_cancellable, + wifi_list_rescan_cb, + wifi_list_data); +} + static void wifi_list_rescan_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { @@ -2985,22 +3003,47 @@ wifi_list_rescan_cb (GObject *source_object, GAsyncResult *res, gpointer user_da gs_free_error GError *error = NULL; WifiListData *wifi_list_data; gboolean force_finished; + gboolean done; nm_device_wifi_request_scan_finish (wifi, res, &error); if (nm_utils_error_is_cancelled (error)) return; + wifi_list_data = user_data; + if (g_error_matches (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED)) { - /* This likely means that scanning is already in progress. There's - * a good chance we'll get updated results soon; wait for them. */ - force_finished = FALSE; - } else if (error) + if (nm_device_get_state (NM_DEVICE (wifi)) < NM_DEVICE_STATE_DISCONNECTED) { + /* the device is either unmanaged or unavailable. + * + * If it's unmanaged, we don't expect any scan result and are done. + * If it's unavailable, that usually means that we wait for wpa_supplicant + * to start. In that case, also quit (without scan results). */ + force_finished = TRUE; + done = TRUE; + } else { + /* This likely means that scanning is already in progress. There's + * a good chance we'll get updated results soon; wait for them. + * + * But also, NetworkManager ratelimits (and rejects requests). That + * means, possibly we were just ratelimited, so waiting will not lead + * to a new scan result. Instead, repeatedly ask new scans... */ + nm_utils_invoke_on_timeout (1000, + wifi_list_data->scan_cancellable, + wifi_list_rescan_retry_cb, + wifi_list_data); + force_finished = FALSE; + done = FALSE; + } + } else if (error) { force_finished = TRUE; - else + done = TRUE; + } else { force_finished = FALSE; + done = TRUE; + } - wifi_list_data = user_data; - g_clear_object (&wifi_list_data->scan_cancellable); + if (done) + g_clear_object (&wifi_list_data->scan_cancellable); wifi_list_finish (wifi_list_data, force_finished); } diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index c06399dda8..61e3e26716 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -3655,9 +3655,9 @@ _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...) typedef struct { gpointer callback_user_data; GCancellable *cancellable; + GSource *source; NMUtilsInvokeOnIdleCallback callback; gulong cancelled_id; - guint idle_id; } InvokeOnIdleData; static gboolean @@ -3665,12 +3665,13 @@ _nm_utils_invoke_on_idle_cb_idle (gpointer user_data) { InvokeOnIdleData *data = user_data; - data->idle_id = 0; nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id); data->callback (data->callback_user_data, data->cancellable); + nm_g_object_unref (data->cancellable); - g_slice_free (InvokeOnIdleData, data); + g_source_destroy (data->source); + nm_g_slice_free (data); return G_SOURCE_REMOVE; } @@ -3680,41 +3681,87 @@ _nm_utils_invoke_on_idle_cb_cancelled (GCancellable *cancellable, { /* on cancellation, we invoke the callback synchronously. */ nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id); - nm_clear_g_source (&data->idle_id); + nm_clear_g_source_inst (&data->source); data->callback (data->callback_user_data, data->cancellable); nm_g_object_unref (data->cancellable); - g_slice_free (InvokeOnIdleData, data); + nm_g_slice_free (data); } -void -nm_utils_invoke_on_idle (NMUtilsInvokeOnIdleCallback callback, - gpointer callback_user_data, - GCancellable *cancellable) +static void +_nm_utils_invoke_on_idle_start (gboolean use_timeout, + guint timeout_msec, + GCancellable *cancellable, + NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data) { InvokeOnIdleData *data; + GSource *source; g_return_if_fail (callback); data = g_slice_new (InvokeOnIdleData); - data->callback = callback; - data->callback_user_data = callback_user_data; - data->cancellable = nm_g_object_ref (cancellable); - if ( cancellable - && !g_cancellable_is_cancelled (cancellable)) { - /* if we are passed a non-cancelled cancellable, we register to the "cancelled" - * signal an invoke the callback synchronously (from the signal handler). - * - * We don't do that, - * - if the cancellable is already cancelled (because we don't want to invoke - * the callback synchronously from the caller). - * - if we have no cancellable at hand. */ - data->cancelled_id = g_signal_connect (cancellable, - "cancelled", - G_CALLBACK (_nm_utils_invoke_on_idle_cb_cancelled), - data); - } else - data->cancelled_id = 0; - data->idle_id = g_idle_add (_nm_utils_invoke_on_idle_cb_idle, data); + *data = (InvokeOnIdleData) { + .callback = callback, + .callback_user_data = callback_user_data, + .cancellable = nm_g_object_ref (cancellable), + .cancelled_id = 0, + }; + + if (cancellable) { + if (g_cancellable_is_cancelled (cancellable)) { + /* the cancellable is already cancelled. We ignore the timeout + * and always schedule an idle action. */ + use_timeout = FALSE; + } else { + /* if we are passed a non-cancelled cancellable, we register to the "cancelled" + * signal an invoke the callback synchronously (from the signal handler). + * + * We don't do that, + * - if the cancellable is already cancelled (because we don't want to invoke + * the callback synchronously from the caller). + * - if we have no cancellable at hand. */ + data->cancelled_id = g_signal_connect (cancellable, + "cancelled", + G_CALLBACK (_nm_utils_invoke_on_idle_cb_cancelled), + data); + } + } + + if (use_timeout) { + source = nm_g_timeout_source_new (timeout_msec, + G_PRIORITY_DEFAULT, + _nm_utils_invoke_on_idle_cb_idle, + data, + NULL); + } else { + source = nm_g_idle_source_new (G_PRIORITY_DEFAULT, + _nm_utils_invoke_on_idle_cb_idle, + data, + NULL); + } + + /* use the current thread default context. */ + g_source_attach (source, + g_main_context_get_thread_default ()); + + data->source = source; +} + +void +nm_utils_invoke_on_idle (GCancellable *cancellable, + NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data) +{ + _nm_utils_invoke_on_idle_start (FALSE, 0, cancellable, callback, callback_user_data); +} + +void +nm_utils_invoke_on_timeout (guint timeout_msec, + GCancellable *cancellable, + NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data) +{ + _nm_utils_invoke_on_idle_start (TRUE, timeout_msec, cancellable, callback, callback_user_data); } /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 38b100416d..9200f80fdf 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1629,12 +1629,17 @@ void _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...); /*****************************************************************************/ -typedef void (*NMUtilsInvokeOnIdleCallback) (gpointer callback_user_data, +typedef void (*NMUtilsInvokeOnIdleCallback) (gpointer user_data, GCancellable *cancellable); -void nm_utils_invoke_on_idle (NMUtilsInvokeOnIdleCallback callback, - gpointer callback_user_data, - GCancellable *cancellable); +void nm_utils_invoke_on_idle (GCancellable *cancellable, + NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data); + +void nm_utils_invoke_on_timeout (guint timeout_msec, + GCancellable *cancellable, + NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data); /*****************************************************************************/ diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index 6ff96c323b..0bbac4c435 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -1251,9 +1251,9 @@ _network_server_unregister_bridge (NMBluezManager *self, if (r_req_data) { nm_clear_g_cancellable (&r_req_data->int_cancellable); - nm_utils_invoke_on_idle (_network_server_unregister_bridge_complete_on_idle_cb, - nm_utils_user_data_pack (r_req_data, g_strdup (reason)), - r_req_data->ext_cancellable); + nm_utils_invoke_on_idle (r_req_data->ext_cancellable, + _network_server_unregister_bridge_complete_on_idle_cb, + nm_utils_user_data_pack (r_req_data, g_strdup (reason))); } _nm_device_bridge_notify_unregister_bt_nap (device, reason); diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c index 951b578892..10f9fa9431 100644 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -310,7 +310,7 @@ deactivate_async (NMDevice *device, nm_device_get_iface (device))) { _LOGT (LOGD_CORE, "deactivate: link not present, proceeding"); nm_device_update_from_platform_link (NM_DEVICE (self), NULL); - nm_utils_invoke_on_idle (deactivate_cb_on_idle, data, cancellable); + nm_utils_invoke_on_idle (cancellable, deactivate_cb_on_idle, data); return; } diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 3c1d5b2298..3dccd1cb94 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -507,7 +507,7 @@ deactivate_async (NMDevice *device, user_data = nm_utils_user_data_pack (g_object_ref (self), callback, callback_user_data); if (!priv->dbus_obj) { - nm_utils_invoke_on_idle (disconnect_cb_on_idle, user_data, cancellable); + nm_utils_invoke_on_idle (cancellable, disconnect_cb_on_idle, user_data); return; } diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 266a842514..bf3e6ad27a 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -684,7 +684,7 @@ deactivate_async (NMDevice *device, user_data = nm_utils_user_data_pack (g_object_ref (self), callback, callback_user_data); if (!priv->sup_iface) { - nm_utils_invoke_on_idle (disconnect_cb_on_idle, user_data, cancellable); + nm_utils_invoke_on_idle (cancellable, disconnect_cb_on_idle, user_data); return; } @@ -1509,7 +1509,11 @@ request_wireless_scan (NMDeviceWifi *self, nm_supplicant_interface_request_scan (priv->sup_iface, ssids ? (GBytes *const*) ssids->pdata : NULL, - ssids ? ssids->len : 0u); + ssids ? ssids->len : 0u, + NULL, + NULL, + NULL); + request_started = TRUE; } else _LOGD (LOGD_WIFI, "wifi-scan: scanning requested but not allowed at this time"); diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index f89ec86c9f..3fdc5ac54b 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -1254,9 +1254,9 @@ disconnect (NMModem *modem, /* Already cancelled or no simple-iface? We are done. */ if ( !ctx->self->_priv.simple_iface || g_cancellable_is_cancelled (cancellable)) { - nm_utils_invoke_on_idle (disconnect_context_complete_on_idle, - ctx, - cancellable); + nm_utils_invoke_on_idle (cancellable, + disconnect_context_complete_on_idle, + ctx); return; } diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index 2fc44881a9..96b08e7cff 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -211,9 +211,9 @@ disconnect (NMModem *modem, if ( state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled (cancellable)) { - nm_utils_invoke_on_idle (disconnect_context_complete_on_idle, - ctx, - cancellable); + nm_utils_invoke_on_idle (cancellable, + disconnect_context_complete_on_idle, + ctx); return; } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index f7249bb71e..014cca71da 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -5131,9 +5131,9 @@ sysctl_set_async (NMPlatform *platform, callback, data, error); - nm_utils_invoke_on_idle (sysctl_set_async_return_idle, - packed, - cancellable); + nm_utils_invoke_on_idle (cancellable, + sysctl_set_async_return_idle, + packed); return; } } else @@ -7390,7 +7390,7 @@ out_idle: g_steal_pointer (&error), callback, data); - nm_utils_invoke_on_idle (sriov_idle_cb, packed, cancellable); + nm_utils_invoke_on_idle (cancellable, sriov_idle_cb, packed); } } diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index a02f540256..099c3bf2ca 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -1123,7 +1123,7 @@ set_state (NMSupplicantInterface *self, NMSupplicantInterfaceState new_state) if (new_state == priv->state) return; - _LOGT ("set state \"%s\" (was \"%s\")", + _LOGT ("state: set state \"%s\" (was \"%s\")", nm_supplicant_interface_state_to_string (new_state), nm_supplicant_interface_state_to_string (priv->state)); @@ -1789,8 +1789,12 @@ _properties_changed_main (NMSupplicantInterface *self, g_variant_unref (v_v); } - if (nm_g_variant_lookup (properties, "Scanning", "b", &v_b)) - priv->scanning_property = v_b; + if (nm_g_variant_lookup (properties, "Scanning", "b", &v_b)) { + if (priv->scanning_property != (!!v_b)) { + _LOGT ("scanning: %s (plain property)", v_b ? "yes" : "no"); + priv->scanning_property = v_b; + } + } if (nm_g_variant_lookup (properties, "Ifname", "&s", &v_s)) { if (nm_utils_strdup_reset (&priv->ifname, v_s)) @@ -1816,8 +1820,13 @@ _properties_changed_main (NMSupplicantInterface *self, state = wpas_state_string_to_enum (v_s); if (state == NM_SUPPLICANT_INTERFACE_STATE_INVALID) - _LOGT ("ignore unknown supplicant state '%s'", v_s); + _LOGT ("state: ignore unknown supplicant state '%s' (is %s, plain property)", + v_s, + nm_supplicant_interface_state_to_string (priv->supp_state)); else if (priv->supp_state != state) { + _LOGT ("state: %s (was %s, plain property)", + nm_supplicant_interface_state_to_string (state), + nm_supplicant_interface_state_to_string (priv->supp_state)); priv->supp_state = state; if (priv->state > NM_SUPPLICANT_INTERFACE_STATE_STARTING) { /* Only transition to actual wpa_supplicant interface states (ie, @@ -2328,40 +2337,82 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self, /*****************************************************************************/ +typedef struct { + NMSupplicantInterface *self; + GCancellable *cancellable; + NMSupplicantInterfaceRequestScanCallback callback; + gpointer user_data; +} ScanRequestData; + static void scan_request_cb (GObject *source, GAsyncResult *result, gpointer user_data) { + gs_unref_object NMSupplicantInterface *self_keep_alive = NULL; NMSupplicantInterface *self; gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; + ScanRequestData *data = user_data; + gboolean cancelled = FALSE; res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); - if (nm_utils_error_is_cancelled (error)) - return; - - self = NM_SUPPLICANT_INTERFACE (user_data); - if (error) { - if (_nm_dbus_error_has_name (error, "fi.w1.wpa_supplicant1.Interface.ScanError")) - _LOGD ("request-scan: could not get scan request result: %s", error->message); - else { - g_dbus_error_strip_remote_error (error); - _LOGW ("request-scan: could not get scan request result: %s", error->message); + if (nm_utils_error_is_cancelled (error)) { + if (!data->callback) { + /* the self instance was not kept alive. We also must not touch it. Return. */ + nm_g_object_unref (data->cancellable); + nm_g_slice_free (data); + return; } - } else - _LOGT ("request-scan: request scanning success"); + cancelled = TRUE; + } + + self = data->self; + if (data->callback) { + /* the self instance was kept alive. Balance the reference count. */ + self_keep_alive = self; + } + + /* we don't propagate the error/success. That is, because either answer is not + * reliable. What is important to us is whether the request completed, and + * the current nm_supplicant_interface_get_scanning() state. */ + if (cancelled) + _LOGD ("request-scan: request cancelled"); + else { + if (error) { + if (_nm_dbus_error_has_name (error, "fi.w1.wpa_supplicant1.Interface.ScanError")) + _LOGD ("request-scan: could not get scan request result: %s", error->message); + else { + g_dbus_error_strip_remote_error (error); + _LOGW ("request-scan: could not get scan request result: %s", error->message); + } + } else + _LOGT ("request-scan: request scanning success"); + } + + if (data->callback) + data->callback (self, data->cancellable, data->user_data); + + nm_g_object_unref (data->cancellable); + nm_g_slice_free (data); } void nm_supplicant_interface_request_scan (NMSupplicantInterface *self, GBytes *const*ssids, - guint ssids_len) + guint ssids_len, + GCancellable *cancellable, + NMSupplicantInterfaceRequestScanCallback callback, + gpointer user_data) { NMSupplicantInterfacePrivate *priv; GVariantBuilder builder; + ScanRequestData *data; guint i; g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); + nm_assert ( (!cancellable && !callback) + || (G_IS_CANCELLABLE (cancellable) && callback)); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); _LOGT ("request-scan: request scanning (%u ssids)...", ssids_len); @@ -2381,6 +2432,26 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface *self, g_variant_builder_add (&builder, "{sv}", "SSIDs", g_variant_builder_end (&ssids_builder)); } + data = g_slice_new (ScanRequestData); + *data = (ScanRequestData) { + .self = self, + .callback = callback, + .user_data = user_data, + .cancellable = nm_g_object_ref (cancellable), + }; + + if (callback) { + /* A callback was provided. This keeps @self alive. The caller + * must provide a cancellable as the caller must never leave an asynchronous + * operation pending indefinitely. */ + nm_assert (G_IS_CANCELLABLE (cancellable)); + g_object_ref (self); + } else { + /* We don't keep @self alive, and we don't accept a cancellable either. */ + nm_assert (!cancellable); + cancellable = priv->main_cancellable; + } + _dbus_connection_call (self, NM_WPAS_DBUS_IFACE_INTERFACE, "Scan", @@ -2388,9 +2459,9 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface *self, G_VARIANT_TYPE ("()"), G_DBUS_CALL_FLAGS_NONE, DBUS_TIMEOUT_MSEC, - priv->main_cancellable, + cancellable, scan_request_cb, - self); + data); } /*****************************************************************************/ diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index eb414f26f5..9ef198167f 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -128,9 +128,16 @@ nm_supplicant_interface_disconnect_async (NMSupplicantInterface * self, NMSupplicantInterfaceDisconnectCb callback, gpointer user_data); +typedef void (*NMSupplicantInterfaceRequestScanCallback) (NMSupplicantInterface *self, + GCancellable *cancellable, + gpointer user_data); + void nm_supplicant_interface_request_scan (NMSupplicantInterface *self, GBytes *const*ssids, - guint ssids_len); + guint ssids_len, + GCancellable *cancellable, + NMSupplicantInterfaceRequestScanCallback callback, + gpointer user_data); NMSupplicantInterfaceState nm_supplicant_interface_get_state (NMSupplicantInterface * self); |