diff options
author | Thomas Haller <thaller@redhat.com> | 2017-06-14 11:30:34 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-06-14 11:30:34 +0200 |
commit | 49f8fc90bd2458174397c9c712c03fd35d96d5da (patch) | |
tree | 53f786a98e13bc24f4d4fe6bccce4bdf5c042231 | |
parent | b6fa87a4c07c968614d123750be47a74de62f04d (diff) | |
parent | 9bfb4f0d09c20b84aac9a406b265328d267e0d8b (diff) | |
download | NetworkManager-49f8fc90bd2458174397c9c712c03fd35d96d5da.tar.gz |
wifi: merge branch 'th/wifi-wps-chain-async-bgo783499'
https://bugzilla.gnome.org/show_bug.cgi?id=783499
-rw-r--r-- | src/supplicant/nm-supplicant-interface.c | 345 |
1 files changed, 258 insertions, 87 deletions
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index ddbc868634..0ebe345837 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -49,6 +49,16 @@ struct _AddNetworkData; typedef struct { NMSupplicantInterface *self; + char *type; + char *bssid; + char *pin; + GDBusProxy *proxy; + GCancellable *cancellable; + bool is_cancelling; +} WpsData; + +typedef struct { + NMSupplicantInterface *self; NMSupplicantConfig *cfg; GCancellable *cancellable; NMSupplicantInterfaceAssocCb callback; @@ -109,8 +119,7 @@ typedef struct { GDBusProxy * iface_proxy; GCancellable * other_cancellable; - GDBusProxy * wps_proxy; /* We only have a WPS proxy when the enrollment was initiated */ - GCancellable * wps_cancellable; /* This can cancel the initiation, not the enrollment */ + WpsData *wps_data; AssocData * assoc_data; @@ -587,68 +596,89 @@ nm_supplicant_interface_set_pmf_support (NMSupplicantInterface *self, priv->pmf_support = pmf_support; } -typedef struct { - NMSupplicantInterface *self; - const char *type; - char *bssid; - char *pin; -} WpsEnrollStartData; +/*****************************************************************************/ static void -wps_enroll_start_data_free (WpsEnrollStartData *data) +_wps_data_free (WpsData *data) { + g_free (data->type); g_free (data->pin); g_free (data->bssid); - g_slice_free (WpsEnrollStartData, data); + g_clear_object (&data->cancellable); + if (data->proxy && data->self) + g_signal_handlers_disconnect_by_data (data->proxy, data->self); + g_clear_object (&data->proxy); + g_slice_free (WpsData, data); } static void -wpas_iface_wps_credentials (GDBusProxy *proxy, - GVariant *props, - gpointer user_data) +_wps_credentials_changed_cb (GDBusProxy *proxy, + GVariant *props, + gpointer user_data) { NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + _LOGT ("wps: new credentials"); g_signal_emit (self, signals[WPS_CREDENTIALS], 0, props); } static void -on_wps_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +_wps_handle_start_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { - WpsEnrollStartData *data = user_data; - NMSupplicantInterface *self = data->self; - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantInterface *self; + WpsData *data; + gs_unref_variant GVariant *result = NULL; + gs_free_error GError *error = NULL; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if ( !result + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + data = user_data; + self = data->self; + + if (result) + _LOGT ("wps: started with success"); + else + _LOGW ("wps: start failed with %s", error->message); + + g_clear_object (&data->cancellable); + nm_clear_g_free (&data->type); + nm_clear_g_free (&data->pin); + nm_clear_g_free (&data->bssid); +} + +static void +_wps_handle_set_pc_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + WpsData *data; + NMSupplicantInterface *self; + gs_unref_variant GVariant *result = NULL; + gs_free_error GError *error = NULL; GVariantBuilder start_args; guint8 bssid_buf[ETH_ALEN]; - gs_free_error GError *error = NULL; - priv->wps_proxy = g_dbus_proxy_new_for_bus_finish (result, &error); - if (!priv->wps_proxy) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - _LOGW ("failed to acquire WPS proxy: (%s)", error->message); - set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN); - } - wps_enroll_start_data_free (data); + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if ( !result + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } - /* Enable Credentials processing. */ - _nm_dbus_signal_connect (priv->wps_proxy, "Credentials", G_VARIANT_TYPE ("(a{sv})"), - G_CALLBACK (wpas_iface_wps_credentials), self); + data = user_data; + self = data->self; - g_dbus_proxy_call (priv->wps_proxy, - "org.freedesktop.DBus.Properties.Set", - g_variant_new ("(ssv)", - WPAS_DBUS_IFACE_INTERFACE_WPS, - "ProcessCredentials", - g_variant_new_boolean (TRUE)), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - NULL, - NULL); + if (result) + _LOGT ("wps: ProcessCredentials successfully set, starting..."); + else + _LOGW ("wps: ProcessCredentials failed to set (%s), starting...", error->message); + + _nm_dbus_signal_connect (data->proxy, "Credentials", G_VARIANT_TYPE ("(a{sv})"), + G_CALLBACK (_wps_credentials_changed_cb), self); - /* Initiate the enrollment. */ g_variant_builder_init (&start_args, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&start_args, "{sv}", "Role", g_variant_new_string ("enrollee")); g_variant_builder_add (&start_args, "{sv}", "Type", g_variant_new_string (data->type)); @@ -659,80 +689,213 @@ on_wps_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_da /* The BSSID is in fact not mandatory. If it is not set the supplicant would * enroll with any BSS in range. */ if (!nm_utils_hwaddr_aton (data->bssid, bssid_buf, sizeof (bssid_buf))) - g_return_if_reached (); + nm_assert_not_reached (); g_variant_builder_add (&start_args, "{sv}", "Bssid", g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid_buf, ETH_ALEN, sizeof (guint8))); - _LOGI ("starting '%s' WPS enrollment for BSSID '%s'", data->type, data->bssid); - } else { - _LOGI ("starting '%s' WPS enrollment", data->type); } - g_dbus_proxy_call (priv->wps_proxy, + g_dbus_proxy_call (data->proxy, "Start", g_variant_new ("(a{sv})", &start_args), G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - NULL, - NULL); - wps_enroll_start_data_free (data); + data->cancellable, + _wps_handle_start_cb, + data); } -void -nm_supplicant_interface_enroll_wps (NMSupplicantInterface *self, - const char *type, - const char *bssid, - const char *pin) +static void +_wps_call_set_pc (WpsData *data) { - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - WpsEnrollStartData *data; + g_dbus_proxy_call (data->proxy, + "org.freedesktop.DBus.Properties.Set", + g_variant_new ("(ssv)", + WPAS_DBUS_IFACE_INTERFACE_WPS, + "ProcessCredentials", + g_variant_new_boolean (TRUE)), + G_DBUS_CALL_FLAGS_NONE, + -1, + data->cancellable, + _wps_handle_set_pc_cb, + data); +} - data = g_slice_new0 (WpsEnrollStartData); - data->self = self; - data->type = type; - data->bssid = g_strdup (bssid); - data->pin = g_strdup (pin); +static void +_wps_handle_proxy_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + WpsData *data; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; - /* Supersede any previous WPS initiations. */ - nm_supplicant_interface_cancel_wps (self); + proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - priv->wps_cancellable = g_cancellable_new (); + data = user_data; + self = data->self; + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, - WPAS_DBUS_SERVICE, - priv->object_path, - WPAS_DBUS_IFACE_INTERFACE_WPS, - priv->wps_cancellable, - (GAsyncReadyCallback) on_wps_proxy_acquired, - data); + if (!proxy) { + _LOGW ("wps: failure to create D-Bus proxy: %s", error->message); + _wps_data_free (data); + priv->wps_data = NULL; + return; + } + + data->proxy = proxy; + _LOGT ("wps: D-Bus proxy created. set ProcessCredentials..."); + _wps_call_set_pc (data); } -void -nm_supplicant_interface_cancel_wps (NMSupplicantInterface *self) +static void +_wps_handle_cancel_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + WpsData *data; + gs_unref_variant GVariant *result = NULL; + gs_free_error GError *error = NULL; + + result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); + if ( !result + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + data = user_data; + self = data->self; + + if (!self) { + _wps_data_free (data); + if (result) + _LOGT ("wps: cancel completed successfully, after supplicant interface is gone"); + else + _LOGW ("wps: cancel failed (%s), after supplicant interface is gone", error->message); + return; + } + + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + data->is_cancelling = FALSE; + + if (!data->type) { + priv->wps_data = NULL; + _wps_data_free (data); + if (result) + _LOGT ("wps: cancel completed successfully"); + else + _LOGW ("wps: cancel failed (%s)", error->message); + return; + } + + if (result) + _LOGT ("wps: cancel completed successfully, setting ProcessCredentials now..."); + else + _LOGW ("wps: cancel failed (%s), setting ProcessCredentials now...", error->message); + _wps_call_set_pc (data); +} + +static void +_wps_start (NMSupplicantInterface *self, + const char *type, + const char *bssid, + const char *pin) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + WpsData *data = priv->wps_data; + + if (type) + _LOGI ("wps: type %s start...", type); - nm_clear_g_cancellable (&priv->wps_cancellable); + if (!data) { + if (!type) + return; - if (!priv->wps_proxy) + data = g_slice_new0 (WpsData); + data->self = self; + data->type = g_strdup (type); + data->bssid = g_strdup (bssid); + data->pin = g_strdup (pin); + data->cancellable = g_cancellable_new (); + + priv->wps_data = data; + + _LOGT ("wps: create D-Bus proxy..."); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + WPAS_DBUS_SERVICE, + priv->object_path, + WPAS_DBUS_IFACE_INTERFACE_WPS, + data->cancellable, + _wps_handle_proxy_cb, + data); return; + } + + g_free (data->type); + g_free (data->bssid); + g_free (data->pin); + data->type = g_strdup (type); + data->bssid = g_strdup (bssid); + data->pin = g_strdup (pin); + + if (!data->proxy) { + if (!type) { + nm_clear_g_cancellable (&data->cancellable); + priv->wps_data = NULL; + _wps_data_free (data); - _LOGD ("cancelling WPS enrollment"); - g_signal_handlers_disconnect_by_data (priv->wps_proxy, self); - g_dbus_proxy_call (priv->wps_proxy, + _LOGT ("wps: abort creation of D-Bus proxy"); + } else + _LOGT ("wps: new enrollment. Wait for D-Bus proxy..."); + return; + } + + if (data->is_cancelling) + return; + + _LOGT ("wps: cancel previous enrollment..."); + + data->is_cancelling = TRUE; + if (!data->cancellable) + data->cancellable = g_cancellable_new (); + g_signal_handlers_disconnect_by_data (data->proxy, self); + g_dbus_proxy_call (data->proxy, "Cancel", NULL, G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - NULL, - NULL); - g_clear_object (&priv->wps_proxy); + data->cancellable, + _wps_handle_cancel_cb, + data); } +void +nm_supplicant_interface_enroll_wps (NMSupplicantInterface *self, + const char *type, + const char *bssid, + const char *pin) +{ + _wps_start (self, type, bssid, pin); +} + +void +nm_supplicant_interface_cancel_wps (NMSupplicantInterface *self) +{ + _wps_start (self, NULL, NULL, NULL); +} + +/*****************************************************************************/ + static void iface_introspect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { @@ -1775,6 +1938,16 @@ dispose (GObject *object) NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (object); NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + nm_supplicant_interface_cancel_wps (self); + if (priv->wps_data) { + /* we shut down, but an asynchronous Cancel request is pending. + * We don't want to cancel it, so mark wps-data that @self is gone. + * This way, _wps_handle_cancel_cb() knows it must no longer touch + * @self */ + priv->wps_data->self = NULL; + priv->wps_data = NULL; + } + if (priv->assoc_data) { gs_free GError *error = NULL; @@ -1792,8 +1965,6 @@ dispose (GObject *object) g_clear_object (&priv->wpas_proxy); g_clear_pointer (&priv->bss_proxies, (GDestroyNotify) g_hash_table_destroy); - nm_supplicant_interface_cancel_wps (self); - g_clear_pointer (&priv->net_path, g_free); g_clear_pointer (&priv->dev, g_free); g_clear_pointer (&priv->object_path, g_free); |