summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 */