summaryrefslogtreecommitdiff
path: root/src/supplicant/nm-supplicant-interface.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-04-24 16:42:13 +0200
committerThomas Haller <thaller@redhat.com>2020-04-24 19:36:53 +0200
commit2eb398648f26c6284070ecb4934368813c005de4 (patch)
tree8bf53c45e354e8f907215f88248d86cdf1f572ff /src/supplicant/nm-supplicant-interface.c
parent6d0ea83949c144b25926f4f72ebea76e9ea3382b (diff)
wifi: add callback to nm_supplicant_interface_request_scan()
While we request a scan, we are not yet actually scanning. That means, the supplicant's "scanning" property will only change to TRUE a while after we initiate the scan. It may even never happen. We thus need to handle that the request is currently pending and react when the request completes. (cherry picked from commit 16c1869476106859b684151eb1b101c24cff3451)
Diffstat (limited to 'src/supplicant/nm-supplicant-interface.c')
-rw-r--r--src/supplicant/nm-supplicant-interface.c92
1 files changed, 77 insertions, 15 deletions
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c
index bfee298445..099c3bf2ca 100644
--- a/src/supplicant/nm-supplicant-interface.c
+++ b/src/supplicant/nm-supplicant-interface.c
@@ -2337,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);
@@ -2390,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",
@@ -2397,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);
}
/*****************************************************************************/