supplicant-interface: add support for WPS enrollment

This commit is contained in:
Lubomir Rintel 2017-04-13 10:42:32 +02:00
parent e6f95b50c8
commit 1d15e9c6de
2 changed files with 180 additions and 8 deletions

View file

@ -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"
/*****************************************************************************/
@ -69,6 +70,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 };
@ -107,6 +109,9 @@ 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 */
AssocData * assoc_data;
char * net_path;
@ -580,6 +585,152 @@ 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)
{
g_free (data->pin);
g_free (data->bssid);
g_slice_free (WpsEnrollStartData, data);
}
static void
wpas_iface_wps_credentials (GDBusProxy *proxy,
GVariant *props,
gpointer user_data)
{
NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
g_signal_emit (self, signals[WPS_CREDENTIALS], 0, props);
}
static void
on_wps_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
WpsEnrollStartData *data = user_data;
NMSupplicantInterface *self = data->self;
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
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);
return;
}
/* Enable Credentials processing. */
_nm_dbus_signal_connect (priv->wps_proxy, "Credentials", G_VARIANT_TYPE ("(a{sv})"),
G_CALLBACK (wpas_iface_wps_credentials), 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);
/* 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));
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)))
g_return_if_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,
"Start",
g_variant_new ("(a{sv})", &start_args),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
NULL,
NULL);
wps_enroll_start_data_free (data);
}
void
nm_supplicant_interface_enroll_wps (NMSupplicantInterface *self,
const char *type,
const char *bssid,
const char *pin)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
WpsEnrollStartData *data;
data = g_slice_new0 (WpsEnrollStartData);
data->self = self;
data->type = type;
data->bssid = g_strdup (bssid);
data->pin = g_strdup (pin);
/* Supersede any previous WPS initiations. */
nm_supplicant_interface_cancel_wps (self);
priv->wps_cancellable = g_cancellable_new ();
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);
}
void
nm_supplicant_interface_cancel_wps (NMSupplicantInterface *self)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
nm_clear_g_cancellable (&priv->wps_cancellable);
if (!priv->wps_proxy)
return;
_LOGD ("cancelling WPS enrollment");
g_signal_handlers_disconnect_by_data (priv->wps_proxy, self);
g_dbus_proxy_call (priv->wps_proxy,
"Cancel",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
NULL,
NULL);
g_clear_object (&priv->wps_proxy);
}
static void
iface_introspect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
@ -1173,6 +1324,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
@ -1636,6 +1790,8 @@ 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);
@ -1749,5 +1905,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);
}

View file

@ -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 - 2010 Red Hat, Inc.
* Copyright (C) 2006 - 2017 Red Hat, Inc.
* Copyright (C) 2007 - 2008 Novell, Inc.
*/
@ -69,6 +69,7 @@ typedef enum {
#define NM_SUPPLICANT_INTERFACE_BSS_REMOVED "bss-removed"
#define NM_SUPPLICANT_INTERFACE_SCAN_DONE "scan-done"
#define NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST "credentials-request"
#define NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS "wps-credentials"
typedef struct _NMSupplicantInterfaceClass NMSupplicantInterfaceClass;
@ -131,4 +132,12 @@ void nm_supplicant_interface_set_fast_support (NMSupplicantInterface *self,
void nm_supplicant_interface_set_pmf_support (NMSupplicantInterface *self,
NMSupplicantFeature pmf_support);
void nm_supplicant_interface_enroll_wps (NMSupplicantInterface *self,
const char *const type,
const char *bssid,
const char *pin);
void nm_supplicant_interface_cancel_wps (NMSupplicantInterface *self);
#endif /* __NM_SUPPLICANT_INTERFACE_H__ */