about summary refs log tree commit diff
path: root/src/supplicant
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-05-08 21:40:53 +0200
committerMichael Biebl <biebl@debian.org>2020-05-08 21:40:53 +0200
commitd460892bbfece74fb6d3cd846bf6ef548290be41 (patch)
tree0474e5be0b5e5fac0d2f3a1e554382e8d1aa6397 /src/supplicant
parent1e5977b62f896e844b548c3007ace9e1dfa7f9ed (diff)
New upstream version 1.24.0 upstream/1.24.0
Diffstat (limited to 'src/supplicant')
-rw-r--r--src/supplicant/nm-supplicant-interface.c168
-rw-r--r--src/supplicant/nm-supplicant-interface.h9
-rw-r--r--src/supplicant/nm-supplicant-manager.c3
3 files changed, 142 insertions, 38 deletions
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c
index cc3d109e..1c7b9a42 100644
--- a/src/supplicant/nm-supplicant-interface.c
+++ b/src/supplicant/nm-supplicant-interface.c
@@ -154,6 +154,9 @@ typedef struct _NMSupplicantInterfacePrivate {
 	bool           is_ready_main:1;
 	bool           is_ready_p2p_device:1;
 
+	bool           prop_scan_active:1;
+	bool           prop_scan_ssid:1;
+
 } NMSupplicantInterfacePrivate;
 
 struct _NMSupplicantInterfaceClass {
@@ -1123,7 +1126,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));
 
@@ -1167,10 +1170,11 @@ static void
 parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities)
 {
 	NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-	gboolean have_active = FALSE;
-	gboolean have_ssid = FALSE;
+	const gboolean old_prop_scan_active = priv->prop_scan_active;
+	const gboolean old_prop_scan_ssid = priv->prop_scan_ssid;
+	const guint32 old_max_scan_ssids = priv->max_scan_ssids;
 	gboolean have_ft = FALSE;
-	gint32 max_scan_ssids = -1;
+	gint32 max_scan_ssids;
 	const char **array;
 
 	nm_assert (capabilities && g_variant_is_of_type (capabilities, G_VARIANT_TYPE_VARDICT));
@@ -1195,23 +1199,37 @@ parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities)
 	}
 
 	if (g_variant_lookup (capabilities, "Scan", "^a&s", &array)) {
-		if (g_strv_contains (array, "active"))
-			have_active = TRUE;
-		if (g_strv_contains (array, "ssid"))
-			have_ssid = TRUE;
+		const char **a;
+
+		priv->prop_scan_active = FALSE;
+		priv->prop_scan_ssid = FALSE;
+		for (a = array; *a; a++) {
+			if (nm_streq (*a, "active"))
+				priv->prop_scan_active = TRUE;
+			else if (nm_streq (*a, "ssid"))
+				priv->prop_scan_ssid = TRUE;
+		}
 		g_free (array);
 	}
 
 	if (g_variant_lookup (capabilities, "MaxScanSSID", "i", &max_scan_ssids)) {
-		/* We need active scan and SSID probe capabilities to care about MaxScanSSIDs */
-		if (max_scan_ssids > 0 && have_active && have_ssid) {
-			/* wpa_supplicant's NM_WPAS_MAX_SCAN_SSIDS value is 16, but for speed
-			 * and to ensure we don't disclose too many SSIDs from the hidden
-			 * list, we'll limit to 5.
-			 */
-			priv->max_scan_ssids = CLAMP (max_scan_ssids, 0, 5);
-			_LOGD ("supports %d scan SSIDs", priv->max_scan_ssids);
-		}
+		const gint32 WPAS_MAX_SCAN_SSIDS = 16;
+
+		/* Even if supplicant claims that 20 SSIDs are supported, the Scan request
+		 * still only accepts WPAS_MAX_SCAN_SSIDS SSIDs. Otherwise the D-Bus
+		 * request will be rejected with "fi.w1.wpa_supplicant1.InvalidArgs"
+		 * Body: ('Did not receive correct message arguments.', 'Too many ssids specified. Specify at most four')
+		 * */
+		priv->max_scan_ssids = CLAMP (max_scan_ssids, 0, WPAS_MAX_SCAN_SSIDS);
+	}
+
+	if (   old_max_scan_ssids != priv->max_scan_ssids
+	    || old_prop_scan_active != priv->prop_scan_active
+	    || old_prop_scan_ssid != priv->prop_scan_ssid) {
+		_LOGD ("supports %u scan SSIDs (scan: %cactive %cssid)",
+		       (guint32) priv->max_scan_ssids,
+		       priv->prop_scan_active ? '+' : '-',
+		       priv->prop_scan_ssid ? '+' : '-');
 	}
 }
 
@@ -1789,8 +1807,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 +1838,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 +2355,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 +2450,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 +2477,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);
 }
 
 /*****************************************************************************/
@@ -2438,9 +2527,14 @@ nm_supplicant_interface_get_ifname (NMSupplicantInterface *self)
 guint
 nm_supplicant_interface_get_max_scan_ssids (NMSupplicantInterface *self)
 {
+	NMSupplicantInterfacePrivate *priv;
+
 	g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), 0);
 
-	return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->max_scan_ssids;
+	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+	return   priv->prop_scan_active && priv->prop_scan_ssid
+	       ? priv->max_scan_ssids
+	       : 0u;
 }
 
 /*****************************************************************************/
@@ -2504,7 +2598,7 @@ nm_supplicant_interface_p2p_connect (NMSupplicantInterface *self,
 	                              NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
 	                              "Connect",
 	                              g_variant_new ("(a{sv})", &builder),
-	                              G_VARIANT_TYPE ("()"),
+	                              G_VARIANT_TYPE ("(s)"),
 	                              "p2p-connect");
 }
 
diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h
index eb414f26..9ef19816 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);
 
diff --git a/src/supplicant/nm-supplicant-manager.c b/src/supplicant/nm-supplicant-manager.c
index cf5cf111..b1a2dea8 100644
--- a/src/supplicant/nm-supplicant-manager.c
+++ b/src/supplicant/nm-supplicant-manager.c
@@ -562,6 +562,9 @@ _create_iface_dbus_call_create_interface_cb (GObject *source,
 			       NM_HASH_OBFUSCATE_PTR (handle),
 			       iface_path_str,
 			       handle->name_owner->str);
+			nm_utils_error_set (&error,
+			                    NM_UTILS_ERROR_UNKNOWN,
+			                    "Request already cancelled");
 		} else {
 			_LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: name owner changed, still remove interface %s in %s",
 			       NM_HASH_OBFUSCATE_PTR (handle),