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 16c1869476)
This commit is contained in:
Thomas Haller 2020-04-24 16:42:13 +02:00
parent 6d0ea83949
commit 2eb398648f
3 changed files with 90 additions and 17 deletions

View file

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

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

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