supplicant: large rework of wpa_supplicant handling

Avoid GDBusProxy, instead use GDBusConnection directly. I very much
prefer this because that way we have explicit control over what happens
on D-Bus. With GDBusProxy this is hidden under another layer of complex
code. The hardest part when using a D-Bus interface is to manage the
state via an asynchronous medium. GDBusProxy contains state about the
D-Bus interface and duplicate the state that we track. This makes it hard
to reason about things.

Rework creation of NMSupplicantInterface. Previously, a NMSupplicantInterface
had multiple initialization states. In particular, the first state would not
yet tie the interface to a certain D-Bus object path. Instead, NMSupplicantInterface
would try and retry to create the D-Bus object.
Now, NMSupplicantManager has an asynchronous method to create interface
instances. The manager only creates an interface instance after the D-Bus
path is known. That means, a NMSupplicantInterface instance is now
strongly tied to a name-owner and D-Bus path.

It follows that the state of NMSupplicantInterface can only go from STARTING,
via the supplicant states, to DOWN. Never back. That was already previously
the case that the state from DOWN was final and once the 3 initial
states were passed, the interface's state would never go back to the initial
state. Now this is more strict and more formalized. The 3 initialization states
are combined.

I think the tighter state handling simplifies users of NMSupplicantInterface.
See for example "nm-device-ethernet.c". It's still complicated, because handling
state is fundamentally difficult.

NMSupplicantManager will take care to D-Bus activate wpa_supplicant only
when necessary (poke). Previously, creating the manager instance
would always start suppliant service. Now, it's started on demand.
This commit is contained in:
Thomas Haller 2020-01-21 15:05:16 +01:00
parent 0586e9700d
commit b83f07916a
14 changed files with 4228 additions and 2944 deletions

View file

@ -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 *
@ -615,19 +620,87 @@ build_supplicant_config (NMDeviceEthernet *self,
return config;
}
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);
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;
wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
return;
}
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 FALSE;
}
static gboolean
supplicant_interface_init (NMDeviceEthernet *self)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
guint timeout;
supplicant_interface_release (self);
priv->supplicant.iface = nm_supplicant_manager_create_interface (priv->supplicant.mgr,
nm_device_get_iface (NM_DEVICE (self)),
NM_SUPPLICANT_DRIVER_WIRED);
if (!priv->supplicant.iface) {
_LOGE (LOGD_DEVICE | LOGD_ETHER,
"Couldn't initialize supplicant interface");
return FALSE;
return G_SOURCE_REMOVE;
}
/* Listen for its state signals */
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 void
supplicant_interface_create_cb (NMSupplicantManager *supplicant_manager,
NMSupplMgrCreateIfaceHandle *handle,
NMSupplicantInterface *iface,
GError *error,
gpointer user_data)
{
NMDeviceEthernet *self;
NMDeviceEthernetPrivate *priv;
guint timeout;
if (nm_utils_error_is_cancelled (error))
return;
self = user_data;
priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
nm_assert (priv->supplicant.create_handle == handle);
priv->supplicant.create_handle = NULL;
if (error) {
_LOGE (LOGD_DEVICE | LOGD_ETHER,
"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;
}
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

View file

@ -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);
@ -264,21 +271,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,
@ -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);
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:
;
nm_device_state_changed (NM_DEVICE (self),
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
return;
}
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 FALSE;
}
static gboolean
supplicant_interface_init (NMDeviceMacsec *self)
{
NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
NMDevice *parent;
guint timeout;
parent = nm_device_parent_get_device (NM_DEVICE (self));
g_return_val_if_fail (parent, FALSE);
supplicant_interface_release (self);
priv->supplicant.iface = nm_supplicant_manager_create_interface (priv->supplicant.mgr,
nm_device_get_iface (parent),
NM_SUPPLICANT_DRIVER_MACSEC);
if (!priv->supplicant.iface) {
_LOGE (LOGD_DEVICE,
"Couldn't initialize supplicant interface");
return FALSE;
return G_SOURCE_REMOVE;
}
/* Listen for its state signals */
_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 void
supplicant_interface_create_cb (NMSupplicantManager *supplicant_manager,
NMSupplMgrCreateIfaceHandle *handle,
NMSupplicantInterface *iface,
GError *error,
gpointer user_data)
{
NMDeviceMacsec *self;
NMDeviceMacsecPrivate *priv;
guint timeout;
if (nm_utils_error_is_cancelled (error))
return;
self = user_data;
priv = NM_DEVICE_MACSEC_GET_PRIVATE (self);
nm_assert (priv->supplicant.create_handle == handle);
priv->supplicant.create_handle = NULL;
if (error) {
_LOGE (LOGD_DEVICE,
"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;
}
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

View file

@ -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-setting-connection.h"
#include "nm-setting-wireless.h"
#include "nm-setting-wireless-security.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-security.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;
ssid = g_bytes_new (name, NM_MIN (32u, strlen (name)));
bss_path = nm_ref_string_new (path);
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"));
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));
rsn = vardict_from_network_type (type);
if (rsn)
g_variant_builder_add (&builder, "{sv}", "RSN", rsn);
ap = nm_wifi_ap_new_from_properties (&bss_info);
props = g_variant_new ("a{sv}", &builder);
ap = nm_wifi_ap_new_from_properties (path, props);
nm_wifi_ap_set_ssid_arr (ap,
(const guint8 *) name,
NM_MIN (32, strlen (name)));
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)

