From 55407fd0275004a17aa422277b843e42d5dd5b5a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 8 Oct 2018 19:42:07 +0200 Subject: [PATCH 1/9] supplicant: Handle interface removal The signal was not handled, potentially creating corner cases where NetworkManager may not notice an interface removal. Add a handler and ensure the supplicant interface is brought down when it is removed from wpa_supplicant for a reason other than NetworkManager requesting it. --- src/supplicant/nm-supplicant-interface.c | 41 ++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 5237acb263..562b754d3f 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -1289,6 +1289,38 @@ interface_add_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) } } +static void +interface_removed_cb (GDBusProxy *proxy, + const char *path, + gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + + self = NM_SUPPLICANT_INTERFACE (user_data); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + if (g_strcmp0 (priv->object_path, path) != 0) + return; + + _LOGD ("Received interface removed signal"); + + /* The interface may lose its last reference during signal handling otherwise. */ + g_object_ref (self); + + /* Invalidate the object path to prevent the manager from trying to remove + * a non-existing interface. */ + g_clear_pointer (&priv->object_path, g_free); + + /* No need to clean up everything now, that will happen at dispose time. */ + + /* Interface is down and has been removed. */ + set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN); + g_signal_emit (self, signals[REMOVED], 0); + + g_object_unref (self); +} + #if HAVE_WEXT #define DEFAULT_WIFI_DRIVER "nl80211,wext" #else @@ -1320,6 +1352,10 @@ on_wpas_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d priv->wpas_proxy = wpas_proxy; + /* Watch for interface removal. */ + _nm_dbus_signal_connect (priv->wpas_proxy, "InterfaceRemoved", G_VARIANT_TYPE ("(o)"), + G_CALLBACK (interface_removed_cb), self); + /* Try to add the interface to the supplicant. If the supplicant isn't * running, this will start it via D-Bus activation and return the response * when the supplicant has started. @@ -1374,8 +1410,7 @@ interface_add (NMSupplicantInterface *self) priv->init_cancellable = g_cancellable_new (); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, WPAS_DBUS_SERVICE, WPAS_DBUS_PATH, @@ -1983,6 +2018,8 @@ dispose (GObject *object) nm_clear_g_cancellable (&priv->init_cancellable); nm_clear_g_cancellable (&priv->other_cancellable); + if (priv->wpas_proxy) + g_signal_handlers_disconnect_by_data (priv->wpas_proxy, object); g_clear_object (&priv->wpas_proxy); g_clear_pointer (&priv->bss_proxies, g_hash_table_destroy); From e2a99cabdad967cd62cdb903ae439252852df8b5 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 10 Oct 2018 17:50:34 +0200 Subject: [PATCH 2/9] supplicant: Detect P2P and WFD support Add detection for P2P and WFD support in wpa_supplicant and pass the information to the NMSupplicantInterface. --- src/supplicant/nm-supplicant-interface.c | 64 +++++++++++++++++++++++- src/supplicant/nm-supplicant-interface.h | 14 +++++- src/supplicant/nm-supplicant-manager.c | 31 +++++++++++- 3 files changed, 105 insertions(+), 4 deletions(-) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 562b754d3f..bd7d48a58e 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -94,6 +94,8 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface, PROP_AP_SUPPORT, PROP_PMF_SUPPORT, PROP_FILS_SUPPORT, + PROP_P2P_SUPPORT, + PROP_WFD_SUPPORT, ); typedef struct { @@ -104,6 +106,8 @@ typedef struct { NMSupplicantFeature ap_support; /* Lightweight AP mode support */ NMSupplicantFeature pmf_support; NMSupplicantFeature fils_support; + NMSupplicantFeature p2p_support; + NMSupplicantFeature wfd_support; guint32 max_scan_ssids; guint32 ready_count; @@ -573,6 +577,18 @@ nm_supplicant_interface_get_fils_support (NMSupplicantInterface *self) return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->fils_support; } +NMSupplicantFeature +nm_supplicant_interface_get_p2p_support (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_support; +} + +NMSupplicantFeature +nm_supplicant_interface_get_wfd_support (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->wfd_support; +} + void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, NMSupplicantFeature ap_support) @@ -613,6 +629,24 @@ nm_supplicant_interface_set_fils_support (NMSupplicantInterface *self, priv->fils_support = fils_support; } +void +nm_supplicant_interface_set_p2p_support (NMSupplicantInterface *self, + NMSupplicantFeature p2p_support) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + priv->p2p_support = p2p_support; +} + +void +nm_supplicant_interface_set_wfd_support (NMSupplicantInterface *self, + NMSupplicantFeature wfd_support) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + priv->wfd_support = wfd_support; +} + /*****************************************************************************/ static void @@ -1953,6 +1987,14 @@ set_property (GObject *object, /* construct-only */ priv->fils_support = g_value_get_int (value); break; + case PROP_P2P_SUPPORT: + /* construct-only */ + priv->p2p_support = g_value_get_int (value); + break; + case PROP_WFD_SUPPORT: + /* construct-only */ + priv->wfd_support = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1974,7 +2016,9 @@ nm_supplicant_interface_new (const char *ifname, NMSupplicantFeature fast_support, NMSupplicantFeature ap_support, NMSupplicantFeature pmf_support, - NMSupplicantFeature fils_support) + NMSupplicantFeature fils_support, + NMSupplicantFeature p2p_support, + NMSupplicantFeature wfd_support) { g_return_val_if_fail (ifname != NULL, NULL); @@ -1985,6 +2029,8 @@ nm_supplicant_interface_new (const char *ifname, NM_SUPPLICANT_INTERFACE_AP_SUPPORT, (int) ap_support, NM_SUPPLICANT_INTERFACE_PMF_SUPPORT, (int) pmf_support, NM_SUPPLICANT_INTERFACE_FILS_SUPPORT, (int) fils_support, + NM_SUPPLICANT_INTERFACE_P2P_SUPPORT, (int) p2p_support, + NM_SUPPLICANT_INTERFACE_WFD_SUPPORT, (int) wfd_support, NULL); } @@ -2094,6 +2140,22 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_P2P_SUPPORT] = + g_param_spec_int (NM_SUPPLICANT_INTERFACE_P2P_SUPPORT, "", "", + NM_SUPPLICANT_FEATURE_UNKNOWN, + NM_SUPPLICANT_FEATURE_YES, + NM_SUPPLICANT_FEATURE_UNKNOWN, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_WFD_SUPPORT] = + g_param_spec_int (NM_SUPPLICANT_INTERFACE_WFD_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); diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index 0365fdcd63..a62f9dadee 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -62,6 +62,8 @@ typedef enum { #define NM_SUPPLICANT_INTERFACE_AP_SUPPORT "ap-support" #define NM_SUPPLICANT_INTERFACE_PMF_SUPPORT "pmf-support" #define NM_SUPPLICANT_INTERFACE_FILS_SUPPORT "fils-support" +#define NM_SUPPLICANT_INTERFACE_P2P_SUPPORT "p2p-support" +#define NM_SUPPLICANT_INTERFACE_WFD_SUPPORT "wfd-support" /* Signals */ #define NM_SUPPLICANT_INTERFACE_STATE "state" @@ -81,7 +83,9 @@ NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname, NMSupplicantFeature fast_support, NMSupplicantFeature ap_support, NMSupplicantFeature pmf_support, - NMSupplicantFeature fils_support); + NMSupplicantFeature fils_support, + NMSupplicantFeature p2p_support, + NMSupplicantFeature wfd_support); void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self, gboolean available); @@ -128,6 +132,8 @@ gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self); NMSupplicantFeature nm_supplicant_interface_get_pmf_support (NMSupplicantInterface *self); NMSupplicantFeature nm_supplicant_interface_get_fils_support (NMSupplicantInterface *self); +NMSupplicantFeature nm_supplicant_interface_get_p2p_support (NMSupplicantInterface *self); +NMSupplicantFeature nm_supplicant_interface_get_wfd_support (NMSupplicantInterface *self); void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, NMSupplicantFeature apmode); @@ -141,6 +147,12 @@ void nm_supplicant_interface_set_pmf_support (NMSupplicantInterface *self, void nm_supplicant_interface_set_fils_support (NMSupplicantInterface *self, NMSupplicantFeature fils_support); +void nm_supplicant_interface_set_p2p_support (NMSupplicantInterface *self, + NMSupplicantFeature p2p_support); + +void nm_supplicant_interface_set_wfd_support (NMSupplicantInterface *self, + NMSupplicantFeature wfd_support); + void nm_supplicant_interface_enroll_wps (NMSupplicantInterface *self, const char *const type, const char *bssid, diff --git a/src/supplicant/nm-supplicant-manager.c b/src/supplicant/nm-supplicant-manager.c index 5ab96f88f1..65cb5e20e7 100644 --- a/src/supplicant/nm-supplicant-manager.c +++ b/src/supplicant/nm-supplicant-manager.c @@ -41,6 +41,8 @@ typedef struct { NMSupplicantFeature ap_support; NMSupplicantFeature pmf_support; NMSupplicantFeature fils_support; + NMSupplicantFeature p2p_support; + NMSupplicantFeature wfd_support; guint die_count_reset_id; guint die_count; } NMSupplicantManagerPrivate; @@ -163,7 +165,9 @@ nm_supplicant_manager_create_interface (NMSupplicantManager *self, priv->fast_support, priv->ap_support, priv->pmf_support, - priv->fils_support); + priv->fils_support, + priv->p2p_support, + priv->wfd_support); priv->ifaces = g_slist_prepend (priv->ifaces, iface); g_object_add_toggle_ref ((GObject *) iface, _sup_iface_last_ref, self); @@ -199,6 +203,8 @@ update_capabilities (NMSupplicantManager *self) priv->ap_support = NM_SUPPLICANT_FEATURE_UNKNOWN; priv->pmf_support = NM_SUPPLICANT_FEATURE_UNKNOWN; priv->fils_support = NM_SUPPLICANT_FEATURE_UNKNOWN; + /* P2P support is newer than the capabilities property */ + priv->p2p_support = NM_SUPPLICANT_FEATURE_NO; value = g_dbus_proxy_get_cached_property (priv->proxy, "Capabilities"); if (value) { @@ -207,6 +213,7 @@ update_capabilities (NMSupplicantManager *self) priv->ap_support = NM_SUPPLICANT_FEATURE_NO; priv->pmf_support = NM_SUPPLICANT_FEATURE_NO; priv->fils_support = NM_SUPPLICANT_FEATURE_NO; + priv->p2p_support = NM_SUPPLICANT_FEATURE_NO; if (array) { if (g_strv_contains (array, "ap")) priv->ap_support = NM_SUPPLICANT_FEATURE_YES; @@ -214,17 +221,20 @@ update_capabilities (NMSupplicantManager *self) priv->pmf_support = NM_SUPPLICANT_FEATURE_YES; if (g_strv_contains (array, "fils")) priv->fils_support = NM_SUPPLICANT_FEATURE_YES; + if (g_strv_contains (array, "p2p")) + priv->p2p_support = NM_SUPPLICANT_FEATURE_YES; g_free (array); } } g_variant_unref (value); } - /* Tell all interfaces about results of the AP/PMF/FILS check */ + /* Tell all interfaces about results of the AP/PMF/FILS/P2P check */ for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) { nm_supplicant_interface_set_ap_support (ifaces->data, priv->ap_support); nm_supplicant_interface_set_pmf_support (ifaces->data, priv->pmf_support); nm_supplicant_interface_set_fils_support (ifaces->data, priv->fils_support); + nm_supplicant_interface_set_p2p_support (ifaces->data, priv->p2p_support); } _LOGD ("AP mode is %ssupported", @@ -236,6 +246,9 @@ update_capabilities (NMSupplicantManager *self) _LOGD ("FILS is %ssupported", (priv->fils_support == NM_SUPPLICANT_FEATURE_YES) ? "" : (priv->fils_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); + _LOGD ("P2P is %ssupported", + (priv->p2p_support == NM_SUPPLICANT_FEATURE_YES) ? "" : + (priv->p2p_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); /* EAP-FAST */ priv->fast_support = NM_SUPPLICANT_FEATURE_NO; @@ -264,6 +277,20 @@ update_capabilities (NMSupplicantManager *self) _LOGD ("EAP-FAST is %ssupported", (priv->fast_support == NM_SUPPLICANT_FEATURE_YES) ? "" : (priv->fast_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); + + priv->wfd_support = NM_SUPPLICANT_FEATURE_NO; + value = g_dbus_proxy_get_cached_property (priv->proxy, "WFDIEs"); + if (value) { + priv->wfd_support = NM_SUPPLICANT_FEATURE_YES; + g_variant_unref (value); + } + + for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) + nm_supplicant_interface_set_wfd_support (ifaces->data, priv->fast_support); + + _LOGD ("WFD is %ssupported", + (priv->wfd_support == NM_SUPPLICANT_FEATURE_YES) ? "" : + (priv->wfd_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); } static void From ae22631d66027b8e186096159fa4927b9bdc20f5 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 10 Oct 2018 18:35:20 +0200 Subject: [PATCH 3/9] supplicant: Connect to P2PDevice supplicant interface The wpa_supplicant interface has a P2PDevice when P2P is supported. Create a proxy for this and wait for it to be ready before marking the interface as ready. --- src/supplicant/nm-supplicant-interface.c | 104 +++++++++++++++++++++-- src/supplicant/nm-supplicant-interface.h | 1 + 2 files changed, 97 insertions(+), 8 deletions(-) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index bd7d48a58e..3f5449ec66 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -31,12 +31,13 @@ #include "nm-core-internal.h" #include "nm-dbus-compat.h" -#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" +#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" +#define WPAS_DBUS_IFACE_INTERFACE_WPS WPAS_DBUS_INTERFACE ".Interface.WPS" +#define WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE WPAS_DBUS_INTERFACE ".Interface.P2PDevice" +#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" /*****************************************************************************/ @@ -90,6 +91,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface, PROP_SCANNING, PROP_CURRENT_BSS, PROP_DRIVER, + PROP_P2P_AVAILABLE, PROP_FAST_SUPPORT, PROP_AP_SUPPORT, PROP_PMF_SUPPORT, @@ -124,6 +126,10 @@ typedef struct { GCancellable * init_cancellable; GDBusProxy * iface_proxy; GCancellable * other_cancellable; + GDBusProxy * p2p_proxy; + + gboolean p2p_proxy_acquired; + gboolean p2p_capable; WpsData *wps_data; @@ -454,12 +460,24 @@ static void parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - gboolean have_active = FALSE, have_ssid = FALSE; + gboolean have_active = FALSE, have_p2p = FALSE, have_ssid = FALSE; gint32 max_scan_ssids = -1; const char **array; g_return_if_fail (capabilities && g_variant_is_of_type (capabilities, G_VARIANT_TYPE_VARDICT)); + if ( g_variant_lookup (capabilities, "Modes", "^a&s", &array) + && array) { + if (g_strv_contains (array, "p2p")) + have_p2p = TRUE; + g_free (array); + } + + if (priv->p2p_capable != have_p2p) { + priv->p2p_capable = have_p2p; + _notify (self, PROP_P2P_AVAILABLE); + } + if ( g_variant_lookup (capabilities, "Scan", "^a&s", &array) && array) { if (g_strv_contains (array, "active")) @@ -1190,7 +1208,6 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ NULL); /* Check whether NetworkReply and AP mode are supported */ - priv->ready_count = 1; g_dbus_proxy_call (priv->iface_proxy, "NetworkReply", g_variant_new ("(oss)", @@ -1221,6 +1238,47 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ } } +static void +on_p2p_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + gs_free_error GError *error = NULL; + + 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); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + _LOGW ("failed to acquire wpa_supplicant p2p proxy: (%s)", error->message); + + g_clear_object (&priv->p2p_proxy); + + iface_check_ready (self); + } + return; + } + + self = NM_SUPPLICANT_INTERFACE (user_data); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + /* TODO: + * * DeviceFound + * * DeviceLost + * * GroupStarted + * * GroupFinished + * * GroupFormationFailure + * * WpsFailed + * * FindStopped + * * GONegotationFailure + * * InvitationReceived + */ + + priv->p2p_proxy_acquired = TRUE; + _notify (self, PROP_P2P_AVAILABLE); + + iface_check_ready (self); +} + static void interface_add_done (NMSupplicantInterface *self, const char *path) { @@ -1228,6 +1286,9 @@ interface_add_done (NMSupplicantInterface *self, const char *path) _LOGD ("interface added to supplicant"); + /* Iface ready check happens in iface_check_netreply_cb */ + priv->ready_count = 1; + priv->object_path = g_strdup (path); priv->iface_proxy = g_object_new (G_TYPE_DBUS_PROXY, "g-bus-type", G_BUS_TYPE_SYSTEM, @@ -1242,6 +1303,22 @@ interface_add_done (NMSupplicantInterface *self, const char *path) priv->init_cancellable, (GAsyncReadyCallback) on_iface_proxy_acquired, self); + + if (priv->p2p_support == NM_SUPPLICANT_FEATURE_YES) { + priv->ready_count++; + priv->p2p_proxy = g_object_new (G_TYPE_DBUS_PROXY, + "g-bus-type", G_BUS_TYPE_SYSTEM, + "g-flags", G_DBUS_PROXY_FLAGS_NONE, + "g-name", WPAS_DBUS_SERVICE, + "g-object-path", priv->object_path, + "g-interface-name", WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, + NULL); + g_async_initable_init_async (G_ASYNC_INITABLE (priv->p2p_proxy), + G_PRIORITY_DEFAULT, + priv->init_cancellable, + (GAsyncReadyCallback) on_p2p_proxy_acquired, + self); + } } static void @@ -1947,6 +2024,9 @@ get_property (GObject *object, case PROP_CURRENT_BSS: g_value_set_string (value, priv->current_bss); break; + case PROP_P2P_AVAILABLE: + g_value_set_boolean (value, priv->p2p_capable && priv->p2p_proxy_acquired); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2060,6 +2140,9 @@ dispose (GObject *object) if (priv->iface_proxy) g_signal_handlers_disconnect_by_data (priv->iface_proxy, object); g_clear_object (&priv->iface_proxy); + if (priv->p2p_proxy) + g_signal_handlers_disconnect_by_data (priv->p2p_proxy, object); + g_clear_object (&priv->p2p_proxy); nm_clear_g_cancellable (&priv->init_cancellable); nm_clear_g_cancellable (&priv->other_cancellable); @@ -2108,6 +2191,11 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_P2P_AVAILABLE] = + g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE, "", "", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_FAST_SUPPORT] = g_param_spec_int (NM_SUPPLICANT_INTERFACE_FAST_SUPPORT, "", "", NM_SUPPLICANT_FEATURE_UNKNOWN, diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index a62f9dadee..58de1dac3b 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -58,6 +58,7 @@ typedef enum { #define NM_SUPPLICANT_INTERFACE_SCANNING "scanning" #define NM_SUPPLICANT_INTERFACE_CURRENT_BSS "current-bss" #define NM_SUPPLICANT_INTERFACE_DRIVER "driver" +#define NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE "p2p-available" #define NM_SUPPLICANT_INTERFACE_FAST_SUPPORT "fast-support" #define NM_SUPPLICANT_INTERFACE_AP_SUPPORT "ap-support" #define NM_SUPPLICANT_INTERFACE_PMF_SUPPORT "pmf-support" From 08c28ef96ba52486ba037c04e55c30fd472af8f4 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 10 Oct 2018 21:27:34 +0200 Subject: [PATCH 4/9] supplicant: Monitor existance of P2P Peers found --- src/supplicant/nm-supplicant-interface.c | 199 ++++++++++++++++++++++- src/supplicant/nm-supplicant-interface.h | 2 + 2 files changed, 199 insertions(+), 2 deletions(-) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 3f5449ec66..43104cf4ce 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -35,6 +35,7 @@ #define WPAS_DBUS_IFACE_INTERFACE_WPS WPAS_DBUS_INTERFACE ".Interface.WPS" #define WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE WPAS_DBUS_INTERFACE ".Interface.P2PDevice" #define WPAS_DBUS_IFACE_BSS WPAS_DBUS_INTERFACE ".BSS" +#define WPAS_DBUS_IFACE_PEER WPAS_DBUS_INTERFACE ".Peer" #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" @@ -46,6 +47,11 @@ typedef struct { gulong change_id; } BssData; +typedef struct { + GDBusProxy *proxy; + gulong change_id; +} PeerData; + struct _AddNetworkData; typedef struct { @@ -79,6 +85,8 @@ enum { REMOVED, /* interface was removed by the supplicant */ BSS_UPDATED, /* a new BSS appeared or an existing had properties changed */ BSS_REMOVED, /* supplicant removed BSS from its scan list */ + PEER_UPDATED, /* a new Peer appeared or an existing had properties changed */ + PEER_REMOVED, /* supplicant removed Peer from its scan list */ SCAN_DONE, /* wifi scan is complete */ CREDENTIALS_REQUEST, /* 802.1x identity or password requested */ WPS_CREDENTIALS, /* WPS credentials received */ @@ -139,6 +147,8 @@ typedef struct { GHashTable * bss_proxies; char * current_bss; + GHashTable * peer_proxies; + gint64 last_scan; /* timestamp as returned by nm_utils_get_monotonic_timestamp_ms() */ } NMSupplicantInterfacePrivate; @@ -321,6 +331,122 @@ bss_add_new (NMSupplicantInterface *self, const char *object_path) self); } +static void +peer_data_destroy (gpointer user_data) +{ + PeerData *peer_data = user_data; + + nm_clear_g_signal_handler (peer_data->proxy, &peer_data->change_id); + g_object_unref (peer_data->proxy); + g_slice_free (PeerData, peer_data); +} + +static void +peer_proxy_properties_changed_cb (GDBusProxy *proxy, + GVariant *changed_properties, + char **invalidated_properties, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + + g_signal_emit (self, signals[PEER_UPDATED], 0, + g_dbus_proxy_get_object_path (proxy), + changed_properties); +} + +static GVariant * +peer_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); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + 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); + } + } + return g_variant_builder_end (&builder); +} + +static void +peer_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + gs_free_error GError *error = NULL; + GVariant *props = NULL; + const char *object_path; + PeerData *peer_data; + gboolean success; + + success = g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error); + if ( !success + && 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 (!success) { + _LOGD ("failed to acquire Peer proxy: (%s)", error->message); + g_hash_table_remove (priv->peer_proxies, + g_dbus_proxy_get_object_path (proxy)); + return; + } + + object_path = g_dbus_proxy_get_object_path (proxy); + peer_data = g_hash_table_lookup (priv->peer_proxies, object_path); + if (!peer_data) + return; + + peer_data->change_id = g_signal_connect (proxy, "g-properties-changed", G_CALLBACK (peer_proxy_properties_changed_cb), self); + + props = peer_proxy_get_properties (self, proxy); + + g_signal_emit (self, signals[PEER_UPDATED], 0, + g_dbus_proxy_get_object_path (proxy), + g_variant_ref_sink (props)); + g_variant_unref (props); +} + +static void +peer_add_new (NMSupplicantInterface *self, const char *object_path) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + GDBusProxy *peer_proxy; + PeerData *peer_data; + + g_return_if_fail (object_path != NULL); + + if (g_hash_table_lookup (priv->peer_proxies, object_path)) + return; + + peer_proxy = g_object_new (G_TYPE_DBUS_PROXY, + "g-bus-type", G_BUS_TYPE_SYSTEM, + "g-flags", G_DBUS_PROXY_FLAGS_NONE, + "g-name", WPAS_DBUS_SERVICE, + "g-object-path", object_path, + "g-interface-name", WPAS_DBUS_IFACE_PEER, + NULL); + peer_data = g_slice_new0 (PeerData); + peer_data->proxy = peer_proxy; + g_hash_table_insert (priv->peer_proxies, + (char *) g_dbus_proxy_get_object_path (peer_proxy), + peer_data); + g_async_initable_init_async (G_ASYNC_INITABLE (peer_proxy), + G_PRIORITY_DEFAULT, + priv->other_cancellable, + (GAsyncReadyCallback) peer_proxy_acquired_cb, + self); +} + /*****************************************************************************/ static void @@ -1155,6 +1281,54 @@ props_changed_cb (GDBusProxy *proxy, g_object_thaw_notify (G_OBJECT (self)); } +static void +p2p_props_changed_cb (GDBusProxy *proxy, + GVariant *changed_properties, + GStrv invalidated_properties, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + const char **array, **iter; + + g_object_freeze_notify (G_OBJECT (self)); + + if (g_variant_lookup (changed_properties, "Peers", "^a&o", &array)) { + iter = array; + while (*iter) + peer_add_new (self, *iter++); + g_free (array); + } + + g_object_thaw_notify (G_OBJECT (self)); +} + +static void +p2p_device_found (GDBusProxy *proxy, + const char *path, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + + peer_add_new (self, path); +} + +static void +p2p_device_lost (GDBusProxy *proxy, + const char *path, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + PeerData *peer_data; + + peer_data = g_hash_table_lookup (priv->peer_proxies, path); + if (!peer_data) + return; + g_hash_table_steal (priv->peer_proxies, path); + g_signal_emit (self, signals[PEER_REMOVED], 0, path); + peer_data_destroy (peer_data); +} + static void on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { @@ -1261,9 +1435,11 @@ on_p2p_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_da self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + _nm_dbus_signal_connect (priv->p2p_proxy, "DeviceFound", G_VARIANT_TYPE ("(o)"), + G_CALLBACK (p2p_device_found), self); + _nm_dbus_signal_connect (priv->p2p_proxy, "DeviceLost", G_VARIANT_TYPE ("(o)"), + G_CALLBACK (p2p_device_lost), self); /* TODO: - * * DeviceFound - * * DeviceLost * * GroupStarted * * GroupFinished * * GroupFormationFailure @@ -1313,6 +1489,7 @@ interface_add_done (NMSupplicantInterface *self, const char *path) "g-object-path", priv->object_path, "g-interface-name", WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, NULL); + g_signal_connect (priv->p2p_proxy, "g-properties-changed", G_CALLBACK (p2p_props_changed_cb), self); g_async_initable_init_async (G_ASYNC_INITABLE (priv->p2p_proxy), G_PRIORITY_DEFAULT, priv->init_cancellable, @@ -2088,6 +2265,7 @@ nm_supplicant_interface_init (NMSupplicantInterface * self) priv->state = NM_SUPPLICANT_INTERFACE_STATE_INIT; priv->bss_proxies = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, bss_data_destroy); + priv->peer_proxies = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, peer_data_destroy); } NMSupplicantInterface * @@ -2151,6 +2329,7 @@ dispose (GObject *object) g_signal_handlers_disconnect_by_data (priv->wpas_proxy, object); g_clear_object (&priv->wpas_proxy); g_clear_pointer (&priv->bss_proxies, g_hash_table_destroy); + g_clear_pointer (&priv->peer_proxies, g_hash_table_destroy); g_clear_pointer (&priv->net_path, g_free); g_clear_pointer (&priv->dev, g_free); @@ -2279,6 +2458,22 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); + signals[PEER_UPDATED] = + g_signal_new (NM_SUPPLICANT_INTERFACE_PEER_UPDATED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VARIANT); + + signals[PEER_REMOVED] = + g_signal_new (NM_SUPPLICANT_INTERFACE_PEER_REMOVED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_STRING); + signals[SCAN_DONE] = g_signal_new (NM_SUPPLICANT_INTERFACE_SCAN_DONE, G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index 58de1dac3b..b8aca5b185 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -71,6 +71,8 @@ typedef enum { #define NM_SUPPLICANT_INTERFACE_REMOVED "removed" #define NM_SUPPLICANT_INTERFACE_BSS_UPDATED "bss-updated" #define NM_SUPPLICANT_INTERFACE_BSS_REMOVED "bss-removed" +#define NM_SUPPLICANT_INTERFACE_PEER_UPDATED "peer-updated" +#define NM_SUPPLICANT_INTERFACE_PEER_REMOVED "peer-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" From 15b7b36718292e95f5023fd78292432ff18d990e Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 10 Oct 2018 22:43:49 +0200 Subject: [PATCH 5/9] supplicant: Allow creating an interface from object path wpa_supplicant will create a new interface for P2P devices. In this case we need to fetch the supplicant interface using the object path and then fetch the interface name via dbus to setup the IP interface of the P2P device later. --- src/supplicant/nm-supplicant-interface.c | 96 ++++++++++++++++-------- src/supplicant/nm-supplicant-interface.h | 2 + src/supplicant/nm-supplicant-manager.c | 58 ++++++++++++++ src/supplicant/nm-supplicant-manager.h | 2 + 4 files changed, 126 insertions(+), 32 deletions(-) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 43104cf4ce..050c939895 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -22,6 +22,7 @@ #include "nm-default.h" #include "nm-supplicant-interface.h" +#include "nm-supplicant-manager.h" #include #include @@ -96,6 +97,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface, PROP_IFACE, + PROP_OBJECT_PATH, PROP_SCANNING, PROP_CURRENT_BSS, PROP_DRIVER, @@ -1278,6 +1280,14 @@ props_changed_cb (GDBusProxy *proxy, _LOGW ("connection disconnected (reason %d)", priv->disconnect_reason); } + /* We may not have priv->dev set yet if this interface was created from a + * known wpa_supplicant interface without knowing the device name. + */ + if (priv->dev == NULL && g_variant_lookup (changed_properties, "Ifname", "&s", &s)) { + priv->dev = g_strdup (s); + _notify (self, PROP_IFACE); + } + g_object_thaw_notify (G_OBJECT (self)); } @@ -1466,6 +1476,7 @@ interface_add_done (NMSupplicantInterface *self, const char *path) priv->ready_count = 1; priv->object_path = g_strdup (path); + _notify (self, PROP_OBJECT_PATH); priv->iface_proxy = g_object_new (G_TYPE_DBUS_PROXY, "g-bus-type", G_BUS_TYPE_SYSTEM, "g-flags", G_DBUS_PROXY_FLAGS_NONE, @@ -1599,6 +1610,7 @@ interface_removed_cb (GDBusProxy *proxy, /* Invalidate the object path to prevent the manager from trying to remove * a non-existing interface. */ g_clear_pointer (&priv->object_path, g_free); + _notify (self, PROP_OBJECT_PATH); /* No need to clean up everything now, that will happen at dispose time. */ @@ -1623,7 +1635,6 @@ on_wpas_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d gs_free_error GError *error = NULL; GDBusProxy *wpas_proxy; GVariantBuilder props; - const char *driver_name = NULL; wpas_proxy = g_dbus_proxy_new_for_bus_finish (result, &error); if (!wpas_proxy) { @@ -1649,36 +1660,44 @@ on_wpas_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d * when the supplicant has started. */ - switch (priv->driver) { - case NM_SUPPLICANT_DRIVER_WIRELESS: - driver_name = DEFAULT_WIFI_DRIVER; - break; - case NM_SUPPLICANT_DRIVER_WIRED: - driver_name = "wired"; - break; - case NM_SUPPLICANT_DRIVER_MACSEC: - driver_name = "macsec_linux"; - break; + if (priv->dev != NULL) { + const char *driver_name = NULL; + + switch (priv->driver) { + case NM_SUPPLICANT_DRIVER_WIRELESS: + driver_name = DEFAULT_WIFI_DRIVER; + break; + case NM_SUPPLICANT_DRIVER_WIRED: + driver_name = "wired"; + break; + case NM_SUPPLICANT_DRIVER_MACSEC: + driver_name = "macsec_linux"; + break; + } + + g_return_if_fail (driver_name); + + g_variant_builder_init (&props, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&props, "{sv}", + "Driver", + g_variant_new_string (driver_name)); + g_variant_builder_add (&props, "{sv}", + "Ifname", + g_variant_new_string (priv->dev)); + + g_dbus_proxy_call (priv->wpas_proxy, + "CreateInterface", + g_variant_new ("(a{sv})", &props), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->init_cancellable, + (GAsyncReadyCallback) interface_add_cb, + self); + } else if (priv->object_path) { + interface_add_done (self, priv->object_path); + } else { + g_assert_not_reached (); } - - g_return_if_fail (driver_name); - - g_variant_builder_init (&props, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&props, "{sv}", - "Driver", - g_variant_new_string (driver_name)); - g_variant_builder_add (&props, "{sv}", - "Ifname", - g_variant_new_string (priv->dev)); - - g_dbus_proxy_call (priv->wpas_proxy, - "CreateInterface", - g_variant_new ("(a{sv})", &props), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->init_cancellable, - (GAsyncReadyCallback) interface_add_cb, - self); } static void @@ -2222,7 +2241,10 @@ set_property (GObject *object, case PROP_IFACE: /* construct-only */ priv->dev = g_value_dup_string (value); - g_return_if_fail (priv->dev); + break; + case PROP_OBJECT_PATH: + /* construct-only */ + priv->object_path = g_value_dup_string (value); break; case PROP_DRIVER: /* construct-only */ @@ -2270,6 +2292,7 @@ nm_supplicant_interface_init (NMSupplicantInterface * self) NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname, + const char *object_path, NMSupplicantDriver driver, NMSupplicantFeature fast_support, NMSupplicantFeature ap_support, @@ -2278,10 +2301,13 @@ nm_supplicant_interface_new (const char *ifname, NMSupplicantFeature p2p_support, NMSupplicantFeature wfd_support) { - g_return_val_if_fail (ifname != NULL, NULL); + /* One of ifname or path need to be set */ + g_return_val_if_fail (ifname != NULL || object_path != NULL, NULL); + g_return_val_if_fail (ifname == NULL || object_path == NULL, NULL); return g_object_new (NM_TYPE_SUPPLICANT_INTERFACE, NM_SUPPLICANT_INTERFACE_IFACE, ifname, + NM_SUPPLICANT_INTERFACE_OBJECT_PATH, object_path, NM_SUPPLICANT_INTERFACE_DRIVER, (guint) driver, NM_SUPPLICANT_INTERFACE_FAST_SUPPORT, (int) fast_support, NM_SUPPLICANT_INTERFACE_AP_SUPPORT, (int) ap_support, @@ -2364,6 +2390,12 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_OBJECT_PATH] = + g_param_spec_string (NM_SUPPLICANT_INTERFACE_OBJECT_PATH, "", "", + NULL, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_DRIVER] = g_param_spec_uint (NM_SUPPLICANT_INTERFACE_DRIVER, "", "", 0, G_MAXUINT, NM_SUPPLICANT_DRIVER_WIRELESS, diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index b8aca5b185..aed72af8bf 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -55,6 +55,7 @@ typedef enum { /* Properties */ #define NM_SUPPLICANT_INTERFACE_IFACE "iface" +#define NM_SUPPLICANT_INTERFACE_OBJECT_PATH "object-path" #define NM_SUPPLICANT_INTERFACE_SCANNING "scanning" #define NM_SUPPLICANT_INTERFACE_CURRENT_BSS "current-bss" #define NM_SUPPLICANT_INTERFACE_DRIVER "driver" @@ -82,6 +83,7 @@ typedef struct _NMSupplicantInterfaceClass NMSupplicantInterfaceClass; GType nm_supplicant_interface_get_type (void); NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname, + const char *object_path, NMSupplicantDriver driver, NMSupplicantFeature fast_support, NMSupplicantFeature ap_support, diff --git a/src/supplicant/nm-supplicant-manager.c b/src/supplicant/nm-supplicant-manager.c index 65cb5e20e7..64a057f384 100644 --- a/src/supplicant/nm-supplicant-manager.c +++ b/src/supplicant/nm-supplicant-manager.c @@ -161,6 +161,7 @@ nm_supplicant_manager_create_interface (NMSupplicantManager *self, } iface = nm_supplicant_interface_new (ifname, + NULL, driver, priv->fast_support, priv->ap_support, @@ -183,6 +184,63 @@ nm_supplicant_manager_create_interface (NMSupplicantManager *self, return iface; } +/** + * nm_supplicant_manager_create_interface_from_path: + * @self: the #NMSupplicantManager + * @object_path: the DBus object path for which to obtain the supplicant interface + * + * Note: the manager owns a reference to the instance and the only way to + * get the manager to release it, is by dropping all other references + * to the supplicant-interface (or destroying the manager). + * + * Returns: (transfer full): returns a #NMSupplicantInterface or %NULL. + * Must be unrefed at the end. + * */ +NMSupplicantInterface * +nm_supplicant_manager_create_interface_from_path (NMSupplicantManager *self, + const char *object_path) +{ + NMSupplicantManagerPrivate *priv; + NMSupplicantInterface *iface; + GSList *ifaces; + + g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL); + g_return_val_if_fail (object_path != NULL, NULL); + + priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + + _LOGD ("creating new supplicant interface for dbus path %s", object_path); + + /* assert against not requesting duplicate interfaces. */ + for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) { + if (g_strcmp0 (nm_supplicant_interface_get_object_path (ifaces->data), object_path) == 0) + g_return_val_if_reached (NULL); + } + + iface = nm_supplicant_interface_new (NULL, + object_path, + NM_SUPPLICANT_DRIVER_WIRELESS, + priv->fast_support, + priv->ap_support, + priv->pmf_support, + priv->fils_support, + priv->p2p_support, + priv->wfd_support); + + priv->ifaces = g_slist_prepend (priv->ifaces, iface); + g_object_add_toggle_ref ((GObject *) iface, _sup_iface_last_ref, self); + + /* If we're making the supplicant take a time out for a bit, don't + * let the supplicant interface start immediately, just let it hang + * around in INIT state until we're ready to talk to the supplicant + * again. + */ + if (is_available (self)) + nm_supplicant_interface_set_supplicant_available (iface, TRUE); + + return iface; +} + static void update_capabilities (NMSupplicantManager *self) { diff --git a/src/supplicant/nm-supplicant-manager.h b/src/supplicant/nm-supplicant-manager.h index 8928cf206b..7225a36b58 100644 --- a/src/supplicant/nm-supplicant-manager.h +++ b/src/supplicant/nm-supplicant-manager.h @@ -41,5 +41,7 @@ NMSupplicantManager *nm_supplicant_manager_get (void); NMSupplicantInterface *nm_supplicant_manager_create_interface (NMSupplicantManager *mgr, const char *ifname, NMSupplicantDriver driver); +NMSupplicantInterface *nm_supplicant_manager_create_interface_from_path (NMSupplicantManager *self, + const char *object_path); #endif /* __NETWORKMANAGER_SUPPLICANT_MANAGER_H__ */ From f05b7a78c9aad185e76517eb4d0c6d1c8dd96d73 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 10 Oct 2018 23:08:15 +0200 Subject: [PATCH 6/9] supplicant: Track P2P Group information, creation and destruction Add basic tracking of P2P group information and the creation and destruction of them. --- src/supplicant/nm-supplicant-interface.c | 279 ++++++++++++++++++++++- src/supplicant/nm-supplicant-interface.h | 9 + 2 files changed, 276 insertions(+), 12 deletions(-) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 050c939895..139242094c 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -37,6 +37,7 @@ #define WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE WPAS_DBUS_INTERFACE ".Interface.P2PDevice" #define WPAS_DBUS_IFACE_BSS WPAS_DBUS_INTERFACE ".BSS" #define WPAS_DBUS_IFACE_PEER WPAS_DBUS_INTERFACE ".Peer" +#define WPAS_DBUS_IFACE_GROUP WPAS_DBUS_INTERFACE ".Group" #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" @@ -82,15 +83,18 @@ typedef struct _AddNetworkData { } AddNetworkData; enum { - STATE, /* change in the interface's state */ - REMOVED, /* interface was removed by the supplicant */ - BSS_UPDATED, /* a new BSS appeared or an existing had properties changed */ - BSS_REMOVED, /* supplicant removed BSS from its scan list */ - PEER_UPDATED, /* a new Peer appeared or an existing had properties changed */ - PEER_REMOVED, /* supplicant removed Peer from its scan list */ - SCAN_DONE, /* wifi scan is complete */ - CREDENTIALS_REQUEST, /* 802.1x identity or password requested */ - WPS_CREDENTIALS, /* WPS credentials received */ + STATE, /* change in the interface's state */ + REMOVED, /* interface was removed by the supplicant */ + BSS_UPDATED, /* a new BSS appeared or an existing had properties changed */ + BSS_REMOVED, /* supplicant removed BSS from its scan list */ + PEER_UPDATED, /* a new Peer appeared or an existing had properties changed */ + PEER_REMOVED, /* supplicant removed Peer from its scan list */ + SCAN_DONE, /* wifi scan is complete */ + CREDENTIALS_REQUEST, /* 802.1x identity or password requested */ + WPS_CREDENTIALS, /* WPS credentials received */ + GROUP_STARTED, /* a new Group (interface) was created */ + GROUP_FINISHED, /* a Group (interface) has been finished */ + GROUP_FORMATION_FAILURE, /* P2P Group formation failed */ LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -98,6 +102,8 @@ static guint signals[LAST_SIGNAL] = { 0 }; NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface, PROP_IFACE, PROP_OBJECT_PATH, + PROP_P2P_GROUP_JOINED, + PROP_P2P_GROUP_OWNER, PROP_SCANNING, PROP_CURRENT_BSS, PROP_DRIVER, @@ -137,10 +143,14 @@ typedef struct { GDBusProxy * iface_proxy; GCancellable * other_cancellable; GDBusProxy * p2p_proxy; + GDBusProxy * group_proxy; gboolean p2p_proxy_acquired; + gboolean group_proxy_acquired; gboolean p2p_capable; + gboolean p2p_group_owner; + WpsData *wps_data; AssocData * assoc_data; @@ -705,6 +715,18 @@ iface_check_netreply_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ iface_check_ready (self); } +gboolean +nm_supplicant_interface_get_p2p_group_joined (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->group_proxy_acquired; +} + +gboolean +nm_supplicant_interface_get_p2p_group_owner (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_group_owner; +} + NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self) { @@ -1291,6 +1313,83 @@ props_changed_cb (GDBusProxy *proxy, g_object_thaw_notify (G_OBJECT (self)); } +static void +group_props_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); + char *s; + + g_object_freeze_notify (G_OBJECT (self)); + +#if 0 + v = g_variant_lookup_value (properties, "BSSID", G_VARIANT_TYPE_BYTESTRING); + if (v) { + bytes = g_variant_get_fixed_array (v, &len, 1); + if ( len == ETH_ALEN + && memcmp (bytes, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0 + && memcmp (bytes, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) + nm_wifi_p2p_group_set_bssid_bin (group, bytes); + g_variant_unref (v); + } + + v = g_variant_lookup_value (properties, "SSID", G_VARIANT_TYPE_BYTESTRING); + if (v) { + bytes = g_variant_get_fixed_array (v, &len, 1); + len = MIN (32, len); + + /* Stupid ieee80211 layer uses */ + if ( bytes && len + && !(((len == 8) || (len == 9)) && !memcmp (bytes, "", 8)) + && !nm_utils_is_empty_ssid (bytes, len)) + nm_wifi_p2p_group_set_ssid (group, bytes, len); + + g_variant_unref (v); + } +#endif + + if (g_variant_lookup (changed_properties, "Role", "s", &s)) { + priv->p2p_group_owner = g_strcmp0 (s, "GO") == 0; + _notify (self, PROP_P2P_GROUP_OWNER); + g_free (s); + } + + /* TODO: Members! */ + + g_object_thaw_notify (G_OBJECT (self)); +} + +static void +group_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + gs_free_error GError *error = NULL; + gboolean success; + + success = g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error); + if ( !success + && 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 (!success) { + _LOGD ("failed to acquire Group proxy: (%s)", error->message); + g_clear_object (&priv->group_proxy); + return; + } + + priv->group_proxy_acquired = TRUE; + _notify (self, PROP_P2P_GROUP_JOINED); + + iface_check_ready (self); +} + static void p2p_props_changed_cb (GDBusProxy *proxy, GVariant *changed_properties, @@ -1298,7 +1397,9 @@ p2p_props_changed_cb (GDBusProxy *proxy, gpointer user_data) { NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); const char **array, **iter; + const char *path = NULL; g_object_freeze_notify (G_OBJECT (self)); @@ -1309,6 +1410,41 @@ p2p_props_changed_cb (GDBusProxy *proxy, g_free (array); } + if (g_variant_lookup (changed_properties, "Group", "&o", &path)) { + if (priv->group_proxy && g_strcmp0 (path, g_dbus_proxy_get_object_path (priv->group_proxy)) == 0) { + /* We already have the proxy, nothing to do. */ + } else if (path && g_strcmp0 (path, "/") != 0) { + if (priv->group_proxy != NULL) { + _LOGW ("P2P: Unexpected udpate of the group object path"); + priv->group_proxy_acquired = FALSE; + _notify (self, PROP_P2P_GROUP_JOINED); + g_clear_object (&priv->group_proxy); + } + + /* Delay ready state if we have not reached it yet. */ + if (priv->ready_count) + priv->ready_count++; + + priv->group_proxy = g_object_new (G_TYPE_DBUS_PROXY, + "g-bus-type", G_BUS_TYPE_SYSTEM, + "g-flags", G_DBUS_PROXY_FLAGS_NONE, + "g-name", WPAS_DBUS_SERVICE, + "g-object-path", path, + "g-interface-name", WPAS_DBUS_IFACE_GROUP, + NULL); + g_signal_connect (priv->group_proxy, "g-properties-changed", G_CALLBACK (group_props_changed_cb), self); + g_async_initable_init_async (G_ASYNC_INITABLE (priv->group_proxy), + G_PRIORITY_DEFAULT, + priv->other_cancellable, + (GAsyncReadyCallback) group_proxy_acquired_cb, + self); + } else { + priv->group_proxy_acquired = FALSE; + _notify (self, PROP_P2P_GROUP_JOINED); + g_clear_object (&priv->group_proxy); + } + } + g_object_thaw_notify (G_OBJECT (self)); } @@ -1339,6 +1475,79 @@ p2p_device_lost (GDBusProxy *proxy, peer_data_destroy (peer_data); } +static void +p2p_group_started (GDBusProxy *proxy, + GVariant *params, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantInterface *iface = NULL; + char *group_path = NULL; + char *iface_path = NULL; + + /* There is one more parameter: the role, but we don't really care about that here. */ + if (!g_variant_lookup (params, "group_object", "&o", &group_path)) { + _LOGW ("P2P: GroupStarted signal is missing the \"group_object\" parameter"); + return; + } + + if (!g_variant_lookup (params, "interface_object", "&o", &iface_path)) { + _LOGW ("P2P: GroupStarted signal is missing the \"interface\" parameter"); + return; + } + + if (g_strcmp0 (iface_path, priv->object_path) == 0) { + _LOGW ("P2P: GroupStarted on existing interface"); + iface = g_object_ref (self); + } else { + iface = nm_supplicant_manager_create_interface_from_path (nm_supplicant_manager_get (), + iface_path); + if (iface == NULL) { + _LOGW ("P2P: Group interface already exists in GroupStarted handler, aborting further processing."); + return; + } + } + + /* Signal existance of the (new) interface. */ + g_signal_emit (self, signals[GROUP_STARTED], 0, iface); + g_object_unref (iface); +} + +static void +p2p_group_formation_failure (GDBusProxy *proxy, + const char *group, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + + g_signal_emit (self, signals[GROUP_FORMATION_FAILURE], 0, group); +} + +static void +p2p_group_finished (GDBusProxy *proxy, + GVariant *params, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + const char *iface_path = NULL; + /* TODO: Group finished is called on the management interface! + * This means the signal consumer will currently need to assume which + * interface is finishing or it needs to match the object paths. + */ + + if (!g_variant_lookup (params, "interface_object", "&o", &iface_path)) { + _LOGW ("P2P: GroupFinished signal is missing the \"interface\" parameter"); + return; + } + + _LOGD ("P2P: GroupFinished signal on interface %s for interface %s", priv->object_path, iface_path); + + /* Signal group finish interface (on management interface). */ + g_signal_emit (self, signals[GROUP_FINISHED], 0, iface_path); +} + static void on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { @@ -1449,10 +1658,13 @@ on_p2p_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_da G_CALLBACK (p2p_device_found), self); _nm_dbus_signal_connect (priv->p2p_proxy, "DeviceLost", G_VARIANT_TYPE ("(o)"), G_CALLBACK (p2p_device_lost), self); + _nm_dbus_signal_connect (priv->p2p_proxy, "GroupStarted", G_VARIANT_TYPE ("(a{sv})"), + G_CALLBACK (p2p_group_started), self); + _nm_dbus_signal_connect (priv->p2p_proxy, "GroupFormationFailure", G_VARIANT_TYPE ("(s)"), + G_CALLBACK (p2p_group_formation_failure), self); + _nm_dbus_signal_connect (priv->p2p_proxy, "GroupFinished", G_VARIANT_TYPE ("(a{sv})"), + G_CALLBACK (p2p_group_finished), self); /* TODO: - * * GroupStarted - * * GroupFinished - * * GroupFormationFailure * * WpsFailed * * FindStopped * * GONegotationFailure @@ -2220,6 +2432,12 @@ get_property (GObject *object, case PROP_CURRENT_BSS: g_value_set_string (value, priv->current_bss); break; + case PROP_P2P_GROUP_JOINED: + g_value_set_boolean (value, priv->p2p_capable && priv->group_proxy_acquired); + break; + case PROP_P2P_GROUP_OWNER: + g_value_set_boolean (value, priv->p2p_group_owner); + break; case PROP_P2P_AVAILABLE: g_value_set_boolean (value, priv->p2p_capable && priv->p2p_proxy_acquired); break; @@ -2347,6 +2565,9 @@ dispose (GObject *object) if (priv->p2p_proxy) g_signal_handlers_disconnect_by_data (priv->p2p_proxy, object); g_clear_object (&priv->p2p_proxy); + if (priv->group_proxy) + g_signal_handlers_disconnect_by_data (priv->group_proxy, object); + g_clear_object (&priv->group_proxy); nm_clear_g_cancellable (&priv->init_cancellable); nm_clear_g_cancellable (&priv->other_cancellable); @@ -2396,6 +2617,16 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_P2P_GROUP_JOINED] = + g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED, "", "", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_P2P_GROUP_OWNER] = + g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_P2P_GROUP_OWNER, "", "", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_DRIVER] = g_param_spec_uint (NM_SUPPLICANT_INTERFACE_DRIVER, "", "", 0, G_MAXUINT, NM_SUPPLICANT_DRIVER_WIRELESS, @@ -2529,4 +2760,28 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_VARIANT); + + signals[GROUP_STARTED] = + g_signal_new (NM_SUPPLICANT_INTERFACE_GROUP_STARTED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, NM_TYPE_SUPPLICANT_INTERFACE); + + signals[GROUP_FINISHED] = + g_signal_new (NM_SUPPLICANT_INTERFACE_GROUP_FINISHED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[GROUP_FORMATION_FAILURE] = + g_signal_new (NM_SUPPLICANT_INTERFACE_GROUP_FORMATION_FAILURE, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_VARIANT); } diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index aed72af8bf..6af9798ea7 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -58,6 +58,8 @@ typedef enum { #define NM_SUPPLICANT_INTERFACE_OBJECT_PATH "object-path" #define NM_SUPPLICANT_INTERFACE_SCANNING "scanning" #define NM_SUPPLICANT_INTERFACE_CURRENT_BSS "current-bss" +#define NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED "p2p-group-joined" +#define NM_SUPPLICANT_INTERFACE_P2P_GROUP_OWNER "p2p-group-owner" #define NM_SUPPLICANT_INTERFACE_DRIVER "driver" #define NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE "p2p-available" #define NM_SUPPLICANT_INTERFACE_FAST_SUPPORT "fast-support" @@ -77,6 +79,9 @@ typedef enum { #define NM_SUPPLICANT_INTERFACE_SCAN_DONE "scan-done" #define NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST "credentials-request" #define NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS "wps-credentials" +#define NM_SUPPLICANT_INTERFACE_GROUP_STARTED "group-started" +#define NM_SUPPLICANT_INTERFACE_GROUP_FINISHED "group-finished" +#define NM_SUPPLICANT_INTERFACE_GROUP_FORMATION_FAILURE "group-formation-failure" typedef struct _NMSupplicantInterfaceClass NMSupplicantInterfaceClass; @@ -129,6 +134,10 @@ guint nm_supplicant_interface_get_max_scan_ssids (NMSupplicantInterface *self); gboolean nm_supplicant_interface_get_has_credentials_request (NMSupplicantInterface *self); +gboolean nm_supplicant_interface_get_p2p_group_joined (NMSupplicantInterface *self); + +gboolean nm_supplicant_interface_get_p2p_group_owner (NMSupplicantInterface *self); + gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, const char *field, const char *value, From 6352213e160e764da766f471f2f21097614b925a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 11 Dec 2018 18:21:37 +0100 Subject: [PATCH 7/9] supplicant: Export group path of active group This can be used to check whether a peer is joined to our group. --- src/supplicant/nm-supplicant-interface.c | 29 +++++++++++++++++++++++- src/supplicant/nm-supplicant-interface.h | 3 +++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 139242094c..e09c7814f7 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -103,6 +103,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface, PROP_IFACE, PROP_OBJECT_PATH, PROP_P2P_GROUP_JOINED, + PROP_P2P_GROUP_PATH, PROP_P2P_GROUP_OWNER, PROP_SCANNING, PROP_CURRENT_BSS, @@ -721,6 +722,17 @@ nm_supplicant_interface_get_p2p_group_joined (NMSupplicantInterface *self) return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->group_proxy_acquired; } +const char* +nm_supplicant_interface_get_p2p_group_path (NMSupplicantInterface *self) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + if (priv->group_proxy_acquired) + return g_dbus_proxy_get_object_path (priv->group_proxy); + else + return NULL; +} + gboolean nm_supplicant_interface_get_p2p_group_owner (NMSupplicantInterface *self) { @@ -1357,7 +1369,11 @@ group_props_changed_cb (GDBusProxy *proxy, g_free (s); } - /* TODO: Members! */ + /* NOTE: We do not seem to get any property change notifications for the Members + * property. However, we can keep track of these indirectly either by querying + * the groups that each peer is in or listening to the Join/Disconnect + * notifications. + */ g_object_thaw_notify (G_OBJECT (self)); } @@ -1386,6 +1402,7 @@ group_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ priv->group_proxy_acquired = TRUE; _notify (self, PROP_P2P_GROUP_JOINED); + _notify (self, PROP_P2P_GROUP_PATH); iface_check_ready (self); } @@ -1418,6 +1435,7 @@ p2p_props_changed_cb (GDBusProxy *proxy, _LOGW ("P2P: Unexpected udpate of the group object path"); priv->group_proxy_acquired = FALSE; _notify (self, PROP_P2P_GROUP_JOINED); + _notify (self, PROP_P2P_GROUP_PATH); g_clear_object (&priv->group_proxy); } @@ -1441,6 +1459,7 @@ p2p_props_changed_cb (GDBusProxy *proxy, } else { priv->group_proxy_acquired = FALSE; _notify (self, PROP_P2P_GROUP_JOINED); + _notify (self, PROP_P2P_GROUP_PATH); g_clear_object (&priv->group_proxy); } } @@ -2435,6 +2454,9 @@ get_property (GObject *object, case PROP_P2P_GROUP_JOINED: g_value_set_boolean (value, priv->p2p_capable && priv->group_proxy_acquired); break; + case PROP_P2P_GROUP_PATH: + g_value_set_string (value, nm_supplicant_interface_get_p2p_group_path (NM_SUPPLICANT_INTERFACE (object))); + break; case PROP_P2P_GROUP_OWNER: g_value_set_boolean (value, priv->p2p_group_owner); break; @@ -2622,6 +2644,11 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_P2P_GROUP_PATH] = + g_param_spec_string (NM_SUPPLICANT_INTERFACE_P2P_GROUP_PATH, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_P2P_GROUP_OWNER] = g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_P2P_GROUP_OWNER, "", "", FALSE, diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index 6af9798ea7..d44c002179 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -59,6 +59,7 @@ typedef enum { #define NM_SUPPLICANT_INTERFACE_SCANNING "scanning" #define NM_SUPPLICANT_INTERFACE_CURRENT_BSS "current-bss" #define NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED "p2p-group-joined" +#define NM_SUPPLICANT_INTERFACE_P2P_GROUP_PATH "p2p-group-path" #define NM_SUPPLICANT_INTERFACE_P2P_GROUP_OWNER "p2p-group-owner" #define NM_SUPPLICANT_INTERFACE_DRIVER "driver" #define NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE "p2p-available" @@ -136,6 +137,8 @@ gboolean nm_supplicant_interface_get_has_credentials_request (NMSupplicantInterf gboolean nm_supplicant_interface_get_p2p_group_joined (NMSupplicantInterface *self); +const char* nm_supplicant_interface_get_p2p_group_path (NMSupplicantInterface *self); + gboolean nm_supplicant_interface_get_p2p_group_owner (NMSupplicantInterface *self); gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, From c05aa3b309835b4789ffbe502be82c087a3e4ef9 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 10 Oct 2018 23:14:08 +0200 Subject: [PATCH 8/9] supplicant: Add API to join/cancel/disconnect a P2P Group --- src/supplicant/nm-supplicant-interface.c | 89 ++++++++++++++++++++++++ src/supplicant/nm-supplicant-interface.h | 7 ++ 2 files changed, 96 insertions(+) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index e09c7814f7..6e29df60bd 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -2436,6 +2436,95 @@ nm_supplicant_interface_get_max_scan_ssids (NMSupplicantInterface *self) /*****************************************************************************/ +void +nm_supplicant_interface_p2p_connect (NMSupplicantInterface * self, + const char * peer, + const char * wps_method, + const char * wps_pin) +{ + NMSupplicantInterfacePrivate *priv; + GVariantBuilder builder; + + g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); + + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + /* Don't do anything if there is no connection to the supplicant yet. */ + if (!priv->p2p_proxy || !priv->object_path) + return; + + /* Connect parameters */ + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + + g_variant_builder_add (&builder, "{sv}", "wps_method", g_variant_new_string (wps_method)); + + if (wps_pin) + g_variant_builder_add (&builder, "{sv}", "pin", g_variant_new_string (wps_pin)); + + g_variant_builder_add (&builder, "{sv}", "peer", g_variant_new_object_path (peer)); + + g_variant_builder_add (&builder, "{sv}", "join", g_variant_new_boolean (FALSE)); + g_variant_builder_add (&builder, "{sv}", "persistent", g_variant_new_boolean (FALSE)); + g_variant_builder_add (&builder, "{sv}", "go_intent", g_variant_new_int32 (7)); + + g_dbus_proxy_call (priv->p2p_proxy, + "Connect", + g_variant_new ("(a{sv})", &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->other_cancellable, + (GAsyncReadyCallback) log_result_cb, + "p2p connect"); +} + +void +nm_supplicant_interface_p2p_cancel_connect (NMSupplicantInterface * self) +{ + NMSupplicantInterfacePrivate *priv; + + g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); + + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + /* Don't do anything if there is no connection to the supplicant yet. */ + if (!priv->p2p_proxy || !priv->object_path) + return; + + g_dbus_proxy_call (priv->p2p_proxy, + "Cancel", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->other_cancellable, + (GAsyncReadyCallback) log_result_cb, + "cancel p2p connect"); +} + +void +nm_supplicant_interface_p2p_disconnect (NMSupplicantInterface * self) +{ + NMSupplicantInterfacePrivate *priv; + + g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); + + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + /* Don't do anything if there is no connection to the supplicant. */ + if (!priv->p2p_proxy || !priv->object_path) + return; + + g_dbus_proxy_call (priv->p2p_proxy, + "Disconnect", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->other_cancellable, + (GAsyncReadyCallback) log_result_cb, + "p2p disconnect"); +} + +/*****************************************************************************/ + static void get_property (GObject *object, guint prop_id, diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index d44c002179..b9d1b28393 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -146,6 +146,13 @@ gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, const char *value, GError **error); +void nm_supplicant_interface_p2p_connect (NMSupplicantInterface * self, + const char * peer, + const char * wps_method, + const char * wps_pin); +void nm_supplicant_interface_p2p_cancel_connect (NMSupplicantInterface * self); +void nm_supplicant_interface_p2p_disconnect (NMSupplicantInterface * self); + NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self); NMSupplicantFeature nm_supplicant_interface_get_pmf_support (NMSupplicantInterface *self); NMSupplicantFeature nm_supplicant_interface_get_fils_support (NMSupplicantInterface *self); From 1371414e3d39fb0974db1282a136bb96448e6287 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 15 Oct 2018 15:11:34 +0200 Subject: [PATCH 9/9] supplicant: Add methods to start/stop a P2P Find operation The timeout is limited to be in the range of 1-600s. This is arbitrary, but the point is that a timeout of 0 is not permitted to prevent a client from making us run a find continuously simply by forgetting to call the stop method. --- src/supplicant/nm-supplicant-interface.c | 47 ++++++++++++++++++++++++ src/supplicant/nm-supplicant-interface.h | 4 ++ 2 files changed, 51 insertions(+) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 6e29df60bd..6e4d178a05 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -2436,6 +2436,53 @@ nm_supplicant_interface_get_max_scan_ssids (NMSupplicantInterface *self) /*****************************************************************************/ +void +nm_supplicant_interface_p2p_start_find (NMSupplicantInterface *self, + guint timeout) +{ + NMSupplicantInterfacePrivate *priv; + GVariantBuilder builder; + + g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); + g_return_if_fail (timeout > 0 && timeout <= 600); + + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + /* Find parameters */ + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&builder, "{sv}", "Timeout", g_variant_new_int32 (timeout)); + + g_dbus_proxy_call (priv->p2p_proxy, + "Find", + g_variant_new ("(a{sv})", &builder), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->other_cancellable, + (GAsyncReadyCallback) log_result_cb, + self); +} + +void +nm_supplicant_interface_p2p_stop_find (NMSupplicantInterface *self) +{ + NMSupplicantInterfacePrivate *priv; + + g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); + + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + g_dbus_proxy_call (priv->p2p_proxy, + "StopFind", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->other_cancellable, + (GAsyncReadyCallback) scan_request_cb, + self); +} + +/*****************************************************************************/ + void nm_supplicant_interface_p2p_connect (NMSupplicantInterface * self, const char * peer, diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index b9d1b28393..0aa7732ac4 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -146,6 +146,10 @@ gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, const char *value, GError **error); +void nm_supplicant_interface_p2p_start_find (NMSupplicantInterface *self, + guint timeout); +void nm_supplicant_interface_p2p_stop_find (NMSupplicantInterface *self); + void nm_supplicant_interface_p2p_connect (NMSupplicantInterface * self, const char * peer, const char * wps_method,