From fbe98ba107ebe47df1be4838e6ba0e027e093d23 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 15 Feb 2017 10:14:54 +0100 Subject: [PATCH] supplicant: cleanup network when cancelling "AddNetwork" request If the assoc-request is cancelled while an "AddNetwork" request is pending, we must cleanup the added network when the request succeeds. The issue can also happen when NetworkManager shuts down and exits the mainloop. This scenario is unsolved as the cleanup action "RemoveNetwork" has no chance to run. "AddBlob" works differently in that blogs are added with a specific name, not like "AddNetwork", where a new D-Bus path is created. Maybe we should also cleanup blobs that were added by us, but currently we don't. (cherry picked from commit c47026715ec6a9612752f469358a7251aabbdee7) --- src/supplicant/nm-supplicant-interface.c | 58 +++++++++++++++++++++--- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index ebedad6fe0..44bd27a80d 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -39,15 +39,24 @@ /*****************************************************************************/ +struct _AddNetworkData; + typedef struct { + NMSupplicantInterface *self; NMSupplicantConfig *cfg; GCancellable *cancellable; NMSupplicantInterfaceAssocCb callback; gpointer user_data; guint fail_on_idle_id; guint blobs_left; + struct _AddNetworkData *add_network_data; } AssocData; +typedef struct _AddNetworkData { + /* the assoc_data at the time when doing the call. */ + AssocData *assoc_data; +} AddNetworkData; + enum { STATE, /* change in the interface's state */ REMOVED, /* interface was removed by the supplicant */ @@ -1032,6 +1041,11 @@ assoc_return (NMSupplicantInterface *self, GError *error, const char *message) } else _LOGD ("assoc[%p]: association request successful", assoc_data); + if (assoc_data->add_network_data) { + /* signal that this request already completed */ + assoc_data->add_network_data->assoc_data = NULL; + } + nm_clear_g_source (&assoc_data->fail_on_idle_id); nm_clear_g_cancellable (&assoc_data->cancellable); @@ -1153,6 +1167,8 @@ assoc_add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) static void assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { + AddNetworkData *add_network_data = user_data; + AssocData *assoc_data; NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; gs_unref_variant GVariant *reply = NULL; @@ -1162,17 +1178,40 @@ assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat const char *blob_name; GByteArray *blob_data; + assoc_data = add_network_data->assoc_data; + if (assoc_data) + assoc_data->add_network_data = NULL; + g_slice_free (AddNetworkData, add_network_data); + reply = _nm_dbus_proxy_call_finish (proxy, result, G_VARIANT_TYPE ("(o)"), &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + + if (!assoc_data) { + if (!error) { + gs_free char *net_path = NULL; + + /* the assoc-request was already cancelled, but the AddNetwork request succeeded. + * Cleanup the created network. + * + * This cleanup action does not work when NetworkManager is about to exit + * and leaves the mainloop. During program shutdown, we may orphan networks. */ + g_variant_get (reply, "(o)", &net_path); + g_dbus_proxy_call (proxy, + "RemoveNetwork", + g_variant_new ("(o)", net_path), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + NULL, + NULL); + } return; + } - self = NM_SUPPLICANT_INTERFACE (user_data); + self = NM_SUPPLICANT_INTERFACE (assoc_data->self); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - nm_clear_g_free (&priv->net_path); - if (error) { assoc_return (self, error, "failure to add network"); return; @@ -1213,6 +1252,7 @@ assoc_set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat NMSupplicantInterfacePrivate *priv; gs_unref_variant GVariant *reply = NULL; gs_free_error GError *error = NULL; + AddNetworkData *add_network_data; reply = g_dbus_proxy_call_finish (proxy, result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) @@ -1230,14 +1270,19 @@ assoc_set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat priv->assoc_data, nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg)); + add_network_data = g_slice_new0 (AddNetworkData); + priv->assoc_data->add_network_data = add_network_data; + + add_network_data->assoc_data = priv->assoc_data; + g_dbus_proxy_call (priv->iface_proxy, "AddNetwork", g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->assoc_data->cfg)), G_DBUS_CALL_FLAGS_NONE, -1, - priv->assoc_data->cancellable, + NULL, (GAsyncReadyCallback) assoc_add_network_cb, - self); + add_network_data); } static gboolean @@ -1287,6 +1332,7 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self, assoc_data = g_slice_new0 (AssocData); priv->assoc_data = assoc_data; + assoc_data->self = self; assoc_data->cfg = g_object_ref (cfg); assoc_data->callback = callback; assoc_data->user_data = user_data;