View file

@ -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-ip4-config.h"
#include "platform/nm-platform.h"
#include "nm-manager.h"
#include "nm-core-internal.h"
#include "nm-glib-aux/nm-ref-string.h"
#include "nm-ip4-config.h"
#include "nm-manager.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");
nm_device_queue_recheck_available (device,
NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY)
_set_is_waiting_for_supplicant (self, FALSE);
break;
case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
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);
break;
default:
break;
return;
}
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);
_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))
@ -754,6 +724,24 @@ check_group_iface_ready (NMDeviceWifiP2P *self)
nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (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,
@ -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),
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_PEER_REMOVED,
G_CALLBACK (supplicant_iface_peer_removed_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

View file

@ -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;
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
g_return_if_fail (self != NULL);
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,42 +1649,12 @@ 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)
{
@ -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");

View file

@ -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;
NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
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;
NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
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;
NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
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);
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;
NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap);
g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE);
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);
nm_assert ( !priv->supplicant_path
|| priv->supplicant_path == bss_info->bss_path);
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;
changed |= nm_wifi_ap_set_ssid_arr (ap, bytes, len);
g_variant_unref (v);
}
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);
}
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));
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 (max_rate)
changed |= nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000);
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);
}
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);
}
if (!priv->supplicant_path) {
priv->supplicant_path = g_strdup (supplicant_path);
priv->supplicant_path = nm_ref_string_ref (bss_info->bss_path);
changed = TRUE;
}
changed |= nm_wifi_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_sec ());
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);
if (bss_info->bssid_valid)
changed |= nm_wifi_ap_set_address_bin (ap, bss_info->bssid);
else {
/* we don't actually clear the value. */
}
changed |= nm_wifi_ap_set_max_bitrate (ap, bss_info->max_rate);
if (priv->metered != bss_info->metered) {
priv->metered = bss_info->metered;
changed = TRUE;
}
changed |= nm_wifi_ap_set_wpa_flags (ap, bss_info->wpa_flags);
changed |= nm_wifi_ap_set_rsn_flags (ap, bss_info->rsn_flags);
changed |= nm_wifi_ap_set_last_seen (ap, bss_info->last_seen_msec);
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);

View file

@ -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);

View file

@ -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);
nm_assert ( !priv->supplicant_path
|| priv->supplicant_path == peer_info->peer_path);
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);
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);
}
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);

View file

@ -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);

File diff suppressed because it is too large Load diff

View file

@ -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);
void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self,
gboolean available);
NMRefString *nm_supplicant_interface_get_name_owner (NMSupplicantInterface *self);
NMRefString *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface);
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);

File diff suppressed because it is too large Load diff

View file

@ -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__ */

View file

@ -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 */