diff options
Diffstat (limited to 'src/supplicant/nm-supplicant-interface.c')
| -rw-r--r-- | src/supplicant/nm-supplicant-interface.c | 388 |
1 files changed, 377 insertions, 11 deletions
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index ab8a0670..44f887cb 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2006 - 2012 Red Hat, Inc. + * Copyright (C) 2006 - 2017 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -31,11 +31,12 @@ #include "nm-core-internal.h" #include "nm-dbus-compat.h" -#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" -#define WPAS_DBUS_IFACE_BSS WPAS_DBUS_INTERFACE ".BSS" -#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network" -#define WPAS_ERROR_INVALID_IFACE WPAS_DBUS_INTERFACE ".InvalidInterface" -#define WPAS_ERROR_EXISTS_ERROR WPAS_DBUS_INTERFACE ".InterfaceExists" +#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" +#define WPAS_DBUS_IFACE_INTERFACE_WPS WPAS_DBUS_INTERFACE ".Interface.WPS" +#define WPAS_DBUS_IFACE_BSS WPAS_DBUS_INTERFACE ".BSS" +#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network" +#define WPAS_ERROR_INVALID_IFACE WPAS_DBUS_INTERFACE ".InvalidInterface" +#define WPAS_ERROR_EXISTS_ERROR WPAS_DBUS_INTERFACE ".InterfaceExists" /*****************************************************************************/ @@ -48,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; @@ -69,6 +80,7 @@ enum { BSS_REMOVED, /* supplicant removed BSS from its scan list */ SCAN_DONE, /* wifi scan is complete */ CREDENTIALS_REQUEST, /* 802.1x identity or password requested */ + WPS_CREDENTIALS, /* WPS credentials received */ LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -80,6 +92,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface, PROP_DRIVER, PROP_FAST_SUPPORT, PROP_AP_SUPPORT, + PROP_PMF_SUPPORT, ); typedef struct { @@ -88,6 +101,7 @@ typedef struct { gboolean has_credreq; /* Whether querying 802.1x credentials is supported */ NMSupplicantFeature fast_support; NMSupplicantFeature ap_support; /* Lightweight AP mode support */ + NMSupplicantFeature pmf_support; guint32 max_scan_ssids; guint32 ready_count; @@ -105,6 +119,8 @@ typedef struct { GDBusProxy * iface_proxy; GCancellable * other_cancellable; + WpsData *wps_data; + AssocData * assoc_data; char * net_path; @@ -543,6 +559,12 @@ nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self) return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->ap_support; } +NMSupplicantFeature +nm_supplicant_interface_get_pmf_support (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->pmf_support; +} + void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, NMSupplicantFeature ap_support) @@ -565,6 +587,315 @@ nm_supplicant_interface_set_fast_support (NMSupplicantInterface *self, priv->fast_support = fast_support; } +void +nm_supplicant_interface_set_pmf_support (NMSupplicantInterface *self, + NMSupplicantFeature pmf_support) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + priv->pmf_support = pmf_support; +} + +/*****************************************************************************/ + +static void +_wps_data_free (WpsData *data) +{ + g_free (data->type); + g_free (data->pin); + g_free (data->bssid); + 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 +_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 +_wps_handle_start_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + 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]; + + 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: 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); + + 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)); + if (data->pin) + g_variant_builder_add (&start_args, "{sv}", "Pin", g_variant_new_string (data->pin)); + + if (data->bssid) { + /* 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))) + 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))); + } + + g_dbus_proxy_call (data->proxy, + "Start", + g_variant_new ("(a{sv})", &start_args), + G_DBUS_CALL_FLAGS_NONE, + -1, + data->cancellable, + _wps_handle_start_cb, + data); +} + +static void +_wps_call_set_pc (WpsData *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); +} + +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; + + proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if ( !proxy + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + data = user_data; + self = data->self; + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + 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); +} + +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); + + if (!data) { + if (!type) + return; + + 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); + + _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; + nm_clear_g_cancellable (&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, + 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) { @@ -786,7 +1117,7 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ /* Scan result aging parameters */ g_dbus_proxy_call (priv->iface_proxy, - "org.freedesktop.DBus.Properties.Set", + DBUS_INTERFACE_PROPERTIES ".Set", g_variant_new ("(ssv)", WPAS_DBUS_IFACE_INTERFACE, "BSSExpireAge", @@ -797,7 +1128,7 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ NULL, NULL); g_dbus_proxy_call (priv->iface_proxy, - "org.freedesktop.DBus.Properties.Set", + DBUS_INTERFACE_PROPERTIES ".Set", g_variant_new ("(ssv)", WPAS_DBUS_IFACE_INTERFACE, "BSSExpireCount", @@ -1158,6 +1489,9 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self) g_free (priv->net_path); priv->net_path = NULL; } + + /* Cancel any WPS enrollment, if any */ + nm_supplicant_interface_cancel_wps (self); } static void @@ -1455,6 +1789,7 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface *self, const GPtrArr /* Scan parameters */ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&builder, "{sv}", "Type", g_variant_new_string ("active")); + g_variant_builder_add (&builder, "{sv}", "AllowRoam", g_variant_new_boolean (FALSE)); if (ssids) { GVariantBuilder ssids_builder; @@ -1561,6 +1896,10 @@ set_property (GObject *object, /* construct-only */ priv->ap_support = g_value_get_int (value); break; + case PROP_PMF_SUPPORT: + /* construct-only */ + priv->pmf_support = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1573,14 +1912,15 @@ 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, bss_data_destroy); + priv->bss_proxies = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, bss_data_destroy); } NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname, NMSupplicantDriver driver, NMSupplicantFeature fast_support, - NMSupplicantFeature ap_support) + NMSupplicantFeature ap_support, + NMSupplicantFeature pmf_support) { g_return_val_if_fail (ifname != NULL, NULL); @@ -1589,6 +1929,7 @@ nm_supplicant_interface_new (const char *ifname, NM_SUPPLICANT_INTERFACE_DRIVER, (guint) driver, NM_SUPPLICANT_INTERFACE_FAST_SUPPORT, (int) fast_support, NM_SUPPLICANT_INTERFACE_AP_SUPPORT, (int) ap_support, + NM_SUPPLICANT_INTERFACE_PMF_SUPPORT, (int) pmf_support, NULL); } @@ -1598,6 +1939,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_error GError *error = NULL; @@ -1670,6 +2021,14 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_PMF_SUPPORT] = + g_param_spec_int (NM_SUPPLICANT_INTERFACE_PMF_SUPPORT, "", "", + NM_SUPPLICANT_FEATURE_UNKNOWN, + NM_SUPPLICANT_FEATURE_YES, + NM_SUPPLICANT_FEATURE_UNKNOWN, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); @@ -1720,5 +2079,12 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); -} + signals[WPS_CREDENTIALS] = + g_signal_new (NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_VARIANT); +} |