wifi: merge branch 'th/cli-trigger-scan-retry'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/476

(cherry picked from commit fe84237cf0)
This commit is contained in:
Thomas Haller 2020-04-24 19:34:44 +02:00
commit dbe7b8749d
12 changed files with 256 additions and 79 deletions

View file

@ -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;
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)
force_finished = TRUE;
else
force_finished = FALSE;
wifi_list_data = user_data;
g_clear_object (&wifi_list_data->scan_cancellable);
if (g_error_matches (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED)) {
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;
done = TRUE;
} else {
force_finished = FALSE;
done = TRUE;
}
if (done)
g_clear_object (&wifi_list_data->scan_cancellable);
wifi_list_finish (wifi_list_data, force_finished);
}

View file

@ -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);
}
/*****************************************************************************/

View file

@ -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);
/*****************************************************************************/

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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");

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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);
}
/*****************************************************************************/

View file

@ -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);