mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-07 03:10:16 +01:00
supplicant: delay SCAN_DONE signal until all BSS are initialized
We initialize the BSS asyncronously. Don't declare SCAN_DONE until all BSS are up. Otherwise, especially during the very first scan we declare SCAN_DONE when having no BSS yet. This wrongly removes the pending action "wifi-scan", while "autoconnect" cannot happen as there are not BSS yet. Thus we declare "startup-complete" too early. Another issue is that we may start autoconnecting with an incomplete scan list, and thus pick a non-preferred connections. https://bugzilla.gnome.org/show_bug.cgi?id=777831
This commit is contained in:
parent
e3a489180b
commit
e0f9677018
1 changed files with 114 additions and 56 deletions
|
|
@ -37,10 +37,13 @@
|
|||
#define WPAS_ERROR_INVALID_IFACE WPAS_DBUS_INTERFACE ".InvalidInterface"
|
||||
#define WPAS_ERROR_EXISTS_ERROR WPAS_DBUS_INTERFACE ".InterfaceExists"
|
||||
|
||||
static NM_CACHED_QUARK_FCN ("bss-proxy-inited", bss_proxy_inited_quark)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
GDBusProxy *proxy;
|
||||
gulong change_id;
|
||||
} BssData;
|
||||
|
||||
struct _AddNetworkData;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -92,7 +95,10 @@ typedef struct {
|
|||
NMSupplicantInterfaceState state;
|
||||
int disconnect_reason;
|
||||
|
||||
gboolean scanning;
|
||||
gboolean scanning:1;
|
||||
|
||||
bool scan_done_pending:1;
|
||||
bool scan_done_success:1;
|
||||
|
||||
GDBusProxy * wpas_proxy;
|
||||
GCancellable * init_cancellable;
|
||||
|
|
@ -144,6 +150,10 @@ G_DEFINE_TYPE (NMSupplicantInterface, nm_supplicant_interface, G_TYPE_OBJECT)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void scan_done_emit_signal (NMSupplicantInterface *self);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NM_UTILS_LOOKUP_STR_DEFINE (nm_supplicant_interface_state_to_string, NMSupplicantInterfaceState,
|
||||
NM_UTILS_LOOKUP_DEFAULT_WARN ("unknown"),
|
||||
NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INVALID, "invalid"),
|
||||
|
|
@ -166,10 +176,20 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_supplicant_interface_state_to_string, NMSupplican
|
|||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
bss_props_changed_cb (GDBusProxy *proxy,
|
||||
GVariant *changed_properties,
|
||||
char **invalidated_properties,
|
||||
gpointer user_data)
|
||||
bss_data_destroy (gpointer user_data)
|
||||
{
|
||||
BssData *bss_data = user_data;
|
||||
|
||||
nm_clear_g_signal_handler (bss_data->proxy, &bss_data->change_id);
|
||||
g_object_unref (bss_data->proxy);
|
||||
g_slice_free (BssData, bss_data);
|
||||
}
|
||||
|
||||
static void
|
||||
bss_proxy_properties_changed_cb (GDBusProxy *proxy,
|
||||
GVariant *changed_properties,
|
||||
char **invalidated_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
|
||||
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
|
||||
|
|
@ -183,61 +203,73 @@ bss_props_changed_cb (GDBusProxy *proxy,
|
|||
}
|
||||
|
||||
static GVariant *
|
||||
_get_bss_proxy_properties (NMSupplicantInterface *self, GDBusProxy *proxy)
|
||||
bss_proxy_get_properties (NMSupplicantInterface *self, GDBusProxy *proxy)
|
||||
{
|
||||
gs_strfreev char **properties = NULL;
|
||||
GVariantBuilder builder;
|
||||
char **iter;
|
||||
|
||||
iter = properties = g_dbus_proxy_get_cached_property_names (proxy);
|
||||
if (!iter)
|
||||
return NULL;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
while (*iter) {
|
||||
GVariant *copy = g_dbus_proxy_get_cached_property (proxy, *iter);
|
||||
if (iter) {
|
||||
while (*iter) {
|
||||
GVariant *copy = g_dbus_proxy_get_cached_property (proxy, *iter);
|
||||
|
||||
g_variant_builder_add (&builder, "{sv}", *iter++, copy);
|
||||
g_variant_unref (copy);
|
||||
g_variant_builder_add (&builder, "{sv}", *iter++, copy);
|
||||
g_variant_unref (copy);
|
||||
}
|
||||
}
|
||||
|
||||
return g_variant_builder_end (&builder);
|
||||
}
|
||||
|
||||
static void
|
||||
on_bss_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
|
||||
bss_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
NMSupplicantInterface *self;
|
||||
NMSupplicantInterfacePrivate *priv;
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_unref_variant GVariant *props = NULL;
|
||||
GVariant *props = NULL;
|
||||
const char *object_path;
|
||||
BssData *bss_data;
|
||||
|
||||
if (!g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error)) {
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||
self = NM_SUPPLICANT_INTERFACE (user_data);
|
||||
_LOGD ("failed to acquire BSS proxy: (%s)", error->message);
|
||||
g_hash_table_remove (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->bss_proxies,
|
||||
g_dbus_proxy_get_object_path (proxy));
|
||||
}
|
||||
g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error);
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
|
||||
self = NM_SUPPLICANT_INTERFACE (user_data);
|
||||
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
|
||||
|
||||
if (error) {
|
||||
_LOGD ("failed to acquire BSS proxy: (%s)", error->message);
|
||||
g_hash_table_remove (priv->bss_proxies,
|
||||
g_dbus_proxy_get_object_path (proxy));
|
||||
return;
|
||||
}
|
||||
|
||||
self = NM_SUPPLICANT_INTERFACE (user_data);
|
||||
props = _get_bss_proxy_properties (self, proxy);
|
||||
if (!props)
|
||||
object_path = g_dbus_proxy_get_object_path (proxy);
|
||||
bss_data = g_hash_table_lookup (priv->bss_proxies, object_path);
|
||||
if (!bss_data)
|
||||
return;
|
||||
|
||||
g_object_set_qdata (G_OBJECT (proxy), bss_proxy_inited_quark (), GUINT_TO_POINTER (TRUE));
|
||||
bss_data->change_id = g_signal_connect (proxy, "g-properties-changed", G_CALLBACK (bss_proxy_properties_changed_cb), self);
|
||||
|
||||
props = bss_proxy_get_properties (self, proxy);
|
||||
g_signal_emit (self, signals[BSS_UPDATED], 0,
|
||||
g_dbus_proxy_get_object_path (proxy),
|
||||
g_variant_ref_sink (props));
|
||||
g_variant_unref (props);
|
||||
|
||||
if (priv->scan_done_pending)
|
||||
scan_done_emit_signal (self);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_new_bss (NMSupplicantInterface *self, const char *object_path)
|
||||
bss_add_new (NMSupplicantInterface *self, const char *object_path)
|
||||
{
|
||||
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
|
||||
GDBusProxy *bss_proxy;
|
||||
BssData *bss_data;
|
||||
|
||||
g_return_if_fail (object_path != NULL);
|
||||
|
||||
|
|
@ -251,17 +283,20 @@ handle_new_bss (NMSupplicantInterface *self, const char *object_path)
|
|||
"g-object-path", object_path,
|
||||
"g-interface-name", WPAS_DBUS_IFACE_BSS,
|
||||
NULL);
|
||||
bss_data = g_slice_new0 (BssData);
|
||||
bss_data->proxy = bss_proxy;
|
||||
g_hash_table_insert (priv->bss_proxies,
|
||||
(char *) g_dbus_proxy_get_object_path (bss_proxy),
|
||||
bss_proxy);
|
||||
g_signal_connect (bss_proxy, "g-properties-changed", G_CALLBACK (bss_props_changed_cb), self);
|
||||
bss_data);
|
||||
g_async_initable_init_async (G_ASYNC_INITABLE (bss_proxy),
|
||||
G_PRIORITY_DEFAULT,
|
||||
priv->other_cancellable,
|
||||
(GAsyncReadyCallback) on_bss_proxy_acquired,
|
||||
(GAsyncReadyCallback) bss_proxy_acquired_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
set_state (NMSupplicantInterface *self, NMSupplicantInterfaceState new_state)
|
||||
{
|
||||
|
|
@ -561,6 +596,42 @@ iface_introspect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data
|
|||
iface_check_ready (self);
|
||||
}
|
||||
|
||||
static void
|
||||
scan_done_emit_signal (NMSupplicantInterface *self)
|
||||
{
|
||||
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
|
||||
const char *object_path;
|
||||
BssData *bss_data;
|
||||
gboolean success;
|
||||
GHashTableIter iter;
|
||||
|
||||
g_hash_table_iter_init (&iter, priv->bss_proxies);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &bss_data)) {
|
||||
/* we have some BSS' that need to be initialized first. Delay
|
||||
* emitting signal. */
|
||||
if (!bss_data->change_id) {
|
||||
priv->scan_done_pending = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit BSS_UPDATED so that wifi device has the APs (in case it removed them) */
|
||||
g_hash_table_iter_init (&iter, priv->bss_proxies);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &object_path, (gpointer *) &bss_data)) {
|
||||
gs_unref_variant GVariant *props = NULL;
|
||||
|
||||
props = bss_proxy_get_properties (self, bss_data->proxy);
|
||||
g_signal_emit (self, signals[BSS_UPDATED], 0,
|
||||
object_path,
|
||||
g_variant_ref_sink (props));
|
||||
}
|
||||
|
||||
success = priv->scan_done_success;
|
||||
priv->scan_done_success = FALSE;
|
||||
priv->scan_done_pending = FALSE;
|
||||
g_signal_emit (self, signals[SCAN_DONE], 0, success);
|
||||
}
|
||||
|
||||
static void
|
||||
wpas_iface_scan_done (GDBusProxy *proxy,
|
||||
gboolean success,
|
||||
|
|
@ -568,29 +639,11 @@ wpas_iface_scan_done (GDBusProxy *proxy,
|
|||
{
|
||||
NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
|
||||
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
|
||||
GVariant *props;
|
||||
GHashTableIter iter;
|
||||
char *bss_path;
|
||||
GDBusProxy *bss_proxy;
|
||||
|
||||
/* Cache last scan completed time */
|
||||
priv->last_scan = nm_utils_get_monotonic_timestamp_s ();
|
||||
|
||||
/* Emit BSS_UPDATED so that wifi device has the APs (in case it removed them) */
|
||||
g_hash_table_iter_init (&iter, priv->bss_proxies);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer) &bss_path, (gpointer) &bss_proxy)) {
|
||||
if (g_object_get_qdata (G_OBJECT (bss_proxy), bss_proxy_inited_quark ())) {
|
||||
props = _get_bss_proxy_properties (self, bss_proxy);
|
||||
if (props) {
|
||||
g_signal_emit (self, signals[BSS_UPDATED], 0,
|
||||
bss_path,
|
||||
g_variant_ref_sink (props));
|
||||
g_variant_unref (props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_emit (self, signals[SCAN_DONE], 0, success);
|
||||
priv->scan_done_success |= success;
|
||||
scan_done_emit_signal (self);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -605,7 +658,7 @@ wpas_iface_bss_added (GDBusProxy *proxy,
|
|||
if (priv->scanning)
|
||||
priv->last_scan = nm_utils_get_monotonic_timestamp_s ();
|
||||
|
||||
handle_new_bss (self, path);
|
||||
bss_add_new (self, path);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -615,9 +668,14 @@ wpas_iface_bss_removed (GDBusProxy *proxy,
|
|||
{
|
||||
NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
|
||||
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
|
||||
BssData *bss_data;
|
||||
|
||||
bss_data = g_hash_table_lookup (priv->bss_proxies, path);
|
||||
if (!bss_data)
|
||||
return;
|
||||
g_hash_table_steal (priv->bss_proxies, path);
|
||||
g_signal_emit (self, signals[BSS_REMOVED], 0, path);
|
||||
g_hash_table_remove (priv->bss_proxies, path);
|
||||
bss_data_destroy (bss_data);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -665,7 +723,7 @@ props_changed_cb (GDBusProxy *proxy,
|
|||
if (g_variant_lookup (changed_properties, "BSSs", "^a&o", &array)) {
|
||||
iter = array;
|
||||
while (*iter)
|
||||
handle_new_bss (self, *iter++);
|
||||
bss_add_new (self, *iter++);
|
||||
g_free (array);
|
||||
}
|
||||
|
||||
|
|
@ -1517,7 +1575,7 @@ nm_supplicant_interface_init (NMSupplicantInterface * self)
|
|||
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
|
||||
|
||||
priv->state = NM_SUPPLICANT_INTERFACE_STATE_INIT;
|
||||
priv->bss_proxies = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
|
||||
priv->bss_proxies = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, bss_data_destroy);
|
||||
}
|
||||
|
||||
NMSupplicantInterface *
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue