summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-01-21 15:05:16 +0100
committerThomas Haller <thaller@redhat.com>2020-03-09 13:51:23 +0100
commitba58aa9c65a741781127b6d6f1ab046000c72f52 (patch)
tree4cb84d03c91e91cbf270a53efcf10217a062fac4
parentb6e61651fd0b49259b26aca721b906ada2959ac5 (diff)
downloadNetworkManager-ba58aa9c65a741781127b6d6f1ab046000c72f52.tar.gz
supplicant: large rework of wpa_supplicant handling
Avoid GDBusProxy, instead use GDBusConnection directly. I very much prefer this because that way we have explicit control over what happens on D-Bus. With GDBusProxy this is hidden under another layer of complex code. The hardest part when using a D-Bus interface is to manage the state via an asynchronous medium. GDBusProxy contains state about the D-Bus interface and duplicate the state that we track. This makes it hard to reason about things. Rework creation of NMSupplicantInterface. Previously, a NMSupplicantInterface had multiple initialization states. In particular, the first state would not yet tie the interface to a certain D-Bus object path. Instead, NMSupplicantInterface would try and retry to create the D-Bus object. Now, NMSupplicantManager has an asynchronous method to create interface instances. The manager only creates an interface instance after the D-Bus path is known. That means, a NMSupplicantInterface instance is now strongly tied to a name-owner and D-Bus path. It follows that the state of NMSupplicantInterface can only go from STARTING, via the supplicant states, to DOWN. Never back. That was already previously the case that the state from DOWN was final and once the 3 initial states were passed, the interface's state would never go back to the initial state. Now this is more strict and more formalized. The 3 initialization states are combined. I think the tighter state handling simplifies users of NMSupplicantInterface. See for example "nm-device-ethernet.c". It's still complicated, because handling state is fundamentally difficult. NMSupplicantManager will take care to D-Bus activate wpa_supplicant only when necessary (poke). Previously, creating the manager instance would always start suppliant service. Now, it's started on demand.
-rw-r--r--src/devices/nm-device-ethernet.c238
-rw-r--r--src/devices/nm-device-macsec.c294
-rw-r--r--src/devices/wifi/nm-device-iwd.c124
-rw-r--r--src/devices/wifi/nm-device-wifi-p2p.c179
-rw-r--r--src/devices/wifi/nm-device-wifi.c311
-rw-r--r--src/devices/wifi/nm-wifi-ap.c295
-rw-r--r--src/devices/wifi/nm-wifi-ap.h12
-rw-r--r--src/devices/wifi/nm-wifi-p2p-peer.c108
-rw-r--r--src/devices/wifi/nm-wifi-p2p-peer.h10
-rw-r--r--src/supplicant/nm-supplicant-interface.c3781
-rw-r--r--src/supplicant/nm-supplicant-interface.h49
-rw-r--r--src/supplicant/nm-supplicant-manager.c1354
-rw-r--r--src/supplicant/nm-supplicant-manager.h36
-rw-r--r--src/supplicant/nm-supplicant-types.h63
14 files changed, 4069 insertions, 2785 deletions
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index c9dd75d6af..0f66fe8680 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -43,6 +43,8 @@ _LOG_DECLARE_SELF(NMDeviceEthernet);
#define PPPOE_RECONNECT_DELAY 7
#define PPPOE_ENCAP_OVERHEAD 8 /* 2 bytes for PPP, 6 for PPPoE */
+#define SUPPLICANT_LNK_TIMEOUT_SEC 15
+
/*****************************************************************************/
typedef enum {
@@ -74,16 +76,17 @@ typedef struct _NMDeviceEthernetPrivate {
struct {
NMSupplicantManager *mgr;
+ NMSupplMgrCreateIfaceHandle *create_handle;
NMSupplicantInterface *iface;
- /* signal handler ids */
gulong iface_state_id;
gulong auth_state_id;
- /* Timeouts and idles */
guint con_timeout_id;
- guint timeout_id;
+ guint lnk_timeout_id;
+
+ bool is_associated:1;
} supplicant;
NMActRequestGetSecretsCallId *wired_secrets_id;
@@ -399,7 +402,9 @@ supplicant_interface_release (NMDeviceEthernet *self)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
- nm_clear_g_source (&priv->supplicant.timeout_id);
+ nm_clear_pointer (&priv->supplicant.create_handle, nm_supplicant_manager_create_interface_cancel);
+
+ nm_clear_g_source (&priv->supplicant.lnk_timeout_id);
nm_clear_g_source (&priv->supplicant.con_timeout_id);
nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_state_id);
nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.auth_state_id);
@@ -537,7 +542,7 @@ wired_secrets_get_secrets (NMDeviceEthernet *self,
}
static gboolean
-link_timeout_cb (gpointer user_data)
+supplicant_lnk_timeout_cb (gpointer user_data)
{
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
@@ -546,13 +551,13 @@ link_timeout_cb (gpointer user_data)
NMConnection *applied_connection;
const char *setting_name;
- priv->supplicant.timeout_id = 0;
+ priv->supplicant.lnk_timeout_id = 0;
req = nm_device_get_act_request (device);
if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) {
wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT);
- return FALSE;
+ return G_SOURCE_REMOVE;
}
/* Disconnect event during initial authentication and credentials
@@ -577,13 +582,13 @@ link_timeout_cb (gpointer user_data)
nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
wired_secrets_get_secrets (self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW);
- return FALSE;
+ return G_SOURCE_REMOVE;
time_out:
_LOGW (LOGD_DEVICE | LOGD_ETHER, "link timed out.");
wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
- return FALSE;
+ return G_SOURCE_REMOVE;
}
static NMSupplicantConfig *
@@ -616,18 +621,86 @@ build_supplicant_config (NMDeviceEthernet *self,
}
static void
+supplicant_iface_state_is_completed (NMDeviceEthernet *self,
+ NMSupplicantInterfaceState state)
+{
+ NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+
+ if (state == NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) {
+ nm_clear_g_source (&priv->supplicant.lnk_timeout_id);
+ nm_clear_g_source (&priv->supplicant.con_timeout_id);
+
+ /* If this is the initial association during device activation,
+ * schedule the next activation stage.
+ */
+ if (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_CONFIG) {
+ _LOGI (LOGD_DEVICE | LOGD_ETHER,
+ "Activation: (ethernet) Stage 2 of 5 (Device Configure) successful.");
+ nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (self));
+ }
+ return;
+ }
+
+ if ( !priv->supplicant.lnk_timeout_id
+ && !priv->supplicant.con_timeout_id)
+ priv->supplicant.lnk_timeout_id = g_timeout_add_seconds (SUPPLICANT_LNK_TIMEOUT_SEC, supplicant_lnk_timeout_cb, self);
+}
+
+static void
supplicant_iface_assoc_cb (NMSupplicantInterface *iface,
GError *error,
gpointer user_data)
{
- NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
+ NMDeviceEthernet *self;
+ NMDeviceEthernetPrivate *priv;
- if (error && !nm_utils_error_is_cancelled_or_disposing (error)) {
+ if (nm_utils_error_is_cancelled_or_disposing (error))
+ return;
+
+ self = NM_DEVICE_ETHERNET (user_data);
+ priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+
+ if (error) {
supplicant_interface_release (self);
nm_device_queue_state (NM_DEVICE (self),
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
+ return;
}
+
+ nm_assert (!priv->supplicant.lnk_timeout_id);
+ nm_assert (!priv->supplicant.is_associated);
+
+ priv->supplicant.is_associated = TRUE;
+ supplicant_iface_state_is_completed (self,
+ nm_supplicant_interface_get_state (priv->supplicant.iface));
+}
+
+static gboolean
+supplicant_iface_start (NMDeviceEthernet *self)
+{
+ NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+ gs_unref_object NMSupplicantConfig *config = NULL;
+ gs_free_error GError *error = NULL;
+
+ config = build_supplicant_config (self, &error);
+ if (!config) {
+ _LOGE (LOGD_DEVICE | LOGD_ETHER,
+ "Activation: (ethernet) couldn't build security configuration: %s",
+ error->message);
+ supplicant_interface_release (self);
+ nm_device_state_changed (NM_DEVICE (self),
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
+ return FALSE;
+ }
+
+ nm_supplicant_interface_disconnect (priv->supplicant.iface);
+ nm_supplicant_interface_assoc (priv->supplicant.iface,
+ config,
+ supplicant_iface_assoc_cb,
+ self);
+ return TRUE;
}
static void
@@ -639,69 +712,26 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
{
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
- NMDevice *device = NM_DEVICE (self);
- NMSupplicantConfig *config;
- NMDeviceState devstate;
- GError *error = NULL;
NMSupplicantInterfaceState new_state = new_state_i;
NMSupplicantInterfaceState old_state = old_state_i;
- if (new_state == old_state)
- return;
-
_LOGI (LOGD_DEVICE | LOGD_ETHER, "supplicant interface state: %s -> %s",
nm_supplicant_interface_state_to_string (old_state),
nm_supplicant_interface_state_to_string (new_state));
- devstate = nm_device_get_state (device);
-
- switch (new_state) {
- case NM_SUPPLICANT_INTERFACE_STATE_READY:
- config = build_supplicant_config (self, &error);
- if (config) {
- nm_supplicant_interface_assoc (priv->supplicant.iface, config,
- supplicant_iface_assoc_cb, self);
- g_object_unref (config);
- } else {
- _LOGE (LOGD_DEVICE | LOGD_ETHER,
- "Activation: (ethernet) couldn't build security configuration: %s",
- error->message);
- g_clear_error (&error);
-
- nm_device_state_changed (device,
- NM_DEVICE_STATE_FAILED,
- NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
- }
- break;
- case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
- nm_clear_g_source (&priv->supplicant.timeout_id);
- nm_clear_g_source (&priv->supplicant.con_timeout_id);
-
- /* If this is the initial association during device activation,
- * schedule the next activation stage.
- */
- if (devstate == NM_DEVICE_STATE_CONFIG) {
- _LOGI (LOGD_DEVICE | LOGD_ETHER,
- "Activation: (ethernet) Stage 2 of 5 (Device Configure) successful.");
- nm_device_activate_schedule_stage3_ip_config_start (device);
- }
- break;
- case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED:
- if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) {
- /* Start the link timeout so we allow some time for reauthentication */
- if (!priv->supplicant.timeout_id)
- priv->supplicant.timeout_id = g_timeout_add_seconds (15, link_timeout_cb, device);
- }
- break;
- case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
+ if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
supplicant_interface_release (self);
+ wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ return;
+ }
- if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device))
- wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
- break;
- default:
- break;
+ if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) {
+ if (!supplicant_iface_start (self))
+ return;
}
+
+ if (priv->supplicant.is_associated)
+ supplicant_iface_state_is_completed (self, new_state);
}
static NMActStageReturn
@@ -770,43 +800,70 @@ supplicant_connection_timeout_cb (gpointer user_data)
if (nm_settings_connection_get_timestamp (connection, &timestamp))
new_secrets = !timestamp;
- if (handle_auth_or_fail (self, req, new_secrets) == NM_ACT_STAGE_RETURN_FAILURE)
+ if (handle_auth_or_fail (self, req, new_secrets) == NM_ACT_STAGE_RETURN_FAILURE) {
wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_NO_SECRETS);
+ return G_SOURCE_REMOVE;
+ }
+
+ if ( !priv->supplicant.lnk_timeout_id
+ && priv->supplicant.iface) {
+ NMSupplicantInterfaceState state;
- return FALSE;
+ state = nm_supplicant_interface_get_state (priv->supplicant.iface);
+ if (state != NM_SUPPLICANT_INTERFACE_STATE_COMPLETED
+ && NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (state))
+ priv->supplicant.lnk_timeout_id = g_timeout_add_seconds (SUPPLICANT_LNK_TIMEOUT_SEC, supplicant_lnk_timeout_cb, self);
+ }
+
+ return G_SOURCE_REMOVE;
}
-static gboolean
-supplicant_interface_init (NMDeviceEthernet *self)
+static void
+supplicant_interface_create_cb (NMSupplicantManager *supplicant_manager,
+ NMSupplMgrCreateIfaceHandle *handle,
+ NMSupplicantInterface *iface,
+ GError *error,
+ gpointer user_data)
{
- NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+ NMDeviceEthernet *self;
+ NMDeviceEthernetPrivate *priv;
guint timeout;
- supplicant_interface_release (self);
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
+ self = user_data;
+ priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
- priv->supplicant.iface = nm_supplicant_manager_create_interface (priv->supplicant.mgr,
- nm_device_get_iface (NM_DEVICE (self)),
- NM_SUPPLICANT_DRIVER_WIRED);
+ nm_assert (priv->supplicant.create_handle == handle);
+ priv->supplicant.create_handle = NULL;
- if (!priv->supplicant.iface) {
+ if (error) {
_LOGE (LOGD_DEVICE | LOGD_ETHER,
- "Couldn't initialize supplicant interface");
- return FALSE;
+ "Couldn't initialize supplicant interface: %s",
+ error->message);
+ supplicant_interface_release (self);
+ nm_device_state_changed (NM_DEVICE (self),
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ return;
}
- /* Listen for its state signals */
+ priv->supplicant.iface = g_object_ref (iface);
+ priv->supplicant.is_associated = FALSE;
+
priv->supplicant.iface_state_id = g_signal_connect (priv->supplicant.iface,
NM_SUPPLICANT_INTERFACE_STATE,
G_CALLBACK (supplicant_iface_state_cb),
self);
- /* Set up a timeout on the connection attempt */
timeout = nm_device_get_supplicant_timeout (NM_DEVICE (self));
priv->supplicant.con_timeout_id = g_timeout_add_seconds (timeout,
supplicant_connection_timeout_cb,
self);
- return TRUE;
+ if (NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (nm_supplicant_interface_get_state (iface)))
+ supplicant_iface_start (self);
}
static NMPlatformLinkDuplexType
@@ -973,18 +1030,21 @@ supplicant_check_secrets_needed (NMDeviceEthernet *self, NMDeviceStateReason *ou
ret = handle_auth_or_fail (self, req, FALSE);
if (ret != NM_ACT_STAGE_RETURN_POSTPONE)
NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS);
- } else {
- _LOGI (LOGD_DEVICE | LOGD_ETHER,
- "Activation: (ethernet) connection '%s' requires no security. No secrets needed.",
- nm_connection_get_id (connection));
-
- if (supplicant_interface_init (self))
- ret = NM_ACT_STAGE_RETURN_POSTPONE;
- else
- NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+ return ret;
}
- return ret;
+ _LOGI (LOGD_DEVICE | LOGD_ETHER,
+ "Activation: (ethernet) connection '%s' requires no security. No secrets needed.",
+ nm_connection_get_id (connection));
+
+ supplicant_interface_release (self);
+
+ priv->supplicant.create_handle = nm_supplicant_manager_create_interface (priv->supplicant.mgr,
+ nm_device_get_ifindex (NM_DEVICE (self)),
+ NM_SUPPLICANT_DRIVER_WIRED,
+ supplicant_interface_create_cb,
+ self);
+ return NM_ACT_STAGE_RETURN_POSTPONE;
}
static void
diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c
index fb18736703..bf8c6c7898 100644
--- a/src/devices/nm-device-macsec.c
+++ b/src/devices/nm-device-macsec.c
@@ -23,6 +23,10 @@ _LOG_DECLARE_SELF(NMDeviceMacsec);
/*****************************************************************************/
+#define SUPPLICANT_LNK_TIMEOUT_SEC 15
+
+/*****************************************************************************/
+
NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceMacsec,
PROP_SCI,
PROP_CIPHER_SUITE,
@@ -45,16 +49,17 @@ typedef struct {
struct {
NMSupplicantManager *mgr;
+ NMSupplMgrCreateIfaceHandle *create_handle;
NMSupplicantInterface *iface;
- /* signal handler ids */
gulong iface_state_id;
- /* Timeouts and idles */
guint con_timeout_id;
+ guint lnk_timeout_id;
+
+ bool is_associated:1;
} supplicant;
- guint supplicant_timeout_id;
NMActRequestGetSecretsCallId *macsec_secrets_id;
} NMDeviceMacsecPrivate;
@@ -254,7 +259,9 @@ supplicant_interface_release (NMDeviceMacsec *self)
{
NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
- nm_clear_g_source (&priv->supplicant_timeout_id);
+ nm_clear_pointer (&priv->supplicant.create_handle, nm_supplicant_manager_create_interface_cancel);
+
+ nm_clear_g_source (&priv->supplicant.lnk_timeout_id);
nm_clear_g_source (&priv->supplicant.con_timeout_id);
nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_state_id);
@@ -265,21 +272,6 @@ supplicant_interface_release (NMDeviceMacsec *self)
}
static void
-supplicant_iface_assoc_cb (NMSupplicantInterface *iface,
- GError *error,
- gpointer user_data)
-{
- NMDeviceMacsec *self = NM_DEVICE_MACSEC (user_data);
-
- if (error && !nm_utils_error_is_cancelled_or_disposing (error)) {
- supplicant_interface_release (self);
- nm_device_queue_state (NM_DEVICE (self),
- NM_DEVICE_STATE_FAILED,
- NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
- }
-}
-
-static void
macsec_secrets_cb (NMActRequest *req,
NMActRequestGetSecretsCallId *call_id,
NMSettingsConnection *connection,
@@ -351,7 +343,7 @@ macsec_secrets_get_secrets (NMDeviceMacsec *self,
}
static gboolean
-link_timeout_cb (gpointer user_data)
+supplicant_lnk_timeout_cb (gpointer user_data)
{
NMDeviceMacsec *self = NM_DEVICE_MACSEC (user_data);
NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
@@ -360,7 +352,7 @@ link_timeout_cb (gpointer user_data)
NMConnection *applied_connection;
const char *setting_name;
- priv->supplicant_timeout_id = 0;
+ priv->supplicant.lnk_timeout_id = 0;
req = nm_device_get_act_request (dev);
@@ -368,7 +360,7 @@ link_timeout_cb (gpointer user_data)
nm_device_state_changed (dev,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT);
- return FALSE;
+ return G_SOURCE_REMOVE;
}
/* Disconnect event during initial authentication and credentials
@@ -392,13 +384,98 @@ link_timeout_cb (gpointer user_data)
nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
macsec_secrets_get_secrets (self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW);
- return FALSE;
+ return G_SOURCE_REMOVE;
time_out:
_LOGW (LOGD_DEVICE | LOGD_ETHER, "link timed out.");
nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
- return FALSE;
+ return G_SOURCE_REMOVE;
+}
+
+static void
+supplicant_iface_state_is_completed (NMDeviceMacsec *self,
+ NMSupplicantInterfaceState state)
+{
+ NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
+
+ if (state == NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) {
+ nm_clear_g_source (&priv->supplicant.lnk_timeout_id);
+ nm_clear_g_source (&priv->supplicant.con_timeout_id);
+
+ nm_device_bring_up (NM_DEVICE (self), TRUE, NULL);
+
+ /* If this is the initial association during device activation,
+ * schedule the next activation stage.
+ */
+ if (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_CONFIG) {
+ _LOGI (LOGD_DEVICE,
+ "Activation: Stage 2 of 5 (Device Configure) successful.");
+ nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (self));
+ }
+ return;
+ }
+
+ if ( !priv->supplicant.lnk_timeout_id
+ && !priv->supplicant.con_timeout_id)
+ priv->supplicant.lnk_timeout_id = g_timeout_add_seconds (SUPPLICANT_LNK_TIMEOUT_SEC, supplicant_lnk_timeout_cb, self);
+}
+
+static void
+supplicant_iface_assoc_cb (NMSupplicantInterface *iface,
+ GError *error,
+ gpointer user_data)
+{
+ NMDeviceMacsec *self;
+ NMDeviceMacsecPrivate *priv;
+
+ if (nm_utils_error_is_cancelled_or_disposing (error))
+ return;
+
+ self = user_data;
+ priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
+
+ if (error) {
+ supplicant_interface_release (self);
+ nm_device_queue_state (NM_DEVICE (self),
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
+ return;
+ }
+
+ nm_assert (!priv->supplicant.lnk_timeout_id);
+ nm_assert (!priv->supplicant.is_associated);
+
+ priv->supplicant.is_associated = TRUE;
+ supplicant_iface_state_is_completed (self,
+ nm_supplicant_interface_get_state (priv->supplicant.iface));
+}
+
+static gboolean
+supplicant_iface_start (NMDeviceMacsec *self)
+{
+ NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
+ gs_unref_object NMSupplicantConfig *config = NULL;
+ gs_free_error GError *error = NULL;
+
+ config = build_supplicant_config (self, &error);
+ if (!config) {
+ _LOGE (LOGD_DEVICE,
+ "Activation: couldn't build security configuration: %s",
+ error->message);
+ supplicant_interface_release (self);
+ nm_device_state_changed (NM_DEVICE (self),
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
+ return FALSE;
+ }
+
+ nm_supplicant_interface_disconnect (priv->supplicant.iface);
+ nm_supplicant_interface_assoc (priv->supplicant.iface,
+ config,
+ supplicant_iface_assoc_cb,
+ self);
+ return TRUE;
}
static void
@@ -410,73 +487,28 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
{
NMDeviceMacsec *self = NM_DEVICE_MACSEC (user_data);
NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
- NMDevice *device = NM_DEVICE (self);
- NMSupplicantConfig *config;
- NMDeviceState devstate;
- GError *error = NULL;
NMSupplicantInterfaceState new_state = new_state_i;
NMSupplicantInterfaceState old_state = old_state_i;
- if (new_state == old_state)
- return;
-
_LOGI (LOGD_DEVICE, "supplicant interface state: %s -> %s",
nm_supplicant_interface_state_to_string (old_state),
nm_supplicant_interface_state_to_string (new_state));
- devstate = nm_device_get_state (device);
-
- switch (new_state) {
- case NM_SUPPLICANT_INTERFACE_STATE_READY:
- config = build_supplicant_config (self, &error);
- if (config) {
- nm_supplicant_interface_assoc (priv->supplicant.iface, config,
- supplicant_iface_assoc_cb, self);
- g_object_unref (config);
- } else {
- _LOGE (LOGD_DEVICE,
- "Activation: couldn't build security configuration: %s",
- error->message);
- g_clear_error (&error);
-
- nm_device_state_changed (device,
- NM_DEVICE_STATE_FAILED,
- NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
- }
- break;
- case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
- nm_clear_g_source (&priv->supplicant_timeout_id);
- nm_clear_g_source (&priv->supplicant.con_timeout_id);
- nm_device_bring_up (device, TRUE, NULL);
-
- /* If this is the initial association during device activation,
- * schedule the next activation stage.
- */
- if (devstate == NM_DEVICE_STATE_CONFIG) {
- _LOGI (LOGD_DEVICE,
- "Activation: Stage 2 of 5 (Device Configure) successful.");
- nm_device_activate_schedule_stage3_ip_config_start (device);
- }
- break;
- case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED:
- if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) {
- /* Start the link timeout so we allow some time for reauthentication */
- if (!priv->supplicant_timeout_id)
- priv->supplicant_timeout_id = g_timeout_add_seconds (15, link_timeout_cb, device);
- }
- break;
- case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
+ if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
supplicant_interface_release (self);
+ nm_device_state_changed (NM_DEVICE (self),
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ return;
+ }
- if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) {
- nm_device_state_changed (device,
- NM_DEVICE_STATE_FAILED,
- NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
- }
- break;
- default:
- ;
+ if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) {
+ if (!supplicant_iface_start (self))
+ return;
}
+
+ if (priv->supplicant.is_associated)
+ supplicant_iface_state_is_completed (self, new_state);
}
static NMActStageReturn
@@ -527,11 +559,10 @@ supplicant_connection_timeout_cb (gpointer user_data)
"Activation: (macsec) association took too long.");
supplicant_interface_release (self);
- req = nm_device_get_act_request (device);
- g_assert (req);
+ req = nm_device_get_act_request (device);
connection = nm_act_request_get_settings_connection (req);
- g_assert (connection);
+ g_return_val_if_fail (connection, G_SOURCE_REMOVE);
/* Ask for new secrets only if we've never activated this connection
* before. If we've connected before, don't bother the user with dialogs,
@@ -540,48 +571,73 @@ supplicant_connection_timeout_cb (gpointer user_data)
if (nm_settings_connection_get_timestamp (connection, &timestamp))
new_secrets = !timestamp;
- if (handle_auth_or_fail (self, req, new_secrets) == NM_ACT_STAGE_RETURN_POSTPONE)
- _LOGW (LOGD_DEVICE, "Activation: (macsec) asking for new secrets");
- else
+ if (handle_auth_or_fail (self, req, new_secrets) != NM_ACT_STAGE_RETURN_POSTPONE) {
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS);
+ return G_SOURCE_REMOVE;
+ }
- return FALSE;
+ _LOGW (LOGD_DEVICE, "Activation: (macsec) asking for new secrets");
+
+ if ( !priv->supplicant.lnk_timeout_id
+ && priv->supplicant.iface) {
+ NMSupplicantInterfaceState state;
+
+ state = nm_supplicant_interface_get_state (priv->supplicant.iface);
+ if (state != NM_SUPPLICANT_INTERFACE_STATE_COMPLETED
+ && NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (state))
+ priv->supplicant.lnk_timeout_id = g_timeout_add_seconds (SUPPLICANT_LNK_TIMEOUT_SEC, supplicant_lnk_timeout_cb, self);
+ }
+
+ return G_SOURCE_REMOVE;
}
-static gboolean
-supplicant_interface_init (NMDeviceMacsec *self)
+static void
+supplicant_interface_create_cb (NMSupplicantManager *supplicant_manager,
+ NMSupplMgrCreateIfaceHandle *handle,
+ NMSupplicantInterface *iface,
+ GError *error,
+ gpointer user_data)
{
- NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
- NMDevice *parent;
+ NMDeviceMacsec *self;
+ NMDeviceMacsecPrivate *priv;
guint timeout;
- parent = nm_device_parent_get_device (NM_DEVICE (self));
- g_return_val_if_fail (parent, FALSE);
+ if (nm_utils_error_is_cancelled (error))
+ return;
- supplicant_interface_release (self);
+ self = user_data;
+ priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
+
+ nm_assert (priv->supplicant.create_handle == handle);
- priv->supplicant.iface = nm_supplicant_manager_create_interface (priv->supplicant.mgr,
- nm_device_get_iface (parent),
- NM_SUPPLICANT_DRIVER_MACSEC);
+ priv->supplicant.create_handle = NULL;
- if (!priv->supplicant.iface) {
+ if (error) {
_LOGE (LOGD_DEVICE,
- "Couldn't initialize supplicant interface");
- return FALSE;
+ "Couldn't initialize supplicant interface: %s",
+ error->message);
+ supplicant_interface_release (self);
+ nm_device_state_changed (NM_DEVICE (self),
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ return;
}
- /* Listen for its state signals */
+ priv->supplicant.iface = g_object_ref (iface);
+ priv->supplicant.is_associated = FALSE;
+
priv->supplicant.iface_state_id = g_signal_connect (priv->supplicant.iface,
NM_SUPPLICANT_INTERFACE_STATE,
G_CALLBACK (supplicant_iface_state_cb),
self);
- /* Set up a timeout on the connection attempt */
timeout = nm_device_get_supplicant_timeout (NM_DEVICE (self));
priv->supplicant.con_timeout_id = g_timeout_add_seconds (timeout,
supplicant_connection_timeout_cb,
self);
- return TRUE;
+
+ if (NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (nm_supplicant_interface_get_state (iface)))
+ supplicant_iface_start (self);
}
static NMActStageReturn
@@ -591,7 +647,9 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
NMConnection *connection;
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
+ NMDevice *parent;
const char *setting_name;
+ int ifindex;
connection = nm_device_get_applied_connection (NM_DEVICE (self));
@@ -612,18 +670,26 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
ret = handle_auth_or_fail (self, req, FALSE);
if (ret != NM_ACT_STAGE_RETURN_POSTPONE)
NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS);
- } else {
- _LOGI (LOGD_DEVICE | LOGD_ETHER,
- "Activation: connection '%s' requires no security. No secrets needed.",
- nm_connection_get_id (connection));
-
- if (supplicant_interface_init (self))
- ret = NM_ACT_STAGE_RETURN_POSTPONE;
- else
- NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+ return ret;
}
- return ret;
+ _LOGI (LOGD_DEVICE | LOGD_ETHER,
+ "Activation: connection '%s' requires no security. No secrets needed.",
+ nm_connection_get_id (connection));
+
+ supplicant_interface_release (self);
+
+ parent = nm_device_parent_get_device (NM_DEVICE (self));
+ g_return_val_if_fail (parent, NM_ACT_STAGE_RETURN_FAILURE);
+ ifindex = nm_device_get_ifindex (parent);
+ g_return_val_if_fail (ifindex > 0, NM_ACT_STAGE_RETURN_FAILURE);
+
+ priv->supplicant.create_handle = nm_supplicant_manager_create_interface (priv->supplicant.mgr,
+ ifindex,
+ NM_SUPPLICANT_DRIVER_MACSEC,
+ supplicant_interface_create_cb,
+ self);
+ return NM_ACT_STAGE_RETURN_POSTPONE;
}
static void
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index b504c9bc90..0cf7f5125d 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -7,24 +7,26 @@
#include "nm-device-iwd.h"
-#include "nm-libnm-core-intern/nm-common-macros.h"
-#include "devices/nm-device.h"
#include "devices/nm-device-private.h"
-#include "nm-utils.h"
+#include "devices/nm-device.h"
#include "nm-act-request.h"
+#include "nm-config.h"
+#include "nm-core-internal.h"
+#include "nm-dbus-manager.h"
+#include "nm-glib-aux/nm-ref-string.h"
+#include "nm-iwd-manager.h"
+#include "nm-libnm-core-intern/nm-common-macros.h"
+#include "nm-setting-8021x.h"
#include "nm-setting-connection.h"
-#include "nm-setting-wireless.h"
#include "nm-setting-wireless-security.h"
-#include "nm-setting-8021x.h"
+#include "nm-setting-wireless.h"
+#include "nm-std-aux/nm-dbus-compat.h"
+#include "nm-utils.h"
+#include "nm-wifi-common.h"
+#include "nm-wifi-utils.h"
#include "settings/nm-settings-connection.h"
#include "settings/nm-settings.h"
-#include "nm-wifi-utils.h"
-#include "nm-wifi-common.h"
-#include "nm-core-internal.h"
-#include "nm-config.h"
-#include "nm-iwd-manager.h"
-#include "nm-dbus-manager.h"
-#include "nm-std-aux/nm-dbus-compat.h"
+#include "supplicant/nm-supplicant-types.h"
#include "devices/nm-device-logging.h"
_LOG_DECLARE_SELF(NMDeviceIwd);
@@ -191,45 +193,41 @@ remove_all_aps (NMDeviceIwd *self)
nm_device_recheck_available_connections (NM_DEVICE (self));
}
-static GVariant *
-vardict_from_network_type (const char *type)
+static NM80211ApSecurityFlags
+ap_security_flags_from_network_type (const char *type)
{
- GVariantBuilder builder;
- const char *key_mgmt = "";
- const char *pairwise = "ccmp";
+ NM80211ApSecurityFlags flags;
- if (!strcmp (type, "psk"))
- key_mgmt = "wpa-psk";
- else if (!strcmp (type, "8021x"))
- key_mgmt = "wpa-eap";
+ if (nm_streq (type, "psk"))
+ flags = NM_802_11_AP_SEC_KEY_MGMT_PSK;
+ else if (nm_streq (type, "8021x"))
+ flags = NM_802_11_AP_SEC_KEY_MGMT_802_1X;
else
- return NULL;
+ return NM_802_11_AP_SEC_NONE;
- g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add (&builder, "{sv}", "KeyMgmt",
- g_variant_new_strv (&key_mgmt, 1));
- g_variant_builder_add (&builder, "{sv}", "Pairwise",
- g_variant_new_strv (&pairwise, 1));
- g_variant_builder_add (&builder, "{sv}", "Group",
- g_variant_new_string ("ccmp"));
- return g_variant_new ("a{sv}", &builder);
+ flags |= NM_802_11_AP_SEC_PAIR_CCMP;
+ flags |= NM_802_11_AP_SEC_GROUP_CCMP;
+ return flags;
}
static void
insert_ap_from_network (NMDeviceIwd *self,
GHashTable *aps,
const char *path,
+ gint64 last_seen_msec,
int16_t signal,
uint32_t ap_id)
{
gs_unref_object GDBusProxy *network_proxy = NULL;
- gs_unref_variant GVariant *name_value = NULL, *type_value = NULL;
- const char *name, *type;
- GVariantBuilder builder;
- gs_unref_variant GVariant *props = NULL;
- GVariant *rsn;
+ gs_unref_variant GVariant *name_value = NULL;
+ gs_unref_variant GVariant *type_value = NULL;
+ nm_auto_ref_string NMRefString *bss_path = NULL;
+ const char *name;
+ const char *type;
+ NMSupplicantBssInfo bss_info;
uint8_t bssid[6];
NMWifiAP *ap;
+ gs_unref_bytes GBytes *ssid = NULL;
if (g_hash_table_lookup (aps, path)) {
_LOGD (LOGD_WIFI, "Duplicate network at %s", path);
@@ -253,6 +251,11 @@ insert_ap_from_network (NMDeviceIwd *self,
name = g_variant_get_string (name_value, NULL);
type = g_variant_get_string (type_value, NULL);
+ if (nm_streq (type, "wep")) {
+ /* WEP not supported */
+ return;
+ }
+
/* What we get from IWD are networks, or ESSs, that may contain
* multiple APs, or BSSs, each. We don't get information about any
* specific BSSs within an ESS but we can safely present each ESS
@@ -268,31 +271,24 @@ insert_ap_from_network (NMDeviceIwd *self,
bssid[4] = ap_id >> 8;
bssid[5] = ap_id;
- /* WEP not supported */
- if (nm_streq (type, "wep"))
- return;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add (&builder, "{sv}", "BSSID",
- g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid, 6, 1));
- g_variant_builder_add (&builder, "{sv}", "Mode",
- g_variant_new_string ("infrastructure"));
-
- rsn = vardict_from_network_type (type);
- if (rsn)
- g_variant_builder_add (&builder, "{sv}", "RSN", rsn);
-
- props = g_variant_new ("a{sv}", &builder);
+ ssid = g_bytes_new (name, NM_MIN (32u, strlen (name)));
+ bss_path = nm_ref_string_new (path);
- ap = nm_wifi_ap_new_from_properties (path, props);
+ bss_info = (NMSupplicantBssInfo) {
+ .bss_path = bss_path,
+ .last_seen_msec = last_seen_msec,
+ .bssid_valid = TRUE,
+ .mode = NM_802_11_MODE_INFRA,
+ .rsn_flags = ap_security_flags_from_network_type (type),
+ .ssid = ssid,
+ .signal_percent = nm_wifi_utils_level_to_quality (signal / 100),
+ .frequency = 2417,
+ .max_rate = 65000,
+ };
+ memcpy (bss_info.bssid, bssid, sizeof (bssid));
- nm_wifi_ap_set_ssid_arr (ap,
- (const guint8 *) name,
- NM_MIN (32, strlen (name)));
+ ap = nm_wifi_ap_new_from_properties (&bss_info);
- nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (signal / 100));
- nm_wifi_ap_set_freq (ap, 2417);
- nm_wifi_ap_set_max_bitrate (ap, 65000);
g_hash_table_insert (aps, (gpointer) nm_wifi_ap_get_supplicant_path (ap), ap);
}
@@ -313,6 +309,7 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data)
gboolean compat;
const char *return_sig;
static uint32_t ap_id = 0;
+ gint64 last_seen_msec;
variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error);
if (!variant) {
@@ -340,12 +337,13 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data)
g_variant_get (variant, return_sig, &networks);
+ last_seen_msec = nm_utils_get_monotonic_timestamp_msec ();
if (compat) {
while (g_variant_iter_next (networks, "(&o&sn&s)", &path, &name, &signal, &type))
- insert_ap_from_network (self, new_aps, path, signal, ap_id++);
+ insert_ap_from_network (self, new_aps, path, last_seen_msec, signal, ap_id++);
} else {
while (g_variant_iter_next (networks, "(&on)", &path, &signal))
- insert_ap_from_network (self, new_aps, path, signal, ap_id++);
+ insert_ap_from_network (self, new_aps, path, last_seen_msec, signal, ap_id++);
}
g_variant_iter_free (networks);
@@ -1148,7 +1146,7 @@ try_reply_agent_request (NMDeviceIwd *self,
*replied = FALSE;
- if (!strcmp (method_name, "RequestPassphrase")) {
+ if (nm_streq (method_name, "RequestPassphrase")) {
const char *psk;
if (!s_wireless_sec)
@@ -1168,7 +1166,7 @@ try_reply_agent_request (NMDeviceIwd *self,
*setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
*setting_key = NM_SETTING_WIRELESS_SECURITY_PSK;
return TRUE;
- } else if (!strcmp (method_name, "RequestPrivateKeyPassphrase")) {
+ } else if (nm_streq (method_name, "RequestPrivateKeyPassphrase")) {
const char *password;
if (!s_8021x)
@@ -1188,7 +1186,7 @@ try_reply_agent_request (NMDeviceIwd *self,
*setting_name = NM_SETTING_802_1X_SETTING_NAME;
*setting_key = NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD;
return TRUE;
- } else if (!strcmp (method_name, "RequestUserNameAndPassword")) {
+ } else if (nm_streq (method_name, "RequestUserNameAndPassword")) {
const char *identity, *password;
if (!s_8021x)
@@ -1212,7 +1210,7 @@ try_reply_agent_request (NMDeviceIwd *self,
else
*setting_key = NM_SETTING_802_1X_PASSWORD;
return TRUE;
- } else if (!strcmp (method_name, "RequestUserPassword")) {
+ } else if (nm_streq (method_name, "RequestUserPassword")) {
const char *password;
if (!s_8021x)
diff --git a/src/devices/wifi/nm-device-wifi-p2p.c b/src/devices/wifi/nm-device-wifi-p2p.c
index e3860ebf2f..08c904dd4c 100644
--- a/src/devices/wifi/nm-device-wifi-p2p.c
+++ b/src/devices/wifi/nm-device-wifi-p2p.c
@@ -12,19 +12,20 @@
#include "supplicant/nm-supplicant-manager.h"
#include "supplicant/nm-supplicant-interface.h"
-#include "nm-manager.h"
-#include "nm-utils.h"
-#include "nm-wifi-p2p-peer.h"
#include "NetworkManagerUtils.h"
#include "devices/nm-device-private.h"
-#include "settings/nm-settings.h"
-#include "nm-setting-wifi-p2p.h"
#include "nm-act-request.h"
+#include "nm-core-internal.h"
+#include "nm-glib-aux/nm-ref-string.h"
#include "nm-ip4-config.h"
-#include "platform/nm-platform.h"
#include "nm-manager.h"
-#include "nm-core-internal.h"
+#include "nm-manager.h"
+#include "nm-setting-wifi-p2p.h"
+#include "nm-utils.h"
+#include "nm-wifi-p2p-peer.h"
+#include "platform/nm-platform.h"
#include "platform/nmp-object.h"
+#include "settings/nm-settings.h"
#include "devices/nm-device-logging.h"
_LOG_DECLARE_SELF(NMDeviceWifiP2P);
@@ -227,11 +228,7 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
return FALSE;
supplicant_state = nm_supplicant_interface_get_state (priv->mgmt_iface);
- if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_READY
- || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED)
- return FALSE;
-
- return TRUE;
+ return NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (supplicant_state);
}
static gboolean
@@ -649,52 +646,49 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
NMSupplicantInterfaceState new_state = new_state_i;
NMSupplicantInterfaceState old_state = old_state_i;
- if (new_state == old_state)
- return;
-
_LOGI (LOGD_DEVICE | LOGD_WIFI,
"supplicant management interface state: %s -> %s",
nm_supplicant_interface_state_to_string (old_state),
nm_supplicant_interface_state_to_string (new_state));
- switch (new_state) {
- case NM_SUPPLICANT_INTERFACE_STATE_READY:
- _LOGD (LOGD_WIFI, "supplicant ready");
+ if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
+ supplicant_interfaces_release (self, TRUE);
nm_device_queue_recheck_available (device,
NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ return;
+ }
- if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY)
- _set_is_waiting_for_supplicant (self, FALSE);
- break;
- case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
- supplicant_interfaces_release (self, TRUE);
+ if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) {
+ _LOGD (LOGD_WIFI, "supplicant ready");
nm_device_queue_recheck_available (device,
NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
- break;
- default:
- break;
+ _set_is_waiting_for_supplicant (self, FALSE);
}
}
static void
-supplicant_iface_peer_updated_cb (NMSupplicantInterface *iface,
- const char *object_path,
- GVariant *properties,
+supplicant_iface_peer_changed_cb (NMSupplicantInterface *iface,
+ NMSupplicantPeerInfo *peer_info,
+ gboolean is_present,
NMDeviceWifiP2P *self)
{
- NMDeviceWifiP2PPrivate *priv;
+ NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self);
NMWifiP2PPeer *found_peer;
- g_return_if_fail (self != NULL);
- g_return_if_fail (object_path != NULL);
+ found_peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, peer_info->peer_path->str);
- priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self);
+ if (!is_present) {
+ if (!found_peer)
+ return;
+
+ peer_add_remove (self, FALSE, found_peer, TRUE);
+ goto out;
+ }
- found_peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, object_path);
if (found_peer) {
- if (!nm_wifi_p2p_peer_update_from_properties (found_peer, object_path, properties))
+ if (!nm_wifi_p2p_peer_update_from_properties (found_peer, peer_info))
return;
update_disconnect_on_connection_peer_missing (self);
@@ -702,35 +696,11 @@ supplicant_iface_peer_updated_cb (NMSupplicantInterface *iface,
} else {
gs_unref_object NMWifiP2PPeer *peer = NULL;
- peer = nm_wifi_p2p_peer_new_from_properties (object_path, properties);
- if (!peer) {
- _LOGD (LOGD_WIFI, "invalid P2P peer properties received for %s", object_path);
- return;
- }
-
+ peer = nm_wifi_p2p_peer_new_from_properties (peer_info);
peer_add_remove (self, TRUE, peer, TRUE);
}
- schedule_peer_list_dump (self);
-}
-
-static void
-supplicant_iface_peer_removed_cb (NMSupplicantInterface *iface,
- const char *object_path,
- NMDeviceWifiP2P *self)
-{
- NMDeviceWifiP2PPrivate *priv;
- NMWifiP2PPeer *peer;
-
- g_return_if_fail (self != NULL);
- g_return_if_fail (object_path != NULL);
-
- priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self);
- peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, object_path);
- if (!peer)
- return;
-
- peer_add_remove (self, FALSE, peer, TRUE);
+out:
schedule_peer_list_dump (self);
}
@@ -742,7 +712,7 @@ check_group_iface_ready (NMDeviceWifiP2P *self)
if (!priv->group_iface)
return;
- if (nm_supplicant_interface_get_state (priv->group_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ if (!NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (nm_supplicant_interface_get_state (priv->group_iface)))
return;
if (!nm_supplicant_interface_get_p2p_group_joined (priv->group_iface))
@@ -755,6 +725,24 @@ check_group_iface_ready (NMDeviceWifiP2P *self)
}
static void
+supplicant_group_iface_is_ready (NMDeviceWifiP2P *self)
+{
+ NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self);
+
+ _LOGD (LOGD_WIFI, "P2P Group supplicant ready");
+
+ if (!nm_device_set_ip_iface (NM_DEVICE (self), nm_supplicant_interface_get_ifname (priv->group_iface))) {
+ nm_device_state_changed (NM_DEVICE (self),
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ return;
+ }
+
+ _set_is_waiting_for_supplicant (self, FALSE);
+ check_group_iface_ready (self);
+}
+
+static void
supplicant_group_iface_state_cb (NMSupplicantInterface *iface,
int new_state_i,
int old_state_i,
@@ -762,44 +750,26 @@ supplicant_group_iface_state_cb (NMSupplicantInterface *iface,
gpointer user_data)
{
NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data);
- NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self);
- NMDevice *device = NM_DEVICE (self);
NMSupplicantInterfaceState new_state = new_state_i;
NMSupplicantInterfaceState old_state = old_state_i;
- if (new_state == old_state)
- return;
-
_LOGI (LOGD_DEVICE | LOGD_WIFI,
"P2P Group supplicant interface state: %s -> %s",
nm_supplicant_interface_state_to_string (old_state),
nm_supplicant_interface_state_to_string (new_state));
- switch (new_state) {
- case NM_SUPPLICANT_INTERFACE_STATE_READY:
- _LOGD (LOGD_WIFI, "P2P Group supplicant ready");
-
- if (!nm_device_set_ip_iface (device, nm_supplicant_interface_get_ifname (priv->group_iface))) {
- nm_device_state_changed (device,
- NM_DEVICE_STATE_FAILED,
- NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
- break;
- }
-
- if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY)
- _set_is_waiting_for_supplicant (self, FALSE);
-
- check_group_iface_ready (self);
- break;
- case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
+ if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
supplicant_group_interface_release (self);
- nm_device_state_changed (device,
+ nm_device_state_changed (NM_DEVICE (self),
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
- break;
- default:
- break;
+ return;
+ }
+
+ if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) {
+ supplicant_group_iface_is_ready (self);
+ return;
}
}
@@ -833,8 +803,9 @@ supplicant_iface_group_started_cb (NMSupplicantInterface *iface,
NMDeviceWifiP2P *self)
{
NMDeviceWifiP2PPrivate *priv;
+ NMSupplicantInterfaceState state;
- g_return_if_fail (self != NULL);
+ g_return_if_fail (self);
if (!nm_device_is_activating (NM_DEVICE (self))) {
_LOGW (LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant notified a group start but we are not trying to connect! Ignoring the event.");
@@ -844,6 +815,7 @@ supplicant_iface_group_started_cb (NMSupplicantInterface *iface,
priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self);
supplicant_group_interface_release (self);
+
priv->group_iface = g_object_ref (group_iface);
/* We need to wait for the interface to be ready and the group
@@ -862,10 +834,13 @@ supplicant_iface_group_started_cb (NMSupplicantInterface *iface,
G_CALLBACK (supplicant_group_iface_group_finished_cb),
self);
- if (nm_supplicant_interface_get_state (priv->group_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ state = nm_supplicant_interface_get_state (priv->group_iface);
+ if (state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) {
_set_is_waiting_for_supplicant (self, TRUE);
+ return;
+ }
- check_group_iface_ready (self);
+ supplicant_group_iface_is_ready (self);
}
static void
@@ -935,9 +910,8 @@ device_state_changed (NMDevice *device,
break;
case NM_DEVICE_STATE_UNAVAILABLE:
if ( !priv->mgmt_iface
- || nm_supplicant_interface_get_state (priv->mgmt_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY)
+ || !NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (nm_supplicant_interface_get_state (priv->mgmt_iface)))
_set_is_waiting_for_supplicant (self, TRUE);
-
break;
case NM_DEVICE_STATE_NEED_AUTH:
/* Disconnect? */
@@ -1084,20 +1058,20 @@ nm_device_wifi_p2p_set_mgmt_iface (NMDeviceWifiP2P *self,
goto done;
_LOGD (LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant management interface changed to %s.",
- nm_supplicant_interface_get_object_path (iface));
+ nm_ref_string_get_str (nm_supplicant_interface_get_object_path (iface)));
priv->mgmt_iface = g_object_ref (iface);
- g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_STATE,
+ g_signal_connect (priv->mgmt_iface,
+ NM_SUPPLICANT_INTERFACE_STATE,
G_CALLBACK (supplicant_iface_state_cb),
self);
- g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_PEER_UPDATED,
- G_CALLBACK (supplicant_iface_peer_updated_cb),
- self);
- g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_PEER_REMOVED,
- G_CALLBACK (supplicant_iface_peer_removed_cb),
+ g_signal_connect (priv->mgmt_iface,
+ NM_SUPPLICANT_INTERFACE_PEER_CHANGED,
+ G_CALLBACK (supplicant_iface_peer_changed_cb),
self);
- g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_GROUP_STARTED,
+ g_signal_connect (priv->mgmt_iface,
+ NM_SUPPLICANT_INTERFACE_GROUP_STARTED,
G_CALLBACK (supplicant_iface_group_started_cb),
self);
done:
@@ -1106,8 +1080,7 @@ done:
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
_set_is_waiting_for_supplicant (self,
!priv->mgmt_iface
- || ( nm_supplicant_interface_get_state (priv->mgmt_iface)
- < NM_SUPPLICANT_INTERFACE_STATE_READY));
+ || !NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (nm_supplicant_interface_get_state (priv->mgmt_iface)));
}
void
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 6df55e3a46..1beeb4becf 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -11,6 +11,7 @@
#include <netinet/in.h>
#include <unistd.h>
+#include "nm-glib-aux/nm-ref-string.h"
#include "nm-device-wifi-p2p.h"
#include "nm-wifi-ap.h"
#include "nm-libnm-core-intern/nm-common-macros.h"
@@ -90,6 +91,7 @@ typedef struct {
guint ap_dump_id;
NMSupplicantManager *sup_mgr;
+ NMSupplMgrCreateIfaceHandle *sup_create_handle;
NMSupplicantInterface *sup_iface;
guint sup_timeout_id; /* supplicant association timeout */
@@ -137,28 +139,31 @@ G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE)
static gboolean check_scanning_prohibited (NMDeviceWifi *self, gboolean periodic);
+static void supplicant_iface_state_down (NMDeviceWifi *self);
+
static void schedule_scan (NMDeviceWifi *self, gboolean backoff);
static void cleanup_association_attempt (NMDeviceWifi * self,
gboolean disconnect);
+static void supplicant_iface_state (NMDeviceWifi *self,
+ NMSupplicantInterfaceState new_state,
+ NMSupplicantInterfaceState old_state,
+ int disconnect_reason,
+ gboolean is_real_signal);
+
static void supplicant_iface_state_cb (NMSupplicantInterface *iface,
int new_state_i,
int old_state_i,
int disconnect_reason,
gpointer user_data);
-static void supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface,
- const char *object_path,
- GVariant *properties,
- NMDeviceWifi *self);
-
-static void supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface,
- const char *object_path,
+static void supplicant_iface_bss_changed_cb (NMSupplicantInterface *iface,
+ NMSupplicantBssInfo *bss_info,
+ gboolean is_present,
NMDeviceWifi *self);
static void supplicant_iface_scan_done_cb (NMSupplicantInterface * iface,
- gboolean success,
NMDeviceWifi * self);
static void supplicant_iface_wps_credentials_cb (NMSupplicantInterface *iface,
@@ -237,36 +242,40 @@ unmanaged_on_quit (NMDevice *self)
return TRUE;
}
-static gboolean
-supplicant_interface_acquire (NMDeviceWifi *self)
+static void
+supplicant_interface_acquire_cb (NMSupplicantManager *supplicant_manager,
+ NMSupplMgrCreateIfaceHandle *handle,
+ NMSupplicantInterface *iface,
+ GError *error,
+ gpointer user_data)
{
+ NMDeviceWifi *self = user_data;
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
- g_return_val_if_fail (self != NULL, FALSE);
- g_return_val_if_fail (!priv->sup_iface, TRUE);
+ if (nm_utils_error_is_cancelled (error))
+ return;
- priv->sup_iface = nm_supplicant_manager_create_interface (priv->sup_mgr,
- nm_device_get_iface (NM_DEVICE (self)),
- NM_SUPPLICANT_DRIVER_WIRELESS);
- if (!priv->sup_iface) {
- _LOGE (LOGD_WIFI, "Couldn't initialize supplicant interface");
- return FALSE;
+ nm_assert (priv->sup_create_handle == handle);
+
+ priv->sup_create_handle = NULL;
+
+ if (error) {
+ _LOGE (LOGD_WIFI, "Couldn't initialize supplicant interface: %s",
+ error->message);
+ supplicant_iface_state_down (self);
+ nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE);
+ return;
}
- if (nm_supplicant_interface_get_state (priv->sup_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY)
- nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, FALSE);
+ priv->sup_iface = g_object_ref (iface);
g_signal_connect (priv->sup_iface,
NM_SUPPLICANT_INTERFACE_STATE,
G_CALLBACK (supplicant_iface_state_cb),
self);
g_signal_connect (priv->sup_iface,
- NM_SUPPLICANT_INTERFACE_BSS_UPDATED,
- G_CALLBACK (supplicant_iface_bss_updated_cb),
- self);
- g_signal_connect (priv->sup_iface,
- NM_SUPPLICANT_INTERFACE_BSS_REMOVED,
- G_CALLBACK (supplicant_iface_bss_removed_cb),
+ NM_SUPPLICANT_INTERFACE_BSS_CHANGED,
+ G_CALLBACK (supplicant_iface_bss_changed_cb),
self);
g_signal_connect (priv->sup_iface,
NM_SUPPLICANT_INTERFACE_SCAN_DONE,
@@ -291,7 +300,30 @@ supplicant_interface_acquire (NMDeviceWifi *self)
_notify_scanning (self);
- return TRUE;
+ if (nm_supplicant_interface_get_state (priv->sup_iface) != NM_SUPPLICANT_INTERFACE_STATE_STARTING) {
+ /* fake an initial state change. */
+ supplicant_iface_state (user_data,
+ NM_SUPPLICANT_INTERFACE_STATE_STARTING,
+ nm_supplicant_interface_get_state (priv->sup_iface),
+ 0,
+ FALSE);
+ }
+}
+
+static void
+supplicant_interface_acquire (NMDeviceWifi *self)
+{
+ NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+
+ nm_assert (!priv->sup_iface);
+ nm_assert (!priv->sup_create_handle);
+
+ priv->sup_create_handle = nm_supplicant_manager_create_interface (priv->sup_mgr,
+ nm_device_get_ifindex (NM_DEVICE (self)),
+ NM_SUPPLICANT_DRIVER_WIRELESS,
+ supplicant_interface_acquire_cb,
+ self);
+ nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE);
}
static void
@@ -310,18 +342,17 @@ _requested_scan_set (NMDeviceWifi *self, gboolean value)
nm_device_add_pending_action ((NMDevice *) self, NM_PENDING_ACTION_WIFI_SCAN, TRUE);
else {
nm_device_emit_recheck_auto_activate (NM_DEVICE (self));
- nm_device_remove_pending_action ((NMDevice *) self, NM_PENDING_ACTION_WIFI_SCAN, TRUE);
+ nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WIFI_SCAN, TRUE);
}
}
static void
supplicant_interface_release (NMDeviceWifi *self)
{
- NMDeviceWifiPrivate *priv;
-
- g_return_if_fail (self != NULL);
+ NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
- priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+ if (nm_clear_pointer (&priv->sup_create_handle, nm_supplicant_manager_create_interface_cancel))
+ nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE);
_requested_scan_set (self, FALSE);
@@ -936,7 +967,7 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
return FALSE;
supplicant_state = nm_supplicant_interface_get_state (priv->sup_iface);
- if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_READY
+ if ( supplicant_state <= NM_SUPPLICANT_INTERFACE_STATE_STARTING
|| supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED)
return FALSE;
@@ -1198,7 +1229,8 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self,
}
last_scan = nm_supplicant_interface_get_last_scan (priv->sup_iface);
- if (last_scan && (nm_utils_get_monotonic_timestamp_msec () - last_scan) < 10 * NM_UTILS_MSEC_PER_SEC) {
+ if ( last_scan > 0
+ && (nm_utils_get_monotonic_timestamp_msec () - last_scan) < 10 * NM_UTILS_MSEC_PER_SEC) {
g_dbus_method_invocation_return_error_literal (invocation,
NM_DEVICE_ERROR,
NM_DEVICE_ERROR_NOT_ALLOWED,
@@ -1469,16 +1501,15 @@ schedule_scan (NMDeviceWifi *self, gboolean backoff)
static void
supplicant_iface_scan_done_cb (NMSupplicantInterface *iface,
- gboolean success,
NMDeviceWifi *self)
{
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
- _LOGD (LOGD_WIFI, "wifi-scan: scan-done callback: %s", success ? "successful" : "failed");
+ _LOGD (LOGD_WIFI, "wifi-scan: scan-done callback");
priv->last_scan = nm_utils_get_monotonic_timestamp_msec ();
_notify (self, PROP_LAST_SCAN);
- schedule_scan (self, success);
+ schedule_scan (self, TRUE);
_requested_scan_set (self, FALSE);
}
@@ -1552,40 +1583,43 @@ try_fill_ssid_for_hidden_ap (NMDeviceWifi *self,
}
static void
-supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface,
- const char *object_path,
- GVariant *properties,
+supplicant_iface_bss_changed_cb (NMSupplicantInterface *iface,
+ NMSupplicantBssInfo *bss_info,
+ gboolean is_present,
NMDeviceWifi *self)
{
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
- NMDeviceState state;
- NMWifiAP *found_ap = NULL;
+ NMWifiAP *found_ap;
GBytes *ssid;
- g_return_if_fail (self != NULL);
- g_return_if_fail (properties != NULL);
- g_return_if_fail (iface != NULL);
+ found_ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, bss_info->bss_path->str);
- /* Ignore new APs when unavailable, unmanaged, or in AP mode */
- state = nm_device_get_state (NM_DEVICE (self));
- if (state <= NM_DEVICE_STATE_UNAVAILABLE)
- return;
- if (NM_DEVICE_WIFI_GET_PRIVATE (self)->mode == NM_802_11_MODE_AP)
+ if (!is_present) {
+ if (!found_ap)
+ return;
+ if (found_ap == priv->current_ap) {
+ /* The current AP cannot be removed (to prevent NM indicating that
+ * it is connected, but to nothing), but it must be removed later
+ * when the current AP is changed or cleared. Set 'fake' to
+ * indicate that this AP is now unknown to the supplicant.
+ */
+ if (nm_wifi_ap_set_fake (found_ap, TRUE))
+ _ap_dump (self, LOGL_DEBUG, found_ap, "updated", 0);
+ } else {
+ ap_add_remove (self, FALSE, found_ap, TRUE);
+ schedule_ap_list_dump (self);
+ }
return;
+ }
- found_ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, object_path);
if (found_ap) {
- if (!nm_wifi_ap_update_from_properties (found_ap, object_path, properties))
+ if (!nm_wifi_ap_update_from_properties (found_ap, bss_info))
return;
_ap_dump (self, LOGL_DEBUG, found_ap, "updated", 0);
} else {
gs_unref_object NMWifiAP *ap = NULL;
- ap = nm_wifi_ap_new_from_properties (object_path, properties);
- if (!ap) {
- _LOGD (LOGD_WIFI, "invalid AP properties received for %s", object_path);
- return;
- }
+ ap = nm_wifi_ap_new_from_properties (bss_info);
/* Let the manager try to fill in the SSID from seen-bssids lists */
ssid = nm_wifi_ap_get_ssid (ap);
@@ -1615,43 +1649,13 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface,
/* Update the current AP if the supplicant notified a current BSS change
* before it sent the current BSS's scan result.
*/
- if (g_strcmp0 (nm_supplicant_interface_get_current_bss (iface), object_path) == 0)
+ if (nm_supplicant_interface_get_current_bss (iface) == bss_info->bss_path)
supplicant_iface_notify_current_bss (priv->sup_iface, NULL, self);
schedule_ap_list_dump (self);
}
static void
-supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface,
- const char *object_path,
- NMDeviceWifi *self)
-{
- NMDeviceWifiPrivate *priv;
- NMWifiAP *ap;
-
- g_return_if_fail (self != NULL);
- g_return_if_fail (object_path != NULL);
-
- priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
- ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, object_path);
- if (!ap)
- return;
-
- if (ap == priv->current_ap) {
- /* The current AP cannot be removed (to prevent NM indicating that
- * it is connected, but to nothing), but it must be removed later
- * when the current AP is changed or cleared. Set 'fake' to
- * indicate that this AP is now unknown to the supplicant.
- */
- if (nm_wifi_ap_set_fake (ap, TRUE))
- _ap_dump (self, LOGL_DEBUG, ap, "updated", 0);
- } else {
- ap_add_remove (self, FALSE, ap, TRUE);
- schedule_ap_list_dump (self);
- }
-}
-
-static void
cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect)
{
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
@@ -2029,50 +2033,71 @@ reacquire_interface_cb (gpointer user_data)
}
static void
-supplicant_iface_state_cb (NMSupplicantInterface *iface,
- int new_state_i,
- int old_state_i,
- int disconnect_reason,
- gpointer user_data)
+supplicant_iface_state_down (NMDeviceWifi *self)
+{
+ NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+ NMDevice *device = NM_DEVICE (self);
+
+ nm_device_queue_recheck_available (device,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ cleanup_association_attempt (self, FALSE);
+
+ /* If the device is already in UNAVAILABLE state then the state change
+ * is a NOP and the interface won't be re-acquired in the device state
+ * change handler. So ensure we have a new one here so that we're
+ * ready if the supplicant comes back.
+ */
+ supplicant_interface_release (self);
+ if (priv->failed_iface_count < 5)
+ priv->reacquire_iface_id = g_timeout_add_seconds (10, reacquire_interface_cb, self);
+ else
+ _LOGI (LOGD_DEVICE | LOGD_WIFI, "supplicant interface keeps failing, giving up");
+}
+
+static void
+supplicant_iface_state (NMDeviceWifi *self,
+ NMSupplicantInterfaceState new_state,
+ NMSupplicantInterfaceState old_state,
+ int disconnect_reason,
+ gboolean is_real_signal)
{
- NMDeviceWifi *self = NM_DEVICE_WIFI (user_data);
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
NMDevice *device = NM_DEVICE (self);
NMDeviceState devstate;
gboolean scanning;
- NMSupplicantInterfaceState new_state = new_state_i;
- NMSupplicantInterfaceState old_state = old_state_i;
-
- if (new_state == old_state)
- return;
_LOGI (LOGD_DEVICE | LOGD_WIFI,
- "supplicant interface state: %s -> %s",
+ "supplicant interface state: %s -> %s%s",
nm_supplicant_interface_state_to_string (old_state),
- nm_supplicant_interface_state_to_string (new_state));
+ nm_supplicant_interface_state_to_string (new_state),
+ is_real_signal ? "" : " (simulated signal)");
+
+ if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
+ supplicant_iface_state_down (self);
+ goto out;
+ }
devstate = nm_device_get_state (device);
- scanning = nm_supplicant_interface_get_scanning (iface);
+ scanning = nm_supplicant_interface_get_scanning (priv->sup_iface);
+
+ if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) {
+ _LOGD (LOGD_WIFI, "supplicant ready");
+ nm_device_queue_recheck_available (NM_DEVICE (device),
+ NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
+ NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
+ priv->scan_interval = SCAN_INTERVAL_MIN;
+ }
/* In these states we know the supplicant is actually talking to something */
if ( new_state >= NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING
&& new_state <= NM_SUPPLICANT_INTERFACE_STATE_COMPLETED)
priv->ssid_found = TRUE;
- if ( old_state < NM_SUPPLICANT_INTERFACE_STATE_READY
- && new_state >= NM_SUPPLICANT_INTERFACE_STATE_READY)
+ if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING)
recheck_p2p_availability (self);
switch (new_state) {
- case NM_SUPPLICANT_INTERFACE_STATE_READY:
- _LOGD (LOGD_WIFI, "supplicant ready");
- nm_device_queue_recheck_available (NM_DEVICE (device),
- NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
- NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
- priv->scan_interval = SCAN_INTERVAL_MIN;
- if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY)
- nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE);
- break;
case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
nm_clear_g_source (&priv->sup_timeout_id);
nm_clear_g_source (&priv->link_timeout_id);
@@ -2127,26 +2152,6 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
}
}
break;
- case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
- nm_device_queue_recheck_available (NM_DEVICE (device),
- NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
- NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
- cleanup_association_attempt (self, FALSE);
-
- if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY)
- nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE);
-
- /* If the device is already in UNAVAILABLE state then the state change
- * is a NOP and the interface won't be re-acquired in the device state
- * change handler. So ensure we have a new one here so that we're
- * ready if the supplicant comes back.
- */
- supplicant_interface_release (self);
- if (priv->failed_iface_count < 5)
- priv->reacquire_iface_id = g_timeout_add_seconds (10, reacquire_interface_cb, self);
- else
- _LOGI (LOGD_DEVICE | LOGD_WIFI, "supplicant interface keeps failing, giving up");
- break;
case NM_SUPPLICANT_INTERFACE_STATE_INACTIVE:
/* we would clear _requested_scan_set() and trigger a new scan.
* However, we don't want to cancel the current pending action, so force
@@ -2157,10 +2162,25 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
break;
}
- /* Signal scanning state changes */
- if ( new_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING
- || old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
- _notify_scanning (self);
+out:
+ _notify_scanning (self);
+
+ if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING)
+ nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE);
+}
+
+static void
+supplicant_iface_state_cb (NMSupplicantInterface *iface,
+ int new_state_i,
+ int old_state_i,
+ int disconnect_reason,
+ gpointer user_data)
+{
+ supplicant_iface_state (user_data,
+ new_state_i,
+ old_state_i,
+ disconnect_reason,
+ TRUE);
}
static void
@@ -2197,12 +2217,12 @@ supplicant_iface_notify_current_bss (NMSupplicantInterface *iface,
NMDeviceWifi *self)
{
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
- const char *current_bss;
+ NMRefString *current_bss;
NMWifiAP *new_ap = NULL;
current_bss = nm_supplicant_interface_get_current_bss (iface);
if (current_bss)
- new_ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, current_bss);
+ new_ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, current_bss->str);
if (new_ap != priv->current_ap) {
const char *new_bssid = NULL;
@@ -2293,11 +2313,8 @@ supplicant_iface_notify_p2p_available (NMSupplicantInterface *iface,
GParamSpec *pspec,
NMDeviceWifi *self)
{
- /* Do not update when the interface is still initializing. */
- if (nm_supplicant_interface_get_state (iface) < NM_SUPPLICANT_INTERFACE_STATE_READY)
- return;
-
- recheck_p2p_availability (self);
+ if (nm_supplicant_interface_get_state (iface) > NM_SUPPLICANT_INTERFACE_STATE_STARTING)
+ recheck_p2p_availability (self);
}
static gboolean
@@ -3058,8 +3075,7 @@ device_state_changed (NMDevice *device,
/* Clean up the supplicant interface because in these states the
* device cannot be used.
*/
- if (priv->sup_iface)
- supplicant_interface_release (self);
+ supplicant_interface_release (self);
nm_clear_g_source (&priv->periodic_source_id);
@@ -3160,8 +3176,7 @@ set_enabled (NMDevice *device, gboolean enabled)
/* Re-initialize the supplicant interface and wait for it to be ready */
cleanup_supplicant_failures (self);
- if (priv->sup_iface)
- supplicant_interface_release (self);
+ supplicant_interface_release (self);
supplicant_interface_acquire (self);
_LOGD (LOGD_WIFI, "enable waiting on supplicant state");
diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c
index 18f1a5a910..ef0c70cc7f 100644
--- a/src/devices/wifi/nm-wifi-ap.c
+++ b/src/devices/wifi/nm-wifi-ap.c
@@ -10,15 +10,16 @@
#include <stdlib.h>
-#include "nm-setting-wireless.h"
-
-#include "nm-wifi-utils.h"
#include "NetworkManagerUtils.h"
-#include "nm-utils.h"
-#include "nm-core-internal.h"
-#include "platform/nm-platform.h"
#include "devices/nm-device.h"
+#include "nm-core-internal.h"
#include "nm-dbus-manager.h"
+#include "nm-glib-aux/nm-ref-string.h"
+#include "nm-setting-wireless.h"
+#include "nm-utils.h"
+#include "nm-wifi-utils.h"
+#include "platform/nm-platform.h"
+#include "supplicant/nm-supplicant-interface.h"
#define PROTO_WPA "wpa"
#define PROTO_RSN "rsn"
@@ -39,7 +40,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMWifiAP,
);
struct _NMWifiAPPrivate {
- char *supplicant_path; /* D-Bus object path of this AP from wpa_supplicant */
+ NMRefString *supplicant_path;
/* Scanned or cached values */
GBytes * ssid;
@@ -49,6 +50,9 @@ struct _NMWifiAPPrivate {
guint32 freq; /* Frequency in MHz; ie 2412 (== 2.412 GHz) */
guint32 max_bitrate; /* Maximum bitrate of the AP in Kbit/s (ie 54000 Kb/s == 54Mbit/s) */
+ gint64 last_seen_msec; /* Timestamp when the AP was seen lastly (in nm_utils_get_monotonic_timestamp_*() scale).
+ * Note that this value might be negative! */
+
NM80211ApFlags flags; /* General flags */
NM80211ApSecurityFlags wpa_flags; /* WPA-related flags */
NM80211ApSecurityFlags rsn_flags; /* RSN (WPA2) -related flags */
@@ -58,7 +62,6 @@ struct _NMWifiAPPrivate {
/* Non-scanned attributes */
bool fake:1; /* Whether or not the AP is from a scan */
bool hotspot:1; /* Whether the AP is a local device's hotspot network */
- gint32 last_seen; /* Timestamp when the AP was seen lastly (obtained via nm_utils_get_monotonic_timestamp_sec()) */
};
typedef struct _NMWifiAPPrivate NMWifiAPPrivate;
@@ -78,7 +81,7 @@ nm_wifi_ap_get_supplicant_path (NMWifiAP *ap)
{
g_return_val_if_fail (NM_IS_WIFI_AP (ap), NULL);
- return NM_WIFI_AP_GET_PRIVATE (ap)->supplicant_path;
+ return nm_ref_string_get_str (NM_WIFI_AP_GET_PRIVATE (ap)->supplicant_path);
}
GBytes *
@@ -148,11 +151,7 @@ nm_wifi_ap_set_ssid (NMWifiAP *ap, GBytes *ssid)
static gboolean
nm_wifi_ap_set_flags (NMWifiAP *ap, NM80211ApFlags flags)
{
- NMWifiAPPrivate *priv;
-
- g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
-
- priv = NM_WIFI_AP_GET_PRIVATE (ap);
+ NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
if (priv->flags != flags) {
priv->flags = flags;
@@ -165,11 +164,8 @@ nm_wifi_ap_set_flags (NMWifiAP *ap, NM80211ApFlags flags)
static gboolean
nm_wifi_ap_set_wpa_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags)
{
- NMWifiAPPrivate *priv;
-
- g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
+ NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
- priv = NM_WIFI_AP_GET_PRIVATE (ap);
if (priv->wpa_flags != flags) {
priv->wpa_flags = flags;
_notify (ap, PROP_WPA_FLAGS);
@@ -181,11 +177,8 @@ nm_wifi_ap_set_wpa_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags)
static gboolean
nm_wifi_ap_set_rsn_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags)
{
- NMWifiAPPrivate *priv;
-
- g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
+ NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
- priv = NM_WIFI_AP_GET_PRIVATE (ap);
if (priv->rsn_flags != flags) {
priv->rsn_flags = flags;
_notify (ap, PROP_RSN_FLAGS);
@@ -203,11 +196,9 @@ nm_wifi_ap_get_address (const NMWifiAP *ap)
}
static gboolean
-nm_wifi_ap_set_address_bin (NMWifiAP *ap, const guint8 *addr /* ETH_ALEN bytes */)
+nm_wifi_ap_set_address_bin (NMWifiAP *ap, const guint8 addr[static 6 /* ETH_ALEN */])
{
- NMWifiAPPrivate *priv;
-
- priv = NM_WIFI_AP_GET_PRIVATE (ap);
+ NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
if ( !priv->address
|| !nm_utils_hwaddr_matches (addr, ETH_ALEN, priv->address, -1)) {
@@ -241,16 +232,14 @@ nm_wifi_ap_get_mode (NMWifiAP *ap)
}
static gboolean
-nm_wifi_ap_set_mode (NMWifiAP *ap, const NM80211Mode mode)
+nm_wifi_ap_set_mode (NMWifiAP *ap, NM80211Mode mode)
{
- NMWifiAPPrivate *priv;
-
- g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
- g_return_val_if_fail ( mode == NM_802_11_MODE_ADHOC
- || mode == NM_802_11_MODE_INFRA
- || mode == NM_802_11_MODE_MESH, FALSE);
+ NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
- priv = NM_WIFI_AP_GET_PRIVATE (ap);
+ nm_assert (NM_IN_SET (mode, NM_802_11_MODE_UNKNOWN,
+ NM_802_11_MODE_ADHOC,
+ NM_802_11_MODE_INFRA,
+ NM_802_11_MODE_MESH));
if (priv->mode != mode) {
priv->mode = mode;
@@ -277,13 +266,9 @@ nm_wifi_ap_get_strength (NMWifiAP *ap)
}
gboolean
-nm_wifi_ap_set_strength (NMWifiAP *ap, const gint8 strength)
+nm_wifi_ap_set_strength (NMWifiAP *ap, gint8 strength)
{
- NMWifiAPPrivate *priv;
-
- g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
-
- priv = NM_WIFI_AP_GET_PRIVATE (ap);
+ NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
if (priv->strength != strength) {
priv->strength = strength;
@@ -303,13 +288,9 @@ nm_wifi_ap_get_freq (NMWifiAP *ap)
gboolean
nm_wifi_ap_set_freq (NMWifiAP *ap,
- const guint32 freq)
+ guint32 freq)
{
- NMWifiAPPrivate *priv;
-
- g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
-
- priv = NM_WIFI_AP_GET_PRIVATE (ap);
+ NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
if (priv->freq != freq) {
priv->freq = freq;
@@ -378,16 +359,12 @@ nm_wifi_ap_get_flags (const NMWifiAP *ap)
}
static gboolean
-nm_wifi_ap_set_last_seen (NMWifiAP *ap, gint32 last_seen)
+nm_wifi_ap_set_last_seen (NMWifiAP *ap, gint32 last_seen_msec)
{
- NMWifiAPPrivate *priv;
-
- g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
-
- priv = NM_WIFI_AP_GET_PRIVATE (ap);
+ NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
- if (priv->last_seen != last_seen) {
- priv->last_seen = last_seen;
+ if (priv->last_seen_msec != last_seen_msec) {
+ priv->last_seen_msec = last_seen_msec;
_notify (ap, PROP_LAST_SEEN);
return TRUE;
}
@@ -402,180 +379,53 @@ nm_wifi_ap_get_metered (const NMWifiAP *self)
/*****************************************************************************/
-static NM80211ApSecurityFlags
-security_from_vardict (GVariant *security)
-{
- NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE;
- const char **array, *tmp;
-
- g_return_val_if_fail (g_variant_is_of_type (security, G_VARIANT_TYPE_VARDICT), NM_802_11_AP_SEC_NONE);
-
- if ( g_variant_lookup (security, "KeyMgmt", "^a&s", &array)
- && array) {
- if (g_strv_contains (array, "wpa-psk") ||
- g_strv_contains (array, "wpa-ft-psk"))
- flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK;
- if (g_strv_contains (array, "wpa-eap") ||
- g_strv_contains (array, "wpa-ft-eap") ||
- g_strv_contains (array, "wpa-fils-sha256") ||
- g_strv_contains (array, "wpa-fils-sha384"))
- flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X;
- if (g_strv_contains (array, "sae"))
- flags |= NM_802_11_AP_SEC_KEY_MGMT_SAE;
- if (g_strv_contains (array, "owe"))
- flags |= NM_802_11_AP_SEC_KEY_MGMT_OWE;
- g_free (array);
- }
-
- if ( g_variant_lookup (security, "Pairwise", "^a&s", &array)
- && array) {
- if (g_strv_contains (array, "tkip"))
- flags |= NM_802_11_AP_SEC_PAIR_TKIP;
- if (g_strv_contains (array, "ccmp"))
- flags |= NM_802_11_AP_SEC_PAIR_CCMP;
- g_free (array);
- }
-
- if (g_variant_lookup (security, "Group", "&s", &tmp)) {
- if (strcmp (tmp, "wep40") == 0)
- flags |= NM_802_11_AP_SEC_GROUP_WEP40;
- if (strcmp (tmp, "wep104") == 0)
- flags |= NM_802_11_AP_SEC_GROUP_WEP104;
- if (strcmp (tmp, "tkip") == 0)
- flags |= NM_802_11_AP_SEC_GROUP_TKIP;
- if (strcmp (tmp, "ccmp") == 0)
- flags |= NM_802_11_AP_SEC_GROUP_CCMP;
- }
-
- return flags;
-}
-
-/*****************************************************************************/
-
gboolean
nm_wifi_ap_update_from_properties (NMWifiAP *ap,
- const char *supplicant_path,
- GVariant *properties)
+ const NMSupplicantBssInfo *bss_info)
{
NMWifiAPPrivate *priv;
- const guint8 *bytes;
- GVariant *v;
- gsize len;
- gsize i;
- gboolean b = FALSE;
- const char *s;
- gint16 i16;
- guint16 u16;
gboolean changed = FALSE;
- gboolean metered;
- guint32 max_rate, rate;
g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
- g_return_val_if_fail (properties, FALSE);
+ g_return_val_if_fail (bss_info, FALSE);
+ nm_assert (NM_IS_REF_STRING (bss_info->bss_path));
priv = NM_WIFI_AP_GET_PRIVATE (ap);
- g_object_freeze_notify (G_OBJECT (ap));
-
- if (g_variant_lookup (properties, "Privacy", "b", &b) && b)
- changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_PRIVACY);
-
- v = g_variant_lookup_value (properties, "WPS", G_VARIANT_TYPE_VARDICT);
- if (v) {
- if (g_variant_lookup (v, "Type", "&s", &s)) {
- changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_WPS);
- if (strcmp (s, "pbc") == 0)
- changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_WPS_PBC);
- else if (strcmp (s, "pin") == 0)
- changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_WPS_PIN);
- }
- g_variant_unref (v);
- }
-
- if (g_variant_lookup (properties, "Mode", "&s", &s)) {
- if (!g_strcmp0 (s, "infrastructure"))
- changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA);
- else if (!g_strcmp0 (s, "ad-hoc"))
- changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_ADHOC);
- else if (!g_strcmp0 (s, "mesh"))
- changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_MESH);
- }
-
- if (g_variant_lookup (properties, "Signal", "n", &i16))
- changed |= nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (i16));
-
- if (g_variant_lookup (properties, "Frequency", "q", &u16))
- changed |= nm_wifi_ap_set_freq (ap, u16);
-
- 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 <hidden> */
- if ( bytes
- && len
- && !( NM_IN_SET (len, 8, 9)
- && memcmp (bytes, "<hidden>", len) == 0)
- && !nm_utils_is_empty_ssid (bytes, len)) {
- /* good */
- } else
- len = 0;
+ nm_assert ( !priv->supplicant_path
+ || priv->supplicant_path == bss_info->bss_path);
- changed |= nm_wifi_ap_set_ssid_arr (ap, bytes, len);
-
- g_variant_unref (v);
- }
+ g_object_freeze_notify (G_OBJECT (ap));
- 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)
- changed |= nm_wifi_ap_set_address_bin (ap, bytes);
- g_variant_unref (v);
+ if (!priv->supplicant_path) {
+ priv->supplicant_path = nm_ref_string_ref (bss_info->bss_path);
+ changed = TRUE;
}
- max_rate = 0;
- v = g_variant_lookup_value (properties, "Rates", G_VARIANT_TYPE ("au"));
- if (v) {
- const guint32 *rates = g_variant_get_fixed_array (v, &len, sizeof (guint32));
+ changed |= nm_wifi_ap_set_flags (ap, bss_info->ap_flags);
+ changed |= nm_wifi_ap_set_mode (ap, bss_info->mode);
+ changed |= nm_wifi_ap_set_strength (ap, bss_info->signal_percent);
+ changed |= nm_wifi_ap_set_freq (ap, bss_info->frequency);
+ changed |= nm_wifi_ap_set_ssid (ap, bss_info->ssid);
- for (i = 0; i < len; i++)
- max_rate = NM_MAX (max_rate, rates[i]);
- g_variant_unref (v);
- }
- v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING);
- if (v) {
- bytes = g_variant_get_fixed_array (v, &len, 1);
- nm_wifi_utils_parse_ies (bytes, len, &rate, &metered);
- max_rate = NM_MAX (max_rate, rate);
- g_variant_unref (v);
- priv->metered = metered;
+ if (bss_info->bssid_valid)
+ changed |= nm_wifi_ap_set_address_bin (ap, bss_info->bssid);
+ else {
+ /* we don't actually clear the value. */
}
- if (max_rate)
- changed |= nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000);
+ changed |= nm_wifi_ap_set_max_bitrate (ap, bss_info->max_rate);
- v = g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT);
- if (v) {
- changed |= nm_wifi_ap_set_wpa_flags (ap, priv->wpa_flags | security_from_vardict (v));
- g_variant_unref (v);
+ if (priv->metered != bss_info->metered) {
+ priv->metered = bss_info->metered;
+ changed = TRUE;
}
- v = g_variant_lookup_value (properties, "RSN", G_VARIANT_TYPE_VARDICT);
- if (v) {
- changed |= nm_wifi_ap_set_rsn_flags (ap, priv->rsn_flags | security_from_vardict (v));
- g_variant_unref (v);
- }
+ changed |= nm_wifi_ap_set_wpa_flags (ap, bss_info->wpa_flags);
+ changed |= nm_wifi_ap_set_rsn_flags (ap, bss_info->rsn_flags);
- if (!priv->supplicant_path) {
- priv->supplicant_path = g_strdup (supplicant_path);
- changed = TRUE;
- }
+ changed |= nm_wifi_ap_set_last_seen (ap, bss_info->last_seen_msec);
- changed |= nm_wifi_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_sec ());
changed |= nm_wifi_ap_set_fake (ap, FALSE);
g_object_thaw_notify (G_OBJECT (ap));
@@ -674,9 +524,10 @@ nm_wifi_ap_to_string (const NMWifiAP *self,
g_return_val_if_fail (NM_IS_WIFI_AP (self), NULL);
priv = NM_WIFI_AP_GET_PRIVATE (self);
+
chan = nm_utils_wifi_freq_to_channel (priv->freq);
if (priv->supplicant_path)
- supplicant_id = strrchr (priv->supplicant_path, '/') ?: supplicant_id;
+ supplicant_id = strrchr (priv->supplicant_path->str, '/') ?: supplicant_id;
export_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self));
if (export_path)
@@ -703,7 +554,9 @@ nm_wifi_ap_to_string (const NMWifiAP *self,
priv->metered ? 'M' : '_',
priv->wpa_flags & 0xFFFF,
priv->rsn_flags & 0xFFFF,
- priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_sec ()) - priv->last_seen) : -1,
+ priv->last_seen_msec != G_MININT64
+ ? (int) ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_sec ()) - (priv->last_seen_msec / 1000))
+ : -1,
supplicant_id,
export_path);
return str_buf;
@@ -856,9 +709,9 @@ get_property (GObject *object, guint prop_id,
break;
case PROP_LAST_SEEN:
g_value_set_int (value,
- priv->last_seen > 0
- ? (int) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NSEC_PER_SEC)
- : -1);
+ priv->last_seen_msec != G_MININT64
+ ? (int) NM_MAX (nm_utils_monotonic_timestamp_as_boottime (priv->last_seen_msec, NM_UTILS_NSEC_PER_MSEC) / 1000, 1)
+ : -1);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -883,26 +736,16 @@ nm_wifi_ap_init (NMWifiAP *self)
priv->flags = NM_802_11_AP_FLAGS_NONE;
priv->wpa_flags = NM_802_11_AP_SEC_NONE;
priv->rsn_flags = NM_802_11_AP_SEC_NONE;
- priv->last_seen = -1;
+ priv->last_seen_msec = G_MININT64;
}
NMWifiAP *
-nm_wifi_ap_new_from_properties (const char *supplicant_path, GVariant *properties)
+nm_wifi_ap_new_from_properties (const NMSupplicantBssInfo *bss_info)
{
NMWifiAP *ap;
- g_return_val_if_fail (supplicant_path != NULL, NULL);
- g_return_val_if_fail (properties != NULL, NULL);
-
- ap = (NMWifiAP *) g_object_new (NM_TYPE_WIFI_AP, NULL);
- nm_wifi_ap_update_from_properties (ap, supplicant_path, properties);
-
- /* ignore APs with invalid or missing BSSIDs */
- if (!nm_wifi_ap_get_address (ap)) {
- g_object_unref (ap);
- return NULL;
- }
-
+ ap = g_object_new (NM_TYPE_WIFI_AP, NULL);
+ nm_wifi_ap_update_from_properties (ap, bss_info);
return ap;
}
@@ -1028,7 +871,7 @@ finalize (GObject *object)
nm_assert (!self->wifi_device);
nm_assert (c_list_is_empty (&self->aps_lst));
- g_free (priv->supplicant_path);
+ nm_ref_string_unref (priv->supplicant_path);
if (priv->ssid)
g_bytes_unref (priv->ssid);
g_free (priv->address);
diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h
index 472dfdf908..f9d258b06c 100644
--- a/src/devices/wifi/nm-wifi-ap.h
+++ b/src/devices/wifi/nm-wifi-ap.h
@@ -36,17 +36,17 @@ typedef struct {
struct _NMWifiAPPrivate *_priv;
} NMWifiAP;
+struct _NMSupplicantBssInfo;
+
typedef struct _NMWifiAPClass NMWifiAPClass;
GType nm_wifi_ap_get_type (void);
-NMWifiAP * nm_wifi_ap_new_from_properties (const char *supplicant_path,
- GVariant *properties);
-NMWifiAP * nm_wifi_ap_new_fake_from_connection (NMConnection *connection);
+NMWifiAP *nm_wifi_ap_new_from_properties (const struct _NMSupplicantBssInfo *bss_info);
+NMWifiAP *nm_wifi_ap_new_fake_from_connection (NMConnection *connection);
-gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap,
- const char *supplicant_path,
- GVariant *properties);
+gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap,
+ const struct _NMSupplicantBssInfo *bss_info);
gboolean nm_wifi_ap_check_compatible (NMWifiAP *self,
NMConnection *connection);
diff --git a/src/devices/wifi/nm-wifi-p2p-peer.c b/src/devices/wifi/nm-wifi-p2p-peer.c
index 51f5a505ae..c58bd95e29 100644
--- a/src/devices/wifi/nm-wifi-p2p-peer.c
+++ b/src/devices/wifi/nm-wifi-p2p-peer.c
@@ -9,15 +9,16 @@
#include <stdlib.h>
-#include "nm-setting-wireless.h"
-
-#include "nm-wifi-utils.h"
#include "NetworkManagerUtils.h"
-#include "nm-utils.h"
-#include "nm-core-internal.h"
-#include "platform/nm-platform.h"
#include "devices/nm-device.h"
+#include "nm-core-internal.h"
#include "nm-dbus-manager.h"
+#include "nm-glib-aux/nm-ref-string.h"
+#include "nm-setting-wireless.h"
+#include "nm-utils.h"
+#include "nm-wifi-utils.h"
+#include "platform/nm-platform.h"
+#include "supplicant/nm-supplicant-types.h"
/*****************************************************************************/
@@ -35,7 +36,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMWifiP2PPeer,
);
struct _NMWifiP2PPeerPrivate {
- char *supplicant_path; /* D-Bus object path of this Peer from wpa_supplicant */
+ NMRefString *supplicant_path; /* D-Bus object path of this Peer from wpa_supplicant */
/* Scanned or cached values */
char * name;
@@ -150,7 +151,7 @@ nm_wifi_p2p_peer_get_supplicant_path (NMWifiP2PPeer *peer)
{
g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL);
- return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->supplicant_path;
+ return nm_ref_string_get_str (NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->supplicant_path);
}
const char *
@@ -372,69 +373,42 @@ nm_wifi_p2p_peer_set_last_seen (NMWifiP2PPeer *peer, gint32 last_seen)
gboolean
nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer,
- const char *supplicant_path,
- GVariant *properties)
+ const NMSupplicantPeerInfo *peer_info)
{
NMWifiP2PPeerPrivate *priv;
- const guint8 *bytes;
- GVariant *v;
- gsize len;
- const char *s;
- gint32 i32;
gboolean changed = FALSE;
g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE);
- g_return_val_if_fail (properties, FALSE);
+ g_return_val_if_fail (peer_info, FALSE);
+ nm_assert (NM_IS_REF_STRING (peer_info->peer_path));
priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer);
- g_object_freeze_notify (G_OBJECT (peer));
-
- if (g_variant_lookup (properties, "level", "i", &i32))
- changed |= nm_wifi_p2p_peer_set_strength (peer, nm_wifi_utils_level_to_quality (i32));
-
- if (g_variant_lookup (properties, "DeviceName", "&s", &s))
- changed |= nm_wifi_p2p_peer_set_name (peer, s);
-
- if (g_variant_lookup (properties, "Manufacturer", "&s", &s))
- changed |= nm_wifi_p2p_peer_set_manufacturer (peer, s);
+ nm_assert ( !priv->supplicant_path
+ || priv->supplicant_path == peer_info->peer_path);
- if (g_variant_lookup (properties, "Model", "&s", &s))
- changed |= nm_wifi_p2p_peer_set_model (peer, s);
-
- if (g_variant_lookup (properties, "ModelNumber", "&s", &s))
- changed |= nm_wifi_p2p_peer_set_model_number (peer, s);
-
- if (g_variant_lookup (properties, "Serial", "&s", &s))
- changed |= nm_wifi_p2p_peer_set_serial (peer, s);
-
- v = g_variant_lookup_value (properties, "DeviceAddress", 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)
- changed |= nm_wifi_p2p_peer_set_address_bin (peer, bytes);
- g_variant_unref (v);
- }
-
- /* The IEs property contains the WFD R1 subelements */
- v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING);
- if (v) {
- gs_unref_bytes GBytes *b = NULL;
-
- bytes = g_variant_get_fixed_array (v, &len, 1);
- b = g_bytes_new (bytes, len);
- changed |= nm_wifi_p2p_peer_set_wfd_ies (peer, b);
- g_variant_unref (v);
- }
+ g_object_freeze_notify (G_OBJECT (peer));
if (!priv->supplicant_path) {
- priv->supplicant_path = g_strdup (supplicant_path);
+ priv->supplicant_path = nm_ref_string_ref (peer_info->peer_path);
changed = TRUE;
}
- changed |= nm_wifi_p2p_peer_set_last_seen (peer, nm_utils_get_monotonic_timestamp_sec ());
+ changed |= nm_wifi_p2p_peer_set_strength (peer, peer_info->signal_percent);
+ changed |= nm_wifi_p2p_peer_set_name (peer, peer_info->device_name);
+ changed |= nm_wifi_p2p_peer_set_manufacturer (peer, peer_info->manufacturer);
+ changed |= nm_wifi_p2p_peer_set_model (peer, peer_info->model);
+ changed |= nm_wifi_p2p_peer_set_model_number (peer, peer_info->model_number);
+ changed |= nm_wifi_p2p_peer_set_serial (peer, peer_info->serial);
+
+ if (peer_info->address_valid)
+ changed |= nm_wifi_p2p_peer_set_address_bin (peer, peer_info->address);
+ else {
+ /* we don't reset the address. */
+ }
+
+ changed |= nm_wifi_p2p_peer_set_wfd_ies (peer, peer_info->ies);
+ changed |= nm_wifi_p2p_peer_set_last_seen (peer, peer_info->last_seen_msec / 1000u);
g_object_thaw_notify (G_OBJECT (peer));
@@ -456,7 +430,7 @@ nm_wifi_p2p_peer_to_string (const NMWifiP2PPeer *self,
priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self);
if (priv->supplicant_path)
- supplicant_id = strrchr (priv->supplicant_path, '/') ?: supplicant_id;
+ supplicant_id = strrchr (priv->supplicant_path->str, '/') ?: supplicant_id;
export_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self));
if (export_path)
@@ -572,22 +546,14 @@ nm_wifi_p2p_peer_init (NMWifiP2PPeer *self)
}
NMWifiP2PPeer *
-nm_wifi_p2p_peer_new_from_properties (const char *supplicant_path, GVariant *properties)
+nm_wifi_p2p_peer_new_from_properties (const NMSupplicantPeerInfo *peer_info)
{
NMWifiP2PPeer *peer;
- g_return_val_if_fail (supplicant_path != NULL, NULL);
- g_return_val_if_fail (properties != NULL, NULL);
-
- peer = (NMWifiP2PPeer *) g_object_new (NM_TYPE_WIFI_P2P_PEER, NULL);
- nm_wifi_p2p_peer_update_from_properties (peer, supplicant_path, properties);
-
- /* ignore peers with invalid or missing address */
- if (!nm_wifi_p2p_peer_get_address (peer)) {
- g_object_unref (peer);
- return NULL;
- }
+ g_return_val_if_fail (peer_info, NULL);
+ peer = g_object_new (NM_TYPE_WIFI_P2P_PEER, NULL);
+ nm_wifi_p2p_peer_update_from_properties (peer, peer_info);
return peer;
}
@@ -600,7 +566,7 @@ finalize (GObject *object)
nm_assert (!self->wifi_device);
nm_assert (c_list_is_empty (&self->peers_lst));
- g_free (priv->supplicant_path);
+ nm_ref_string_unref (priv->supplicant_path);
g_free (priv->name);
g_free (priv->manufacturer);
g_free (priv->model);
diff --git a/src/devices/wifi/nm-wifi-p2p-peer.h b/src/devices/wifi/nm-wifi-p2p-peer.h
index e84789c094..59f9c5d269 100644
--- a/src/devices/wifi/nm-wifi-p2p-peer.h
+++ b/src/devices/wifi/nm-wifi-p2p-peer.h
@@ -37,14 +37,14 @@ typedef struct {
typedef struct _NMWifiP2PPeerClass NMWifiP2PPeerClass;
+struct _NMSupplicantPeerInfo;
+
GType nm_wifi_p2p_peer_get_type (void);
-NMWifiP2PPeer * nm_wifi_p2p_peer_new_from_properties (const char *supplicant_path,
- GVariant *properties);
+NMWifiP2PPeer *nm_wifi_p2p_peer_new_from_properties (const struct _NMSupplicantPeerInfo *peer_info);
-gboolean nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer,
- const char *supplicant_path,
- GVariant *properties);
+gboolean nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer,
+ const struct _NMSupplicantPeerInfo *peer_info);
gboolean nm_wifi_p2p_peer_check_compatible (NMWifiP2PPeer *self,
NMConnection *connection);
diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c
index 04f35e4182..6edeef682a 100644
--- a/src/supplicant/nm-supplicant-interface.c
+++ b/src/supplicant/nm-supplicant-interface.c
@@ -7,39 +7,35 @@
#include "nm-default.h"
#include "nm-supplicant-interface.h"
-#include "nm-supplicant-manager.h"
#include <stdio.h>
#include "NetworkManagerUtils.h"
-#include "nm-supplicant-config.h"
#include "nm-core-internal.h"
+#include "nm-glib-aux/nm-c-list.h"
+#include "nm-glib-aux/nm-ref-string.h"
#include "nm-std-aux/nm-dbus-compat.h"
+#include "nm-supplicant-config.h"
+#include "nm-supplicant-manager.h"
+#include "shared/nm-glib-aux/nm-dbus-aux.h"
-/*****************************************************************************/
-
-typedef struct {
- GDBusProxy *proxy;
- gulong change_id;
-} BssData;
-
-typedef struct {
- GDBusProxy *proxy;
- gulong change_id;
-} PeerData;
+#define DBUS_TIMEOUT_MSEC 20000
-struct _AddNetworkData;
+/*****************************************************************************/
typedef struct {
NMSupplicantInterface *self;
char *type;
char *bssid;
char *pin;
- GDBusProxy *proxy;
+ guint signal_id;
GCancellable *cancellable;
- bool is_cancelling;
+ bool needs_cancelling:1;
+ bool is_cancelling:1;
} WpsData;
+struct _AddNetworkData;
+
typedef struct {
NMSupplicantInterface *self;
NMSupplicantConfig *cfg;
@@ -54,32 +50,28 @@ typedef struct {
typedef struct _AddNetworkData {
/* the assoc_data at the time when doing the call. */
AssocData *assoc_data;
+ NMRefString *name_owner;
+ NMRefString *object_path;
+ GObject *shutdown_wait_obj;
} AddNetworkData;
-typedef struct {
- NMSupplicantInterface *self;
- NMSupplicantInterfaceDisconnectCb callback;
- gpointer user_data;
-} DisconnectData;
-
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 */
+ BSS_CHANGED, /* a new BSS appeared, was updated, or was removed. */
+ PEER_CHANGED, /* a new Peer appeared, was updated, or was removed */
SCAN_DONE, /* wifi scan is complete */
WPS_CREDENTIALS, /* WPS credentials received */
GROUP_STARTED, /* a new Group (interface) was created */
GROUP_FINISHED, /* a Group (interface) has been finished */
LAST_SIGNAL
};
+
static guint signals[LAST_SIGNAL] = { 0 };
NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface,
- PROP_IFACE,
- PROP_OBJECT_PATH,
+ PROP_SUPPLICANT_MANAGER,
+ PROP_DBUS_OBJECT_PATH,
+ PROP_IFINDEX,
PROP_P2P_GROUP_JOINED,
PROP_P2P_GROUP_PATH,
PROP_P2P_GROUP_OWNER,
@@ -87,53 +79,76 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface,
PROP_CURRENT_BSS,
PROP_DRIVER,
PROP_P2P_AVAILABLE,
- PROP_GLOBAL_CAPABILITIES,
PROP_AUTH_STATE,
);
typedef struct _NMSupplicantInterfacePrivate {
- char * dev;
- NMSupplicantDriver driver;
- NMSupplCapMask global_capabilities;
- NMSupplCapMask iface_capabilities;
- guint32 max_scan_ssids;
- guint32 ready_count;
- char * object_path;
- NMSupplicantInterfaceState state;
- int disconnect_reason;
+ NMSupplicantManager *supplicant_manager;
- GDBusProxy * wpas_proxy;
- GCancellable * init_cancellable;
- GDBusProxy * iface_proxy;
- GCancellable * other_cancellable;
- GDBusProxy * p2p_proxy;
- GDBusProxy * group_proxy;
+ GDBusConnection *dbus_connection;
+ NMRefString *name_owner;
+ NMRefString *object_path;
- WpsData *wps_data;
+ char *ifname;
+
+ GCancellable *main_cancellable;
+
+ NMRefString *p2p_group_path;
- AssocData * assoc_data;
+ GCancellable *p2p_group_properties_cancellable;
- char * net_path;
- GHashTable * bss_proxies;
- char * current_bss;
+ WpsData *wps_data;
- GHashTable * peer_proxies;
+ AssocData *assoc_data;
- gint64 last_scan; /* timestamp as returned by nm_utils_get_monotonic_timestamp_msec() */
+ char *net_path;
+
+ char *driver;
+
+ GHashTable *bss_idx;
+ CList bss_lst_head;
+ CList bss_initializing_lst_head;
+
+ NMRefString *current_bss;
+
+ GHashTable *peer_idx;
+ CList peer_lst_head;
+ CList peer_initializing_lst_head;
+
+ gint64 last_scan_msec;
NMSupplicantAuthState auth_state;
- bool scanning:1;
+ NMSupplicantDriver requested_driver;
+ NMSupplCapMask global_capabilities;
+ NMSupplCapMask iface_capabilities;
- bool scan_done_pending:1;
- bool scan_done_success:1;
+ guint properties_changed_id;
+ guint signal_id;
+ guint bss_properties_changed_id;
+ guint peer_properties_changed_id;
+ guint p2p_group_properties_changed_id;
+
+ int ifindex;
+
+ int starting_pending_count;
+
+ guint32 max_scan_ssids;
+
+ gint32 disconnect_reason;
+
+ NMSupplicantInterfaceState state;
+ NMSupplicantInterfaceState supp_state;
+
+ bool scanning:1;
- bool p2p_proxy_acquired:1;
- bool group_proxy_acquired:1;
bool p2p_capable:1;
- bool p2p_group_owner:1;
+ bool p2p_group_is_owner:1;
+
+ bool is_ready_main:1;
+ bool is_ready_p2p_device:1;
} NMSupplicantInterfacePrivate;
@@ -147,43 +162,73 @@ G_DEFINE_TYPE (NMSupplicantInterface, nm_supplicant_interface, G_TYPE_OBJECT)
/*****************************************************************************/
+static const char *
+_log_pretty_object_path (NMSupplicantInterfacePrivate *priv)
+{
+ const char *s;
+
+ nm_assert (priv);
+ nm_assert (NM_IS_REF_STRING (priv->object_path));
+
+ s = priv->object_path->str;
+ if (NM_STR_HAS_PREFIX (s, "/fi/w1/wpa_supplicant1/Interfaces/")) {
+ s += NM_STRLEN ("/fi/w1/wpa_supplicant1/Interfaces/");
+ if ( s[0]
+ && s[0] != '/')
+ return s;
+ }
+ return priv->object_path->str;
+}
+
#define _NMLOG_DOMAIN LOGD_SUPPLICANT
#define _NMLOG_PREFIX_NAME "sup-iface"
#define _NMLOG(level, ...) \
G_STMT_START { \
- char _sbuf[64]; \
- const char *__ifname = self ? NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev : NULL; \
+ NMSupplicantInterface *_self = (self); \
+ NMSupplicantInterfacePrivate *_priv = _self ? NM_SUPPLICANT_INTERFACE_GET_PRIVATE (_self) : NULL; \
+ char _sbuf[255]; \
+ const char *_ifname = _priv ? _priv->ifname : NULL; \
\
- nm_log ((level), _NMLOG_DOMAIN, __ifname, NULL, \
+ nm_log ((level), _NMLOG_DOMAIN, _ifname, NULL, \
"%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
_NMLOG_PREFIX_NAME, \
- ((self) ? nm_sprintf_buf (_sbuf, "[%p,%s]", (self), __ifname) : "") \
+ ( _self \
+ ? nm_sprintf_buf (_sbuf, \
+ "["NM_HASH_OBFUSCATE_PTR_FMT",%s,%s]", \
+ NM_HASH_OBFUSCATE_PTR (_self), \
+ _log_pretty_object_path (_priv), \
+ _ifname ?: "???") \
+ : "") \
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
} G_STMT_END
/*****************************************************************************/
-static void scan_done_emit_signal (NMSupplicantInterface *self);
+static void _starting_check_ready (NMSupplicantInterface *self);
+
+static void assoc_return (NMSupplicantInterface *self,
+ GError *error,
+ const char *message);
/*****************************************************************************/
NM_UTILS_LOOKUP_STR_DEFINE (nm_supplicant_interface_state_to_string, NMSupplicantInterfaceState,
- NM_UTILS_LOOKUP_DEFAULT_WARN ("unknown"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INVALID, "invalid"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INIT, "init"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_STARTING, "starting"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_READY, "ready"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DISABLED, "disabled"),
+ NM_UTILS_LOOKUP_DEFAULT_WARN ("internal-unknown"),
+ NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INVALID, "internal-invalid"),
+ NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_STARTING, "internal-starting"),
+
+ NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE, "4way_handshake"),
+ NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED, "associated"),
+ NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING, "associating"),
+ NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING, "authenticating"),
+ NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_COMPLETED, "completed"),
NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, "disconnected"),
+ NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE, "group_handshake"),
NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INACTIVE, "inactive"),
+ NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DISABLED, "interface_disabled"),
NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_SCANNING, "scanning"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING, "authenticating"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING, "associating"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED, "associated"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE, "4-way handshake"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE, "group handshake"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_COMPLETED, "completed"),
- NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DOWN, "down"),
+
+ NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DOWN, "internal-down"),
);
static
@@ -206,346 +251,847 @@ NM_UTILS_STRING_TABLE_LOOKUP_DEFINE (
/*****************************************************************************/
+static NM80211ApSecurityFlags
+security_from_vardict (GVariant *security)
+{
+ NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE;
+ const char **array;
+ const char *tmp;
+
+ nm_assert (g_variant_is_of_type (security, G_VARIANT_TYPE_VARDICT));
+
+ if (g_variant_lookup (security, "KeyMgmt", "^a&s", &array)) {
+ if (g_strv_contains (array, "wpa-psk") ||
+ g_strv_contains (array, "wpa-ft-psk"))
+ flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK;
+ if (g_strv_contains (array, "wpa-eap") ||
+ g_strv_contains (array, "wpa-ft-eap") ||
+ g_strv_contains (array, "wpa-fils-sha256") ||
+ g_strv_contains (array, "wpa-fils-sha384"))
+ flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X;
+ if (g_strv_contains (array, "sae"))
+ flags |= NM_802_11_AP_SEC_KEY_MGMT_SAE;
+ if (g_strv_contains (array, "owe"))
+ flags |= NM_802_11_AP_SEC_KEY_MGMT_OWE;
+ g_free (array);
+ }
+
+ if (g_variant_lookup (security, "Pairwise", "^a&s", &array)) {
+ if (g_strv_contains (array, "tkip"))
+ flags |= NM_802_11_AP_SEC_PAIR_TKIP;
+ if (g_strv_contains (array, "ccmp"))
+ flags |= NM_802_11_AP_SEC_PAIR_CCMP;
+ g_free (array);
+ }
+
+ if (g_variant_lookup (security, "Group", "&s", &tmp)) {
+ if (nm_streq (tmp, "wep40"))
+ flags |= NM_802_11_AP_SEC_GROUP_WEP40;
+ else if (nm_streq (tmp, "wep104"))
+ flags |= NM_802_11_AP_SEC_GROUP_WEP104;
+ else if (nm_streq (tmp, "tkip"))
+ flags |= NM_802_11_AP_SEC_GROUP_TKIP;
+ else if (nm_streq (tmp, "ccmp"))
+ flags |= NM_802_11_AP_SEC_GROUP_CCMP;
+ }
+
+ return flags;
+}
+
+/*****************************************************************************/
+
+/* Various conditions prevent _starting_check_ready() from completing. For example,
+ * bss_initializing_lst_head, peer_initializing_lst_head and p2p_group_properties_cancellable.
+ * At some places, these conditions might toggle, and it would seems we would have
+ * to call _starting_check_ready() at that point, to ensure we don't miss a state
+ * change that we are ready. However, these places are deep in the call stack and
+ * not suitable to perform this state change. Instead, the callers *MUST* have
+ * added their own starting_pending_count to delay _starting_check_ready().
+ *
+ * Assert that is the case. */
+#define nm_assert_starting_has_pending_count(v) nm_assert ((v) > 0)
+
+/*****************************************************************************/
+
static void
-bss_data_destroy (gpointer user_data)
+_dbus_connection_call (NMSupplicantInterface *self,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ const GVariantType *reply_type,
+ GDBusCallFlags flags,
+ int timeout_msec,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- BssData *bss_data = user_data;
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- nm_clear_g_signal_handler (bss_data->proxy, &bss_data->change_id);
- g_object_unref (bss_data->proxy);
- g_slice_free (BssData, bss_data);
+ g_dbus_connection_call (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->object_path->str,
+ interface_name,
+ method_name,
+ parameters,
+ reply_type,
+ flags,
+ timeout_msec,
+ cancellable,
+ callback,
+ user_data);
}
static void
-bss_proxy_properties_changed_cb (GDBusProxy *proxy,
- GVariant *changed_properties,
- char **invalidated_properties,
+_dbus_connection_call_simple_cb (GObject *source,
+ GAsyncResult *result,
gpointer user_data)
{
- NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+ NMSupplicantInterface *self;
+ gs_unref_variant GVariant *res = NULL;
+ gs_free_error GError *error = NULL;
+ const char *log_reason;
+ gs_free char *remote_error = NULL;
+
+ nm_utils_user_data_unpack (user_data, &self, &log_reason);
+
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
+ if (res) {
+ _LOGT ("call-%s: success", log_reason);
+ return;
+ }
+
+ remote_error = g_dbus_error_get_remote_error (error);
+ if (!nm_streq0 (remote_error, "fi.w1.wpa_supplicant1.NotConnected")) {
+ g_dbus_error_strip_remote_error (error);
+ _LOGW ("call-%s: failed with %s", log_reason, error->message);
+ return;
+ }
+
+ _LOGT ("call-%s: failed with %s", log_reason, error->message);
+}
+
+static void
+_dbus_connection_call_simple (NMSupplicantInterface *self,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ const GVariantType *reply_type,
+ const char *log_reason)
+{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- if (priv->scanning)
- priv->last_scan = nm_utils_get_monotonic_timestamp_msec ();
+ _dbus_connection_call (self,
+ interface_name,
+ method_name,
+ parameters,
+ reply_type,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_TIMEOUT_MSEC,
+ priv->main_cancellable,
+ _dbus_connection_call_simple_cb,
+ nm_utils_user_data_pack (self, log_reason));
+}
+
+/*****************************************************************************/
- g_signal_emit (self, signals[BSS_UPDATED], 0,
- g_dbus_proxy_get_object_path (proxy),
- changed_properties);
+static void
+_emit_signal_state (NMSupplicantInterface *self,
+ NMSupplicantInterfaceState new_state,
+ NMSupplicantInterfaceState old_state,
+ gint32 disconnect_reason)
+{
+ g_signal_emit (self,
+ signals[STATE],
+ 0,
+ (int) new_state,
+ (int) old_state,
+ (int) disconnect_reason);
}
-static GVariant *
-bss_proxy_get_properties (NMSupplicantInterface *self, GDBusProxy *proxy)
+/*****************************************************************************/
+
+static void
+_remove_network (NMSupplicantInterface *self)
{
- gs_strfreev char **properties = NULL;
- GVariantBuilder builder;
- char **iter;
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ gs_free char *net_path = NULL;
+
+ if (!priv->net_path)
+ return;
+
+ net_path = g_steal_pointer (&priv->net_path);
+ _dbus_connection_call_simple (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "RemoveNetwork",
+ g_variant_new ("(o)", net_path),
+ G_VARIANT_TYPE ("()"),
+ "remove-network");
+}
+
+/*****************************************************************************/
+
+static gboolean
+_prop_p2p_available_get (NMSupplicantInterfacePrivate *priv)
+{
+ return priv->is_ready_p2p_device
+ && priv->p2p_capable;
+}
+
+/*****************************************************************************/
+
+static void
+_bss_info_destroy (NMSupplicantBssInfo *bss_info)
+{
+ c_list_unlink_stale (&bss_info->_bss_lst);
+ nm_clear_g_cancellable (&bss_info->_init_cancellable);
+ g_bytes_unref (bss_info->ssid);
+ nm_ref_string_unref (bss_info->bss_path);
+ nm_g_slice_free (bss_info);
+}
+
+static void
+_bss_info_changed_emit (NMSupplicantInterface *self,
+ NMSupplicantBssInfo *bss_info,
+ gboolean is_present)
+{
+ g_signal_emit (self,
+ signals[BSS_CHANGED],
+ 0,
+ bss_info,
+ is_present);
+}
+
+static void
+_bss_info_properties_changed (NMSupplicantInterface *self,
+ NMSupplicantBssInfo *bss_info,
+ GVariant *properties,
+ gboolean initial)
+{
+ gboolean v_b;
+ GVariant *v_v;
+ const char *v_s;
+ gint16 v_i16;
+ guint16 v_u16;
+ guint32 v_u32;
+ NM80211ApFlags p_ap_flags;
+ NM80211Mode p_mode;
+ guint8 p_signal_percent;
+ const guint8 *arr_data;
+ gsize arr_len;
+ gboolean p_metered;
+ guint32 p_max_rate;
+ gboolean p_max_rate_has;
+ gint64 now_msec = 0;
+
+ if (nm_g_variant_lookup (properties, "Age", "u", &v_u32)) {
+ bss_info->last_seen_msec = nm_utils_get_monotonic_timestamp_msec_cached (&now_msec)
+ - (((gint64) v_u32) * 1000);
+ } else if (initial) {
+ /* Unknown Age. Assume we just received it. */
+ bss_info->last_seen_msec = nm_utils_get_monotonic_timestamp_msec_cached (&now_msec);
+ }
+
+ p_ap_flags = bss_info->ap_flags;
+ if (nm_g_variant_lookup (properties, "Privacy", "b", &v_b))
+ p_ap_flags = NM_FLAGS_ASSIGN (p_ap_flags, NM_802_11_AP_FLAGS_PRIVACY, v_b);
+ else {
+ nm_assert ( !initial
+ || !NM_FLAGS_HAS (p_ap_flags, NM_802_11_AP_FLAGS_PRIVACY));
+ }
+ v_v = nm_g_variant_lookup_value (properties, "WPS", G_VARIANT_TYPE_VARDICT);
+ if ( v_v
+ || initial) {
+ NM80211ApFlags f = NM_802_11_AP_FLAGS_NONE;
+
+ if (v_v) {
+ if (g_variant_lookup (v_v, "Type", "&s", &v_s)) {
+ p_ap_flags = NM_802_11_AP_FLAGS_WPS;
+ if (nm_streq (v_s, "pcb"))
+ f |= NM_802_11_AP_FLAGS_WPS_PBC;
+ else if (nm_streq (v_s, "pin"))
+ f |= NM_802_11_AP_FLAGS_WPS_PIN;
+ }
+ g_variant_unref (v_v);
+ }
+ p_ap_flags = NM_FLAGS_ASSIGN_MASK (p_ap_flags,
+ NM_802_11_AP_FLAGS_WPS
+ | NM_802_11_AP_FLAGS_WPS_PBC
+ | NM_802_11_AP_FLAGS_WPS_PIN,
+ f);
+ }
+ if (bss_info->ap_flags != p_ap_flags) {
+ bss_info->ap_flags = p_ap_flags;
+ nm_assert (bss_info->ap_flags == p_ap_flags);
+ }
+
+ if (nm_g_variant_lookup (properties, "Mode", "&s", &v_s)) {
+ if (nm_streq (v_s, "infrastructure"))
+ p_mode = NM_802_11_MODE_INFRA;
+ else if (nm_streq (v_s, "ad-hoc"))
+ p_mode = NM_802_11_MODE_ADHOC;
+ else if (nm_streq (v_s, "mesh"))
+ p_mode = NM_802_11_MODE_MESH;
+ else
+ p_mode = NM_802_11_MODE_UNKNOWN;
+ } else if (initial)
+ p_mode = NM_802_11_MODE_UNKNOWN;
+ else
+ p_mode = bss_info->mode;
+ if (bss_info->mode != p_mode) {
+ bss_info->mode = p_mode;
+ nm_assert (bss_info->mode == p_mode);
+ }
- iter = properties = g_dbus_proxy_get_cached_property_names (proxy);
+ if (nm_g_variant_lookup (properties, "Signal", "n", &v_i16))
+ p_signal_percent = nm_wifi_utils_level_to_quality (v_i16);
+ else if (initial)
+ p_signal_percent = 0;
+ else
+ p_signal_percent = bss_info->signal_percent;
+ bss_info->signal_percent = p_signal_percent;
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
- if (iter) {
- while (*iter) {
- GVariant *copy = g_dbus_proxy_get_cached_property (proxy, *iter);
+ if (nm_g_variant_lookup (properties, "Frequency", "q", &v_u16))
+ bss_info->frequency = v_u16;
+
+ v_v = nm_g_variant_lookup_value (properties, "SSID", G_VARIANT_TYPE_BYTESTRING);
+ if (v_v) {
+ arr_data = g_variant_get_fixed_array (v_v, &arr_len, 1);
+ arr_len = MIN (32, arr_len);
+
+ /* Stupid ieee80211 layer uses <hidden> */
+ if ( arr_data
+ && arr_len
+ && !( NM_IN_SET (arr_len, 8, 9)
+ && memcmp (arr_data, "<hidden>", arr_len) == 0)
+ && !nm_utils_is_empty_ssid (arr_data, arr_len)) {
+ /* good */
+ } else
+ arr_len = 0;
- g_variant_builder_add (&builder, "{sv}", *iter++, copy);
- g_variant_unref (copy);
+ if (!nm_utils_gbytes_equal_mem (bss_info->ssid, arr_data, arr_len)) {
+ _nm_unused gs_unref_bytes GBytes *old_free = g_steal_pointer (&bss_info->ssid);
+
+ bss_info->ssid = (arr_len == 0)
+ ? NULL
+ : g_bytes_new (arr_data, arr_len);
+ }
+
+ g_variant_unref (v_v);
+ } else {
+ nm_assert ( !initial
+ || !bss_info->ssid);
+ }
+
+ v_v = nm_g_variant_lookup_value (properties, "BSSID", G_VARIANT_TYPE_BYTESTRING);
+ if (v_v) {
+ arr_data = g_variant_get_fixed_array (v_v, &arr_len, 1);
+ if ( arr_len == ETH_ALEN
+ && memcmp (arr_data, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0
+ && memcmp (arr_data, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) {
+ /* pass */
+ } else
+ arr_len = 0;
+
+ if (arr_len != 0) {
+ nm_assert (arr_len == sizeof (bss_info->bssid));
+ bss_info->bssid_valid = TRUE;
+ memcpy (bss_info->bssid, arr_data, sizeof (bss_info->bssid));
+ } else if (bss_info->bssid_valid) {
+ bss_info->bssid_valid = FALSE;
+ memset (bss_info->bssid, 0, sizeof (bss_info->bssid));
}
+ g_variant_unref (v_v);
+ } else {
+ nm_assert ( !initial
+ || !bss_info->bssid_valid);
}
- return g_variant_builder_end (&builder);
+ nm_assert ( ( bss_info->bssid_valid
+ && !nm_utils_memeqzero (bss_info->bssid, sizeof (bss_info->bssid)))
+ || ( !bss_info->bssid_valid
+ && nm_utils_memeqzero (bss_info->bssid, sizeof (bss_info->bssid))));
+
+ p_max_rate_has = FALSE;
+ p_max_rate = 0;
+ v_v = nm_g_variant_lookup_value (properties, "Rates", G_VARIANT_TYPE ("au"));
+ if (v_v) {
+ const guint32 *rates = g_variant_get_fixed_array (v_v, &arr_len, sizeof (guint32));
+ gsize i;
+
+ for (i = 0; i < arr_len; i++)
+ p_max_rate = NM_MAX (p_max_rate, rates[i]);
+ p_max_rate_has = TRUE;
+ g_variant_unref (v_v);
+ }
+ v_v = nm_g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING);
+ if (v_v) {
+ guint32 rate;
+
+ arr_data = g_variant_get_fixed_array (v_v, &arr_len, 1);
+ nm_wifi_utils_parse_ies (arr_data, arr_len, &rate, &p_metered);
+ p_max_rate = NM_MAX (p_max_rate, rate);
+ p_max_rate_has = TRUE;
+ g_variant_unref (v_v);
+
+ bss_info->metered = p_metered;
+ }
+ if (p_max_rate_has)
+ bss_info->max_rate = p_max_rate / 1000u;
+
+
+ v_v = nm_g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT);
+ if (v_v) {
+ bss_info->wpa_flags = security_from_vardict (v_v);
+ g_variant_unref (v_v);
+ }
+
+ v_v = nm_g_variant_lookup_value (properties, "RSN", G_VARIANT_TYPE_VARDICT);
+ if (v_v) {
+ bss_info->rsn_flags = security_from_vardict (v_v);
+ g_variant_unref (v_v);
+ }
+
+ _bss_info_changed_emit (self, bss_info, TRUE);
}
static void
-bss_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+_bss_info_get_all_cb (GVariant *result,
+ GError *error,
+ gpointer user_data)
{
+ NMSupplicantBssInfo *bss_info;
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
- gs_free_error GError *error = NULL;
- GVariant *props = NULL;
- const char *object_path;
- BssData *bss_data;
- gboolean success;
+ gs_unref_variant GVariant *properties = NULL;
- success = g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error);
if (nm_utils_error_is_cancelled (error))
return;
- self = NM_SUPPLICANT_INTERFACE (user_data);
+ bss_info = user_data;
+ self = bss_info->_self;
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- if (!success) {
- _LOGD ("failed to acquire BSS proxy: (%s)", error->message);
- g_hash_table_remove (priv->bss_proxies,
- g_dbus_proxy_get_object_path (proxy));
- return;
- }
+ g_clear_object (&bss_info->_init_cancellable);
+ nm_c_list_move_tail (&priv->bss_lst_head, &bss_info->_bss_lst);
- object_path = g_dbus_proxy_get_object_path (proxy);
- bss_data = g_hash_table_lookup (priv->bss_proxies, object_path);
- if (!bss_data)
- return;
-
- bss_data->change_id = g_signal_connect (proxy, "g-properties-changed", G_CALLBACK (bss_proxy_properties_changed_cb), self);
+ if (result)
+ g_variant_get (result, "(@a{sv})", &properties);
- props = bss_proxy_get_properties (self, proxy);
- g_signal_emit (self, signals[BSS_UPDATED], 0,
- g_dbus_proxy_get_object_path (proxy),
- g_variant_ref_sink (props));
- g_variant_unref (props);
+ _bss_info_properties_changed (self, bss_info, properties, TRUE);
- if (priv->scan_done_pending)
- scan_done_emit_signal (self);
+ _starting_check_ready (self);
}
static void
-bss_add_new (NMSupplicantInterface *self, const char *object_path)
+_bss_info_add (NMSupplicantInterface *self, const char *object_path)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- GDBusProxy *bss_proxy;
- BssData *bss_data;
+ nm_auto_ref_string NMRefString *bss_path = NULL;
+ NMSupplicantBssInfo *bss_info;
- g_return_if_fail (object_path != NULL);
+ bss_path = nm_ref_string_new (nm_dbus_path_not_empty (object_path));
+ if (!bss_path)
+ return;
- if (g_hash_table_lookup (priv->bss_proxies, object_path))
+ bss_info = g_hash_table_lookup (priv->bss_idx, &bss_path);
+ if (bss_info) {
+ bss_info->_bss_dirty = FALSE;
return;
+ }
- bss_proxy = g_object_new (G_TYPE_DBUS_PROXY,
- "g-bus-type", G_BUS_TYPE_SYSTEM,
- "g-flags", G_DBUS_PROXY_FLAGS_NONE,
- "g-name", NM_WPAS_DBUS_SERVICE,
- "g-object-path", object_path,
- "g-interface-name", NM_WPAS_DBUS_IFACE_BSS,
- NULL);
- bss_data = g_slice_new0 (BssData);
- bss_data->proxy = bss_proxy;
- g_hash_table_insert (priv->bss_proxies,
- (char *) g_dbus_proxy_get_object_path (bss_proxy),
- bss_data);
- g_async_initable_init_async (G_ASYNC_INITABLE (bss_proxy),
- G_PRIORITY_DEFAULT,
- priv->other_cancellable,
- (GAsyncReadyCallback) bss_proxy_acquired_cb,
- self);
+ bss_info = g_slice_new (NMSupplicantBssInfo);
+ *bss_info = (NMSupplicantBssInfo) {
+ ._self = self,
+ .bss_path = g_steal_pointer (&bss_path),
+ ._init_cancellable = g_cancellable_new (),
+ };
+ c_list_link_tail (&priv->bss_initializing_lst_head, &bss_info->_bss_lst);
+ g_hash_table_add (priv->bss_idx, bss_info);
+
+ nm_dbus_connection_call_get_all (priv->dbus_connection,
+ priv->name_owner->str,
+ bss_info->bss_path->str,
+ NM_WPAS_DBUS_IFACE_BSS,
+ 5000,
+ bss_info->_init_cancellable,
+ _bss_info_get_all_cb,
+ bss_info);
}
-static void
-peer_data_destroy (gpointer user_data)
+static gboolean
+_bss_info_remove (NMSupplicantInterface *self,
+ NMRefString **p_bss_path)
{
- PeerData *peer_data = user_data;
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ NMSupplicantBssInfo *bss_info;
+ gpointer unused_but_required;
+
+ if (!g_hash_table_steal_extended (priv->bss_idx,
+ p_bss_path,
+ (gpointer *) &bss_info,
+ &unused_but_required))
+ return FALSE;
+
+ c_list_unlink (&bss_info->_bss_lst);
+ if (!bss_info->_init_cancellable)
+ _bss_info_changed_emit (self, bss_info, FALSE);
+ _bss_info_destroy (bss_info);
+
+ nm_assert_starting_has_pending_count (priv->starting_pending_count);
- nm_clear_g_signal_handler (peer_data->proxy, &peer_data->change_id);
- g_object_unref (peer_data->proxy);
- g_slice_free (PeerData, peer_data);
+ return TRUE;
}
+/*****************************************************************************/
+
static void
-peer_proxy_properties_changed_cb (GDBusProxy *proxy,
- GVariant *changed_properties,
- char **invalidated_properties,
- gpointer user_data)
+_peer_info_destroy (NMSupplicantPeerInfo *peer_info)
{
- NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+ c_list_unlink (&peer_info->_peer_lst);
+ nm_clear_g_cancellable (&peer_info->_init_cancellable);
- g_signal_emit (self, signals[PEER_UPDATED], 0,
- g_dbus_proxy_get_object_path (proxy),
- changed_properties);
+ g_free (peer_info->device_name);
+ g_free (peer_info->manufacturer);
+ g_free (peer_info->model);
+ g_free (peer_info->model_number);
+ g_free (peer_info->serial);
+ g_bytes_unref (peer_info->ies);
+
+ nm_g_slice_free (peer_info);
}
-static GVariant *
-peer_proxy_get_properties (NMSupplicantInterface *self, GDBusProxy *proxy)
+static void
+_peer_info_changed_emit (NMSupplicantInterface *self,
+ NMSupplicantPeerInfo *peer_info,
+ gboolean is_present)
{
- gs_strfreev char **properties = NULL;
- GVariantBuilder builder;
- char **iter;
+ g_signal_emit (self,
+ signals[PEER_CHANGED],
+ 0,
+ peer_info,
+ is_present);
+}
+
+static void
+_peer_info_properties_changed (NMSupplicantInterface *self,
+ NMSupplicantPeerInfo *peer_info,
+ GVariant *properties,
+ gboolean initial)
+{
+ GVariant *v_v;
+ const char *v_s;
+ gint32 v_i32;
+ const guint8 *arr_data;
+ gsize arr_len;
+
+ peer_info->last_seen_msec = nm_utils_get_monotonic_timestamp_msec ();
- iter = properties = g_dbus_proxy_get_cached_property_names (proxy);
+ if (nm_g_variant_lookup (properties, "level", "i", &v_i32))
+ peer_info->signal_percent = nm_wifi_utils_level_to_quality (v_i32);
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
- if (iter) {
- while (*iter) {
- GVariant *copy = g_dbus_proxy_get_cached_property (proxy, *iter);
+ if (nm_g_variant_lookup (properties, "DeviceName", "&s", &v_s))
+ nm_utils_strdup_reset (&peer_info->device_name, v_s);
- g_variant_builder_add (&builder, "{sv}", *iter++, copy);
- g_variant_unref (copy);
+ if (nm_g_variant_lookup (properties, "Manufacturer", "&s", &v_s))
+ nm_utils_strdup_reset (&peer_info->manufacturer, v_s);
+
+ if (nm_g_variant_lookup (properties, "Model", "&s", &v_s))
+ nm_utils_strdup_reset (&peer_info->model, v_s);
+
+ if (nm_g_variant_lookup (properties, "ModelNumber", "&s", &v_s))
+ nm_utils_strdup_reset (&peer_info->model_number, v_s);
+
+ if (nm_g_variant_lookup (properties, "Serial", "&s", &v_s))
+ nm_utils_strdup_reset (&peer_info->serial, v_s);
+
+ v_v = nm_g_variant_lookup_value (properties, "DeviceAddress", G_VARIANT_TYPE_BYTESTRING);
+ if (v_v) {
+ arr_data = g_variant_get_fixed_array (v_v, &arr_len, 1);
+ if ( arr_len == ETH_ALEN
+ && memcmp (arr_data, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0
+ && memcmp (arr_data, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) {
+ /* pass */
+ } else
+ arr_len = 0;
+
+ if (arr_len != 0) {
+ nm_assert (arr_len == sizeof (peer_info->address));
+ peer_info->address_valid = TRUE;
+ memcpy (peer_info->address, arr_data, sizeof (peer_info->address));
+ } else if (peer_info->address_valid) {
+ peer_info->address_valid = FALSE;
+ memset (peer_info->address, 0, sizeof (peer_info->address));
}
+ g_variant_unref (v_v);
+ } else {
+ nm_assert ( !initial
+ || !peer_info->address_valid);
}
- return g_variant_builder_end (&builder);
+ nm_assert ( ( peer_info->address_valid
+ && !nm_utils_memeqzero (peer_info->address, sizeof (peer_info->address)))
+ || ( !peer_info->address_valid
+ && nm_utils_memeqzero (peer_info->address, sizeof (peer_info->address))));
+
+ /* The IEs property contains the WFD R1 subelements */
+ v_v = nm_g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING);
+ if (v_v) {
+ arr_data = g_variant_get_fixed_array (v_v, &arr_len, 1);
+ if (!nm_utils_gbytes_equal_mem (peer_info->ies, arr_data, arr_len)) {
+ _nm_unused gs_unref_bytes GBytes *old_free = g_steal_pointer (&peer_info->ies);
+
+ peer_info->ies = g_bytes_new (arr_data, arr_len);
+ } else if ( arr_len == 0
+ && !peer_info->ies)
+ peer_info->ies = g_bytes_new (NULL, 0);
+ g_variant_unref (v_v);
+ }
+
+ _peer_info_changed_emit (self, peer_info, TRUE);
}
static void
-peer_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+_peer_info_get_all_cb (GVariant *result,
+ GError *error,
+ gpointer user_data)
{
+ NMSupplicantPeerInfo *peer_info;
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
- gs_free_error GError *error = NULL;
- GVariant *props = NULL;
- const char *object_path;
- PeerData *peer_data;
- gboolean success;
+ gs_unref_variant GVariant *properties = NULL;
- success = g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error);
if (nm_utils_error_is_cancelled (error))
return;
- self = NM_SUPPLICANT_INTERFACE (user_data);
+ peer_info = user_data;
+ self = peer_info->_self;
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;
+ g_clear_object (&peer_info->_init_cancellable);
+ nm_c_list_move_tail (&priv->peer_lst_head, &peer_info->_peer_lst);
- peer_data->change_id = g_signal_connect (proxy, "g-properties-changed", G_CALLBACK (peer_proxy_properties_changed_cb), self);
+ if (result)
+ g_variant_get (result, "(@a{sv})", &properties);
- props = peer_proxy_get_properties (self, proxy);
+ _peer_info_properties_changed (self, peer_info, properties, TRUE);
- g_signal_emit (self, signals[PEER_UPDATED], 0,
- g_dbus_proxy_get_object_path (proxy),
- g_variant_ref_sink (props));
- g_variant_unref (props);
+ _starting_check_ready (self);
}
static void
-peer_add_new (NMSupplicantInterface *self, const char *object_path)
+_peer_info_add (NMSupplicantInterface *self, const char *object_path)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- GDBusProxy *peer_proxy;
- PeerData *peer_data;
+ nm_auto_ref_string NMRefString *peer_path = NULL;
+ NMSupplicantPeerInfo *peer_info;
+
+ peer_path = nm_ref_string_new (nm_dbus_path_not_empty (object_path));
+ if (!peer_path)
+ return;
- g_return_if_fail (object_path != NULL);
+ peer_info = g_hash_table_lookup (priv->peer_idx, &peer_path);
- if (g_hash_table_lookup (priv->peer_proxies, object_path))
+ if (peer_info) {
+ peer_info->_peer_dirty = FALSE;
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", NM_WPAS_DBUS_SERVICE,
- "g-object-path", object_path,
- "g-interface-name", NM_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);
+ peer_info = g_slice_new (NMSupplicantPeerInfo);
+ *peer_info = (NMSupplicantPeerInfo) {
+ ._self = self,
+ .peer_path = g_steal_pointer (&peer_path),
+ ._init_cancellable = g_cancellable_new (),
+ };
+ c_list_link_tail (&priv->peer_initializing_lst_head, &peer_info->_peer_lst);
+ g_hash_table_add (priv->peer_idx, peer_info);
+
+ nm_dbus_connection_call_get_all (priv->dbus_connection,
+ priv->name_owner->str,
+ peer_info->peer_path->str,
+ NM_WPAS_DBUS_IFACE_PEER,
+ 5000,
+ peer_info->_init_cancellable,
+ _peer_info_get_all_cb,
+ peer_info);
+}
+
+static gboolean
+_peer_info_remove (NMSupplicantInterface *self,
+ NMRefString **p_peer_path)
+{
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ NMSupplicantPeerInfo *peer_info;
+ gpointer unused_but_required;
+
+ if (!g_hash_table_steal_extended (priv->peer_idx,
+ p_peer_path,
+ (gpointer *) &peer_info,
+ &unused_but_required))
+ return FALSE;
+
+ c_list_unlink (&peer_info->_peer_lst);
+ if (!peer_info->_init_cancellable)
+ _peer_info_changed_emit (self, peer_info, FALSE);
+ _peer_info_destroy (peer_info);
+
+ nm_assert_starting_has_pending_count (priv->starting_pending_count);
+
+ return TRUE;
}
/*****************************************************************************/
static void
-set_state (NMSupplicantInterface *self, NMSupplicantInterfaceState new_state)
+set_state_down (NMSupplicantInterface *self,
+ gboolean force_remove_from_supplicant,
+ const char *reason)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- NMSupplicantInterfaceState old_state = priv->state;
+ NMSupplicantBssInfo *bss_info;
+ NMSupplicantPeerInfo *peer_info;
+ NMSupplicantInterfaceState old_state;
- if (new_state == priv->state)
- return;
+ nm_assert (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+ nm_assert (!c_list_is_empty (&self->supp_lst));
+
+ _LOGD ("remove interface \"%s\" on %s (%s)%s",
+ priv->object_path->str,
+ priv->name_owner->str,
+ reason,
+ force_remove_from_supplicant ? " (remove in wpa_supplicant)" : "");
- /* DOWN is a terminal state */
- g_return_if_fail (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+ old_state = priv->state;
- /* Cannot regress to READY, STARTING, or INIT from higher states */
- if (priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY)
- g_return_if_fail (new_state > NM_SUPPLICANT_INTERFACE_STATE_READY);
+ priv->state = NM_SUPPLICANT_INTERFACE_STATE_DOWN;
- if (new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) {
- nm_clear_g_cancellable (&priv->other_cancellable);
- priv->other_cancellable = g_cancellable_new ();
- } else if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
- nm_clear_g_cancellable (&priv->init_cancellable);
- nm_clear_g_cancellable (&priv->other_cancellable);
+ _nm_supplicant_manager_unregister_interface (priv->supplicant_manager, self);
- if (priv->iface_proxy)
- g_signal_handlers_disconnect_by_data (priv->iface_proxy, self);
+ nm_assert (c_list_is_empty (&self->supp_lst));
+
+ if (force_remove_from_supplicant) {
+ _nm_supplicant_manager_dbus_call_remove_interface (priv->supplicant_manager,
+ priv->name_owner->str,
+ priv->object_path->str);
}
- priv->state = new_state;
+ _emit_signal_state (self, priv->state, old_state, 0);
+
+ nm_clear_g_dbus_connection_signal (priv->dbus_connection, &priv->properties_changed_id);
+ nm_clear_g_dbus_connection_signal (priv->dbus_connection, &priv->signal_id);
+ nm_clear_g_dbus_connection_signal (priv->dbus_connection, &priv->bss_properties_changed_id);
+ nm_clear_g_dbus_connection_signal (priv->dbus_connection, &priv->peer_properties_changed_id);
+ nm_clear_g_dbus_connection_signal (priv->dbus_connection, &priv->p2p_group_properties_changed_id);
- if ( priv->state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING
- || old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
- priv->last_scan = nm_utils_get_monotonic_timestamp_msec ();
+ nm_supplicant_interface_cancel_wps (self);
- /* Disconnect reason is no longer relevant when not in the DISCONNECTED state */
- if (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED)
- priv->disconnect_reason = 0;
+ if (priv->assoc_data) {
+ gs_free_error GError *error = NULL;
- g_signal_emit (self, signals[STATE], 0,
- (int) priv->state,
- (int) old_state,
- (int) priv->disconnect_reason);
-}
+ nm_utils_error_set_cancelled (&error, TRUE, "NMSupplicantInterface");
+ assoc_return (self, error, "cancelled because supplicant interface is going down");
+ }
-static void
-set_state_from_string (NMSupplicantInterface *self, const char *new_state)
-{
- NMSupplicantInterfaceState state;
+ while ((bss_info = c_list_first_entry (&priv->bss_initializing_lst_head, NMSupplicantBssInfo, _bss_lst))) {
+ g_hash_table_remove (priv->bss_idx, bss_info);
+ _bss_info_destroy (bss_info);
+ }
+ while ((bss_info = c_list_first_entry (&priv->bss_lst_head, NMSupplicantBssInfo, _bss_lst))) {
+ g_hash_table_remove (priv->bss_idx, bss_info);
+ _bss_info_destroy (bss_info);
+ }
+ nm_assert (g_hash_table_size (priv->bss_idx) == 0);
- state = wpas_state_string_to_enum (new_state);
- if (state == NM_SUPPLICANT_INTERFACE_STATE_INVALID) {
- _LOGW ("unknown supplicant state '%s'", new_state);
- return;
+ while ((peer_info = c_list_first_entry (&priv->peer_initializing_lst_head, NMSupplicantPeerInfo, _peer_lst))) {
+ g_hash_table_remove (priv->peer_idx, peer_info);
+ _peer_info_destroy (peer_info);
}
- set_state (self, state);
+ while ((peer_info = c_list_first_entry (&priv->peer_lst_head, NMSupplicantPeerInfo, _peer_lst))) {
+ g_hash_table_remove (priv->peer_idx, peer_info);
+ _peer_info_destroy (peer_info);
+ }
+ nm_assert (g_hash_table_size (priv->peer_idx) == 0);
+
+ nm_clear_g_cancellable (&priv->main_cancellable);
+ nm_clear_g_cancellable (&priv->p2p_group_properties_cancellable);
+
+ nm_clear_pointer (&priv->p2p_group_path, nm_ref_string_unref);
+
+ _remove_network (self);
+
+ nm_clear_pointer (&priv->current_bss, nm_ref_string_unref);
}
static void
-set_scanning (NMSupplicantInterface *self, gboolean new_scanning)
+set_state (NMSupplicantInterface *self, NMSupplicantInterfaceState new_state)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ NMSupplicantInterfaceState old_state = priv->state;
- if (priv->scanning != new_scanning) {
- priv->scanning = new_scanning;
+ nm_assert (new_state > NM_SUPPLICANT_INTERFACE_STATE_STARTING);
+ nm_assert (new_state < NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+ nm_assert (NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (new_state));
- /* Cache time of last scan completion */
- if (priv->scanning == FALSE)
- priv->last_scan = nm_utils_get_monotonic_timestamp_msec ();
+ nm_assert (priv->state >= NM_SUPPLICANT_INTERFACE_STATE_STARTING);
+ nm_assert (priv->state < NM_SUPPLICANT_INTERFACE_STATE_DOWN);
- _notify (self, PROP_SCANNING);
- }
-}
+ if (new_state == priv->state)
+ return;
-gboolean
-nm_supplicant_interface_get_scanning (NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv;
+ _LOGT ("set state \"%s\" (was \"%s\")",
+ nm_supplicant_interface_state_to_string (new_state),
+ nm_supplicant_interface_state_to_string (priv->state));
- g_return_val_if_fail (self, FALSE);
+ if (old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
+ priv->last_scan_msec = nm_utils_get_monotonic_timestamp_msec ();
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- if (priv->scanning)
- return TRUE;
- if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
- return TRUE;
- return FALSE;
+ priv->state = new_state;
+
+ _emit_signal_state (self,
+ priv->state,
+ old_state,
+ priv->state != NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED
+ ? 0u
+ : priv->disconnect_reason);
}
-const char *
+NMRefString *
nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self)
{
- NMSupplicantInterfacePrivate *priv;
-
g_return_val_if_fail (self != NULL, FALSE);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- return priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY ? priv->current_bss : NULL;
+ return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->current_bss;
+}
+
+static inline gboolean
+_prop_scanning_get (NMSupplicantInterfacePrivate *priv)
+{
+ return ( priv->scanning
+ || priv->supp_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
+ && NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (priv->state);
+}
+
+gboolean
+nm_supplicant_interface_get_scanning (NMSupplicantInterface *self)
+{
+ g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE);
+
+ return _prop_scanning_get (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self));
}
gint64
nm_supplicant_interface_get_last_scan (NMSupplicantInterface *self)
{
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->last_scan;
+ NMSupplicantInterfacePrivate *priv;
+
+ g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE);
+
+ priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+ /* returns -1 if we are currently scanning. */
+ return _prop_scanning_get (priv)
+ ? -1
+ : priv->last_scan_msec;
}
#define MATCH_PROPERTY(p, n, v, t) (!strcmp (p, n) && g_variant_is_of_type (v, t))
@@ -556,12 +1102,11 @@ parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities)
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
gboolean have_active = FALSE;
gboolean have_ssid = FALSE;
- gboolean have_p2p = FALSE;
gboolean have_ft = FALSE;
gint32 max_scan_ssids = -1;
const char **array;
- g_return_if_fail (capabilities && g_variant_is_of_type (capabilities, G_VARIANT_TYPE_VARDICT));
+ nm_assert (capabilities && g_variant_is_of_type (capabilities, G_VARIANT_TYPE_VARDICT));
if (g_variant_lookup (capabilities, "KeyMgmt", "^a&s", &array)) {
have_ft = g_strv_contains (array, "wpa-ft-psk");
@@ -575,16 +1120,13 @@ parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities)
: NM_TERNARY_FALSE);
if (g_variant_lookup (capabilities, "Modes", "^a&s", &array)) {
- if (g_strv_contains (array, "p2p"))
- have_p2p = TRUE;
+ /* Setting p2p_capable might toggle _prop_p2p_available_get(). However,
+ * we don't need to check for a property changed notification, because
+ * the caller did g_object_freeze_notify() and will perform the check. */
+ priv->p2p_capable = g_strv_contains (array, "p2p");
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)) {
if (g_strv_contains (array, "active"))
have_active = TRUE;
@@ -601,63 +1143,40 @@ parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities)
* list, we'll limit to 5.
*/
priv->max_scan_ssids = CLAMP (max_scan_ssids, 0, 5);
- _LOGI ("supports %d scan SSIDs", priv->max_scan_ssids);
+ _LOGD ("supports %d scan SSIDs", priv->max_scan_ssids);
}
}
}
static void
-iface_check_ready (NMSupplicantInterface *self)
+_starting_check_ready (NMSupplicantInterface *self)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- if (priv->ready_count && priv->state < NM_SUPPLICANT_INTERFACE_STATE_READY) {
- priv->ready_count--;
- if (priv->ready_count == 0)
- set_state (self, NM_SUPPLICANT_INTERFACE_STATE_READY);
- }
-}
-
-static void
-iface_set_pmf_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
-{
- NMSupplicantInterface *self;
- gs_unref_variant GVariant *variant = NULL;
- gs_free_error GError *error = NULL;
-
- variant = g_dbus_proxy_call_finish (proxy, result, &error);
- if (nm_utils_error_is_cancelled (error))
+ if (priv->state != NM_SUPPLICANT_INTERFACE_STATE_STARTING)
return;
- self = NM_SUPPLICANT_INTERFACE (user_data);
+ if (priv->starting_pending_count > 0)
+ return;
- if (error)
- _LOGW ("failed to set Pmf=1: %s", error->message);
+ if (!c_list_is_empty (&priv->bss_initializing_lst_head))
+ return;
- iface_check_ready (self);
-}
+ if (!c_list_is_empty (&priv->peer_initializing_lst_head))
+ return;
-gboolean
-nm_supplicant_interface_get_p2p_group_joined (NMSupplicantInterface *self)
-{
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->group_proxy_acquired;
-}
+ if (priv->p2p_group_properties_cancellable)
+ return;
-const char*
-nm_supplicant_interface_get_p2p_group_path (NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ nm_assert (priv->state == NM_SUPPLICANT_INTERFACE_STATE_STARTING);
- if (priv->group_proxy_acquired)
- return g_dbus_proxy_get_object_path (priv->group_proxy);
- else
- return NULL;
-}
+ if (!NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (priv->supp_state)) {
+ _LOGW ("Supplicant state is unknown during initialization. Destroy the interface");
+ set_state_down (self, TRUE, "failure to get valid interface state");
+ return;
+ }
-gboolean
-nm_supplicant_interface_get_p2p_group_owner (NMSupplicantInterface *self)
-{
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_group_owner;
+ set_state (self, priv->supp_state);
}
static NMTernary
@@ -739,179 +1258,328 @@ nm_supplicant_interface_get_auth_state (NMSupplicantInterface *self)
/*****************************************************************************/
+static gboolean
+_prop_p2p_group_joined_get (NMSupplicantInterfacePrivate *priv)
+{
+ return priv->p2p_group_path
+ && !priv->p2p_group_properties_cancellable;
+}
+
+static gboolean
+_prop_p2p_group_is_owner_get (NMSupplicantInterfacePrivate *priv)
+{
+ return _prop_p2p_group_joined_get (priv)
+ && priv->p2p_group_is_owner;
+}
+
static void
-_wps_data_free (WpsData *data)
+_p2p_group_properties_changed (NMSupplicantInterface *self,
+ GVariant *properties)
{
- 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);
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ gboolean old_val_p2p_group_is_owner;
+ const char *s;
+
+ old_val_p2p_group_is_owner = _prop_p2p_group_is_owner_get (priv);
+
+ if (!properties)
+ priv->p2p_group_is_owner = FALSE;
+ else if (g_variant_lookup (properties, "Role", "&s", &s))
+ priv->p2p_group_is_owner = nm_streq (s, "GO");
+
+ if (old_val_p2p_group_is_owner != _prop_p2p_group_is_owner_get (priv))
+ _notify (self, PROP_P2P_GROUP_OWNER);
}
static void
-_wps_credentials_changed_cb (GDBusProxy *proxy,
- GVariant *props,
- gpointer user_data)
+_p2p_group_properties_changed_cb (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *signal_interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
{
NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ gs_unref_variant GVariant *changed_properties = NULL;
+
+ if (priv->p2p_group_properties_cancellable)
+ return;
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
+ return;
+
+ g_variant_get (parameters,
+ "(&s@a{sv}^a&s)",
+ NULL,
+ &changed_properties,
+ NULL);
+
+ _p2p_group_properties_changed (self, changed_properties);
+}
+
+static void
+_p2p_group_properties_get_all_cb (GVariant *result,
+ GError *error,
+ gpointer user_data)
+{
+ NMSupplicantInterface *self;
+ NMSupplicantInterfacePrivate *priv;
+ gboolean old_val_p2p_group_joined;
+ gboolean old_val_p2p_group_is_owner;
+ gs_unref_variant GVariant *properties = NULL;
+
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
+ self = NM_SUPPLICANT_INTERFACE (user_data);
+ priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+ g_object_freeze_notify (G_OBJECT (self));
+
+ old_val_p2p_group_joined = _prop_p2p_group_joined_get (priv);
+ old_val_p2p_group_is_owner = _prop_p2p_group_is_owner_get (priv);
+
+ nm_clear_g_cancellable (&priv->p2p_group_properties_cancellable);
+
+ if (result)
+ g_variant_get (result, "(@a{sv})", &properties);
+
+ _p2p_group_properties_changed (self, properties);
+
+ _starting_check_ready (self);
+
+ if (old_val_p2p_group_joined != _prop_p2p_group_joined_get (priv))
+ _notify (self, PROP_P2P_GROUP_JOINED);
+ if (old_val_p2p_group_is_owner != _prop_p2p_group_is_owner_get (priv))
+ _notify (self, PROP_P2P_GROUP_OWNER);
+
+ g_object_thaw_notify (G_OBJECT (self));
+}
+
+static void
+_p2p_group_set_path (NMSupplicantInterface *self,
+ const char *path)
+{
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ nm_auto_ref_string NMRefString *group_path = NULL;
+ gboolean old_val_p2p_group_joined;
+ gboolean old_val_p2p_group_is_owner;
+
+ group_path = nm_ref_string_new (nm_dbus_path_not_empty (path));
+
+ if (priv->p2p_group_path == group_path)
+ return;
+
+ old_val_p2p_group_joined = _prop_p2p_group_joined_get (priv);
+ old_val_p2p_group_is_owner = _prop_p2p_group_is_owner_get (priv);
+
+ nm_clear_g_dbus_connection_signal (priv->dbus_connection,
+ &priv->p2p_group_properties_changed_id);
+ nm_clear_g_cancellable (&priv->p2p_group_properties_cancellable);
+
+ nm_ref_string_unref (priv->p2p_group_path);
+ priv->p2p_group_path = g_steal_pointer (&group_path);
+
+ if (priv->p2p_group_path) {
+ priv->p2p_group_properties_cancellable = g_cancellable_new ();
+ priv->p2p_group_properties_changed_id = nm_dbus_connection_signal_subscribe_properties_changed (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->p2p_group_path->str,
+ NM_WPAS_DBUS_IFACE_GROUP,
+ _p2p_group_properties_changed_cb,
+ self,
+ NULL);
+ nm_dbus_connection_call_get_all (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->p2p_group_path->str,
+ NM_WPAS_DBUS_IFACE_GROUP,
+ 5000,
+ priv->p2p_group_properties_cancellable,
+ _p2p_group_properties_get_all_cb,
+ self);
+ }
+
+ _notify (self, PROP_P2P_GROUP_PATH);
+ if (old_val_p2p_group_joined != _prop_p2p_group_joined_get (priv))
+ _notify (self, PROP_P2P_GROUP_JOINED);
+ if (old_val_p2p_group_is_owner != _prop_p2p_group_is_owner_get (priv))
+ _notify (self, PROP_P2P_GROUP_OWNER);
+
+ nm_assert_starting_has_pending_count (priv->starting_pending_count);
+}
+
+/*****************************************************************************/
+
+static void
+_wps_data_free (WpsData *wps_data,
+ GDBusConnection *dbus_connection)
+{
+ nm_clear_g_dbus_connection_signal (dbus_connection,
+ &wps_data->signal_id);
+ nm_clear_g_cancellable (&wps_data->cancellable);
+ g_free (wps_data->type);
+ g_free (wps_data->pin);
+ g_free (wps_data->bssid);
+ nm_g_slice_free (wps_data);
+}
+
+static void
+_wps_credentials_changed_cb (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *signal_interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ NMSupplicantInterface *self = user_data;
+ gs_unref_variant GVariant *props = NULL;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})")))
+ return;
+
+ g_variant_get (parameters, "(@a{sv})", &props);
_LOGT ("wps: new credentials");
g_signal_emit (self, signals[WPS_CREDENTIALS], 0, props);
}
static void
-_wps_handle_start_cb (GObject *source_object,
- GAsyncResult *res,
+_wps_handle_start_cb (GObject *source,
+ GAsyncResult *result,
gpointer user_data)
{
NMSupplicantInterface *self;
- WpsData *data;
- gs_unref_variant GVariant *result = NULL;
+ WpsData *wps_data;
+ gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
- result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if (nm_utils_error_is_cancelled (error))
return;
- data = user_data;
- self = data->self;
+ wps_data = user_data;
+ self = wps_data->self;
- if (result)
+ if (res)
_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);
+ g_clear_object (&wps_data->cancellable);
+ nm_clear_g_free (&wps_data->type);
+ nm_clear_g_free (&wps_data->pin);
+ nm_clear_g_free (&wps_data->bssid);
}
static void
-_wps_handle_set_pc_cb (GObject *source_object,
- GAsyncResult *res,
+_wps_handle_set_pc_cb (GVariant *res,
+ GError *error,
gpointer user_data)
{
- WpsData *data;
NMSupplicantInterface *self;
- gs_unref_variant GVariant *result = NULL;
- gs_free_error GError *error = NULL;
+ NMSupplicantInterfacePrivate *priv;
+ WpsData *wps_data;
GVariantBuilder start_args;
guint8 bssid_buf[ETH_ALEN];
- result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
if (nm_utils_error_is_cancelled (error))
return;
- data = user_data;
- self = data->self;
+ wps_data = user_data;
+ self = wps_data->self;
+ priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- if (result)
+ if (res)
_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);
+ wps_data->signal_id = g_dbus_connection_signal_subscribe (priv->dbus_connection,
+ priv->name_owner->str,
+ NM_WPAS_DBUS_IFACE_INTERFACE_WPS,
+ "Credentials",
+ priv->object_path->str,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ _wps_credentials_changed_cb,
+ self,
+ NULL);
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) {
+ g_variant_builder_add (&start_args, "{sv}", "Type", g_variant_new_string (wps_data->type));
+ if (wps_data->pin)
+ g_variant_builder_add (&start_args, "{sv}", "Pin", g_variant_new_string (wps_data->pin));
+ if (wps_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)))
+ if (!nm_utils_hwaddr_aton (wps_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);
-}
+ wps_data->needs_cancelling = TRUE;
+ if (!wps_data->cancellable)
+ wps_data->cancellable = g_cancellable_new ();
-static void
-_wps_call_set_pc (WpsData *data)
-{
- g_dbus_proxy_call (data->proxy,
- "org.freedesktop.DBus.Properties.Set",
- g_variant_new ("(ssv)",
- NM_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);
+ _dbus_connection_call (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE_WPS,
+ "Start",
+ g_variant_new ("(a{sv})", &start_args),
+ G_VARIANT_TYPE ("(a{sv})"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 5000,
+ wps_data->cancellable,
+ _wps_handle_start_cb,
+ wps_data);
}
static void
-_wps_handle_proxy_cb (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
+_wps_call_set_pc (NMSupplicantInterface *self,
+ WpsData *wps_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 (nm_utils_error_is_cancelled (error))
- return;
-
- data = user_data;
- self = data->self;
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ NMSupplicantInterfacePrivate *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;
- }
+ if (!wps_data->cancellable)
+ wps_data->cancellable = g_cancellable_new ();
- data->proxy = proxy;
- _LOGT ("wps: D-Bus proxy created. set ProcessCredentials...");
- _wps_call_set_pc (data);
+ nm_dbus_connection_call_set (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->object_path->str,
+ NM_WPAS_DBUS_IFACE_INTERFACE_WPS,
+ "ProcessCredentials",
+ g_variant_new_boolean (TRUE),
+ 5000,
+ wps_data->cancellable,
+ _wps_handle_set_pc_cb,
+ wps_data);
}
static void
-_wps_handle_cancel_cb (GObject *source_object,
- GAsyncResult *res,
+_wps_handle_cancel_cb (GObject *source,
+ GAsyncResult *result,
gpointer user_data)
{
+ GDBusConnection *dbus_connection = G_DBUS_CONNECTION (source);
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
- WpsData *data;
- gs_unref_variant GVariant *result = NULL;
+ WpsData *wps_data;
+ gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
- result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error);
- if (nm_utils_error_is_cancelled (error))
- return;
+ res = g_dbus_connection_call_finish (dbus_connection, result, &error);
+ nm_assert (!nm_utils_error_is_cancelled (error));
- data = user_data;
- self = data->self;
+ wps_data = user_data;
+ self = wps_data->self;
if (!self) {
- _wps_data_free (data);
- if (result)
+ _wps_data_free (wps_data, dbus_connection);
+ if (res)
_LOGT ("wps: cancel completed successfully, after supplicant interface is gone");
else
_LOGW ("wps: cancel failed (%s), after supplicant interface is gone", error->message);
@@ -920,23 +1588,24 @@ _wps_handle_cancel_cb (GObject *source_object,
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- data->is_cancelling = FALSE;
+ wps_data->is_cancelling = FALSE;
- if (!data->type) {
+ if (!wps_data->type) {
priv->wps_data = NULL;
- _wps_data_free (data);
- if (result)
+ _wps_data_free (wps_data, dbus_connection);
+ if (res)
_LOGT ("wps: cancel completed successfully");
else
_LOGW ("wps: cancel failed (%s)", error->message);
return;
}
- if (result)
+ if (res)
_LOGT ("wps: cancel completed successfully, setting ProcessCredentials now...");
else
_LOGW ("wps: cancel failed (%s), setting ProcessCredentials now...", error->message);
- _wps_call_set_pc (data);
+
+ _wps_call_set_pc (self, wps_data);
}
static void
@@ -946,74 +1615,71 @@ _wps_start (NMSupplicantInterface *self,
const char *pin)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- WpsData *data = priv->wps_data;
+ WpsData *wps_data;
if (type)
_LOGI ("wps: type %s start...", type);
- if (!data) {
+ wps_data = priv->wps_data;
+
+ if (!wps_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,
- NM_WPAS_DBUS_SERVICE,
- priv->object_path,
- NM_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 (priv->state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
+ _LOGD ("wps: interface is down. Cannot start with WPS");
+ return;
+ }
- if (!data->proxy) {
- if (!type) {
- nm_clear_g_cancellable (&data->cancellable);
- priv->wps_data = NULL;
- _wps_data_free (data);
+ wps_data = g_slice_new (WpsData);
+ *wps_data = (WpsData) {
+ .self = self,
+ .type = g_strdup (type),
+ .bssid = g_strdup (bssid),
+ .pin = g_strdup (pin),
+ };
+ priv->wps_data = wps_data;
+ } else {
+ g_free (wps_data->type);
+ g_free (wps_data->bssid);
+ g_free (wps_data->pin);
+ wps_data->type = g_strdup (type);
+ wps_data->bssid = g_strdup (bssid);
+ wps_data->pin = g_strdup (pin);
+ }
- _LOGT ("wps: abort creation of D-Bus proxy");
- } else
- _LOGT ("wps: new enrollment. Wait for D-Bus proxy...");
+ if (wps_data->is_cancelling) {
+ /* we wait for cancellation to complete. */
return;
}
- if (data->is_cancelling)
+ if ( !type
+ || wps_data->needs_cancelling) {
+
+ _LOGT ("wps: cancel %senrollment...",
+ wps_data->needs_cancelling ? "previous " : "");
+
+ wps_data->is_cancelling = TRUE;
+ wps_data->needs_cancelling = FALSE;
+ nm_clear_g_cancellable (&wps_data->cancellable);
+ nm_clear_g_dbus_connection_signal (priv->dbus_connection,
+ &wps_data->signal_id);
+
+ _dbus_connection_call (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE_WPS,
+ "Cancel",
+ NULL,
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 5000,
+ NULL,
+ _wps_handle_cancel_cb,
+ wps_data);
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);
+ _LOGT ("wps: setting ProcessCredentials...");
+ _wps_call_set_pc (self, wps_data);
}
void
@@ -1034,875 +1700,202 @@ nm_supplicant_interface_cancel_wps (NMSupplicantInterface *self)
/*****************************************************************************/
static void
-iface_introspect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+iface_introspect_cb (GObject *source, GAsyncResult *result, gpointer user_data)
{
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
- gs_unref_variant GVariant *variant = NULL;
+ gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
const char *data;
NMTernary value;
- variant = _nm_dbus_proxy_call_finish (proxy, result,
- G_VARIANT_TYPE ("(s)"),
- &error);
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if (nm_utils_error_is_cancelled (error))
return;
self = NM_SUPPLICANT_INTERFACE (user_data);
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- if (NM_SUPPL_CAP_MASK_GET (priv->global_capabilities, NM_SUPPL_CAP_TYPE_AP) == NM_TERNARY_DEFAULT) {
- /* if the global value is set, we trust it and ignore whatever we get from introspection. */
- } else {
- value = NM_TERNARY_DEFAULT;
- if (variant) {
- g_variant_get (variant, "(&s)", &data);
-
- /* The ProbeRequest method only exists if AP mode has been enabled */
- value = strstr (data, "ProbeRequest")
- ? NM_TERNARY_TRUE
- : NM_TERNARY_FALSE;
- }
- priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET (priv->iface_capabilities, NM_SUPPL_CAP_TYPE_AP, value);
- }
+ nm_assert (NM_SUPPL_CAP_MASK_GET (priv->global_capabilities, NM_SUPPL_CAP_TYPE_AP) == NM_TERNARY_DEFAULT);
- iface_check_ready (self);
-}
+ value = NM_TERNARY_DEFAULT;
+ if (res) {
+ g_variant_get (res, "(&s)", &data);
-static void
-scan_done_emit_signal (NMSupplicantInterface *self)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- const char *object_path;
- BssData *bss_data;
- gboolean success;
- GHashTableIter iter;
-
- g_hash_table_iter_init (&iter, priv->bss_proxies);
- while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &bss_data)) {
- /* we have some BSS' that need to be initialized first. Delay
- * emitting signal. */
- if (!bss_data->change_id) {
- priv->scan_done_pending = TRUE;
- return;
- }
+ /* The ProbeRequest method only exists if AP mode has been enabled */
+ value = strstr (data, "ProbeRequest")
+ ? NM_TERNARY_TRUE
+ : NM_TERNARY_FALSE;
}
- /* Emit BSS_UPDATED so that wifi device has the APs (in case it removed them) */
- g_hash_table_iter_init (&iter, priv->bss_proxies);
- while (g_hash_table_iter_next (&iter, (gpointer *) &object_path, (gpointer *) &bss_data)) {
- gs_unref_variant GVariant *props = NULL;
-
- props = bss_proxy_get_properties (self, bss_data->proxy);
- g_signal_emit (self, signals[BSS_UPDATED], 0,
- object_path,
- g_variant_ref_sink (props));
- }
+ priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET (priv->iface_capabilities, NM_SUPPL_CAP_TYPE_AP, value);
- success = priv->scan_done_success;
- priv->scan_done_success = FALSE;
- priv->scan_done_pending = FALSE;
- g_signal_emit (self, signals[SCAN_DONE], 0, success);
+ priv->starting_pending_count--;
+ _starting_check_ready (self);
}
static void
-wpas_iface_scan_done (GDBusProxy *proxy,
- gboolean success,
- gpointer user_data)
+_properties_changed_main (NMSupplicantInterface *self,
+ GVariant *properties)
{
- NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-
- /* Cache last scan completed time */
- priv->last_scan = nm_utils_get_monotonic_timestamp_msec ();
- priv->scan_done_success |= success;
- scan_done_emit_signal (self);
-}
-
-static void
-wpas_iface_bss_added (GDBusProxy *proxy,
- const char *path,
- GVariant *props,
- gpointer user_data)
-{
- NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-
- if (priv->scanning)
- priv->last_scan = nm_utils_get_monotonic_timestamp_msec ();
-
- bss_add_new (self, path);
-}
-
-static void
-wpas_iface_bss_removed (GDBusProxy *proxy,
- const char *path,
- gpointer user_data)
-{
- NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- BssData *bss_data;
-
- bss_data = g_hash_table_lookup (priv->bss_proxies, path);
- if (!bss_data)
- return;
- g_hash_table_steal (priv->bss_proxies, path);
- g_signal_emit (self, signals[BSS_REMOVED], 0, path);
- bss_data_destroy (bss_data);
-}
-
-static void
-eap_changed (GDBusProxy *proxy,
- const char *status,
- const char *parameter,
- gpointer user_data)
-{
- NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- NMSupplicantAuthState auth_state = NM_SUPPLICANT_AUTH_STATE_UNKNOWN;
-
- if (nm_streq0 (status, "started"))
- auth_state = NM_SUPPLICANT_AUTH_STATE_STARTED;
- else if (nm_streq0 (status, "completion")) {
- if (nm_streq0 (parameter, "success"))
- auth_state = NM_SUPPLICANT_AUTH_STATE_SUCCESS;
- else if (nm_streq0 (parameter, "failure"))
- auth_state = NM_SUPPLICANT_AUTH_STATE_FAILURE;
- }
-
- /* the state eventually reaches one of started, success or failure
- * so ignore any other intermediate (unknown) state change. */
- if ( auth_state != NM_SUPPLICANT_AUTH_STATE_UNKNOWN
- && auth_state != priv->auth_state) {
- priv->auth_state = auth_state;
- _notify (self, PROP_AUTH_STATE);
- }
-}
-
-static void
-props_changed_cb (GDBusProxy *proxy,
- GVariant *changed_properties,
- GStrv invalidated_properties,
- gpointer user_data)
-{
- NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- const char *s, **array, **iter;
- gboolean b = FALSE;
- gint32 i32;
- GVariant *v;
-
- g_object_freeze_notify (G_OBJECT (self));
-
- if (g_variant_lookup (changed_properties, "Scanning", "b", &b))
- set_scanning (self, b);
-
- if ( g_variant_lookup (changed_properties, "State", "&s", &s)
- && priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY) {
- /* Only transition to actual wpa_supplicant interface states (ie,
- * anything > READY) after the NMSupplicantInterface has had a
- * chance to initialize, which is signalled by entering the READY
- * state.
- */
- set_state_from_string (self, s);
- }
-
- if (g_variant_lookup (changed_properties, "BSSs", "^a&o", &array)) {
- iter = array;
- while (*iter)
- bss_add_new (self, *iter++);
- g_free (array);
- }
-
- if (g_variant_lookup (changed_properties, "CurrentBSS", "&o", &s)) {
- s = nm_dbus_path_not_empty (s);
- if (!nm_streq0 (s, priv->current_bss)) {
- g_free (priv->current_bss);
- priv->current_bss = g_strdup (s);
- _notify (self, PROP_CURRENT_BSS);
+ const char **v_strv;
+ const char *v_s;
+ gboolean v_b;
+ gint32 v_i32;
+ GVariant *v_v;
+ gboolean do_log_driver_info = FALSE;
+ gboolean do_set_state = FALSE;
+ gboolean do_notify_current_bss = FALSE;
+
+ nm_assert (properties || g_variant_is_of_type (properties, G_VARIANT_TYPE ("a{sv}")));
+
+ v_v = g_variant_lookup_value (properties, "Capabilities", G_VARIANT_TYPE_VARDICT);
+ if (v_v) {
+ parse_capabilities (self, v_v);
+ g_variant_unref (v_v);
+ }
+
+ if (nm_g_variant_lookup (properties, "Scanning", "b", &v_b)) {
+ if (priv->scanning != (!!v_b)) {
+ if (priv->scanning)
+ priv->last_scan_msec = nm_utils_get_monotonic_timestamp_msec ();
+ priv->scanning = v_b;
}
}
- v = g_variant_lookup_value (changed_properties, "Capabilities", G_VARIANT_TYPE_VARDICT);
- if (v) {
- parse_capabilities (self, v);
- g_variant_unref (v);
+ if (nm_g_variant_lookup (properties, "Ifname", "&s", &v_s)) {
+ if (nm_utils_strdup_reset (&priv->ifname, v_s))
+ do_log_driver_info = TRUE;
+ }
+ if (nm_g_variant_lookup (properties, "Driver", "&s", &v_s)) {
+ if (nm_utils_strdup_reset (&priv->driver, v_s))
+ do_log_driver_info = TRUE;
}
- if (g_variant_lookup (changed_properties, "DisconnectReason", "i", &i32)) {
+ if (nm_g_variant_lookup (properties, "DisconnectReason", "i", &v_i32)) {
/* Disconnect reason is currently only given for deauthentication events,
* not disassociation; currently they are IEEE 802.11 "reason codes",
* defined by (IEEE 802.11-2007, 7.3.1.7, Table 7-22). Any locally caused
* deauthentication will be negative, while authentications caused by the
* AP will be positive.
*/
- priv->disconnect_reason = i32;
- if (priv->disconnect_reason != 0)
- _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));
-}
-
-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 <hidden> */
- if ( bytes && len
- && !(((len == 8) || (len == 9)) && !memcmp (bytes, "<hidden>", 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);
- }
-
- /* 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));
-}
-
-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 (nm_utils_error_is_cancelled (error))
- 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);
- _notify (self, PROP_P2P_GROUP_PATH);
-
- iface_check_ready (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);
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- const char **array, **iter;
- const char *path = NULL;
-
- 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);
- }
-
- 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 (nm_dbus_path_not_empty (path)) {
- if (priv->group_proxy != NULL) {
- _LOGW ("P2P: Unexpected update 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);
+ priv->disconnect_reason = v_i32;
+ }
+
+ if (nm_g_variant_lookup (properties, "State", "&s", &v_s)) {
+ NMSupplicantInterfaceState state;
+
+ state = wpas_state_string_to_enum (v_s);
+ if (state == NM_SUPPLICANT_INTERFACE_STATE_INVALID)
+ _LOGT ("ignore unknown supplicant state '%s'", v_s);
+ else if (priv->supp_state != state) {
+ priv->supp_state = state;
+ if (priv->state > NM_SUPPLICANT_INTERFACE_STATE_STARTING) {
+ /* Only transition to actual wpa_supplicant interface states (ie,
+ * anything > STARTING) after the NMSupplicantInterface has had a
+ * chance to initialize, which is signalled by entering the STARTING
+ * state.
+ */
+ do_set_state = TRUE;
}
-
- /* 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", NM_WPAS_DBUS_SERVICE,
- "g-object-path", path,
- "g-interface-name", NM_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);
- _notify (self, PROP_P2P_GROUP_PATH);
- g_clear_object (&priv->group_proxy);
}
}
- 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
-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;
+ if (nm_g_variant_lookup (properties, "CurrentBSS", "&o", &v_s)) {
+ v_s = nm_dbus_path_not_empty (v_s);
+ if (!nm_ref_string_equals_str (priv->current_bss, v_s)) {
+ nm_ref_string_unref (priv->current_bss);
+ priv->current_bss = nm_ref_string_new (v_s);
+ do_notify_current_bss = TRUE;
}
}
- /* Signal existence of the (new) interface. */
- g_signal_emit (self, signals[GROUP_STARTED], 0, iface);
- g_object_unref (iface);
-}
-
-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;
+ if (do_log_driver_info) {
+ _LOGD ("supplicant interface for ifindex=%d, ifname=%s%s%s, driver=%s%s%s (requested %s)",
+ priv->ifindex,
+ NM_PRINT_FMT_QUOTE_STRING (priv->ifname),
+ NM_PRINT_FMT_QUOTE_STRING (priv->driver),
+ nm_supplicant_driver_to_string (priv->requested_driver));
}
- _LOGD ("P2P: GroupFinished signal on interface %s for interface %s", priv->object_path, iface_path);
+ if (nm_g_variant_lookup (properties, "BSSs", "^a&o", &v_strv)) {
+ NMSupplicantBssInfo *bss_info;
+ NMSupplicantBssInfo *bss_info_safe;
+ const char **iter;
- /* Signal group finish interface (on management interface). */
- g_signal_emit (self, signals[GROUP_FINISHED], 0, iface_path);
-}
+ c_list_for_each_entry (bss_info, &priv->bss_lst_head, _bss_lst)
+ bss_info->_bss_dirty = TRUE;
+ c_list_for_each_entry (bss_info, &priv->bss_initializing_lst_head, _bss_lst)
+ bss_info->_bss_dirty = TRUE;
-static void
-on_iface_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 (!nm_utils_error_is_cancelled (error)) {
- self = NM_SUPPLICANT_INTERFACE (user_data);
- _LOGW ("failed to acquire wpa_supplicant interface proxy: (%s)", error->message);
- set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
- }
- return;
- }
-
- self = NM_SUPPLICANT_INTERFACE (user_data);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-
- _nm_dbus_signal_connect (priv->iface_proxy, "ScanDone", G_VARIANT_TYPE ("(b)"),
- G_CALLBACK (wpas_iface_scan_done), self);
- _nm_dbus_signal_connect (priv->iface_proxy, "BSSAdded", G_VARIANT_TYPE ("(oa{sv})"),
- G_CALLBACK (wpas_iface_bss_added), self);
- _nm_dbus_signal_connect (priv->iface_proxy, "BSSRemoved", G_VARIANT_TYPE ("(o)"),
- G_CALLBACK (wpas_iface_bss_removed), self);
- _nm_dbus_signal_connect (priv->iface_proxy, "EAP", G_VARIANT_TYPE ("(ss)"),
- G_CALLBACK (eap_changed), self);
-
- /* Scan result aging parameters */
- g_dbus_proxy_call (priv->iface_proxy,
- DBUS_INTERFACE_PROPERTIES ".Set",
- g_variant_new ("(ssv)",
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "BSSExpireAge",
- g_variant_new_uint32 (250)),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- priv->init_cancellable,
- NULL,
- NULL);
- g_dbus_proxy_call (priv->iface_proxy,
- DBUS_INTERFACE_PROPERTIES ".Set",
- g_variant_new ("(ssv)",
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "BSSExpireCount",
- g_variant_new_uint32 (2)),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- priv->init_cancellable,
- NULL,
- NULL);
-
- if (_get_capability (priv, NM_SUPPL_CAP_TYPE_PMF) == NM_TERNARY_TRUE) {
- /* Initialize global PMF setting to 'optional' */
- priv->ready_count++;
- g_dbus_proxy_call (priv->iface_proxy,
- DBUS_INTERFACE_PROPERTIES ".Set",
- g_variant_new ("(ssv)",
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "Pmf",
- g_variant_new_string ("1")),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- priv->init_cancellable,
- (GAsyncReadyCallback) iface_set_pmf_cb,
- self);
- }
-
- if (_get_capability (priv, NM_SUPPL_CAP_TYPE_AP) == NM_TERNARY_DEFAULT) {
- /* If the global supplicant capabilities property is not present, we can
- * fall back to checking whether the ProbeRequest method is supported. If
- * neither of these works we have no way of determining if AP mode is
- * supported or not. hostap 1.0 and earlier don't support either of these.
- */
- priv->ready_count++;
- g_dbus_proxy_call (priv->iface_proxy,
- DBUS_INTERFACE_INTROSPECTABLE ".Introspect",
- NULL,
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- priv->init_cancellable,
- (GAsyncReadyCallback) iface_introspect_cb,
- self);
- }
-
- iface_check_ready (self);
-}
-
-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 (!nm_utils_error_is_cancelled (error)) {
- self = NM_SUPPLICANT_INTERFACE (user_data);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- _LOGW ("failed to acquire wpa_supplicant p2p proxy: (%s)", error->message);
+ for (iter = v_strv; *iter; iter++)
+ _bss_info_add (self, *iter);
- g_clear_object (&priv->p2p_proxy);
+ g_free (v_strv);
- iface_check_ready (self);
+ c_list_for_each_entry_safe (bss_info, bss_info_safe, &priv->bss_initializing_lst_head, _bss_lst) {
+ if (bss_info->_bss_dirty)
+ _bss_info_remove (self, &bss_info->bss_path);
}
- return;
- }
-
- 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);
- _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, "GroupFinished", G_VARIANT_TYPE ("(a{sv})"),
- G_CALLBACK (p2p_group_finished), self);
- /* TODO:
- * * 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)
-{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-
- _LOGD ("interface added to supplicant");
-
- 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,
- "g-name", NM_WPAS_DBUS_SERVICE,
- "g-object-path", priv->object_path,
- "g-interface-name", NM_WPAS_DBUS_IFACE_INTERFACE,
- NULL);
- g_signal_connect (priv->iface_proxy, "g-properties-changed", G_CALLBACK (props_changed_cb), self);
- g_async_initable_init_async (G_ASYNC_INITABLE (priv->iface_proxy),
- G_PRIORITY_DEFAULT,
- priv->init_cancellable,
- (GAsyncReadyCallback) on_iface_proxy_acquired,
- self);
-
- if (_get_capability (priv, NM_SUPPL_CAP_TYPE_P2P) == NM_TERNARY_TRUE) {
- 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", NM_WPAS_DBUS_SERVICE,
- "g-object-path", priv->object_path,
- "g-interface-name", NM_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,
- (GAsyncReadyCallback) on_p2p_proxy_acquired,
- self);
- }
-}
-
-static void
-interface_get_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
-{
- NMSupplicantInterface *self;
- gs_unref_variant GVariant *variant = NULL;
- gs_free_error GError *error = NULL;
- const char *path;
-
- variant = _nm_dbus_proxy_call_finish (proxy, result,
- G_VARIANT_TYPE ("(o)"),
- &error);
- if (nm_utils_error_is_cancelled (error))
- return;
-
- self = NM_SUPPLICANT_INTERFACE (user_data);
-
- if (variant) {
- g_variant_get (variant, "(&o)", &path);
- interface_add_done (self, path);
- } else {
- g_dbus_error_strip_remote_error (error);
- _LOGE ("error getting interface: %s", error->message);
- set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
- }
-}
-
-static void
-interface_add_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
-{
- NMSupplicantInterface *self;
- NMSupplicantInterfacePrivate *priv;
- gs_free_error GError *error = NULL;
- gs_unref_variant GVariant *variant = NULL;
- const char *path;
-
- variant = _nm_dbus_proxy_call_finish (proxy, result,
- G_VARIANT_TYPE ("(o)"),
- &error);
- if (nm_utils_error_is_cancelled (error))
- return;
-
- self = NM_SUPPLICANT_INTERFACE (user_data);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
-
- if (variant) {
- g_variant_get (variant, "(&o)", &path);
- interface_add_done (self, path);
- } else if (_nm_dbus_error_has_name (error, NM_WPAS_ERROR_EXISTS_ERROR)) {
- /* Interface already added, just get its object path */
- g_dbus_proxy_call (priv->wpas_proxy,
- "GetInterface",
- g_variant_new ("(s)", priv->dev),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- priv->init_cancellable,
- (GAsyncReadyCallback) interface_get_cb,
- self);
- } else if ( g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)
- || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_EXEC_FAILED)
- || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FORK_FAILED)
- || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FAILED)
- || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMEOUT)
- || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NO_REPLY)
- || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMED_OUT)
- || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) {
- /* Supplicant wasn't running and could not be launched via service
- * activation. Wait for it to start by moving back to the INIT
- * state.
- */
- g_dbus_error_strip_remote_error (error);
- _LOGD ("failed to activate supplicant: %s", error->message);
- set_state (self, NM_SUPPLICANT_INTERFACE_STATE_INIT);
- } else {
- g_dbus_error_strip_remote_error (error);
- _LOGE ("error adding interface: %s", error->message);
- set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
- }
-}
-
-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);
- _notify (self, PROP_OBJECT_PATH);
-
- /* 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);
-}
-
-static void
-on_wpas_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
-{
- NMSupplicantInterface *self;
- NMSupplicantInterfacePrivate *priv;
- gs_free_error GError *error = NULL;
- GDBusProxy *wpas_proxy;
- GVariantBuilder props;
-
- wpas_proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
- if (!wpas_proxy) {
- if (!nm_utils_error_is_cancelled (error)) {
- self = NM_SUPPLICANT_INTERFACE (user_data);
- _LOGW ("failed to acquire wpa_supplicant proxy: (%s)", error->message);
- set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+ c_list_for_each_entry_safe (bss_info, bss_info_safe, &priv->bss_lst_head, _bss_lst) {
+ if (bss_info->_bss_dirty)
+ _bss_info_remove (self, &bss_info->bss_path);
}
- return;
}
- self = NM_SUPPLICANT_INTERFACE (user_data);
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ if (do_notify_current_bss)
+ _notify (self, PROP_CURRENT_BSS);
- 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.
- */
-
- if (priv->dev != NULL) {
- const char *driver_name;
-
- driver_name = nm_supplicant_driver_to_string (priv->driver);
-
- 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 ();
- }
+ if (do_set_state)
+ set_state (self, priv->supp_state);
}
static void
-interface_add (NMSupplicantInterface *self)
+_properties_changed_p2p_device (NMSupplicantInterface *self,
+ GVariant *properties)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ const char **v_strv;
+ const char *v_s;
- /* Can only start the interface from INIT state */
- g_return_if_fail (priv->state == NM_SUPPLICANT_INTERFACE_STATE_INIT);
+ nm_assert (!properties || g_variant_is_of_type (properties, G_VARIANT_TYPE ("a{sv}")));
- _LOGD ("adding interface to supplicant");
+ if (nm_g_variant_lookup (properties, "Peers", "^a&o", &v_strv)) {
+ NMSupplicantPeerInfo *peer_info;
+ NMSupplicantPeerInfo *peer_info_safe;
+ const char *const*iter;
- /* Move to starting to prevent double-calls of interface_add() */
- set_state (self, NM_SUPPLICANT_INTERFACE_STATE_STARTING);
+ c_list_for_each_entry (peer_info, &priv->peer_lst_head, _peer_lst)
+ peer_info->_peer_dirty = TRUE;
+ c_list_for_each_entry (peer_info, &priv->peer_initializing_lst_head, _peer_lst)
+ peer_info->_peer_dirty = TRUE;
- nm_clear_g_cancellable (&priv->init_cancellable);
- priv->init_cancellable = g_cancellable_new ();
+ for (iter = v_strv; *iter; iter++)
+ _peer_info_add (self, *iter);
- g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
- NULL,
- NM_WPAS_DBUS_SERVICE,
- NM_WPAS_DBUS_PATH,
- NM_WPAS_DBUS_INTERFACE,
- priv->init_cancellable,
- (GAsyncReadyCallback) on_wpas_proxy_acquired,
- self);
-}
-
-void
-nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self,
- gboolean available)
-{
- NMSupplicantInterfacePrivate *priv;
-
- g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self));
-
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ g_free (v_strv);
- if (available) {
- /* This can happen if the supplicant couldn't be activated but
- * for some reason was started after the activation failure.
- */
- if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_INIT)
- interface_add (self);
- } else {
- /* The supplicant stopped; so we must tear down the interface */
- set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+ c_list_for_each_entry_safe (peer_info, peer_info_safe, &priv->peer_initializing_lst_head, _peer_lst) {
+ if (peer_info->_peer_dirty)
+ _peer_info_remove (self, &peer_info->peer_path);
+ }
+ c_list_for_each_entry_safe (peer_info, peer_info_safe, &priv->peer_lst_head, _peer_lst) {
+ if (peer_info->_peer_dirty)
+ _peer_info_remove (self, &peer_info->peer_path);
+ }
}
-}
-static void
-log_result_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
-{
- gs_unref_variant GVariant *reply = NULL;
- gs_free_error GError *error = NULL;
-
- reply = g_dbus_proxy_call_finish (proxy, result, &error);
- if ( !reply
- && !nm_utils_error_is_cancelled (error)
- && !strstr (error->message, "fi.w1.wpa_supplicant1.NotConnected")) {
- g_dbus_error_strip_remote_error (error);
- nm_log_warn (_NMLOG_DOMAIN, "%s: failed to %s: %s",
- _NMLOG_PREFIX_NAME, (const char *) user_data, error->message);
- }
+ if (nm_g_variant_lookup (properties, "Group", "&o", &v_s))
+ _p2p_group_set_path (self, v_s);
}
/*****************************************************************************/
static void
-assoc_return (NMSupplicantInterface *self, GError *error, const char *message)
+assoc_return (NMSupplicantInterface *self,
+ GError *error,
+ const char *message)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
AssocData *assoc_data;
@@ -1913,9 +1906,14 @@ assoc_return (NMSupplicantInterface *self, GError *error, const char *message)
if (error) {
g_dbus_error_strip_remote_error (error);
- _LOGW ("assoc[%p]: %s: %s", assoc_data, message, error->message);
- } else
- _LOGD ("assoc[%p]: association request successful", assoc_data);
+ _LOGW ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: %s: %s",
+ NM_HASH_OBFUSCATE_PTR (assoc_data),
+ message,
+ error->message);
+ } else {
+ _LOGD ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: association request successful",
+ NM_HASH_OBFUSCATE_PTR (assoc_data));
+ }
if (assoc_data->add_network_data) {
/* signal that this request already completed */
@@ -1941,111 +1939,82 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self)
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- /* Cancel all pending calls related to a prior connection attempt */
- if (priv->assoc_data) {
- gs_free_error GError *error = NULL;
-
- nm_utils_error_set_cancelled (&error, FALSE, "NMSupplicantInterface");
- assoc_return (self, error, "abort due to disconnect");
- }
-
- /* Don't do anything if there is no connection to the supplicant yet. */
- if (!priv->iface_proxy)
- return;
-
/* Disconnect from the current AP */
if ( (priv->state >= NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
&& (priv->state <= NM_SUPPLICANT_INTERFACE_STATE_COMPLETED)) {
- g_dbus_proxy_call (priv->iface_proxy,
- "Disconnect",
- NULL,
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- (GAsyncReadyCallback) log_result_cb,
- "disconnect");
- }
-
- /* Remove any network that was added by NetworkManager */
- if (priv->net_path) {
- g_dbus_proxy_call (priv->iface_proxy,
- "RemoveNetwork",
- g_variant_new ("(o)", priv->net_path),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- priv->other_cancellable,
- (GAsyncReadyCallback) log_result_cb,
- "remove network");
- g_free (priv->net_path);
- priv->net_path = NULL;
+ _dbus_connection_call_simple (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "Disconnect",
+ NULL,
+ G_VARIANT_TYPE ("()"),
+ "disconnect");
}
+ _remove_network (self);
+
/* Cancel any WPS enrollment, if any */
nm_supplicant_interface_cancel_wps (self);
+
+ /* Cancel all pending calls related to a prior connection attempt */
+ if (priv->assoc_data) {
+ gs_free_error GError *error = NULL;
+
+ nm_utils_error_set_cancelled (&error, FALSE, "NMSupplicantInterface");
+ assoc_return (self, error, "abort due to disconnect");
+ }
}
static void
-disconnect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+disconnect_cb (GObject *source, GAsyncResult *result, gpointer user_data)
{
- DisconnectData *disconnect_data = user_data;
- gs_unref_object NMSupplicantInterface *self = disconnect_data->self;
- gs_unref_variant GVariant *reply = NULL;
+ gs_unref_object NMSupplicantInterface *self = NULL;
+ gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
+ NMSupplicantInterfaceDisconnectCb callback;
+ gpointer callback_user_data;
+
+ nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data);
- reply = g_dbus_proxy_call_finish (proxy, result, &error);
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
- /* an already disconnected interface is not an error*/
- if ( !reply
+ if ( !res
&& !strstr (error->message, "fi.w1.wpa_supplicant1.NotConnected")) {
+ /* an already disconnected interface is not an error*/
g_clear_error(&error);
}
- disconnect_data->callback(self, error, disconnect_data->user_data);
- g_slice_free (DisconnectData, disconnect_data);
+ callback (self, error, callback_user_data);
}
void
-nm_supplicant_interface_disconnect_async ( NMSupplicantInterface * self,
- GCancellable * cancellable,
- NMSupplicantInterfaceDisconnectCb callback,
- gpointer user_data)
+nm_supplicant_interface_disconnect_async (NMSupplicantInterface *self,
+ GCancellable *cancellable,
+ NMSupplicantInterfaceDisconnectCb callback,
+ gpointer user_data)
{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- DisconnectData *disconnect_data;
-
- /* Don't do anything if there is no connection to the supplicant yet. */
- if (!priv->iface_proxy)
- return;
-
g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self));
- g_return_if_fail (NULL != callback);
+ g_return_if_fail (callback);
- disconnect_data = g_slice_new0(DisconnectData);
-
- /* Keep interface alive until disconnect finishes */
- disconnect_data->self = g_object_ref (self);
- disconnect_data->callback = callback;
- disconnect_data->user_data = user_data;
-
- /* Disconnect the interface */
- g_dbus_proxy_call (priv->iface_proxy,
- "Disconnect",
- NULL,
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- cancellable,
- (GAsyncReadyCallback) disconnect_cb,
- disconnect_data);
+ _dbus_connection_call (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "Disconnect",
+ NULL,
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_TIMEOUT_MSEC,
+ cancellable,
+ disconnect_cb,
+ nm_utils_user_data_pack (g_object_ref (self), callback, user_data));
}
static void
-assoc_select_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+assoc_select_network_cb (GObject *source, GAsyncResult *result, gpointer user_data)
{
NMSupplicantInterface *self;
- gs_unref_variant GVariant *reply = NULL;
+ gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
- reply = g_dbus_proxy_call_finish (proxy, result, &error);
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if (nm_utils_error_is_cancelled (error))
return;
@@ -2061,25 +2030,27 @@ assoc_call_select_network (NMSupplicantInterface *self)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
- g_dbus_proxy_call (priv->iface_proxy,
- "SelectNetwork",
- g_variant_new ("(o)", priv->net_path),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- priv->assoc_data->cancellable,
- (GAsyncReadyCallback) assoc_select_network_cb,
- self);
+ _dbus_connection_call (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "SelectNetwork",
+ g_variant_new ("(o)", priv->net_path),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_TIMEOUT_MSEC,
+ priv->assoc_data->cancellable,
+ assoc_select_network_cb,
+ self);
}
static void
-assoc_add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+assoc_add_blob_cb (GObject *source, GAsyncResult *result, gpointer user_data)
{
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
- gs_unref_variant GVariant *reply = NULL;
+ gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
- reply = g_dbus_proxy_call_finish (proxy, result, &error);
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if (nm_utils_error_is_cancelled (error))
return;
@@ -2092,52 +2063,62 @@ assoc_add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
}
priv->assoc_data->blobs_left--;
- _LOGT ("assoc[%p]: blob added (%u left)", priv->assoc_data, priv->assoc_data->blobs_left);
+ _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: blob added (%u left)",
+ NM_HASH_OBFUSCATE_PTR (priv->assoc_data),
+ priv->assoc_data->blobs_left);
if (priv->assoc_data->blobs_left == 0)
assoc_call_select_network (self);
}
static void
-assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+assoc_add_network_cb (GObject *source, GAsyncResult *result, gpointer user_data)
{
AddNetworkData *add_network_data = user_data;
AssocData *assoc_data;
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
- gs_unref_variant GVariant *reply = NULL;
+ gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
GHashTable *blobs;
GHashTableIter iter;
const char *blob_name;
GBytes *blob_data;
+ nm_auto_ref_string NMRefString *name_owner = NULL;
+ nm_auto_ref_string NMRefString *object_path = NULL;
+
+ g_clear_object (&add_network_data->shutdown_wait_obj);
assoc_data = add_network_data->assoc_data;
if (assoc_data)
assoc_data->add_network_data = NULL;
- g_slice_free (AddNetworkData, add_network_data);
+ name_owner = g_steal_pointer (&add_network_data->name_owner);
+ object_path = g_steal_pointer (&add_network_data->object_path);
+ nm_g_slice_free (add_network_data);
- reply = _nm_dbus_proxy_call_finish (proxy, result,
- G_VARIANT_TYPE ("(o)"),
- &error);
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if (!assoc_data) {
if (!error) {
- gs_free char *net_path = NULL;
+ const char *net_path;
/* the assoc-request was already cancelled, but the AddNetwork request succeeded.
* Cleanup the created network.
*
* This cleanup action does not work when NetworkManager is about to exit
* and leaves the mainloop. During program shutdown, we may orphan networks. */
- g_variant_get (reply, "(o)", &net_path);
- g_dbus_proxy_call (proxy,
- "RemoveNetwork",
- g_variant_new ("(o)", net_path),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- NULL,
- NULL);
+ g_variant_get (res, "(&o)", &net_path);
+ g_dbus_connection_call (G_DBUS_CONNECTION (source),
+ name_owner->str,
+ object_path->str,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "RemoveNetwork",
+ g_variant_new ("(o)", net_path),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_TIMEOUT_MSEC,
+ NULL,
+ NULL,
+ NULL);
}
return;
}
@@ -2150,7 +2131,8 @@ assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat
return;
}
- g_variant_get (reply, "(o)", &priv->net_path);
+ nm_assert (!priv->net_path);
+ g_variant_get (res, "(o)", &priv->net_path);
/* Send blobs first; otherwise jump to selecting the network */
blobs = nm_supplicant_config_get_blobs (priv->assoc_data->cfg);
@@ -2158,7 +2140,10 @@ assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat
? g_hash_table_size (blobs)
: 0u;
- _LOGT ("assoc[%p]: network added (%s) (%u blobs left)", priv->assoc_data, priv->net_path, priv->assoc_data->blobs_left);
+ _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: network added (%s) (%u blobs left)",
+ NM_HASH_OBFUSCATE_PTR (priv->assoc_data),
+ priv->net_path,
+ priv->assoc_data->blobs_left);
if (priv->assoc_data->blobs_left == 0) {
assoc_call_select_network (self);
@@ -2167,29 +2152,28 @@ assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat
g_hash_table_iter_init (&iter, blobs);
while (g_hash_table_iter_next (&iter, (gpointer) &blob_name, (gpointer) &blob_data)) {
- g_dbus_proxy_call (priv->iface_proxy,
- "AddBlob",
- g_variant_new ("(s@ay)",
- blob_name,
- nm_utils_gbytes_to_variant_ay (blob_data)),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- priv->assoc_data->cancellable,
- (GAsyncReadyCallback) assoc_add_blob_cb,
- self);
+ _dbus_connection_call (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "AddBlob",
+ g_variant_new ("(s@ay)",
+ blob_name,
+ nm_utils_gbytes_to_variant_ay (blob_data)),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_TIMEOUT_MSEC,
+ priv->assoc_data->cancellable,
+ assoc_add_blob_cb,
+ self);
}
}
static void
-assoc_set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+assoc_set_ap_scan_cb (GVariant *ret, GError *error, gpointer user_data)
{
NMSupplicantInterface *self;
NMSupplicantInterfacePrivate *priv;
- gs_unref_variant GVariant *reply = NULL;
- gs_free_error GError *error = NULL;
AddNetworkData *add_network_data;
- reply = g_dbus_proxy_call_finish (proxy, result, &error);
if (nm_utils_error_is_cancelled (error))
return;
@@ -2201,23 +2185,36 @@ assoc_set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat
return;
}
- _LOGT ("assoc[%p]: set interface ap_scan to %d",
- priv->assoc_data,
+ _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: interface ap_scan set to %d",
+ NM_HASH_OBFUSCATE_PTR (priv->assoc_data),
nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg));
- add_network_data = g_slice_new0 (AddNetworkData);
+ /* the association does not keep @self alive. We want to be able to remove
+ * the network again, even if @self is already gone. Hence, track the data
+ * separately.
+ *
+ * For that we also have a shutdown_wait_obj so that on exit we still wait
+ * to handle the response. */
+ add_network_data = g_slice_new (AddNetworkData);
+ *add_network_data = (AddNetworkData) {
+ .assoc_data = priv->assoc_data,
+ .name_owner = nm_ref_string_ref (priv->name_owner),
+ .object_path = nm_ref_string_ref (priv->object_path),
+ .shutdown_wait_obj = g_object_new (G_TYPE_OBJECT, NULL),
+ };
+ nm_shutdown_wait_obj_register_object (add_network_data->shutdown_wait_obj, "supplicant-add-network");
priv->assoc_data->add_network_data = add_network_data;
- add_network_data->assoc_data = priv->assoc_data;
-
- g_dbus_proxy_call (priv->iface_proxy,
- "AddNetwork",
- g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->assoc_data->cfg)),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- (GAsyncReadyCallback) assoc_add_network_cb,
- add_network_data);
+ _dbus_connection_call (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "AddNetwork",
+ g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->assoc_data->cfg)),
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_TIMEOUT_MSEC,
+ NULL,
+ assoc_add_network_cb,
+ add_network_data);
}
static gboolean
@@ -2264,49 +2261,51 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self,
nm_supplicant_interface_disconnect (self);
- assoc_data = g_slice_new0 (AssocData);
- priv->assoc_data = assoc_data;
+ assoc_data = g_slice_new (AssocData);
+ *assoc_data = (AssocData) {
+ .self = self,
+ .cfg = g_object_ref (cfg),
+ .callback = callback,
+ .user_data = user_data,
+ };
- assoc_data->self = self;
- assoc_data->cfg = g_object_ref (cfg);
- assoc_data->callback = callback;
- assoc_data->user_data = user_data;
+ priv->assoc_data = assoc_data;
- _LOGD ("assoc[%p]: starting association...", assoc_data);
+ _LOGD ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: starting association...",
+ NM_HASH_OBFUSCATE_PTR (assoc_data));
- /* Make sure the supplicant supports EAP-FAST before trying to send
- * it an EAP-FAST configuration.
- */
if ( _get_capability (priv, NM_SUPPL_CAP_TYPE_FAST) == NM_TERNARY_FALSE
&& nm_supplicant_config_fast_required (cfg)) {
+ /* Make sure the supplicant supports EAP-FAST before trying to send
+ * it an EAP-FAST configuration.
+ */
assoc_data->fail_on_idle_id = g_idle_add (assoc_fail_on_idle_cb, self);
return;
}
assoc_data->cancellable = g_cancellable_new();
- g_dbus_proxy_call (priv->iface_proxy,
- DBUS_INTERFACE_PROPERTIES ".Set",
- g_variant_new ("(ssv)",
- NM_WPAS_DBUS_IFACE_INTERFACE,
- "ApScan",
- g_variant_new_uint32 (nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg))),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- priv->assoc_data->cancellable,
- (GAsyncReadyCallback) assoc_set_ap_scan_cb,
- self);
+ nm_dbus_connection_call_set (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->object_path->str,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "ApScan",
+ g_variant_new_uint32 (nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg)),
+ DBUS_TIMEOUT_MSEC,
+ assoc_data->cancellable,
+ assoc_set_ap_scan_cb,
+ self);
}
/*****************************************************************************/
static void
-scan_request_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
+scan_request_cb (GObject *source, GAsyncResult *result, gpointer user_data)
{
NMSupplicantInterface *self;
- gs_unref_variant GVariant *reply = NULL;
+ gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
- reply = g_dbus_proxy_call_finish (proxy, result, &error);
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if (nm_utils_error_is_cancelled (error))
return;
@@ -2350,14 +2349,16 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface *self,
g_variant_builder_add (&builder, "{sv}", "SSIDs", g_variant_builder_end (&ssids_builder));
}
- g_dbus_proxy_call (priv->iface_proxy,
- "Scan",
- g_variant_new ("(a{sv})", &builder),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- priv->other_cancellable,
- (GAsyncReadyCallback) scan_request_cb,
- self);
+ _dbus_connection_call (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "Scan",
+ g_variant_new ("(a{sv})", &builder),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_TIMEOUT_MSEC,
+ priv->main_cancellable,
+ scan_request_cb,
+ self);
}
/*****************************************************************************/
@@ -2370,7 +2371,23 @@ nm_supplicant_interface_get_state (NMSupplicantInterface * self)
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->state;
}
-const char *
+void
+_nm_supplicant_interface_set_state_down (NMSupplicantInterface * self,
+ gboolean force_remove_from_supplicant,
+ const char *reason)
+{
+ set_state_down (self, force_remove_from_supplicant, reason);
+}
+
+NMRefString *
+nm_supplicant_interface_get_name_owner (NMSupplicantInterface *self)
+{
+ g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
+
+ return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->name_owner;
+}
+
+NMRefString *
nm_supplicant_interface_get_object_path (NMSupplicantInterface *self)
{
g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
@@ -2383,7 +2400,7 @@ nm_supplicant_interface_get_ifname (NMSupplicantInterface *self)
{
g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
- return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev;
+ return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->ifname;
}
guint
@@ -2400,133 +2417,478 @@ 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);
-
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);
+ _dbus_connection_call_simple (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
+ "Find",
+ g_variant_new ("(a{sv})", &builder),
+ G_VARIANT_TYPE ("()"),
+ "p2p-find");
}
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);
+ _dbus_connection_call_simple (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
+ "StopFind",
+ NULL,
+ G_VARIANT_TYPE ("()"),
+ "p2p-stop-find");
}
/*****************************************************************************/
void
-nm_supplicant_interface_p2p_connect (NMSupplicantInterface * self,
- const char * peer,
- const char * wps_method,
- const char * wps_pin)
+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");
+ _dbus_connection_call_simple (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
+ "Connect",
+ g_variant_new ("(a{sv})", &builder),
+ G_VARIANT_TYPE ("()"),
+ "p2p-connect");
}
void
nm_supplicant_interface_p2p_cancel_connect (NMSupplicantInterface * self)
{
- NMSupplicantInterfacePrivate *priv;
+ g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self));
+
+ _dbus_connection_call_simple (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
+ "Cancel",
+ NULL,
+ G_VARIANT_TYPE ("()"),
+ "p2p-cancel");
+}
+void
+nm_supplicant_interface_p2p_disconnect (NMSupplicantInterface * self)
+{
g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self));
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ _dbus_connection_call_simple (self,
+ NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
+ "Disconnect",
+ NULL,
+ G_VARIANT_TYPE ("()"),
+ "p2p-disconnect");
+}
+
+/*****************************************************************************/
- /* Don't do anything if there is no connection to the supplicant yet. */
- if (!priv->p2p_proxy || !priv->object_path)
+static void
+_properties_changed (NMSupplicantInterface *self,
+ const char *interface_name,
+ GVariant *properties,
+ gboolean initial)
+{
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ gboolean is_main;
+ gboolean old_val_scanning;
+ gboolean old_val_p2p_available;
+
+ nm_assert (!properties || g_variant_is_of_type (properties, G_VARIANT_TYPE ("a{sv}")));
+
+ if (initial)
+ priv->starting_pending_count--;
+
+ if ( (initial || priv->is_ready_main)
+ && nm_streq (interface_name, NM_WPAS_DBUS_IFACE_INTERFACE))
+ is_main = TRUE;
+ else if ( (initial || priv->is_ready_p2p_device)
+ && nm_streq (interface_name, NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE)) {
+ nm_assert (_get_capability (priv, NM_SUPPL_CAP_TYPE_P2P) == NM_TERNARY_TRUE);
+ is_main = FALSE;
+ } else
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");
+ g_object_freeze_notify (G_OBJECT (self));
+
+ priv->starting_pending_count++;
+
+ old_val_scanning = _prop_scanning_get (priv);
+ old_val_p2p_available = _prop_p2p_available_get (priv);
+
+ if (is_main) {
+ priv->is_ready_main = TRUE;
+ _properties_changed_main (self, properties);
+ } else {
+ priv->is_ready_p2p_device = TRUE;
+ _properties_changed_p2p_device (self, properties);
+ }
+
+ priv->starting_pending_count--;
+ _starting_check_ready (self);
+
+ if (old_val_scanning != _prop_scanning_get (priv))
+ _notify (self, PROP_SCANNING);
+ if (old_val_p2p_available != _prop_p2p_available_get (priv))
+ _notify (self, PROP_P2P_AVAILABLE);
+
+ g_object_thaw_notify (G_OBJECT (self));
}
-void
-nm_supplicant_interface_p2p_disconnect (NMSupplicantInterface * self)
+static void
+_properties_changed_cb (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *signal_interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
{
- NMSupplicantInterfacePrivate *priv;
+ NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+ const char *interface_name;
+ gs_unref_variant GVariant *changed_properties = NULL;
- g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self));
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
+ return;
- priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ g_variant_get (parameters,
+ "(&s@a{sv}^a&s)",
+ &interface_name,
+ &changed_properties,
+ NULL);
+ _properties_changed (self,
+ interface_name,
+ changed_properties,
+ FALSE);
+}
+
+static void
+_bss_properties_changed_cb (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *signal_interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ nm_auto_ref_string NMRefString *bss_path = NULL;
+ gs_unref_variant GVariant *changed_properties = NULL;
+ NMSupplicantBssInfo *bss_info;
- /* Don't do anything if there is no connection to the supplicant. */
- if (!priv->p2p_proxy || !priv->object_path)
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
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");
+ bss_path = nm_ref_string_new (object_path);
+
+ bss_info = g_hash_table_lookup (priv->bss_idx, &bss_path);
+ if (!bss_info)
+ return;
+ if (bss_info->_init_cancellable)
+ return;
+
+ g_variant_get (parameters,
+ "(&s@a{sv}^a&s)",
+ NULL,
+ &changed_properties,
+ NULL);
+ _bss_info_properties_changed (self, bss_info, changed_properties, FALSE);
+}
+
+static void
+_peer_properties_changed_cb (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *signal_interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ nm_auto_ref_string NMRefString *peer_path = NULL;
+ gs_unref_variant GVariant *changed_properties = NULL;
+ NMSupplicantPeerInfo *peer_info;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
+ return;
+
+ peer_path = nm_ref_string_new (object_path);
+
+ peer_info = g_hash_table_lookup (priv->peer_idx, &peer_path);
+ if (!peer_info)
+ return;
+ if (peer_info->_init_cancellable)
+ return;
+
+ g_variant_get (parameters,
+ "(&s@a{sv}^a&s)",
+ NULL,
+ &changed_properties,
+ NULL);
+ _peer_info_properties_changed (self, peer_info, changed_properties, FALSE);
+}
+
+static void
+_get_all_main_cb (GVariant *result,
+ GError *error,
+ gpointer user_data)
+{
+ gs_unref_variant GVariant *properties = NULL;
+
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
+ if (result)
+ g_variant_get (result, "(@a{sv})", &properties);
+ _properties_changed (user_data,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ properties,
+ TRUE);
+}
+
+static void
+_get_all_p2p_device_cb (GVariant *result,
+ GError *error,
+ gpointer user_data)
+{
+ gs_unref_variant GVariant *properties = NULL;
+
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
+ if (result)
+ g_variant_get (result, "(@a{sv})", &properties);
+ _properties_changed (user_data,
+ NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
+ properties,
+ TRUE);
+}
+
+static void
+_signal_handle (NMSupplicantInterface *self,
+ const char *signal_interface_name,
+ const char *signal_name,
+ GVariant *parameters)
+{
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ const char *path;
+
+ if (nm_streq (signal_interface_name, NM_WPAS_DBUS_IFACE_INTERFACE)) {
+
+ if (!priv->is_ready_main)
+ return;
+
+ if (nm_streq (signal_name, "ScanDone")) {
+ priv->last_scan_msec = nm_utils_get_monotonic_timestamp_msec ();
+ _LOGT ("ScanDone signal received");
+ if (priv->state > NM_SUPPLICANT_INTERFACE_STATE_STARTING) {
+ nm_assert (priv->state < NM_SUPPLICANT_INTERFACE_STATE_DOWN);
+ g_signal_emit (self, signals[SCAN_DONE], 0);
+ }
+ return;
+ }
+
+ if (nm_streq (signal_name, "BSSAdded")) {
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(oa{sv})")))
+ return;
+
+ g_variant_get (parameters, "(&oa{sv})", &path, NULL);
+ _bss_info_add (self, path);
+ return;
+ }
+
+ if (nm_streq (signal_name, "BSSRemoved")) {
+ nm_auto_ref_string NMRefString *bss_path = NULL;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ return;
+
+ g_variant_get (parameters, "(&o)", &path);
+ bss_path = nm_ref_string_new (path);
+ _bss_info_remove (self, &bss_path);
+ return;
+ }
+
+ if (nm_streq (signal_name, "EAP")) {
+ NMSupplicantAuthState auth_state = NM_SUPPLICANT_AUTH_STATE_UNKNOWN;
+ const char *status;
+ const char *parameter;
+
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(ss)")))
+ return;
+
+ g_variant_get (parameters, "(&s&s)", &status, &parameter);
+
+ if (nm_streq (status, "started"))
+ auth_state = NM_SUPPLICANT_AUTH_STATE_STARTED;
+ else if (nm_streq (status, "completion")) {
+ if (nm_streq (parameter, "success"))
+ auth_state = NM_SUPPLICANT_AUTH_STATE_SUCCESS;
+ else if (nm_streq (parameter, "failure"))
+ auth_state = NM_SUPPLICANT_AUTH_STATE_FAILURE;
+ }
+
+ /* the state eventually reaches one of started, success or failure
+ * so ignore any other intermediate (unknown) state change. */
+ if ( auth_state != NM_SUPPLICANT_AUTH_STATE_UNKNOWN
+ && auth_state != priv->auth_state) {
+ priv->auth_state = auth_state;
+ _notify (self, PROP_AUTH_STATE);
+ }
+ return;
+ }
+
+ return;
+ }
+
+ if (nm_streq (signal_interface_name, NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE)) {
+
+ if (!priv->is_ready_p2p_device)
+ return;
+
+ if (nm_streq (signal_name, "DeviceFound")) {
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)"))) {
+ g_variant_get (parameters, "(&o)", &path);
+ _peer_info_add (self, path);
+ }
+ return;
+ }
+
+ if (nm_streq (signal_name, "DeviceLost")) {
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)"))) {
+ nm_auto_ref_string NMRefString *peer_path = NULL;
+
+ g_variant_get (parameters, "(&o)", &path);
+ peer_path = nm_ref_string_new (path);
+ _peer_info_remove (self, &peer_path);
+ }
+ return;
+ }
+
+ if (nm_streq (signal_name, "GroupStarted")) {
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) {
+ gs_unref_variant GVariant *args = NULL;
+ gs_unref_object NMSupplicantInterface *iface = NULL;
+ const char *group_path;
+ const char *iface_path;
+
+ g_variant_get (parameters, "(@a{sv})", &args);
+ if (!g_variant_lookup (args, "group_object", "&o", &group_path))
+ return;
+ if (!g_variant_lookup (args, "interface_object", "&o", &iface_path))
+ return;
+
+ if (nm_streq (iface_path, priv->object_path->str)) {
+ _LOGW ("P2P: GroupStarted on existing interface");
+ iface = g_object_ref (self);
+ } else {
+ iface = nm_supplicant_manager_create_interface_from_path (priv->supplicant_manager,
+ iface_path);
+ if (iface == NULL) {
+ _LOGW ("P2P: Group interface already exists in GroupStarted handler, aborting further processing.");
+ return;
+ }
+ }
+
+ /* Signal existence of the (new) interface. */
+ g_signal_emit (self, signals[GROUP_STARTED], 0, iface);
+ }
+ return;
+ }
+
+ if (nm_streq (signal_name, "GroupFinished")) {
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) {
+ gs_unref_variant GVariant *args = NULL;
+ const char *iface_path;
+
+ g_variant_get (parameters, "(@a{sv})", &args);
+
+ /* 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 (args, "interface_object", "&o", &iface_path))
+ return;
+
+ _LOGD ("P2P: GroupFinished signal on interface %s for interface %s", priv->object_path->str, iface_path);
+
+ /* Signal group finish interface (on management interface). */
+ g_signal_emit (self, signals[GROUP_FINISHED], 0, iface_path);
+ }
+ return;
+ }
+
+ return;
+ }
+}
+
+static void
+_signal_cb (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *signal_interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ NMSupplicantInterface *self = user_data;
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+ priv->starting_pending_count++;
+
+ _signal_handle (self, signal_interface_name, signal_name, parameters);
+
+ priv->starting_pending_count--;
+ _starting_check_ready (self);
+}
+
+/*****************************************************************************/
+
+gboolean
+nm_supplicant_interface_get_p2p_available (NMSupplicantInterface *self)
+{
+ return _prop_p2p_available_get (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self));
+}
+
+gboolean
+nm_supplicant_interface_get_p2p_group_joined (NMSupplicantInterface *self)
+{
+ return _prop_p2p_group_joined_get (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self));
+}
+
+const char*
+nm_supplicant_interface_get_p2p_group_path (NMSupplicantInterface *self)
+{
+ return nm_ref_string_get_str (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_group_path);
+}
+
+gboolean
+nm_supplicant_interface_get_p2p_group_owner (NMSupplicantInterface *self)
+{
+ return _prop_p2p_group_is_owner_get (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self));
}
/*****************************************************************************/
@@ -2537,26 +2899,27 @@ get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
- NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object);
+ NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (object);
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
switch (prop_id) {
case PROP_SCANNING:
- g_value_set_boolean (value, priv->scanning);
+ g_value_set_boolean (value, nm_supplicant_interface_get_scanning (self));
break;
case PROP_CURRENT_BSS:
- g_value_set_string (value, priv->current_bss);
+ g_value_set_string (value, nm_ref_string_get_str (nm_supplicant_interface_get_current_bss (self)));
break;
case PROP_P2P_GROUP_JOINED:
- g_value_set_boolean (value, priv->p2p_capable && priv->group_proxy_acquired);
+ g_value_set_boolean (value, nm_supplicant_interface_get_p2p_group_joined (self));
break;
case PROP_P2P_GROUP_PATH:
- g_value_set_string (value, nm_supplicant_interface_get_p2p_group_path (NM_SUPPLICANT_INTERFACE (object)));
+ g_value_set_string (value, nm_supplicant_interface_get_p2p_group_path (self));
break;
case PROP_P2P_GROUP_OWNER:
- g_value_set_boolean (value, priv->p2p_group_owner);
+ g_value_set_boolean (value, nm_supplicant_interface_get_p2p_group_owner (self));
break;
case PROP_P2P_AVAILABLE:
- g_value_set_boolean (value, priv->p2p_capable && priv->p2p_proxy_acquired);
+ g_value_set_boolean (value, nm_supplicant_interface_get_p2p_available (self));
break;
case PROP_AUTH_STATE:
g_value_set_uint (value, priv->auth_state);
@@ -2576,21 +2939,31 @@ set_property (GObject *object,
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object);
switch (prop_id) {
- case PROP_IFACE:
+ case PROP_SUPPLICANT_MANAGER:
/* construct-only */
- priv->dev = g_value_dup_string (value);
+ priv->supplicant_manager = g_object_ref (g_value_get_pointer (value));
+ nm_assert (NM_IS_SUPPLICANT_MANAGER (priv->supplicant_manager));
+
+ priv->dbus_connection = g_object_ref (nm_supplicant_manager_get_dbus_connection (priv->supplicant_manager));
+ nm_assert (G_IS_DBUS_CONNECTION (priv->dbus_connection));
+
+ priv->name_owner = nm_ref_string_ref (nm_supplicant_manager_get_dbus_name_owner (priv->supplicant_manager));
+ nm_assert (NM_IS_REF_STRING (priv->name_owner));
+
+ priv->global_capabilities = nm_supplicant_manager_get_global_capabilities (priv->supplicant_manager);
break;
- case PROP_OBJECT_PATH:
+ case PROP_DBUS_OBJECT_PATH:
/* construct-only */
- priv->object_path = g_value_dup_string (value);
+ priv->object_path = nm_ref_string_ref (g_value_get_pointer (value));
+ nm_assert (NM_IS_REF_STRING (priv->object_path));
break;
- case PROP_DRIVER:
+ case PROP_IFINDEX:
/* construct-only */
- priv->driver = g_value_get_uint (value);
+ priv->ifindex = g_value_get_int (value);
break;
- case PROP_GLOBAL_CAPABILITIES:
+ case PROP_DRIVER:
/* construct-only */
- priv->global_capabilities = g_value_get_uint64 (value);
+ priv->requested_driver = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -2598,6 +2971,8 @@ set_property (GObject *object,
}
}
+/*****************************************************************************/
+
static void
nm_supplicant_interface_init (NMSupplicantInterface * self)
{
@@ -2607,30 +2982,167 @@ nm_supplicant_interface_init (NMSupplicantInterface * self)
self->_priv = priv;
- c_list_init (&self->supp_lst);
-
nm_assert (priv->global_capabilities == NM_SUPPL_CAP_MASK_NONE);
nm_assert (priv->iface_capabilities == NM_SUPPL_CAP_MASK_NONE);
- 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);
+ priv->state = NM_SUPPLICANT_INTERFACE_STATE_STARTING;
+ priv->supp_state = NM_SUPPLICANT_INTERFACE_STATE_INVALID;
+
+ c_list_init (&self->supp_lst);
+
+ G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMSupplicantBssInfo, bss_path) == 0);
+ priv->bss_idx = g_hash_table_new (nm_pdirect_hash, nm_pdirect_equal);
+
+ c_list_init (&priv->bss_lst_head);
+ c_list_init (&priv->bss_initializing_lst_head);
+
+ G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMSupplicantPeerInfo, peer_path) == 0);
+ priv->peer_idx = g_hash_table_new (nm_pdirect_hash, nm_pdirect_equal);
+
+ c_list_init (&priv->peer_lst_head);
+ c_list_init (&priv->peer_initializing_lst_head);
+
+ priv->main_cancellable = g_cancellable_new ();
+}
+
+static void
+constructed (GObject *object)
+{
+ NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (object);
+ NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+
+ G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->constructed (object);
+
+ _LOGD ("new supplicant interface %s on %s",
+ priv->object_path->str,
+ priv->name_owner->str);
+
+ priv->properties_changed_id = nm_dbus_connection_signal_subscribe_properties_changed (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->object_path->str,
+ NULL,
+ _properties_changed_cb,
+ self,
+ NULL);
+
+ priv->bss_properties_changed_id = nm_dbus_connection_signal_subscribe_properties_changed (priv->dbus_connection,
+ priv->name_owner->str,
+ NULL,
+ NM_WPAS_DBUS_IFACE_BSS,
+ _bss_properties_changed_cb,
+ self,
+ NULL);
+
+ priv->signal_id = g_dbus_connection_signal_subscribe (priv->dbus_connection,
+ priv->name_owner->str,
+ NULL,
+ NULL,
+ priv->object_path->str,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ _signal_cb,
+ self,
+ NULL);
+
+ /* Scan result aging parameters */
+ nm_dbus_connection_call_set (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->object_path->str,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "BSSExpireAge",
+ g_variant_new_uint32 (250),
+ DBUS_TIMEOUT_MSEC,
+ NULL,
+ NULL,
+ NULL);
+ nm_dbus_connection_call_set (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->object_path->str,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "BSSExpireCount",
+ g_variant_new_uint32 (2),
+ DBUS_TIMEOUT_MSEC,
+ NULL,
+ NULL,
+ NULL);
+
+ if (_get_capability (priv, NM_SUPPL_CAP_TYPE_PMF) == NM_TERNARY_TRUE) {
+ /* Initialize global PMF setting to 'optional' */
+ nm_dbus_connection_call_set (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->object_path->str,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ "Pmf",
+ g_variant_new_string ("1"),
+ DBUS_TIMEOUT_MSEC,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ if (_get_capability (priv, NM_SUPPL_CAP_TYPE_AP) == NM_TERNARY_DEFAULT) {
+ /* If the global supplicant capabilities property is not present, we can
+ * fall back to checking whether the ProbeRequest method is supported. If
+ * neither of these works we have no way of determining if AP mode is
+ * supported or not. hostap 1.0 and earlier don't support either of these.
+ */
+ priv->starting_pending_count++;
+ _dbus_connection_call (self,
+ DBUS_INTERFACE_INTROSPECTABLE,
+ "Introspect",
+ NULL,
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 5000,
+ priv->main_cancellable,
+ iface_introspect_cb,
+ self);
+ }
+
+ priv->starting_pending_count++;
+ nm_dbus_connection_call_get_all (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->object_path->str,
+ NM_WPAS_DBUS_IFACE_INTERFACE,
+ 5000,
+ priv->main_cancellable,
+ _get_all_main_cb,
+ self);
+
+ if (_get_capability (priv, NM_SUPPL_CAP_TYPE_P2P) == NM_TERNARY_TRUE) {
+ priv->peer_properties_changed_id = nm_dbus_connection_signal_subscribe_properties_changed (priv->dbus_connection,
+ priv->name_owner->str,
+ NULL,
+ NM_WPAS_DBUS_IFACE_PEER,
+ _peer_properties_changed_cb,
+ self,
+ NULL);
+
+ priv->starting_pending_count++;
+ nm_dbus_connection_call_get_all (priv->dbus_connection,
+ priv->name_owner->str,
+ priv->object_path->str,
+ NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE,
+ 5000,
+ priv->main_cancellable,
+ _get_all_p2p_device_cb,
+ self);
+ }
}
NMSupplicantInterface *
-nm_supplicant_interface_new (const char *ifname,
- const char *object_path,
- NMSupplicantDriver driver,
- NMSupplCapMask global_capabilities)
+nm_supplicant_interface_new (NMSupplicantManager *supplicant_manager,
+ NMRefString *object_path,
+ int ifindex,
+ NMSupplicantDriver driver)
{
- /* One of ifname or path need to be set */
- g_return_val_if_fail ((ifname != NULL) != (object_path != NULL), NULL);
+ nm_assert (NM_IS_SUPPLICANT_MANAGER (supplicant_manager));
return g_object_new (NM_TYPE_SUPPLICANT_INTERFACE,
- NM_SUPPLICANT_INTERFACE_IFACE, ifname,
- NM_SUPPLICANT_INTERFACE_OBJECT_PATH, object_path,
+ NM_SUPPLICANT_INTERFACE_SUPPLICANT_MANAGER, supplicant_manager,
+ NM_SUPPLICANT_INTERFACE_DBUS_OBJECT_PATH, object_path,
+ NM_SUPPLICANT_INTERFACE_IFINDEX, ifindex,
NM_SUPPLICANT_INTERFACE_DRIVER, (guint) driver,
- NM_SUPPLICANT_INTERFACE_GLOBAL_CAPABILITIES, (guint64) global_capabilities,
NULL);
}
@@ -2640,9 +3152,11 @@ dispose (GObject *object)
NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (object);
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
+ if (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DOWN)
+ set_state_down (self, TRUE, "NMSupplicantInterface is disposing");
+
nm_assert (c_list_is_empty (&self->supp_lst));
- 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.
@@ -2652,38 +3166,21 @@ dispose (GObject *object)
priv->wps_data = NULL;
}
- if (priv->assoc_data) {
- gs_free_error GError *error = NULL;
-
- nm_utils_error_set_cancelled (&error, TRUE, "NMSupplicantInterface");
- assoc_return (self, error, "cancelled due to dispose of supplicant interface");
- }
-
- 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);
- if (priv->group_proxy)
- g_signal_handlers_disconnect_by_data (priv->group_proxy, object);
- g_clear_object (&priv->group_proxy);
+ nm_assert (!priv->assoc_data);
- nm_clear_g_cancellable (&priv->init_cancellable);
- nm_clear_g_cancellable (&priv->other_cancellable);
+ g_clear_pointer (&priv->bss_idx, g_hash_table_destroy);
+ g_clear_pointer (&priv->peer_idx, g_hash_table_destroy);
- 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);
- 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);
- g_clear_pointer (&priv->object_path, g_free);
- g_clear_pointer (&priv->current_bss, g_free);
+ nm_clear_pointer (&priv->current_bss, nm_ref_string_unref);
G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->dispose (object);
+
+ nm_clear_pointer (&priv->object_path, nm_ref_string_unref);
+ nm_clear_pointer (&priv->name_owner, nm_ref_string_unref);
+ g_clear_object (&priv->supplicant_manager);
+ g_clear_object (&priv->dbus_connection);
+ nm_clear_g_free (&priv->ifname);
+ nm_assert (!priv->net_path);
}
static void
@@ -2693,10 +3190,34 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
g_type_class_add_private (object_class, sizeof (NMSupplicantInterfacePrivate));
+ object_class->constructed = constructed;
object_class->dispose = dispose;
object_class->set_property = set_property;
object_class->get_property = get_property;
+ obj_properties[PROP_SUPPLICANT_MANAGER] =
+ g_param_spec_pointer (NM_SUPPLICANT_INTERFACE_SUPPLICANT_MANAGER, "", "",
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+ obj_properties[PROP_DBUS_OBJECT_PATH] =
+ g_param_spec_pointer (NM_SUPPLICANT_INTERFACE_DBUS_OBJECT_PATH, "", "",
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+ obj_properties[PROP_IFINDEX] =
+ g_param_spec_int (NM_SUPPLICANT_INTERFACE_IFINDEX, "", "",
+ 0, G_MAXINT, 0,
+ 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,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
obj_properties[PROP_SCANNING] =
g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_SCANNING, "", "",
FALSE,
@@ -2707,18 +3228,6 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_IFACE] =
- g_param_spec_string (NM_SUPPLICANT_INTERFACE_IFACE, "", "",
- NULL,
- 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_P2P_GROUP_JOINED] =
g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED, "", "",
FALSE,
@@ -2734,25 +3243,11 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
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,
- 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_GLOBAL_CAPABILITIES] =
- g_param_spec_uint64 (NM_SUPPLICANT_INTERFACE_GLOBAL_CAPABILITIES, "", "",
- 0,
- NM_SUPPL_CAP_MASK_ALL,
- 0,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
obj_properties[PROP_AUTH_STATE] =
g_param_spec_uint (NM_SUPPLICANT_INTERFACE_AUTH_STATE, "", "",
NM_SUPPLICANT_AUTH_STATE_UNKNOWN,
@@ -2771,45 +3266,21 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
NULL, NULL, NULL,
G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
- signals[REMOVED] =
- g_signal_new (NM_SUPPLICANT_INTERFACE_REMOVED,
+ signals[BSS_CHANGED] =
+ g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_CHANGED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
- G_TYPE_NONE, 0);
+ G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
- signals[BSS_UPDATED] =
- g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_UPDATED,
+ signals[PEER_CHANGED] =
+ g_signal_new (NM_SUPPLICANT_INTERFACE_PEER_CHANGED,
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[BSS_REMOVED] =
- g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_REMOVED,
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- 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);
+ G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
signals[SCAN_DONE] =
g_signal_new (NM_SUPPLICANT_INTERFACE_SCAN_DONE,
@@ -2817,7 +3288,7 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
- G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+ G_TYPE_NONE, 0);
signals[WPS_CREDENTIALS] =
g_signal_new (NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS,
diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h
index 25dca98481..8964a4754f 100644
--- a/src/supplicant/nm-supplicant-interface.h
+++ b/src/supplicant/nm-supplicant-interface.h
@@ -16,10 +16,9 @@
* A mix of wpa_supplicant interface states and internal states.
*/
typedef enum {
- NM_SUPPLICANT_INTERFACE_STATE_INVALID = -1,
- NM_SUPPLICANT_INTERFACE_STATE_INIT = 0,
- NM_SUPPLICANT_INTERFACE_STATE_STARTING,
- NM_SUPPLICANT_INTERFACE_STATE_READY,
+ NM_SUPPLICANT_INTERFACE_STATE_INVALID = 0,
+
+ NM_SUPPLICANT_INTERFACE_STATE_STARTING = 1,
NM_SUPPLICANT_INTERFACE_STATE_DISABLED,
NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED,
@@ -35,6 +34,13 @@ typedef enum {
NM_SUPPLICANT_INTERFACE_STATE_DOWN,
} NMSupplicantInterfaceState;
+static inline gboolean
+NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (NMSupplicantInterfaceState state)
+{
+ return state > NM_SUPPLICANT_INTERFACE_STATE_STARTING
+ && state < NM_SUPPLICANT_INTERFACE_STATE_DOWN;
+}
+
typedef enum {
NM_SUPPLICANT_AUTH_STATE_UNKNOWN,
NM_SUPPLICANT_AUTH_STATE_STARTED,
@@ -50,8 +56,9 @@ typedef enum {
#define NM_IS_SUPPLICANT_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SUPPLICANT_INTERFACE))
#define NM_SUPPLICANT_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass))
-#define NM_SUPPLICANT_INTERFACE_IFACE "iface"
-#define NM_SUPPLICANT_INTERFACE_OBJECT_PATH "object-path"
+#define NM_SUPPLICANT_INTERFACE_SUPPLICANT_MANAGER "supplicant-manager"
+#define NM_SUPPLICANT_INTERFACE_DBUS_OBJECT_PATH "dbus-object-path"
+#define NM_SUPPLICANT_INTERFACE_IFINDEX "ifindex"
#define NM_SUPPLICANT_INTERFACE_SCANNING "scanning"
#define NM_SUPPLICANT_INTERFACE_CURRENT_BSS "current-bss"
#define NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED "p2p-group-joined"
@@ -59,15 +66,11 @@ typedef enum {
#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_GLOBAL_CAPABILITIES "global-capabilities"
#define NM_SUPPLICANT_INTERFACE_AUTH_STATE "auth-state"
#define NM_SUPPLICANT_INTERFACE_STATE "state"
-#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_BSS_CHANGED "bss-changed"
+#define NM_SUPPLICANT_INTERFACE_PEER_CHANGED "peer-changed"
#define NM_SUPPLICANT_INTERFACE_SCAN_DONE "scan-done"
#define NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS "wps-credentials"
#define NM_SUPPLICANT_INTERFACE_GROUP_STARTED "group-started"
@@ -85,13 +88,17 @@ struct _NMSupplicantInterface {
GType nm_supplicant_interface_get_type (void);
-NMSupplicantInterface *nm_supplicant_interface_new (const char *ifname,
- const char *object_path,
- NMSupplicantDriver driver,
- NMSupplCapMask global_capabilities);
+NMSupplicantInterface *nm_supplicant_interface_new (NMSupplicantManager *supplicant_manager,
+ NMRefString *object_path,
+ int ifindex,
+ NMSupplicantDriver driver);
+
+NMRefString *nm_supplicant_interface_get_name_owner (NMSupplicantInterface *self);
+NMRefString *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface);
-void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self,
- gboolean available);
+void _nm_supplicant_interface_set_state_down (NMSupplicantInterface * self,
+ gboolean force_remove_from_supplicant,
+ const char *reason);
typedef void (*NMSupplicantInterfaceAssocCb) (NMSupplicantInterface *iface,
GError *error,
@@ -115,8 +122,6 @@ nm_supplicant_interface_disconnect_async (NMSupplicantInterface * self,
NMSupplicantInterfaceDisconnectCb callback,
gpointer user_data);
-const char *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface);
-
void nm_supplicant_interface_request_scan (NMSupplicantInterface *self,
GBytes *const*ssids,
guint ssids_len);
@@ -127,7 +132,7 @@ const char *nm_supplicant_interface_state_to_string (NMSupplicantInterfaceState
gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self);
-const char *nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self);
+NMRefString *nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self);
gint64 nm_supplicant_interface_get_last_scan (NMSupplicantInterface *self);
@@ -135,6 +140,8 @@ const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self);
guint nm_supplicant_interface_get_max_scan_ssids (NMSupplicantInterface *self);
+gboolean nm_supplicant_interface_get_p2p_available (NMSupplicantInterface *self);
+
gboolean nm_supplicant_interface_get_p2p_group_joined (NMSupplicantInterface *self);
const char* nm_supplicant_interface_get_p2p_group_path (NMSupplicantInterface *self);
diff --git a/src/supplicant/nm-supplicant-manager.c b/src/supplicant/nm-supplicant-manager.c
index 08bed98cf3..2f089fb36f 100644
--- a/src/supplicant/nm-supplicant-manager.c
+++ b/src/supplicant/nm-supplicant-manager.c
@@ -8,20 +8,64 @@
#include "nm-supplicant-manager.h"
+#include "nm-core-internal.h"
+#include "nm-dbus-manager.h"
+#include "nm-glib-aux/nm-dbus-aux.h"
+#include "nm-glib-aux/nm-ref-string.h"
#include "nm-supplicant-interface.h"
#include "nm-supplicant-types.h"
-#include "nm-core-internal.h"
+#include "platform/nm-platform.h"
/*****************************************************************************/
-typedef struct {
- GDBusProxy *proxy;
+#define CREATE_IFACE_TRY_COUNT_MAX 7u
+
+struct _NMSupplMgrCreateIfaceHandle {
+ NMSupplicantManager *self;
+ CList create_iface_lst;
GCancellable *cancellable;
+ NMSupplicantManagerCreateInterfaceCb callback;
+ gpointer callback_user_data;
+ NMShutdownWaitObjHandle *shutdown_handle;
+ NMRefString *name_owner;
+ GError *fail_on_idle_error;
+ NMSupplicantDriver driver;
+ int ifindex;
+ guint fail_on_idle_id;
+ guint create_iface_try_count:5;
+};
+
+enum {
+ AVAILABLE_CHANGED,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+typedef struct {
+ GDBusConnection *dbus_connection;
+
+ NMRefString *name_owner;
+
+ GCancellable *get_name_owner_cancellable;
+ GCancellable *get_capabilities_cancellable;
+ GCancellable *poke_name_owner_cancellable;
+
+ GHashTable *supp_ifaces;
CList supp_lst_head;
+
+ CList create_iface_lst_head;
+
NMSupplCapMask capabilities;
- guint die_count_reset_id;
- guint die_count;
- bool running:1;
+
+ guint name_owner_changed_id;
+ guint interface_removed_id;
+ guint poke_name_owner_timeout_id;
+ guint available_reset_id;
+
+ /* see nm_supplicant_manager_get_available(). */
+ NMTernary available:2;
+
} NMSupplicantManagerPrivate;
struct _NMSupplicantManager {
@@ -37,6 +81,8 @@ G_DEFINE_TYPE (NMSupplicantManager, nm_supplicant_manager, G_TYPE_OBJECT)
#define NM_SUPPLICANT_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSupplicantManager, NM_IS_SUPPLICANT_MANAGER)
+NM_DEFINE_SINGLETON_GETTER (NMSupplicantManager, nm_supplicant_manager_get, NM_TYPE_SUPPLICANT_MANAGER);
+
/*****************************************************************************/
#define _NMLOG_DOMAIN LOGD_SUPPLICANT
@@ -48,6 +94,27 @@ NM_CACHED_QUARK_FCN ("nm-supplicant-error-quark", nm_supplicant_error_quark)
/*****************************************************************************/
+static void _create_iface_proceed_all (NMSupplicantManager *self,
+ GError *error);
+static void _supp_iface_add (NMSupplicantManager *self,
+ NMRefString *iface_path,
+ NMSupplicantInterface *supp_iface);
+static void _supp_iface_remove_one (NMSupplicantManager *self,
+ NMSupplicantInterface *supp_iface,
+ gboolean force_remove_from_supplicant,
+ const char *reason);
+static void _create_iface_dbus_call_get_interface (NMSupplicantManager *self,
+ NMSupplMgrCreateIfaceHandle *handle,
+ const char *ifname);
+static void _create_iface_dbus_call_create_interface (NMSupplicantManager *self,
+ NMSupplMgrCreateIfaceHandle *handle,
+ const char *ifname);
+static gboolean _create_iface_fail_on_idle_cb (gpointer user_data);
+
+static gboolean _available_reset_cb (gpointer user_data);
+
+/*****************************************************************************/
+
NM_UTILS_LOOKUP_STR_DEFINE (nm_supplicant_driver_to_string, NMSupplicantDriver,
NM_UTILS_LOOKUP_DEFAULT_WARN (NULL),
NM_UTILS_LOOKUP_ITEM (NM_SUPPLICANT_DRIVER_UNKNOWN, "???"),
@@ -58,6 +125,39 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_supplicant_driver_to_string, NMSupplicantDriver,
/*****************************************************************************/
+NMTernary
+nm_supplicant_manager_is_available (NMSupplicantManager *self)
+{
+ g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NM_TERNARY_FALSE);
+
+ return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->available;
+}
+
+NMRefString *
+nm_supplicant_manager_get_dbus_name_owner (NMSupplicantManager *self)
+{
+ g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL);
+
+ return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->name_owner;
+}
+
+GDBusConnection *nm_supplicant_manager_get_dbus_connection (NMSupplicantManager *self)
+{
+ g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL);
+
+ return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->dbus_connection;
+}
+
+NMSupplCapMask
+nm_supplicant_manager_get_global_capabilities (NMSupplicantManager *self)
+{
+ g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NM_SUPPL_CAP_MASK_NONE);
+
+ return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->capabilities;
+}
+
+/*****************************************************************************/
+
static void
_caps_set (NMSupplicantManagerPrivate *priv,
NMSupplCapType type,
@@ -82,66 +182,52 @@ _caps_to_str (NMSupplicantManagerPrivate *priv,
/*****************************************************************************/
-static gboolean
-die_count_exceeded (guint32 count)
+static void
+_dbus_call_remove_interface (GDBusConnection *dbus_connection,
+ const char *name_owner,
+ const char *iface_path)
{
- return count > 2;
+ nm_assert (G_IS_DBUS_CONNECTION (dbus_connection));
+ nm_assert (name_owner);
+ nm_assert (iface_path);
+
+ g_dbus_connection_call (dbus_connection,
+ name_owner,
+ NM_WPAS_DBUS_PATH,
+ NM_WPAS_DBUS_INTERFACE,
+ "RemoveInterface",
+ g_variant_new ("(o)", iface_path),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ 10000,
+ NULL,
+ NULL,
+ NULL);
}
-static gboolean
-is_available (NMSupplicantManager *self)
+void
+_nm_supplicant_manager_dbus_call_remove_interface (NMSupplicantManager *self,
+ const char *name_owner,
+ const char *iface_path)
{
- NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
-
- return priv->running
- && !die_count_exceeded (priv->die_count);
+ _dbus_call_remove_interface (NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->dbus_connection,
+ name_owner,
+ iface_path);
}
/*****************************************************************************/
static void
-_sup_iface_last_ref (gpointer data,
- GObject *object,
- gboolean is_last_ref)
-{
- NMSupplicantManager *self = data;
- NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- NMSupplicantInterface *sup_iface = NM_SUPPLICANT_INTERFACE (object);
- const char *op;
-
- nm_assert (is_last_ref);
- nm_assert (c_list_contains (&priv->supp_lst_head, &sup_iface->supp_lst));
-
- c_list_unlink (&sup_iface->supp_lst);
-
- if ( priv->running
- && priv->proxy
- && (op = nm_supplicant_interface_get_object_path (sup_iface))) {
- g_dbus_proxy_call (priv->proxy,
- "RemoveInterface",
- g_variant_new ("(o)", op),
- G_DBUS_CALL_FLAGS_NONE,
- 3000,
- NULL,
- NULL,
- NULL);
- }
-
- g_object_remove_toggle_ref (G_OBJECT (sup_iface), _sup_iface_last_ref, self);
-}
-
-static void
on_supplicant_wfd_ies_set (GObject *source_object,
- GAsyncResult *res,
+ GAsyncResult *result,
gpointer user_data)
{
- gs_unref_variant GVariant *result = NULL;
+ gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
- result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), res, &error);
-
- if (!result)
- _LOGW ("failed to set WFD IEs on wpa_supplicant: %s", error->message);
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), result, &error);
+ if (!res)
+ _LOGD ("failed to set WFD IEs on wpa_supplicant: %s", error->message);
}
/**
@@ -164,138 +250,672 @@ nm_supplicant_manager_set_wfd_ies (NMSupplicantManager *self,
priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- _LOGD ("setting WFD IEs for P2P operation");
+ if (!priv->name_owner)
+ return;
+
+ _LOGD ("setting WFD IEs for P2P operation on %s", priv->name_owner->str);
g_variant_builder_init (&params, G_VARIANT_TYPE ("(ssv)"));
- g_variant_builder_add (&params, "s", g_dbus_proxy_get_interface_name (priv->proxy));
+ g_variant_builder_add (&params, "s", NM_WPAS_DBUS_INTERFACE);
g_variant_builder_add (&params, "s", "WFDIEs");
g_variant_builder_add_value (&params,
g_variant_new_variant (nm_utils_gbytes_to_variant_ay (wfd_ies)));
- g_dbus_connection_call (g_dbus_proxy_get_connection (priv->proxy),
- g_dbus_proxy_get_name (priv->proxy),
- g_dbus_proxy_get_object_path (priv->proxy),
- "org.freedesktop.DBus.Properties",
+ g_dbus_connection_call (priv->dbus_connection,
+ priv->name_owner->str,
+ NM_WPAS_DBUS_PATH,
+ DBUS_INTERFACE_PROPERTIES,
"Set",
g_variant_builder_end (&params),
- G_VARIANT_TYPE_UNIT,
+ G_VARIANT_TYPE ("()"),
G_DBUS_CALL_FLAGS_NO_AUTO_START,
- 1000,
+ 3000,
NULL,
on_supplicant_wfd_ies_set,
NULL);
}
-/**
- * nm_supplicant_manager_create_interface:
- * @self: the #NMSupplicantManager
- * @ifname: the interface for which to obtain the supplicant interface
- * @is_wireless: whether the interface is supposed to be wireless.
- *
- * 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 *
+/*****************************************************************************/
+
+static gboolean
+_poke_name_owner_timeout_cb (gpointer user_data)
+{
+ NMSupplicantManager *self = user_data;
+ NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+ gs_free_error GError *error = NULL;
+ gboolean available_changed = FALSE;
+
+ nm_assert (!priv->name_owner);
+
+ priv->poke_name_owner_timeout_id = 0;
+ nm_clear_g_cancellable (&priv->poke_name_owner_cancellable);
+
+ _LOGT ("poke service \"%s\" failed for good with timeout%s",
+ NM_WPAS_DBUS_SERVICE,
+ (priv->available == NM_TERNARY_DEFAULT)
+ ? " (set as not available)"
+ : "");
+
+ if (priv->available == NM_TERNARY_DEFAULT) {
+ /* the available flag usually only changes together with the name-owner.
+ * However, if we tries to poke the service but failed to start it (with
+ * timeout), was also set it as (hard) not available. */
+ priv->available = NM_TERNARY_FALSE;
+ nm_clear_g_source (&priv->available_reset_id);
+ priv->available_reset_id = g_timeout_add_seconds (60,
+ _available_reset_cb,
+ self);
+ available_changed = TRUE;
+ }
+
+ nm_utils_error_set (&error,
+ NM_UTILS_ERROR_UNKNOWN,
+ "Failed to D-Bus activate wpa_supplicant service");
+
+ _create_iface_proceed_all (self, error);
+
+ if (available_changed) {
+ /* We delay the emitting of the notification after aborting all
+ * create-iface handles. */
+ g_signal_emit (self, signals[AVAILABLE_CHANGED], 0);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+_poke_name_owner_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ gs_unref_variant GVariant *res = NULL;
+ gs_free_error GError *error = NULL;
+
+ res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
+ if (!res)
+ _LOGT ("poke service \"%s\" failed: %s", NM_WPAS_DBUS_SERVICE, error->message);
+ else
+ _LOGT ("poke service \"%s\" succeeded", NM_WPAS_DBUS_SERVICE);
+
+ /* in both cases, we react the same: we wait for the name owner to appear
+ * or hit the timeout. */
+}
+
+static void
+_poke_name_owner (NMSupplicantManager *self)
+{
+ NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+
+ if (priv->poke_name_owner_cancellable)
+ return;
+
+ _LOGT ("poke service \"%s\"...", NM_WPAS_DBUS_SERVICE);
+
+ priv->poke_name_owner_cancellable = g_cancellable_new ();
+ priv->poke_name_owner_timeout_id = g_timeout_add (3000,
+ _poke_name_owner_timeout_cb,
+ self);
+ nm_dbus_connection_call_start_service_by_name (priv->dbus_connection,
+ NM_WPAS_DBUS_SERVICE,
+ 5000,
+ priv->poke_name_owner_cancellable,
+ _poke_name_owner_cb,
+ self);
+}
+
+/*****************************************************************************/
+
+static void
+_create_iface_complete (NMSupplMgrCreateIfaceHandle *handle,
+ NMSupplicantInterface *supp_iface,
+ GError *error)
+{
+ nm_assert (!supp_iface || NM_IS_SUPPLICANT_INTERFACE (supp_iface));
+ nm_assert ((!!supp_iface) != (!!error));
+
+ c_list_unlink (&handle->create_iface_lst);
+
+ nm_clear_g_source (&handle->fail_on_idle_id);
+
+ if (handle->callback) {
+ NMSupplicantManagerCreateInterfaceCb callback;
+
+ nm_assert (NM_IS_SUPPLICANT_MANAGER (handle->self));
+
+ callback = handle->callback;
+ handle->callback = NULL;
+ callback (handle->self,
+ handle,
+ supp_iface,
+ error,
+ handle->callback_user_data);
+ }
+
+ g_clear_error (&handle->fail_on_idle_error);
+
+ g_clear_object (&handle->self);
+
+ if (handle->shutdown_handle) {
+ /* we have a pending CreateInterface request. We keep the handle
+ * instance alive. This is to remove the device again, once the
+ * request completes. */
+ return;
+ }
+
+ nm_clear_g_cancellable (&handle->cancellable);
+ nm_ref_string_unref (handle->name_owner);
+
+ nm_g_slice_free_fcn (handle);
+}
+
+static void
+_create_iface_add (NMSupplicantManager *self,
+ NMSupplMgrCreateIfaceHandle *handle,
+ const char *iface_path_str,
+ gboolean created_by_us)
+{
+ NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+ nm_auto_ref_string NMRefString *iface_path = NULL;
+ gs_unref_object NMSupplicantInterface *supp_iface = NULL;
+
+ iface_path = nm_ref_string_new (iface_path_str);
+
+ supp_iface = g_hash_table_lookup (priv->supp_ifaces, iface_path);
+ if (supp_iface) {
+ /* Now this is odd... Reuse the same interface. */
+ g_object_ref (supp_iface);
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: interface %s on %s created (already existing)",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ iface_path_str,
+ priv->name_owner->str);
+ _create_iface_complete (handle, supp_iface, NULL);
+ return;
+ }
+
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: interface %s on %s created%s",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ iface_path_str,
+ priv->name_owner->str,
+ created_by_us ? " (created by us)" : "");
+
+ supp_iface = nm_supplicant_interface_new (self,
+ iface_path,
+ handle->ifindex,
+ handle->driver);
+
+ _supp_iface_add (self, iface_path, supp_iface);
+
+ _create_iface_complete (handle, supp_iface, NULL);
+}
+
+static void
+_create_iface_dbus_call_get_interface_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusConnection *dbus_connection = G_DBUS_CONNECTION (source);
+ NMSupplMgrCreateIfaceHandle *handle;
+ NMSupplicantManager *self;
+ NMSupplicantManagerPrivate *priv;
+ gs_unref_variant GVariant *res = NULL;
+ gs_free_error GError *error = NULL;
+ const char *iface_path_str;
+
+ res = g_dbus_connection_call_finish (dbus_connection, result, &error);
+
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
+ handle = user_data;
+ nm_assert (handle->callback);
+
+ self = handle->self;
+ priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+
+ nm_assert (handle->name_owner == priv->name_owner);
+
+ if (!res) {
+ char ifname[NMP_IFNAMSIZ];
+
+ if ( handle->create_iface_try_count < CREATE_IFACE_TRY_COUNT_MAX
+ && _nm_dbus_error_has_name (error, NM_WPAS_ERROR_UNKNOWN_IFACE)
+ && nm_platform_if_indextoname (NM_PLATFORM_GET, handle->ifindex, ifname)) {
+ /* Before, supplicant told us the interface existed. Was there a race?
+ * Try again. */
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: D-Bus call failed to get interface. Try to create it again (ifname \"%s\")",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ ifname);
+ _create_iface_dbus_call_create_interface (self, handle, ifname);
+ return;
+ }
+
+ g_clear_object (&handle->cancellable);
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: D-Bus call to get interface failed: %s",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ error->message);
+ _create_iface_complete (handle, NULL, error);
+ return;
+ }
+
+ g_clear_object (&handle->cancellable);
+
+ g_variant_get (res, "(&o)", &iface_path_str);
+
+ _create_iface_add (self, handle, iface_path_str, FALSE);
+}
+
+static void
+_create_iface_dbus_call_create_interface_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusConnection *dbus_connection = G_DBUS_CONNECTION (source);
+ NMSupplMgrCreateIfaceHandle *handle = user_data;
+ NMSupplicantManager *self;
+ NMSupplicantManagerPrivate *priv;
+ gs_unref_variant GVariant *res = NULL;
+ gs_free_error GError *error = NULL;
+ const char *iface_path_str;
+ char ifname[NMP_IFNAMSIZ];
+
+ res = g_dbus_connection_call_finish (dbus_connection, result, &error);
+
+ nm_shutdown_wait_obj_unregister (g_steal_pointer (&handle->shutdown_handle));
+
+ if (!res) {
+ if ( handle->callback
+ && ({ nm_assert (handle->self); TRUE; })
+ && _nm_dbus_error_has_name (error, NM_WPAS_ERROR_EXISTS_ERROR)
+ && nm_platform_if_indextoname (NM_PLATFORM_GET, handle->ifindex, ifname)) {
+ self = handle->self;
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: D-Bus call failed to create interface. Try to get existing interface (ifname \"%s\")",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ ifname);
+ _create_iface_dbus_call_get_interface (self, handle, ifname);
+ return;
+ }
+ g_clear_object (&handle->cancellable);
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: D-Bus call failed: %s",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ error->message);
+ _create_iface_complete (handle, NULL, error);
+ return;
+ }
+
+ g_clear_object (&handle->cancellable);
+
+ self = handle->self;
+ priv = self
+ ? NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)
+ : NULL;
+
+ g_variant_get (res, "(&o)", &iface_path_str);
+
+ if ( !handle->callback
+ || priv->name_owner != handle->name_owner) {
+ if (!handle->callback) {
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: request already cancelled but still remove interface %s in %s",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ iface_path_str,
+ handle->name_owner->str);
+ } else {
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: name owner changed, still remove interface %s in %s",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ iface_path_str,
+ handle->name_owner->str);
+ nm_utils_error_set (&error,
+ NM_UTILS_ERROR_UNKNOWN,
+ "The name owner changed since creating the interface");
+ }
+ _dbus_call_remove_interface (dbus_connection,
+ handle->name_owner->str,
+ iface_path_str);
+ _create_iface_complete (handle, NULL, error);
+ return;
+ }
+
+ _create_iface_add (self, handle, iface_path_str, TRUE);
+}
+
+static void
+_create_iface_dbus_call_get_interface (NMSupplicantManager *self,
+ NMSupplMgrCreateIfaceHandle *handle,
+ const char *ifname)
+{
+ NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+
+ nm_assert (handle->cancellable);
+ nm_assert (!handle->shutdown_handle);
+
+ g_dbus_connection_call (priv->dbus_connection,
+ priv->name_owner->str,
+ NM_WPAS_DBUS_PATH,
+ NM_WPAS_DBUS_INTERFACE,
+ "GetInterface",
+ g_variant_new ("(s)", ifname),
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 5000,
+ handle->cancellable,
+ _create_iface_dbus_call_get_interface_cb,
+ handle);
+}
+
+static void
+_create_iface_dbus_call_create_interface (NMSupplicantManager *self,
+ NMSupplMgrCreateIfaceHandle *handle,
+ const char *ifname)
+{
+ NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+ GVariantBuilder builder;
+
+ nm_assert (priv->name_owner == handle->name_owner);
+ nm_assert (handle->cancellable);
+ nm_assert (!handle->shutdown_handle);
+ nm_assert (handle->create_iface_try_count <= CREATE_IFACE_TRY_COUNT_MAX);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add (&builder,
+ "{sv}",
+ "Driver",
+ g_variant_new_string (nm_supplicant_driver_to_string (handle->driver)));
+ g_variant_builder_add (&builder,
+ "{sv}",
+ "Ifname",
+ g_variant_new_string (ifname));
+
+ handle->shutdown_handle = nm_shutdown_wait_obj_register_cancellable_full (handle->cancellable,
+ g_strdup_printf ("wpas-create-" NM_HASH_OBFUSCATE_PTR_FMT,
+ NM_HASH_OBFUSCATE_PTR (handle)),
+ TRUE);
+ handle->create_iface_try_count++;
+ g_dbus_connection_call (priv->dbus_connection,
+ handle->name_owner->str,
+ NM_WPAS_DBUS_PATH,
+ NM_WPAS_DBUS_INTERFACE,
+ "CreateInterface",
+ g_variant_new ("(a{sv})", &builder),
+ G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ 5000,
+ handle->cancellable,
+ _create_iface_dbus_call_create_interface_cb,
+ handle);
+}
+
+static void
+_create_iface_dbus_start (NMSupplicantManager *self,
+ NMSupplMgrCreateIfaceHandle *handle)
+{
+ NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+ char ifname[NMP_IFNAMSIZ];
+
+ nm_assert (priv->name_owner);
+ nm_assert (!handle->cancellable);
+
+ if (!nm_platform_if_indextoname (NM_PLATFORM_GET, handle->ifindex, ifname)) {
+ nm_utils_error_set (&handle->fail_on_idle_error,
+ NM_UTILS_ERROR_UNKNOWN,
+ "Cannot find interface %d",
+ handle->ifindex);
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: creating interface fails to find interface name for ifindex %d",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ handle->ifindex);
+ handle->fail_on_idle_id = g_idle_add (_create_iface_fail_on_idle_cb, handle);
+ return;
+ }
+
+ /* Our handle keeps @self alive. That means, when NetworkManager shall shut
+ * down, it's the responsibility of the callers to cancel the handles,
+ * to initiate coordinated shutdown.
+ *
+ * However, we now issue a CreateInterface call. Even if the handle gets cancelled
+ * (because of shutdown, or because the caller is no longer interested in the
+ * result), we don't want to cancel this request. Instead, we want to get
+ * the interface path and remove it right away.
+ *
+ * That means, the D-Bus call cannot be cancelled (because we always care about
+ * the result). Only the @handle can be cancelled, but parts of the handle will
+ * stick around to complete the task.
+ *
+ * See also handle->shutdown_handle.
+ */
+ handle->name_owner = nm_ref_string_ref (priv->name_owner);
+ handle->cancellable = g_cancellable_new ();
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: creating interface (ifname \"%s\")...",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ ifname);
+ _create_iface_dbus_call_create_interface (self, handle, ifname);
+}
+
+static gboolean
+_create_iface_fail_on_idle_cb (gpointer user_data)
+{
+ NMSupplMgrCreateIfaceHandle *handle = user_data;
+
+ handle->fail_on_idle_id = 0;
+
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: fail with internal error: %s",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ handle->fail_on_idle_error->message);
+
+ _create_iface_complete (handle, NULL, handle->fail_on_idle_error);
+ return G_SOURCE_REMOVE;
+}
+
+NMSupplMgrCreateIfaceHandle *
nm_supplicant_manager_create_interface (NMSupplicantManager *self,
- const char *ifname,
- NMSupplicantDriver driver)
+ int ifindex,
+ NMSupplicantDriver driver,
+ NMSupplicantManagerCreateInterfaceCb callback,
+ gpointer user_data)
{
NMSupplicantManagerPrivate *priv;
- NMSupplicantInterface *sup_iface;
+ NMSupplMgrCreateIfaceHandle *handle;
g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL);
- g_return_val_if_fail (ifname != NULL, NULL);
+ g_return_val_if_fail (ifindex > 0, NULL);
+ g_return_val_if_fail (callback, NULL);
+ nm_assert (nm_supplicant_driver_to_string (driver));
priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- _LOGD ("(%s): creating new supplicant interface", ifname);
+ handle = g_slice_new (NMSupplMgrCreateIfaceHandle);
+ *handle = (NMSupplMgrCreateIfaceHandle) {
+ .self = g_object_ref (self),
+ .callback = callback,
+ .callback_user_data = user_data,
+ .driver = driver,
+ .ifindex = ifindex,
+ };
+ c_list_link_tail (&priv->create_iface_lst_head, &handle->create_iface_lst);
+
+ if (!priv->dbus_connection) {
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: new request interface %d (driver %s). Fail bacause no D-Bus connection to talk to wpa_supplicant...",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ ifindex,
+ nm_supplicant_driver_to_string (driver));
+ nm_utils_error_set (&handle->fail_on_idle_error,
+ NM_UTILS_ERROR_UNKNOWN,
+ "No D-Bus connection to talk to wpa_supplicant");
+ handle->fail_on_idle_id = g_idle_add (_create_iface_fail_on_idle_cb, handle);
+ return handle;
+ }
+
+ if (!priv->name_owner) {
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: new request interface %d (driver %s). %s",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ ifindex,
+ nm_supplicant_driver_to_string (driver),
+ priv->poke_name_owner_cancellable
+ ? "Waiting for supplicant..."
+ : "Poke supplicant...");
+ _poke_name_owner (self);
+ return handle;
+ }
- c_list_for_each_entry (sup_iface, &priv->supp_lst_head, supp_lst) {
- if (nm_streq0 (nm_supplicant_interface_get_ifname (sup_iface), ifname))
- g_return_val_if_reached (NULL);
+ if (priv->get_capabilities_cancellable) {
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: new request interface %d (driver %s). Waiting to fetch capabilities for %s...",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ ifindex,
+ nm_supplicant_driver_to_string (driver),
+ priv->name_owner->str);
+ return handle;
}
- sup_iface = nm_supplicant_interface_new (ifname,
- NULL,
- driver,
- priv->capabilities);
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: new request interface %d (driver %s). create interface on %s...",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ ifindex,
+ nm_supplicant_driver_to_string (driver),
+ priv->name_owner->str);
- c_list_link_tail (&priv->supp_lst_head, &sup_iface->supp_lst);
- g_object_add_toggle_ref (G_OBJECT (sup_iface), _sup_iface_last_ref, self);
+ _create_iface_dbus_start (self, handle);
+ return handle;
+}
- /* 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 (sup_iface, TRUE);
+static void
+_create_iface_proceed_all (NMSupplicantManager *self,
+ GError *error)
+{
+ NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+ NMSupplMgrCreateIfaceHandle *handle;
+
+ nm_assert (error || priv->name_owner);
+ nm_assert (error || !priv->get_capabilities_cancellable);
- return sup_iface;
+ if (c_list_is_empty (&priv->create_iface_lst_head))
+ return;
+
+ if (error) {
+ CList alt_list;
+
+ /* we move the handles we want to proceed to a alternative list.
+ * That is, because we invoke callbacks to the caller, who might
+ * create another request right away. We don't want to proceed
+ * that one. */
+ c_list_init (&alt_list);
+ c_list_splice (&alt_list, &priv->create_iface_lst_head);
+
+ while ((handle = c_list_last_entry (&alt_list, NMSupplMgrCreateIfaceHandle, create_iface_lst))) {
+ /* We don't need to keep @self alive. Every handle holds a reference already. */
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: create interface failed: %s",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ error->message);
+ _create_iface_complete (handle, NULL, error);
+ }
+ return;
+ }
+
+ /* start all the handles. This does not invoke callbacks, so the list of handles
+ * cannot be modified while we iterate it. */
+ c_list_for_each_entry (handle, &priv->create_iface_lst_head, create_iface_lst) {
+ _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: create interface on %s...",
+ NM_HASH_OBFUSCATE_PTR (handle),
+ priv->name_owner->str);
+ _create_iface_dbus_start (self, handle);
+ }
+}
+
+void
+nm_supplicant_manager_create_interface_cancel (NMSupplMgrCreateIfaceHandle *handle)
+{
+ gs_free_error GError *error = NULL;
+
+ if (!handle)
+ return;
+
+ g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (handle->self));
+ g_return_if_fail (handle->callback);
+ nm_assert (!c_list_is_empty (&handle->create_iface_lst));
+
+ nm_utils_error_set_cancelled (&error, FALSE, NULL);
+ _create_iface_complete (handle, NULL, error);
}
-/**
- * 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 *sup_iface;
+ NMSupplicantInterface *supp_iface;
+ nm_auto_ref_string NMRefString *iface_path = NULL;
g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL);
- g_return_val_if_fail (object_path != NULL, NULL);
+ g_return_val_if_fail (object_path, NULL);
priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- _LOGD ("creating new supplicant interface for dbus path %s", object_path);
+ iface_path = nm_ref_string_new (object_path);
- c_list_for_each_entry (sup_iface, &priv->supp_lst_head, supp_lst) {
- if (nm_streq0 (nm_supplicant_interface_get_object_path (sup_iface), object_path))
- g_return_val_if_reached (NULL);
- }
+ supp_iface = g_hash_table_lookup (priv->supp_ifaces, iface_path);
- sup_iface = nm_supplicant_interface_new (NULL,
- object_path,
- NM_SUPPLICANT_DRIVER_WIRELESS,
- priv->capabilities);
+ if (supp_iface)
+ return g_object_ref (supp_iface);
- c_list_link_tail (&priv->supp_lst_head, &sup_iface->supp_lst);
- g_object_add_toggle_ref (G_OBJECT (sup_iface), _sup_iface_last_ref, self);
+ supp_iface = nm_supplicant_interface_new (self,
+ iface_path,
+ 0,
+ NM_SUPPLICANT_DRIVER_UNKNOWN);
- /* 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 (sup_iface, TRUE);
+ _supp_iface_add (self, iface_path, supp_iface);
- return sup_iface;
+ return supp_iface;
}
+/*****************************************************************************/
+
static void
-update_capabilities (NMSupplicantManager *self)
+_dbus_interface_removed_cb (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *signal_interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
{
+ NMSupplicantManager *self = user_data;
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- NMSupplicantInterface *sup_iface;
- const char **array;
- GVariant *value;
+ NMSupplicantInterface *supp_iface;
+ const char *iface_path_str;
+ nm_auto_ref_string NMRefString *iface_path = NULL;
+
+ nm_assert (nm_streq (sender_name, priv->name_owner->str));
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ return;
+
+ g_variant_get (parameters, "(&o)", &iface_path_str);
+
+ iface_path = nm_ref_string_new (iface_path_str);
+
+ supp_iface = g_hash_table_lookup (priv->supp_ifaces, iface_path);
+ if (!supp_iface)
+ return;
+
+ _supp_iface_remove_one (self, supp_iface, FALSE, "InterfaceRemoved signal from wpa_supplicant");
+}
+
+/*****************************************************************************/
+
+static void
+_dbus_get_capabilities_cb (GVariant *res,
+ GError *error,
+ gpointer user_data)
+{
+ NMSupplicantManager *self;
+ NMSupplicantManagerPrivate *priv;
+
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
+ self = user_data;
+ priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+
+ g_clear_object (&priv->get_capabilities_cancellable);
/* The supplicant only advertises global capabilities if the following
* commit has been applied:
@@ -315,53 +935,61 @@ update_capabilities (NMSupplicantManager *self)
_caps_set (priv, NM_SUPPL_CAP_TYPE_FT, NM_TERNARY_FALSE);
_caps_set (priv, NM_SUPPL_CAP_TYPE_SHA384, NM_TERNARY_FALSE);
_caps_set (priv, NM_SUPPL_CAP_TYPE_MESH, NM_TERNARY_FALSE);
-
- value = g_dbus_proxy_get_cached_property (priv->proxy, "Capabilities");
- if (value) {
- if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY)) {
- array = g_variant_get_strv (value, NULL);
- _caps_set (priv, NM_SUPPL_CAP_TYPE_AP, NM_TERNARY_FALSE);
- _caps_set (priv, NM_SUPPL_CAP_TYPE_PMF, NM_TERNARY_FALSE);
- _caps_set (priv, NM_SUPPL_CAP_TYPE_FILS, NM_TERNARY_FALSE);
- if (array) {
- if (g_strv_contains (array, "ap")) _caps_set (priv, NM_SUPPL_CAP_TYPE_AP, NM_TERNARY_TRUE);
- if (g_strv_contains (array, "pmf")) _caps_set (priv, NM_SUPPL_CAP_TYPE_PMF, NM_TERNARY_TRUE);
- if (g_strv_contains (array, "fils")) _caps_set (priv, NM_SUPPL_CAP_TYPE_FILS, NM_TERNARY_TRUE);
- if (g_strv_contains (array, "p2p")) _caps_set (priv, NM_SUPPL_CAP_TYPE_P2P, NM_TERNARY_TRUE);
- if (g_strv_contains (array, "ft")) _caps_set (priv, NM_SUPPL_CAP_TYPE_FT, NM_TERNARY_TRUE);
- if (g_strv_contains (array, "sha384")) _caps_set (priv, NM_SUPPL_CAP_TYPE_SHA384, NM_TERNARY_TRUE);
- if (g_strv_contains (array, "mesh")) _caps_set (priv, NM_SUPPL_CAP_TYPE_MESH, NM_TERNARY_TRUE);
- g_free (array);
+ _caps_set (priv, NM_SUPPL_CAP_TYPE_FAST, NM_TERNARY_FALSE);
+ _caps_set (priv, NM_SUPPL_CAP_TYPE_WFD, NM_TERNARY_FALSE);
+
+ if (res) {
+ nm_auto_free_variant_iter GVariantIter *res_iter = NULL;
+ const char *res_key;
+ GVariant *res_val;
+
+ g_variant_get (res, "(a{sv})", &res_iter);
+ while (g_variant_iter_loop (res_iter, "{&sv}", &res_key, &res_val)) {
+ if (nm_streq (res_key, "Capabilities")) {
+ if (g_variant_is_of_type (res_val, G_VARIANT_TYPE_STRING_ARRAY)) {
+ gs_free const char **array = NULL;
+ const char **a;
+
+ array = g_variant_get_strv (res_val, NULL);
+ _caps_set (priv, NM_SUPPL_CAP_TYPE_AP, NM_TERNARY_FALSE);
+ _caps_set (priv, NM_SUPPL_CAP_TYPE_PMF, NM_TERNARY_FALSE);
+ _caps_set (priv, NM_SUPPL_CAP_TYPE_FILS, NM_TERNARY_FALSE);
+ if (array) {
+ for (a = array; *a; a++) {
+ if (nm_streq (*a, "ap")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_AP, NM_TERNARY_TRUE); continue; }
+ if (nm_streq (*a, "pmf")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_PMF, NM_TERNARY_TRUE); continue; }
+ if (nm_streq (*a, "fils")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_FILS, NM_TERNARY_TRUE); continue; }
+ if (nm_streq (*a, "p2p")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_P2P, NM_TERNARY_TRUE); continue; }
+ if (nm_streq (*a, "ft")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_FT, NM_TERNARY_TRUE); continue; }
+ if (nm_streq (*a, "sha384")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_SHA384, NM_TERNARY_TRUE); continue; }
+ if (nm_streq (*a, "mesh")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_MESH, NM_TERNARY_TRUE); continue; }
+ }
+ }
+ }
+ continue;
}
- }
- g_variant_unref (value);
- }
-
- _caps_set (priv, NM_SUPPL_CAP_TYPE_FAST, NM_TERNARY_FALSE);
- value = g_dbus_proxy_get_cached_property (priv->proxy, "EapMethods");
- if (value) {
- if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY)) {
- array = g_variant_get_strv (value, NULL);
- if (array) {
- const char **a;
-
- for (a = array; *a; a++) {
- if (g_ascii_strcasecmp (*a, "FAST") == 0) {
- _caps_set (priv, NM_SUPPL_CAP_TYPE_FAST, NM_TERNARY_TRUE);
- break;
+ if (nm_streq (res_key, "EapMethods")) {
+ if (g_variant_is_of_type (res_val, G_VARIANT_TYPE_STRING_ARRAY)) {
+ gs_free const char **array = NULL;
+ const char **a;
+
+ array = g_variant_get_strv (res_val, NULL);
+ if (array) {
+ for (a = array; *a; a++) {
+ if (g_ascii_strcasecmp (*a, "FAST") == 0) {
+ _caps_set (priv, NM_SUPPL_CAP_TYPE_FAST, NM_TERNARY_TRUE);
+ break;
+ }
+ }
}
}
- g_free (array);
+ continue;
+ }
+ if (nm_streq (res_key, "WFDIEs")) {
+ _caps_set (priv, NM_SUPPL_CAP_TYPE_WFD, NM_TERNARY_TRUE);
+ continue;
}
}
- g_variant_unref (value);
- }
-
- _caps_set (priv, NM_SUPPL_CAP_TYPE_WFD, NM_TERNARY_FALSE);
- value = g_dbus_proxy_get_cached_property (priv->proxy, "WFDIEs");
- if (value) {
- _caps_set (priv, NM_SUPPL_CAP_TYPE_WFD, NM_TERNARY_TRUE);
- g_variant_unref (value);
}
_LOGD ("AP mode is %s", _caps_to_str (priv, NM_SUPPL_CAP_TYPE_AP));
@@ -374,161 +1002,307 @@ update_capabilities (NMSupplicantManager *self)
_LOGD ("EAP-FAST is %s", _caps_to_str (priv, NM_SUPPL_CAP_TYPE_FAST));
_LOGD ("WFD is %s", _caps_to_str (priv, NM_SUPPL_CAP_TYPE_WFD));
- c_list_for_each_entry (sup_iface, &priv->supp_lst_head, supp_lst) {
- nm_supplicant_interface_set_global_capabilities (sup_iface,
- priv->capabilities);
- }
+ nm_assert (g_hash_table_size (priv->supp_ifaces) == 0);
+ nm_assert (c_list_is_empty (&priv->supp_lst_head));
+
+ _create_iface_proceed_all (self, NULL);
}
-static void
-availability_changed (NMSupplicantManager *self, gboolean available)
+/*****************************************************************************/
+
+void
+_nm_supplicant_manager_unregister_interface (NMSupplicantManager *self,
+ NMSupplicantInterface *supp_iface)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- gs_unref_ptrarray GPtrArray *sup_ifaces = NULL;
- NMSupplicantInterface *sup_iface;
- gsize i, n;
- n = c_list_length (&priv->supp_lst_head);
- if (n == 0)
- return;
+ nm_assert (NM_IS_SUPPLICANT_INTERFACE (supp_iface));
+ nm_assert (c_list_contains (&NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->supp_lst_head, &supp_iface->supp_lst));
- /* setting the supplicant as unavailable might cause the caller to unref
- * the supplicant (and thus remove the instance from the list of interfaces.
- * Delay that by taking an additional reference first. */
+ c_list_unlink (&supp_iface->supp_lst);
+ if (!g_hash_table_remove (priv->supp_ifaces, nm_supplicant_interface_get_object_path (supp_iface)))
+ nm_assert_not_reached ();
+}
- sup_ifaces = g_ptr_array_new_full (n, g_object_unref);
- c_list_for_each_entry (sup_iface, &priv->supp_lst_head, supp_lst)
- g_ptr_array_add (sup_ifaces, g_object_ref (sup_iface));
+static void
+_supp_iface_add (NMSupplicantManager *self,
+ NMRefString *iface_path,
+ NMSupplicantInterface *supp_iface)
+{
+ NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- for (i = 0; i < n; i++)
- nm_supplicant_interface_set_supplicant_available (sup_ifaces->pdata[i], available);
+ c_list_link_tail (&priv->supp_lst_head, &supp_iface->supp_lst);
+ if (!g_hash_table_insert (priv->supp_ifaces, iface_path, supp_iface))
+ nm_assert_not_reached ();
}
static void
-set_running (NMSupplicantManager *self, gboolean now_running)
+_supp_iface_remove_one (NMSupplicantManager *self,
+ NMSupplicantInterface *supp_iface,
+ gboolean force_remove_from_supplicant,
+ const char *reason)
{
- NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- gboolean old_available = is_available (self);
- gboolean new_available;
+ nm_assert (NM_IS_SUPPLICANT_MANAGER (self));
+ nm_assert (NM_IS_SUPPLICANT_INTERFACE (supp_iface));
+ nm_assert (c_list_contains (&NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->supp_lst_head, &supp_iface->supp_lst));
+
+ _nm_supplicant_interface_set_state_down (supp_iface, force_remove_from_supplicant, reason);
- priv->running = now_running;
- new_available = is_available (self);
- if (old_available != new_available)
- availability_changed (self, new_available);
+ nm_assert (c_list_is_empty (&supp_iface->supp_lst));
}
static void
-set_die_count (NMSupplicantManager *self, guint new_die_count)
+_supp_iface_remove_all (NMSupplicantManager *self,
+ gboolean force_remove_from_supplicant,
+ const char *reason)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- gboolean old_available = is_available (self);
- gboolean new_available;
+ NMSupplicantInterface *supp_iface;
- priv->die_count = new_die_count;
- new_available = is_available (self);
- if (old_available != new_available)
- availability_changed (self, new_available);
+ while ((supp_iface = c_list_first_entry (&priv->supp_lst_head, NMSupplicantInterface, supp_lst)))
+ _supp_iface_remove_one (self, supp_iface, force_remove_from_supplicant, reason);
}
+/*****************************************************************************/
+
static gboolean
-wpas_die_count_reset_cb (gpointer user_data)
+_available_reset_cb (gpointer user_data)
{
- NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data);
+ NMSupplicantManager *self = user_data;
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- /* Reset the die count back to zero, which allows use of the supplicant again */
- priv->die_count_reset_id = 0;
- set_die_count (self, 0);
- _LOGI ("wpa_supplicant die count reset");
- return FALSE;
+ priv->available_reset_id = 0;
+ nm_assert (priv->available == NM_TERNARY_FALSE);
+ priv->available = NM_TERNARY_DEFAULT;
+ g_signal_emit (self, signals[AVAILABLE_CHANGED], 0);
+ return G_SOURCE_REMOVE;
}
+/*****************************************************************************/
+
static void
-name_owner_cb (GDBusProxy *proxy, GParamSpec *pspec, gpointer user_data)
+name_owner_changed (NMSupplicantManager *self,
+ const char *name_owner,
+ gboolean first_time)
{
- NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data);
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- char *owner;
-
- g_return_if_fail (proxy == priv->proxy);
-
- owner = g_dbus_proxy_get_name_owner (proxy);
- _LOGI ("wpa_supplicant %s", owner ? "running" : "stopped");
-
- if (owner) {
- update_capabilities (self);
- set_running (self, TRUE);
- } else if (priv->running) {
- /* Reschedule the die count reset timeout. Every time the supplicant
- * dies we wait 10 seconds before resetting the counter. If the
- * supplicant died more than twice before the timer is reset, then
- * we don't try to talk to the supplicant for a while.
- */
- if (priv->die_count_reset_id)
- g_source_remove (priv->die_count_reset_id);
- priv->die_count_reset_id = g_timeout_add_seconds (10, wpas_die_count_reset_cb, self);
- set_die_count (self, priv->die_count + 1);
-
- if (die_count_exceeded (priv->die_count)) {
- _LOGI ("wpa_supplicant die count %d; ignoring for 10 seconds",
- priv->die_count);
+ NMTernary available;
+ gboolean available_changed = FALSE;
+
+ nm_assert (!priv->get_name_owner_cancellable);
+ nm_assert ( !name_owner
+ || name_owner[0]);
+ nm_assert ( ( first_time
+ && !priv->name_owner)
+ || ( !first_time
+ && (!!priv->name_owner) != (!!name_owner)));
+
+ if (first_time) {
+ _LOGD ("wpa_supplicant name owner %s%s%s (%srunning)",
+ NM_PRINT_FMT_QUOTE_STRING (name_owner),
+ name_owner ? "" : "not ");
+ } else {
+ _LOGD ("wpa_supplicant name owner \"%s\" %s (%srunning)",
+ name_owner ?: priv->name_owner->str,
+ name_owner ? "disappeared" : "appeared",
+ name_owner ? "" : "not ");
+ }
+
+ nm_ref_string_unref (priv->name_owner);
+ priv->name_owner = nm_ref_string_new (name_owner);
+
+ nm_clear_g_dbus_connection_signal (priv->dbus_connection,
+ &priv->interface_removed_id);
+
+ if (name_owner) {
+ if (nm_clear_g_source (&priv->poke_name_owner_timeout_id))
+ _LOGT ("poke service \"%s\" completed with name owner change", NM_WPAS_DBUS_SERVICE);
+ nm_clear_g_cancellable (&priv->poke_name_owner_cancellable);
+ }
+
+ nm_clear_g_cancellable (&priv->get_capabilities_cancellable);
+
+ priv->capabilities = NM_SUPPL_CAP_MASK_NONE;
+ if (priv->name_owner) {
+ priv->get_capabilities_cancellable = g_cancellable_new ();
+ nm_dbus_connection_call_get_all (priv->dbus_connection,
+ priv->name_owner->str,
+ NM_WPAS_DBUS_PATH,
+ NM_WPAS_DBUS_INTERFACE,
+ 5000,
+ priv->get_capabilities_cancellable,
+ _dbus_get_capabilities_cb,
+ self);
+ priv->interface_removed_id = g_dbus_connection_signal_subscribe (priv->dbus_connection,
+ priv->name_owner->str,
+ NM_WPAS_DBUS_INTERFACE,
+ "InterfaceRemoved",
+ NULL,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ _dbus_interface_removed_cb,
+ self,
+ NULL);
+ }
+
+ /* if supplicant is running (has a name owner), we may use it.
+ * If this is the first time, and supplicant is not running, we
+ * may also use it (and assume that we probably could D-Bus activate
+ * it).
+ *
+ * Otherwise, somebody else stopped supplicant. It's no longer useable to
+ * us and we block auto starting it. The user has to start the service...
+ *
+ * Actually, below we reset the hard block after a short timeout. This
+ * causes the caller to notify that supplicant may now by around and
+ * retry to D-Bus activate it. */
+ if (priv->name_owner)
+ available = NM_TERNARY_TRUE;
+ else if (first_time)
+ available = NM_TERNARY_DEFAULT;
+ else
+ available = NM_TERNARY_FALSE;
+
+ if (priv->available != available) {
+ priv->available = available;
+ _LOGD ("supplicant is now %savailable",
+ available == FALSE
+ ? "not "
+ : ( available == TRUE
+ ? ""
+ : "maybe "));
+ available_changed = TRUE;
+
+ nm_clear_g_source (&priv->available_reset_id);
+ if (available == NM_TERNARY_FALSE) {
+ /* reset the availability from a hard "no" to a "maybe" in a bit. */
+ priv->available_reset_id = g_timeout_add_seconds (60,
+ _available_reset_cb,
+ self);
}
+ }
- priv->capabilities = NM_SUPPL_CAP_MASK_NONE;
+ _supp_iface_remove_all (self, TRUE, "name-owner changed");
- set_running (self, FALSE);
+ if (!priv->name_owner) {
+ if (priv->poke_name_owner_timeout_id) {
+ /* we are still poking for the service to start. Don't cancel
+ * the pending create requests just yet. */
+ } else {
+ gs_free_error GError *local_error = NULL;
+
+ /* When we loose the name owner, we fail all pending creation requests. */
+ nm_utils_error_set (&local_error,
+ NM_UTILS_ERROR_UNKNOWN,
+ "Name owner lost");
+ _create_iface_proceed_all (self, local_error);
+ }
+ } else {
+ /* We got a name-owner, but we don't do anything. Instead let
+ * _dbus_get_capabilities_cb() complete and kick of the create-iface
+ * handles.
+ *
+ * Note that before the first name-owner change, all create-iface
+ * requests fail right away. So we don't have to handle them here
+ * (by starting to poke the service). */
}
- g_free (owner);
+ if (available_changed)
+ g_signal_emit (self, signals[AVAILABLE_CHANGED], 0);
}
static void
-on_proxy_acquired (GObject *object, GAsyncResult *result, gpointer user_data)
+name_owner_changed_cb (GDBusConnection *connection,
+ const char *sender_name,
+ const char *object_path,
+ const char *interface_name,
+ const char *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
{
- NMSupplicantManager *self;
- NMSupplicantManagerPrivate *priv;
- GError *error = NULL;
- GDBusProxy *proxy;
+ gs_unref_object NMSupplicantManager *self = g_object_ref (user_data);
+ NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+ const char *name_owner;
- proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
- if (!proxy) {
- _LOGW ("failed to acquire wpa_supplicant proxy: Wi-Fi and 802.1x will not be available (%s)",
- error->message);
- g_clear_error (&error);
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)")))
+ return;
+
+ if (priv->get_name_owner_cancellable)
+ return;
+
+ g_variant_get (parameters,
+ "(&s&s&s)",
+ NULL,
+ NULL,
+ &name_owner);
+
+ name_owner = nm_str_not_empty (name_owner);
+
+ if (nm_streq0 (name_owner, nm_ref_string_get_str (priv->name_owner)))
return;
+
+ if ( name_owner
+ && priv->name_owner) {
+ /* odd, we directly switch from one name owner to the next. Can't allow that.
+ * First clear the name owner before resetting. */
+ name_owner_changed (self, NULL, FALSE);
}
+ name_owner_changed (user_data, name_owner, FALSE);
+}
+
+static void
+get_name_owner_cb (const char *name_owner,
+ GError *error,
+ gpointer user_data)
+{
+ NMSupplicantManager *self = user_data;
+ NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
+
+ if ( !name_owner
+ && nm_utils_error_is_cancelled (error))
+ return;
- self = NM_SUPPLICANT_MANAGER (user_data);
+ self = user_data;
priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- priv->proxy = proxy;
- g_signal_connect (priv->proxy, "notify::g-name-owner", G_CALLBACK (name_owner_cb), self);
- name_owner_cb (priv->proxy, NULL, self);
+ g_clear_object (&priv->get_name_owner_cancellable);
+
+ name_owner_changed (self, nm_str_not_empty (name_owner), TRUE);
}
/*****************************************************************************/
-NM_DEFINE_SINGLETON_GETTER (NMSupplicantManager, nm_supplicant_manager_get, NM_TYPE_SUPPLICANT_MANAGER);
-
static void
nm_supplicant_manager_init (NMSupplicantManager *self)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
nm_assert (priv->capabilities == NM_SUPPL_CAP_MASK_NONE);
+ nm_assert (priv->available == NM_TERNARY_FALSE);
+ priv->supp_ifaces = g_hash_table_new (nm_direct_hash, NULL);
c_list_init (&priv->supp_lst_head);
+ c_list_init (&priv->create_iface_lst_head);
+
+ priv->dbus_connection = nm_g_object_ref (NM_MAIN_DBUS_CONNECTION_GET);
+
+ if (!priv->dbus_connection) {
+ _LOGI ("no D-Bus connection to talk to wpa_supplicant");
+ return;
+ }
- priv->cancellable = g_cancellable_new ();
- g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_NONE,
- NULL,
- NM_WPAS_DBUS_SERVICE,
- NM_WPAS_DBUS_PATH,
- NM_WPAS_DBUS_INTERFACE,
- priv->cancellable,
- (GAsyncReadyCallback) on_proxy_acquired,
- self);
+ priv->name_owner_changed_id = nm_dbus_connection_signal_subscribe_name_owner_changed (priv->dbus_connection,
+ NM_WPAS_DBUS_SERVICE,
+ name_owner_changed_cb,
+ self,
+ NULL);
+ priv->get_name_owner_cancellable = g_cancellable_new ();
+ nm_dbus_connection_call_get_name_owner (priv->dbus_connection,
+ NM_WPAS_DBUS_SERVICE,
+ -1,
+ priv->get_name_owner_cancellable,
+ get_name_owner_cb,
+ self);
}
static void
@@ -536,20 +1310,32 @@ dispose (GObject *object)
{
NMSupplicantManager *self = (NMSupplicantManager *) object;
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
- NMSupplicantInterface *sup_iface;
- nm_clear_g_source (&priv->die_count_reset_id);
+ _supp_iface_remove_all (self, TRUE, "NMSupplicantManager is disposing");
- nm_clear_g_cancellable (&priv->cancellable);
+ nm_assert (c_list_is_empty (&priv->create_iface_lst_head));
- while ((sup_iface = c_list_first_entry (&priv->supp_lst_head, NMSupplicantInterface, supp_lst))) {
- c_list_unlink (&sup_iface->supp_lst);
- g_object_remove_toggle_ref (G_OBJECT (sup_iface), _sup_iface_last_ref, self);
- }
+ nm_clear_g_source (&priv->available_reset_id);
+
+ priv->available = NM_TERNARY_FALSE;
+ nm_clear_pointer (&priv->name_owner, nm_ref_string_unref);
+
+ nm_clear_g_source (&priv->poke_name_owner_timeout_id);
+ nm_clear_g_cancellable (&priv->poke_name_owner_cancellable);
- g_clear_object (&priv->proxy);
+ nm_clear_g_dbus_connection_signal (priv->dbus_connection,
+ &priv->interface_removed_id);
+ nm_clear_g_dbus_connection_signal (priv->dbus_connection,
+ &priv->name_owner_changed_id);
+
+ nm_clear_g_cancellable (&priv->get_name_owner_cancellable);
+ nm_clear_g_cancellable (&priv->get_capabilities_cancellable);
G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
+
+ g_clear_object (&priv->dbus_connection);
+
+ nm_clear_pointer (&priv->supp_ifaces, g_hash_table_destroy);
}
static void
@@ -558,5 +1344,11 @@ nm_supplicant_manager_class_init (NMSupplicantManagerClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = dispose;
-}
+ signals[AVAILABLE_CHANGED] =
+ g_signal_new (NM_SUPPLICANT_MANAGER_AVAILABLE_CHANGED,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+}
diff --git a/src/supplicant/nm-supplicant-manager.h b/src/supplicant/nm-supplicant-manager.h
index 18ca53b6f1..b2b814aa50 100644
--- a/src/supplicant/nm-supplicant-manager.h
+++ b/src/supplicant/nm-supplicant-manager.h
@@ -17,19 +17,49 @@
#define NM_IS_SUPPLICANT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SUPPLICANT_MANAGER))
#define NM_SUPPLICANT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SUPPLICANT_MANAGER, NMSupplicantManagerClass))
+#define NM_SUPPLICANT_MANAGER_AVAILABLE_CHANGED "available-changed"
+
typedef struct _NMSupplicantManagerClass NMSupplicantManagerClass;
GType nm_supplicant_manager_get_type (void);
NMSupplicantManager *nm_supplicant_manager_get (void);
+NMTernary nm_supplicant_manager_is_available (NMSupplicantManager *self);
+
+GDBusConnection *nm_supplicant_manager_get_dbus_connection (NMSupplicantManager *self);
+NMRefString *nm_supplicant_manager_get_dbus_name_owner (NMSupplicantManager *self);
+NMSupplCapMask nm_supplicant_manager_get_global_capabilities (NMSupplicantManager *self);
+
void nm_supplicant_manager_set_wfd_ies (NMSupplicantManager *self,
GBytes *wfd_ies);
-NMSupplicantInterface *nm_supplicant_manager_create_interface (NMSupplicantManager *mgr,
- const char *ifname,
- NMSupplicantDriver driver);
+typedef struct _NMSupplMgrCreateIfaceHandle NMSupplMgrCreateIfaceHandle;
+
+typedef void (*NMSupplicantManagerCreateInterfaceCb) (NMSupplicantManager *self,
+ NMSupplMgrCreateIfaceHandle *handle,
+ NMSupplicantInterface *iface,
+ GError *error,
+ gpointer user_data);
+
+NMSupplMgrCreateIfaceHandle *nm_supplicant_manager_create_interface (NMSupplicantManager *self,
+ int ifindex,
+ NMSupplicantDriver driver,
+ NMSupplicantManagerCreateInterfaceCb callback,
+ gpointer user_data);
+
+void nm_supplicant_manager_create_interface_cancel (NMSupplMgrCreateIfaceHandle *handle);
+
NMSupplicantInterface *nm_supplicant_manager_create_interface_from_path (NMSupplicantManager *self,
const char *object_path);
+/*****************************************************************************/
+
+void _nm_supplicant_manager_unregister_interface (NMSupplicantManager *self,
+ NMSupplicantInterface *supp_iface);
+
+void _nm_supplicant_manager_dbus_call_remove_interface (NMSupplicantManager *self,
+ const char *name_owner,
+ const char *iface_path);
+
#endif /* __NETWORKMANAGER_SUPPLICANT_MANAGER_H__ */
diff --git a/src/supplicant/nm-supplicant-types.h b/src/supplicant/nm-supplicant-types.h
index 17fbc0c009..bad52c345a 100644
--- a/src/supplicant/nm-supplicant-types.h
+++ b/src/supplicant/nm-supplicant-types.h
@@ -6,6 +6,8 @@
#ifndef __NETWORKMANAGER_SUPPLICANT_TYPES_H__
#define __NETWORKMANAGER_SUPPLICANT_TYPES_H__
+#include "c-list/src/c-list.h"
+
#define NM_WPAS_DBUS_SERVICE "fi.w1.wpa_supplicant1"
#define NM_WPAS_DBUS_PATH "/fi/w1/wpa_supplicant1"
#define NM_WPAS_DBUS_INTERFACE "fi.w1.wpa_supplicant1"
@@ -138,4 +140,65 @@ const char *nm_supplicant_driver_to_string (NMSupplicantDriver driver);
#define NM_SUPPLICANT_ERROR (nm_supplicant_error_quark ())
GQuark nm_supplicant_error_quark (void);
+typedef struct _NMSupplicantBssInfo {
+ NMRefString *bss_path;
+
+ NMSupplicantInterface *_self;
+ CList _bss_lst;
+ GCancellable *_init_cancellable;
+
+ GBytes *ssid;
+
+ gint64 last_seen_msec;
+
+ NM80211ApSecurityFlags wpa_flags; /* WPA-related flags */
+ NM80211ApSecurityFlags rsn_flags; /* RSN (WPA2) -related flags */
+
+ guint32 frequency;
+
+ guint32 max_rate;
+
+ guint8 signal_percent;
+
+ guint8 bssid[6 /* ETH_ALEN */];
+
+ NM80211ApFlags ap_flags:5;
+
+ NM80211Mode mode:4;
+
+ bool bssid_valid:1;
+
+ bool metered:1;
+
+ bool _bss_dirty:1;
+
+} NMSupplicantBssInfo;
+
+typedef struct _NMSupplicantPeerInfo{
+ NMRefString *peer_path;
+
+ CList _peer_lst;
+ NMSupplicantInterface *_self;
+ GCancellable *_init_cancellable;
+
+ char *device_name;
+ char *manufacturer;
+ char *model;
+ char *model_number;
+ char *serial;
+
+ GBytes *ies;
+
+ gint64 last_seen_msec;
+
+ guint8 address[6 /* ETH_ALEN */];
+
+ gint8 signal_percent;
+
+ bool address_valid:1;
+
+ bool _peer_dirty:1;
+
+} NMSupplicantPeerInfo;
+
#endif /* NM_SUPPLICANT_TYPES_H */