supplicant: collapse supplicant interface states

We only really need one state for the supplicant interface which
simplifies handling in the Wifi and Wired device classes quite a
bit.  It also simplifies the supplicant interface class too.

One behavioral change in the device classes is not running the
supplicant interface state changes from an idle; we'll have to
see if that causes problems.  ISTR long ago that processing the
state change signals directly caused some issues, but we've
significantly reworked somethings since then so we may be able
to get away with this now.
This commit is contained in:
Dan Williams 2010-10-06 11:05:21 -05:00
parent 4d63f08403
commit f3a1366b55
6 changed files with 470 additions and 1067 deletions

View file

@ -78,30 +78,17 @@ typedef enum
#define NM_ETHERNET_ERROR (nm_ethernet_error_quark ())
#define NM_TYPE_ETHERNET_ERROR (nm_ethernet_error_get_type ())
typedef struct SupplicantStateTask {
NMDeviceEthernet *self;
guint32 new_state;
guint32 old_state;
gboolean mgr_task;
guint source_id;
} SupplicantStateTask;
typedef struct Supplicant {
NMSupplicantManager *mgr;
NMSupplicantInterface *iface;
/* signal handler ids */
guint mgr_state_id;
guint iface_error_id;
guint iface_state_id;
guint iface_con_state_id;
/* Timeouts and idles */
guint iface_con_error_cb_id;
guint con_timeout_id;
GSList *iface_tasks;
GSList *mgr_tasks;
} Supplicant;
typedef struct {
@ -996,30 +983,6 @@ remove_supplicant_timeouts (NMDeviceEthernet *self)
}
}
static void
finish_supplicant_task (SupplicantStateTask *task, gboolean remove_source)
{
NMDeviceEthernet *self = task->self;
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
/* idle/timeout handlers should pass FALSE for remove_source, since they
* will tell glib to remove their source from the mainloop by returning
* FALSE when they exit. When called from this NMDevice's dispose handler,
* remove_source should be TRUE to cancel all outstanding idle/timeout
* handlers asynchronously.
*/
if (task->source_id && remove_source)
g_source_remove (task->source_id);
if (task->mgr_task)
priv->supplicant.mgr_tasks = g_slist_remove (priv->supplicant.mgr_tasks, task);
else
priv->supplicant.iface_tasks = g_slist_remove (priv->supplicant.iface_tasks, task);
memset (task, 0, sizeof (SupplicantStateTask));
g_slice_free (SupplicantStateTask, task);
}
static void
remove_supplicant_interface_error_handler (NMDeviceEthernet *self)
{
@ -1044,28 +1007,14 @@ supplicant_interface_release (NMDeviceEthernet *self)
remove_supplicant_timeouts (self);
remove_supplicant_interface_error_handler (self);
/* Clean up all pending supplicant interface state idle tasks */
while (priv->supplicant.iface_tasks)
finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.iface_tasks->data, TRUE);
if (priv->supplicant.iface_con_state_id) {
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_con_state_id);
priv->supplicant.iface_con_state_id = 0;
}
if (priv->supplicant.iface_state_id > 0) {
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_state_id);
priv->supplicant.iface_state_id = 0;
}
if (priv->supplicant.mgr_state_id) {
g_signal_handler_disconnect (priv->supplicant.mgr, priv->supplicant.mgr_state_id);
priv->supplicant.mgr_state_id = 0;
}
if (priv->supplicant.iface) {
nm_supplicant_interface_disconnect (priv->supplicant.iface);
nm_supplicant_manager_release_iface (priv->supplicant.mgr, priv->supplicant.iface);
nm_supplicant_manager_iface_release (priv->supplicant.mgr, priv->supplicant.iface);
priv->supplicant.iface = NULL;
}
}
@ -1127,77 +1076,6 @@ time_out:
return FALSE;
}
static gboolean
schedule_state_handler (NMDeviceEthernet *self,
GSourceFunc handler,
guint32 new_state,
guint32 old_state,
gboolean mgr_task)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
SupplicantStateTask *task;
if (new_state == old_state)
return TRUE;
task = g_slice_new0 (SupplicantStateTask);
if (!task) {
nm_log_err (LOGD_DEVICE, "Not enough memory to process supplicant manager state change.");
return FALSE;
}
task->self = self;
task->new_state = new_state;
task->old_state = old_state;
task->mgr_task = mgr_task;
task->source_id = g_idle_add (handler, task);
if (mgr_task)
priv->supplicant.mgr_tasks = g_slist_append (priv->supplicant.mgr_tasks, task);
else
priv->supplicant.iface_tasks = g_slist_append (priv->supplicant.iface_tasks, task);
return TRUE;
}
static gboolean
supplicant_mgr_state_cb_handler (gpointer user_data)
{
SupplicantStateTask *task = (SupplicantStateTask *) user_data;
NMDevice *device = NM_DEVICE (task->self);
/* If the supplicant went away, release the supplicant interface */
if (task->new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) {
supplicant_interface_release (task->self);
if (nm_device_get_state (device) > NM_DEVICE_STATE_UNAVAILABLE) {
nm_device_state_changed (device, NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
}
}
finish_supplicant_task (task, FALSE);
return FALSE;
}
static void
supplicant_mgr_state_cb (NMSupplicantInterface * iface,
guint32 new_state,
guint32 old_state,
gpointer user_data)
{
nm_log_info (LOGD_DEVICE | LOGD_ETHER,
"(%s): supplicant manager state: %s -> %s",
nm_device_get_iface (NM_DEVICE (user_data)),
nm_supplicant_manager_state_to_string (old_state),
nm_supplicant_manager_state_to_string (new_state));
schedule_state_handler (NM_DEVICE_ETHERNET (user_data),
supplicant_mgr_state_cb_handler,
new_state,
old_state,
TRUE);
}
static NMSupplicantConfig *
build_supplicant_config (NMDeviceEthernet *self)
{
@ -1224,20 +1102,33 @@ build_supplicant_config (NMDeviceEthernet *self)
return config;
}
static gboolean
supplicant_iface_state_cb_handler (gpointer user_data)
static void
supplicant_iface_state_cb (NMSupplicantInterface *iface,
guint32 new_state,
guint32 old_state,
gpointer user_data)
{
SupplicantStateTask *task = (SupplicantStateTask *) user_data;
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (task->self);
NMDevice *device = NM_DEVICE (task->self);
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
NMDevice *device = NM_DEVICE (self);
NMSupplicantConfig *config;
gboolean success = FALSE;
NMDeviceState devstate;
if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) {
NMSupplicantConfig *config;
const char *iface;
gboolean success = FALSE;
if (new_state == old_state)
return;
iface = nm_device_get_iface (device);
config = build_supplicant_config (task->self);
nm_log_info (LOGD_DEVICE | LOGD_ETHER,
"(%s): supplicant interface state: %s -> %s",
nm_device_get_iface (device),
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);
if (config) {
success = nm_supplicant_interface_set_config (priv->supplicant.iface, config);
g_object_unref (config);
@ -1246,99 +1137,54 @@ supplicant_iface_state_cb_handler (gpointer user_data)
nm_log_err (LOGD_DEVICE | LOGD_ETHER,
"Activation (%s/wired): couldn't send security "
"configuration to the supplicant.",
iface);
nm_device_get_iface (device));
}
} else {
nm_log_warn (LOGD_DEVICE | LOGD_ETHER,
"Activation (%s/wired): couldn't build security configuration.",
iface);
nm_device_get_iface (device));
}
if (!success)
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
} else if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
NMDeviceState state = nm_device_get_state (device);
supplicant_interface_release (task->self);
if (nm_device_is_activating (device) || state == NM_DEVICE_STATE_ACTIVATED)
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
}
finish_supplicant_task (task, FALSE);
return FALSE;
}
static void
supplicant_iface_state_cb (NMSupplicantInterface * iface,
guint32 new_state,
guint32 old_state,
gpointer user_data)
{
nm_log_info (LOGD_DEVICE | LOGD_ETHER,
"(%s): supplicant interface state: %s -> %s",
nm_device_get_iface (NM_DEVICE (user_data)),
nm_supplicant_interface_state_to_string (old_state),
nm_supplicant_interface_state_to_string (new_state));
schedule_state_handler (NM_DEVICE_ETHERNET (user_data),
supplicant_iface_state_cb_handler,
new_state,
old_state,
FALSE);
}
static gboolean
supplicant_iface_connection_state_cb_handler (gpointer user_data)
{
SupplicantStateTask *task = (SupplicantStateTask *) user_data;
NMDevice *dev = NM_DEVICE (task->self);
if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED) {
remove_supplicant_interface_error_handler (task->self);
remove_supplicant_timeouts (task->self);
if (!success) {
nm_device_state_changed (device,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED);
}
break;
case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
remove_supplicant_interface_error_handler (self);
remove_supplicant_timeouts (self);
/* If this is the initial association during device activation,
* schedule the next activation stage.
*/
if (nm_device_get_state (dev) == NM_DEVICE_STATE_CONFIG) {
if (devstate == NM_DEVICE_STATE_CONFIG) {
nm_log_info (LOGD_DEVICE | LOGD_ETHER,
"Activation (%s/wired) Stage 2 of 5 (Device Configure) successful.",
nm_device_get_iface (dev));
nm_device_activate_schedule_stage3_ip_config_start (dev);
nm_device_get_iface (device));
nm_device_activate_schedule_stage3_ip_config_start (device);
}
} else if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED) {
if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED || nm_device_is_activating (dev)) {
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (task->self);
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, dev);
priv->supplicant_timeout_id = g_timeout_add_seconds (15, link_timeout_cb, device);
}
break;
case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
supplicant_interface_release (self);
remove_supplicant_timeouts (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:
break;
}
finish_supplicant_task (task, FALSE);
return FALSE;
}
static void
supplicant_iface_connection_state_cb (NMSupplicantInterface * iface,
guint32 new_state,
guint32 old_state,
gpointer user_data)
{
nm_log_info (LOGD_DEVICE | LOGD_ETHER,
"(%s) supplicant connection state: %s -> %s",
nm_device_get_iface (NM_DEVICE (user_data)),
nm_supplicant_interface_connection_state_to_string (old_state),
nm_supplicant_interface_connection_state_to_string (new_state));
schedule_state_handler (NM_DEVICE_ETHERNET (user_data),
supplicant_iface_connection_state_cb_handler,
new_state,
old_state,
FALSE);
}
static gboolean
@ -1456,38 +1302,26 @@ supplicant_interface_init (NMDeviceEthernet *self)
iface = nm_device_get_iface (NM_DEVICE (self));
/* Create supplicant interface */
priv->supplicant.iface = nm_supplicant_manager_get_iface (priv->supplicant.mgr, iface, FALSE);
priv->supplicant.iface = nm_supplicant_manager_iface_get (priv->supplicant.mgr, iface, FALSE);
if (!priv->supplicant.iface) {
nm_log_err (LOGD_DEVICE | LOGD_ETHER,
"Couldn't initialize supplicant interface for %s.",
iface);
supplicant_interface_release (self);
return FALSE;
}
/* Listen for it's state signals */
priv->supplicant.iface_state_id = g_signal_connect (priv->supplicant.iface,
"state",
G_CALLBACK (supplicant_iface_state_cb),
self);
"state",
G_CALLBACK (supplicant_iface_state_cb),
self);
/* Hook up error signal handler to capture association errors */
priv->supplicant.iface_error_id = g_signal_connect (priv->supplicant.iface,
"connection-error",
G_CALLBACK (supplicant_iface_connection_error_cb),
self);
priv->supplicant.iface_con_state_id = g_signal_connect (priv->supplicant.iface,
"connection-state",
G_CALLBACK (supplicant_iface_connection_state_cb),
self);
/* Listen for supplicant manager state changes */
priv->supplicant.mgr_state_id = g_signal_connect (priv->supplicant.mgr,
"state",
G_CALLBACK (supplicant_mgr_state_cb),
self);
"connection-error",
G_CALLBACK (supplicant_iface_connection_error_cb),
self);
/* Set up a timeout on the connection attempt to fail it after 25 seconds */
priv->supplicant.con_timeout_id = g_timeout_add_seconds (25, supplicant_connection_timeout_cb, self);
@ -2047,12 +1881,6 @@ dispose (GObject *object)
priv->disposed = TRUE;
/* Clean up all pending supplicant tasks */
while (priv->supplicant.iface_tasks)
finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.iface_tasks->data, TRUE);
while (priv->supplicant.mgr_tasks)
finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.mgr_tasks->data, TRUE);
if (priv->link_connected_id) {
g_signal_handler_disconnect (priv->monitor, priv->link_connected_id);
priv->link_connected_id = 0;

View file

@ -113,34 +113,21 @@ typedef enum {
#define NM_WIFI_ERROR (nm_wifi_error_quark ())
#define NM_TYPE_WIFI_ERROR (nm_wifi_error_get_type ())
typedef struct SupplicantStateTask {
NMDeviceWifi *self;
guint32 new_state;
guint32 old_state;
gboolean mgr_task;
guint source_id;
} SupplicantStateTask;
typedef struct Supplicant {
NMSupplicantManager *mgr;
NMSupplicantInterface *iface;
/* signal handler ids */
guint mgr_state_id;
guint iface_error_id;
guint iface_state_id;
guint iface_scanned_ap_id;
guint iface_scan_request_result_id;
guint iface_scan_results_id;
guint iface_con_state_id;
guint iface_notify_scanning_id;
/* Timeouts and idles */
guint iface_con_error_cb_id;
guint con_timeout_id;
GSList *mgr_tasks;
GSList *iface_tasks;
} Supplicant;
struct _NMDeviceWifiPrivate {
@ -199,15 +186,10 @@ static void cleanup_association_attempt (NMDeviceWifi * self,
static void remove_supplicant_timeouts (NMDeviceWifi *self);
static void supplicant_iface_state_cb (NMSupplicantInterface * iface,
static void supplicant_iface_state_cb (NMSupplicantInterface *iface,
guint32 new_state,
guint32 old_state,
NMDeviceWifi *self);
static void supplicant_iface_connection_state_cb (NMSupplicantInterface * iface,
guint32 new_state,
guint32 old_state,
NMDeviceWifi *self);
gpointer user_data);
static void supplicant_iface_scanned_ap_cb (NMSupplicantInterface * iface,
GHashTable *properties,
@ -221,11 +203,6 @@ static void supplicant_iface_scan_results_cb (NMSupplicantInterface * iface,
guint32 num_bssids,
NMDeviceWifi * self);
static void supplicant_mgr_state_cb (NMSupplicantInterface * iface,
guint32 new_state,
guint32 old_state,
NMDeviceWifi *self);
static void supplicant_iface_notify_scanning_cb (NMSupplicantInterface * iface,
GParamSpec * pspec,
NMDeviceWifi * self);
@ -625,10 +602,7 @@ constructor (GType type,
/* Connect to the supplicant manager */
priv->supplicant.mgr = nm_supplicant_manager_get ();
priv->supplicant.mgr_state_id = g_signal_connect (priv->supplicant.mgr,
"state",
G_CALLBACK (supplicant_mgr_state_cb),
self);
g_assert (priv->supplicant.mgr);
/* The ipw2x00 drivers don't integrate with the kernel rfkill subsystem until
* 2.6.33. Thus all our nice libgudev magic is useless. So we get to poll.
@ -657,17 +631,13 @@ static gboolean
supplicant_interface_acquire (NMDeviceWifi *self)
{
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
guint id, mgr_state;
guint id;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (priv->supplicant.mgr != NULL, FALSE);
/* interface already acquired? */
g_return_val_if_fail (priv->supplicant.iface == NULL, TRUE);
mgr_state = nm_supplicant_manager_get_state (priv->supplicant.mgr);
g_return_val_if_fail (mgr_state == NM_SUPPLICANT_MANAGER_STATE_IDLE, FALSE);
priv->supplicant.iface = nm_supplicant_manager_get_iface (priv->supplicant.mgr,
priv->supplicant.iface = nm_supplicant_manager_iface_get (priv->supplicant.mgr,
nm_device_get_iface (NM_DEVICE (self)),
TRUE);
if (priv->supplicant.iface == NULL) {
@ -700,12 +670,6 @@ supplicant_interface_acquire (NMDeviceWifi *self)
self);
priv->supplicant.iface_scan_results_id = id;
id = g_signal_connect (priv->supplicant.iface,
"connection-state",
G_CALLBACK (supplicant_iface_connection_state_cb),
self);
priv->supplicant.iface_con_state_id = id;
id = g_signal_connect (priv->supplicant.iface,
"notify::scanning",
G_CALLBACK (supplicant_iface_notify_scanning_cb),
@ -715,30 +679,6 @@ supplicant_interface_acquire (NMDeviceWifi *self)
return TRUE;
}
static void
finish_supplicant_task (SupplicantStateTask *task, gboolean remove_source)
{
NMDeviceWifi *self = task->self;
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
/* idle/timeout handlers should pass FALSE for remove_source, since they
* will tell glib to remove their source from the mainloop by returning
* FALSE when they exit. When called from this NMDevice's dispose handler,
* remove_source should be TRUE to cancel all outstanding idle/timeout
* handlers asynchronously.
*/
if (task->source_id && remove_source)
g_source_remove (task->source_id);
if (task->mgr_task)
priv->supplicant.mgr_tasks = g_slist_remove (priv->supplicant.mgr_tasks, task);
else
priv->supplicant.iface_tasks = g_slist_remove (priv->supplicant.iface_tasks, task);
memset (task, 0, sizeof (SupplicantStateTask));
g_slice_free (SupplicantStateTask, task);
}
static void
remove_supplicant_interface_error_handler (NMDeviceWifi *self)
{
@ -776,10 +716,6 @@ supplicant_interface_release (NMDeviceWifi *self)
remove_supplicant_interface_error_handler (self);
/* Clean up all pending supplicant interface state idle tasks */
while (priv->supplicant.iface_tasks)
finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.iface_tasks->data, TRUE);
if (priv->supplicant.iface_state_id > 0) {
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_state_id);
priv->supplicant.iface_state_id = 0;
@ -800,11 +736,6 @@ supplicant_interface_release (NMDeviceWifi *self)
priv->supplicant.iface_scan_results_id = 0;
}
if (priv->supplicant.iface_con_state_id > 0) {
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_con_state_id);
priv->supplicant.iface_con_state_id = 0;
}
if (priv->supplicant.iface_notify_scanning_id > 0) {
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_notify_scanning_id);
priv->supplicant.iface_notify_scanning_id = 0;
@ -814,7 +745,7 @@ supplicant_interface_release (NMDeviceWifi *self)
/* Tell the supplicant to disconnect from the current AP */
nm_supplicant_interface_disconnect (priv->supplicant.iface);
nm_supplicant_manager_release_iface (priv->supplicant.mgr, priv->supplicant.iface);
nm_supplicant_manager_iface_release (priv->supplicant.mgr, priv->supplicant.iface);
priv->supplicant.iface = NULL;
}
}
@ -1837,11 +1768,11 @@ scanning_allowed (NMDeviceWifi *self)
}
/* Don't scan if the supplicant is busy */
sup_state = nm_supplicant_interface_get_connection_state (priv->supplicant.iface);
if ( sup_state == NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATING
|| sup_state == NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATED
|| sup_state == NM_SUPPLICANT_INTERFACE_CON_STATE_4WAY_HANDSHAKE
|| sup_state == NM_SUPPLICANT_INTERFACE_CON_STATE_GROUP_HANDSHAKE
sup_state = nm_supplicant_interface_get_state (priv->supplicant.iface);
if ( sup_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING
|| sup_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED
|| sup_state == NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE
|| sup_state == NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE
|| nm_supplicant_interface_get_scanning (priv->supplicant.iface))
return FALSE;
@ -2441,253 +2372,97 @@ time_out:
return FALSE;
}
static gboolean
schedule_state_handler (NMDeviceWifi *self,
GSourceFunc handler,
guint32 new_state,
guint32 old_state,
gboolean mgr_task)
static void
supplicant_iface_state_cb (NMSupplicantInterface *iface,
guint32 new_state,
guint32 old_state,
gpointer user_data)
{
NMDeviceWifiPrivate *priv;
SupplicantStateTask *task;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (handler != NULL, FALSE);
NMDeviceWifi *self = NM_DEVICE_WIFI (user_data);
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
NMDevice *device = NM_DEVICE (self);
NMDeviceState devstate;
gboolean scanning;
if (new_state == old_state)
return TRUE;
return;
priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
nm_log_info (LOGD_DEVICE | LOGD_WIFI,
"(%s): supplicant interface state: %s -> %s",
nm_device_get_iface (device),
nm_supplicant_interface_state_to_string (old_state),
nm_supplicant_interface_state_to_string (new_state));
task = g_slice_new0 (SupplicantStateTask);
if (!task) {
nm_log_err (LOGD_WIFI, "Not enough memory to process supplicant manager state change.");
return FALSE;
}
devstate = nm_device_get_state (device);
scanning = nm_supplicant_interface_get_scanning (iface);
task->self = self;
task->new_state = new_state;
task->old_state = old_state;
task->mgr_task = mgr_task;
task->source_id = g_idle_add (handler, task);
if (mgr_task)
priv->supplicant.mgr_tasks = g_slist_append (priv->supplicant.mgr_tasks, task);
else
priv->supplicant.iface_tasks = g_slist_append (priv->supplicant.iface_tasks, task);
return TRUE;
}
static gboolean
supplicant_iface_state_cb_handler (gpointer user_data)
{
SupplicantStateTask *task = (SupplicantStateTask *) user_data;
NMDeviceWifi *self;
NMDeviceWifiPrivate *priv;
g_return_val_if_fail (task != NULL, FALSE);
self = task->self;
priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
nm_log_info (LOGD_WIFI, "(%s): supplicant interface state: %s -> %s",
nm_device_get_iface (NM_DEVICE (self)),
nm_supplicant_interface_state_to_string (task->old_state),
nm_supplicant_interface_state_to_string (task->new_state));
if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) {
switch (new_state) {
case NM_SUPPLICANT_INTERFACE_STATE_READY:
priv->scan_interval = SCAN_INTERVAL_MIN;
/* If the interface can now be activated because the supplicant is now
* available, transition to DISCONNECTED.
*/
if ( (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_UNAVAILABLE)
&& nm_device_is_available (NM_DEVICE (self))) {
nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED,
if ((devstate == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device)) {
nm_device_state_changed (device,
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE);
}
nm_log_dbg (LOGD_WIFI_SCAN, "(%s): supplicant ready, requesting initial scan",
nm_device_get_iface (NM_DEVICE (self)));
nm_log_dbg (LOGD_WIFI_SCAN,
"(%s): supplicant ready, requesting initial scan",
nm_device_get_iface (device));
/* Request a scan to get latest results */
cancel_pending_scan (self);
request_wireless_scan (self);
} else if (task->new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
cleanup_association_attempt (self, FALSE);
supplicant_interface_release (self);
nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
}
finish_supplicant_task (task, FALSE);
return FALSE;
}
static void
supplicant_iface_state_cb (NMSupplicantInterface * iface,
guint32 new_state,
guint32 old_state,
NMDeviceWifi *self)
{
g_return_if_fail (self != NULL);
schedule_state_handler (self,
supplicant_iface_state_cb_handler,
new_state,
old_state,
FALSE);
}
static gboolean
supplicant_iface_connection_state_cb_handler (gpointer user_data)
{
SupplicantStateTask *task = (SupplicantStateTask *) user_data;
NMDeviceWifi *self = task->self;
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
NMDevice *dev = NM_DEVICE (self);
gboolean scanning;
if (!nm_device_get_act_request (dev)) {
/* The device is not activating or already activated; do nothing. */
goto out;
}
nm_log_info (LOGD_WIFI, "(%s): supplicant connection state: %s -> %s",
nm_device_get_iface (dev),
nm_supplicant_interface_connection_state_to_string (task->old_state),
nm_supplicant_interface_connection_state_to_string (task->new_state));
scanning = nm_supplicant_interface_get_scanning (priv->supplicant.iface);
if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED) {
break;
case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
remove_supplicant_interface_error_handler (self);
remove_supplicant_timeouts (self);
/* If this is the initial association during device activation,
* schedule the next activation stage.
*/
if (nm_device_get_state (dev) == NM_DEVICE_STATE_CONFIG) {
if (devstate == NM_DEVICE_STATE_CONFIG) {
NMAccessPoint *ap = nm_device_wifi_get_activation_ap (self);
const GByteArray * ssid = nm_ap_get_ssid (ap);
const GByteArray *ssid = nm_ap_get_ssid (ap);
nm_log_info (LOGD_DEVICE | LOGD_WIFI,
"Activation (%s/wireless) Stage 2 of 5 (Device Configure) "
"successful. Connected to wireless network '%s'.",
nm_device_get_iface (dev),
nm_device_get_iface (device),
ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)");
nm_device_activate_schedule_stage3_ip_config_start (dev);
nm_device_activate_schedule_stage3_ip_config_start (device);
}
} else if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED) {
if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED || nm_device_is_activating (dev)) {
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,
* use a longer timeout if we are scanning since some cards take a
* while to scan.
*/
if (!priv->link_timeout_id) {
priv->link_timeout_id = g_timeout_add_seconds (scanning ? 30 : 15,
link_timeout_cb, self);
link_timeout_cb, self);
}
}
break;
case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
cleanup_association_attempt (self, FALSE);
supplicant_interface_release (self);
nm_device_state_changed (device,
NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
break;
default:
break;
}
out:
/* Signal scanning state changes */
if ( task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING
|| task->old_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING)
if ( new_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING
|| old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
g_object_notify (G_OBJECT (self), "scanning");
finish_supplicant_task (task, FALSE);
return FALSE;
}
static void
supplicant_iface_connection_state_cb (NMSupplicantInterface * iface,
guint32 new_state,
guint32 old_state,
NMDeviceWifi *self)
{
g_return_if_fail (self != NULL);
schedule_state_handler (self,
supplicant_iface_connection_state_cb_handler,
new_state,
old_state,
FALSE);
}
static gboolean
supplicant_mgr_state_cb_handler (gpointer user_data)
{
SupplicantStateTask *task = (SupplicantStateTask *) user_data;
NMDeviceWifi *self;
NMDeviceWifiPrivate *priv;
NMDevice *dev;
NMDeviceState dev_state;
g_return_val_if_fail (task != NULL, FALSE);
self = task->self;
priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
dev = NM_DEVICE (self);
nm_log_info (LOGD_WIFI, "(%s): supplicant manager state: %s -> %s",
nm_device_get_iface (NM_DEVICE (self)),
nm_supplicant_manager_state_to_string (task->old_state),
nm_supplicant_manager_state_to_string (task->new_state));
/* If the supplicant went away, release the supplicant interface */
if (task->new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) {
if (priv->supplicant.iface) {
cleanup_association_attempt (self, FALSE);
supplicant_interface_release (self);
}
if (nm_device_get_state (dev) > NM_DEVICE_STATE_UNAVAILABLE) {
nm_device_state_changed (dev, NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
}
} else if (task->new_state == NM_SUPPLICANT_MANAGER_STATE_IDLE) {
dev_state = nm_device_get_state (dev);
if ( priv->enabled
&& !priv->supplicant.iface
&& (dev_state >= NM_DEVICE_STATE_UNAVAILABLE)
&& (nm_device_get_firmware_missing (NM_DEVICE (self)) == FALSE)) {
/* request a supplicant interface from the supplicant manager */
supplicant_interface_acquire (self);
/* if wireless is enabled and we have a supplicant interface,
* we can transition to the DISCONNECTED state.
*/
if (priv->supplicant.iface) {
nm_device_state_changed (dev, NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_NONE);
}
}
}
finish_supplicant_task (task, FALSE);
return FALSE;
}
static void
supplicant_mgr_state_cb (NMSupplicantInterface * iface,
guint32 new_state,
guint32 old_state,
NMDeviceWifi *self)
{
g_return_if_fail (self != NULL);
schedule_state_handler (self,
supplicant_mgr_state_cb_handler,
new_state,
old_state,
TRUE);
}
struct iface_con_error_cb_data {
@ -3845,20 +3620,9 @@ dispose (GObject *object)
priv->periodic_source_id = 0;
}
/* Clean up all pending supplicant tasks */
while (priv->supplicant.iface_tasks)
finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.iface_tasks->data, TRUE);
while (priv->supplicant.mgr_tasks)
finish_supplicant_task ((SupplicantStateTask *) priv->supplicant.mgr_tasks->data, TRUE);
cleanup_association_attempt (self, TRUE);
supplicant_interface_release (self);
if (priv->supplicant.mgr_state_id) {
g_signal_handler_disconnect (priv->supplicant.mgr, priv->supplicant.mgr_state_id);
priv->supplicant.mgr_state_id = 0;
}
if (priv->supplicant.mgr) {
g_object_unref (priv->supplicant.mgr);
priv->supplicant.mgr = NULL;

View file

@ -47,15 +47,6 @@ G_DEFINE_TYPE (NMSupplicantInterface, nm_supplicant_interface, G_TYPE_OBJECT)
NM_TYPE_SUPPLICANT_INTERFACE, \
NMSupplicantInterfacePrivate))
static void nm_supplicant_interface_start (NMSupplicantInterface *self);
static void nm_supplicant_interface_add_to_supplicant (NMSupplicantInterface *self,
gboolean get_only);
static void nm_supplicant_interface_set_state (NMSupplicantInterface *self,
guint32 new_state);
/* Signals */
enum {
STATE, /* change in the interface's state */
@ -63,7 +54,6 @@ enum {
SCANNED_AP, /* interface saw a new access point from a scan */
SCAN_REQ_RESULT, /* result of a wireless scan request */
SCAN_RESULTS, /* scan results returned from supplicant */
CONNECTION_STATE, /* link state of the device's connection */
CONNECTION_ERROR, /* an error occurred during a connection request */
LAST_SIGNAL
};
@ -74,16 +64,14 @@ static guint signals[LAST_SIGNAL] = { 0 };
enum {
PROP_0 = 0,
PROP_STATE,
PROP_CONNECTION_STATE,
PROP_SCANNING,
LAST_PROP
};
typedef struct
{
typedef struct {
NMSupplicantManager * smgr;
gulong smgr_state_sig_handler;
gulong smgr_running_id;
NMDBusManager * dbus_mgr;
char * dev;
gboolean is_wireless;
@ -93,9 +81,9 @@ typedef struct
NMCallStore * assoc_pcalls;
NMCallStore * other_pcalls;
guint32 con_state;
gboolean scanning;
DBusGProxy * wpas_proxy;
DBusGProxy * iface_proxy;
DBusGProxy * net_proxy;
@ -186,28 +174,6 @@ nm_supplicant_info_destroy (gpointer user_data)
}
}
static void
try_remove_iface (DBusGConnection *g_connection,
const char *path)
{
DBusGProxy *proxy;
g_return_if_fail (g_connection != NULL);
g_return_if_fail (path != NULL);
proxy = dbus_g_proxy_new_for_name (g_connection,
WPAS_DBUS_SERVICE,
WPAS_DBUS_PATH,
WPAS_DBUS_INTERFACE);
if (!proxy)
return;
dbus_g_proxy_call_no_reply (proxy, "removeInterface",
DBUS_TYPE_G_OBJECT_PATH, path,
G_TYPE_INVALID);
g_object_unref (proxy);
}
static void
emit_error_helper (NMSupplicantInterface *self,
GError *err)
@ -344,50 +310,80 @@ wpas_iface_query_scan_results (DBusGProxy *proxy, gpointer user_data)
}
static guint32
wpas_state_string_to_enum (const char * str_state)
wpas_state_string_to_enum (const char *str_state)
{
guint32 enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED;
guint32 enum_state = NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED;
if (!strcmp (str_state, "DISCONNECTED"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED;
enum_state = NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED;
else if (!strcmp (str_state, "INACTIVE"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_INACTIVE;
enum_state = NM_SUPPLICANT_INTERFACE_STATE_INACTIVE;
else if (!strcmp (str_state, "SCANNING"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING;
enum_state = NM_SUPPLICANT_INTERFACE_STATE_SCANNING;
else if (!strcmp (str_state, "ASSOCIATING"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATING;
enum_state = NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING;
else if (!strcmp (str_state, "ASSOCIATED"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATED;
enum_state = NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED;
else if (!strcmp (str_state, "4WAY_HANDSHAKE"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_4WAY_HANDSHAKE;
enum_state = NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE;
else if (!strcmp (str_state, "GROUP_HANDSHAKE"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_GROUP_HANDSHAKE;
enum_state = NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE;
else if (!strcmp (str_state, "COMPLETED"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED;
enum_state = NM_SUPPLICANT_INTERFACE_STATE_COMPLETED;
return enum_state;
}
static void
set_state (NMSupplicantInterface *self, guint32 new_state)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
guint32 old_state = priv->state;
g_return_if_fail (new_state < NM_SUPPLICANT_INTERFACE_STATE_LAST);
if (new_state == priv->state)
return;
/* DOWN is a terminal state */
g_return_if_fail (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DOWN);
/* Cannot regress to READY or INIT from higher states */
if (priv->state <= NM_SUPPLICANT_INTERFACE_STATE_READY)
g_return_if_fail (new_state > priv->state);
if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
/* Cancel all pending calls when going down */
cancel_all_callbacks (priv->other_pcalls);
cancel_all_callbacks (priv->assoc_pcalls);
/* Disconnect supplicant manager state listeners since we're done */
if (priv->smgr_running_id) {
g_signal_handler_disconnect (priv->smgr, priv->smgr_running_id);
priv->smgr_running_id = 0;
}
}
priv->state = new_state;
g_signal_emit (self, signals[STATE], 0, priv->state, old_state);
}
/* Supplicant state signal handler */
static void
wpas_iface_handle_state_change (DBusGProxy *proxy,
const char *str_new_state,
const char *str_old_state,
gpointer user_data)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (user_data);
guint32 old_state, enum_new_state;
enum_new_state = wpas_state_string_to_enum (str_new_state);
old_state = priv->con_state;
priv->con_state = enum_new_state;
if (priv->con_state != old_state)
g_signal_emit (user_data, signals[CONNECTION_STATE], 0, priv->con_state, old_state);
set_state (NM_SUPPLICANT_INTERFACE (user_data),
wpas_state_string_to_enum (str_new_state));
}
/* Explicit state request reply handler */
static void
iface_state_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
{
NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
GError *err = NULL;
char *state_str = NULL;
@ -397,12 +393,8 @@ iface_state_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
nm_log_warn (LOGD_SUPPLICANT, "could not get interface state: %s.", err->message);
g_error_free (err);
} else {
NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
priv->con_state = wpas_state_string_to_enum (state_str);
set_state (info->interface, wpas_state_string_to_enum (state_str));
g_free (state_str);
nm_supplicant_interface_set_state (info->interface, NM_SUPPLICANT_INTERFACE_STATE_READY);
}
}
@ -479,225 +471,181 @@ nm_supplicant_interface_get_scanning (NMSupplicantInterface *self)
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
if (priv->scanning)
return TRUE;
if (priv->con_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING)
if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING)
return TRUE;
return FALSE;
}
static void
nm_supplicant_interface_add_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
interface_add_done (NMSupplicantInterface *self, char *path)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
nm_log_dbg (LOGD_SUPPLICANT, "(%s): interface added to supplicant", priv->dev);
priv->object_path = path;
priv->iface_proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
WPAS_DBUS_SERVICE,
path,
WPAS_DBUS_IFACE_INTERFACE);
dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_INVALID);
dbus_g_proxy_add_signal (priv->iface_proxy, "StateChange", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->iface_proxy, "StateChange",
G_CALLBACK (wpas_iface_handle_state_change),
self,
NULL);
dbus_g_proxy_add_signal (priv->iface_proxy, "ScanResultsAvailable", G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->iface_proxy, "ScanResultsAvailable",
G_CALLBACK (wpas_iface_query_scan_results),
self,
NULL);
dbus_g_proxy_add_signal (priv->iface_proxy, "Scanning", G_TYPE_BOOLEAN, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->iface_proxy, "Scanning",
G_CALLBACK (wpas_iface_handle_scanning),
self,
NULL);
/* Interface added to the supplicant; get its initial state. */
wpas_iface_get_state (self);
wpas_iface_get_scanning (self);
set_state (self, NM_SUPPLICANT_INTERFACE_STATE_READY);
}
static void
interface_get_cb (DBusGProxy *proxy,
DBusGProxyCall *call_id,
gpointer user_data)
{
NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
GError *err = NULL;
GError *error = NULL;
char *path = NULL;
if (!dbus_g_proxy_end_call (proxy, call_id, &err,
DBUS_TYPE_G_OBJECT_PATH, &path,
G_TYPE_INVALID)) {
if (dbus_g_error_has_name (err, WPAS_ERROR_INVALID_IFACE)) {
/* Interface not added, try to add it */
nm_supplicant_interface_add_to_supplicant (info->interface, FALSE);
} else if (dbus_g_error_has_name (err, WPAS_ERROR_EXISTS_ERROR)) {
/* Interface already added, just try to get the interface */
nm_supplicant_interface_add_to_supplicant (info->interface, TRUE);
} else {
nm_log_err (LOGD_SUPPLICANT, "(%s): error getting interface: %s",
priv->dev, err->message);
}
g_error_free (err);
if (dbus_g_proxy_end_call (proxy, call_id, &error,
DBUS_TYPE_G_OBJECT_PATH, &path,
G_TYPE_INVALID)) {
interface_add_done (info->interface, path);
} else {
nm_log_dbg (LOGD_SUPPLICANT, "(%s): interface added to supplicant", priv->dev);
priv->object_path = path;
priv->iface_proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
WPAS_DBUS_SERVICE,
path,
WPAS_DBUS_IFACE_INTERFACE);
dbus_g_proxy_add_signal (priv->iface_proxy, "ScanResultsAvailable", G_TYPE_INVALID);
dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING,
G_TYPE_NONE,
G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_INVALID);
dbus_g_proxy_add_signal (priv->iface_proxy, "StateChange", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->iface_proxy, "ScanResultsAvailable",
G_CALLBACK (wpas_iface_query_scan_results),
info->interface,
NULL);
dbus_g_proxy_connect_signal (priv->iface_proxy, "StateChange",
G_CALLBACK (wpas_iface_handle_state_change),
info->interface,
NULL);
dbus_g_proxy_add_signal (priv->iface_proxy, "Scanning", G_TYPE_BOOLEAN, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->iface_proxy, "Scanning",
G_CALLBACK (wpas_iface_handle_scanning),
info->interface,
NULL);
/* Interface added to the supplicant; get its initial state. */
wpas_iface_get_state (info->interface);
wpas_iface_get_scanning (info->interface);
nm_log_err (LOGD_SUPPLICANT, "(%s): error adding interface: %s",
priv->dev, error->message);
g_clear_error (&error);
}
}
static void
nm_supplicant_interface_add_to_supplicant (NMSupplicantInterface * self,
gboolean get_only)
interface_get (NMSupplicantInterface *self)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
NMSupplicantInfo *info;
DBusGProxy *proxy;
DBusGProxyCall *call;
proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
WPAS_DBUS_SERVICE,
WPAS_DBUS_PATH,
WPAS_DBUS_INTERFACE);
info = nm_supplicant_info_new (self, proxy, priv->other_pcalls);
if (get_only) {
call = dbus_g_proxy_begin_call (proxy, "getInterface",
nm_supplicant_interface_add_cb,
info,
nm_supplicant_info_destroy,
G_TYPE_STRING, priv->dev,
G_TYPE_INVALID);
} else {
GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
GValue *driver;
driver = g_new0 (GValue, 1);
g_value_init (driver, G_TYPE_STRING);
g_value_set_string (driver, priv->is_wireless ? "wext" : "wired");
g_hash_table_insert (hash, "driver", driver);
call = dbus_g_proxy_begin_call (proxy, "addInterface",
nm_supplicant_interface_add_cb,
info,
nm_supplicant_info_destroy,
G_TYPE_STRING, priv->dev,
DBUS_TYPE_G_MAP_OF_VARIANT, hash,
G_TYPE_INVALID);
g_value_unset (driver);
g_free (driver);
g_hash_table_destroy (hash);
}
g_object_unref (proxy);
info = nm_supplicant_info_new (self, priv->wpas_proxy, priv->other_pcalls);
call = dbus_g_proxy_begin_call (priv->wpas_proxy, "getInterface",
interface_get_cb,
info,
nm_supplicant_info_destroy,
G_TYPE_STRING, priv->dev,
G_TYPE_INVALID);
nm_supplicant_info_set_call (info, call);
}
static void
nm_supplicant_interface_start (NMSupplicantInterface * self)
interface_add_cb (DBusGProxy *proxy,
DBusGProxyCall *call_id,
gpointer user_data)
{
NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
GError *error = NULL;
char *path = NULL;
if (dbus_g_proxy_end_call (proxy, call_id, &error,
DBUS_TYPE_G_OBJECT_PATH, &path,
G_TYPE_INVALID)) {
interface_add_done (info->interface, path);
} else {
if (dbus_g_error_has_name (error, WPAS_ERROR_EXISTS_ERROR)) {
/* Interface already added, just get its object path */
interface_get (info->interface);
} else {
nm_log_err (LOGD_SUPPLICANT, "(%s): error adding interface: %s",
priv->dev, error->message);
}
g_clear_error (&error);
}
}
static void
interface_add (NMSupplicantInterface * self, gboolean is_wireless)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
guint32 state;
DBusGProxyCall *call;
NMSupplicantInfo *info;
GHashTable *hash;
GValue *driver;
/* Can only start the interface from INIT state */
g_return_if_fail (priv->state == NM_SUPPLICANT_INTERFACE_STATE_INIT);
nm_log_dbg (LOGD_SUPPLICANT, "(%s): adding interface to supplicant", priv->dev);
state = nm_supplicant_manager_get_state (priv->smgr);
if (state == NM_SUPPLICANT_MANAGER_STATE_IDLE) {
nm_supplicant_interface_set_state (self, NM_SUPPLICANT_INTERFACE_STATE_STARTING);
nm_supplicant_interface_add_to_supplicant (self, FALSE);
} else if (state == NM_SUPPLICANT_MANAGER_STATE_DOWN) {
/* Don't do anything; wait for signal from supplicant manager
* that its state has changed.
/* 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.
*/
info = nm_supplicant_info_new (self, priv->wpas_proxy, priv->other_pcalls);
driver = g_new0 (GValue, 1);
g_value_init (driver, G_TYPE_STRING);
g_value_set_string (driver, is_wireless ? "wext" : "wired");
hash = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (hash, "driver", driver);
call = dbus_g_proxy_begin_call (priv->wpas_proxy, "addInterface",
interface_add_cb,
info,
nm_supplicant_info_destroy,
G_TYPE_STRING, priv->dev,
DBUS_TYPE_G_MAP_OF_VARIANT, hash,
G_TYPE_INVALID);
g_hash_table_destroy (hash);
g_value_unset (driver);
g_free (driver);
nm_supplicant_info_set_call (info, call);
}
static void
smgr_running_cb (NMSupplicantManager *smgr,
GParamSpec *pspec,
gpointer user_data)
{
NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (user_data);
if (nm_supplicant_manager_running (smgr)) {
/* This can happen if the supplicant couldn't be activated but
* for some reason was started after the activation failure.
*/
} else
nm_log_warn (LOGD_SUPPLICANT, "Unknown supplicant manager state!");
}
static void
nm_supplicant_interface_handle_supplicant_manager_idle_state (NMSupplicantInterface * self)
{
switch (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->state) {
case NM_SUPPLICANT_INTERFACE_STATE_INIT:
/* Move to STARTING state when supplicant is ready */
nm_supplicant_interface_start (self);
break;
case NM_SUPPLICANT_INTERFACE_STATE_STARTING:
/* Don't do anything here, though we should never hit this */
break;
case NM_SUPPLICANT_INTERFACE_STATE_READY:
/* Don't do anything here, though we should never hit this */
break;
case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
/* Don't do anything here; interface can't get out of DOWN state */
break;
default:
nm_log_warn (LOGD_SUPPLICANT, "Unknown supplicant interface state!");
break;
if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_INIT)
interface_add (self, priv->is_wireless);
} else {
/* The supplicant stopped; so we must tear down the interface */
set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
}
}
static void
nm_supplicant_interface_set_state (NMSupplicantInterface * self,
guint32 new_state)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
guint32 old_state;
g_return_if_fail (new_state < NM_SUPPLICANT_INTERFACE_STATE_LAST);
if (new_state == priv->state)
return;
old_state = priv->state;
if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) {
/* If the interface is transitioning to DOWN and there's are
* in-progress pending calls, cancel them.
*/
cancel_all_callbacks (priv->other_pcalls);
cancel_all_callbacks (priv->assoc_pcalls);
}
priv->state = new_state;
g_signal_emit (self, signals[STATE], 0, priv->state, old_state);
}
static void
smgr_state_changed (NMSupplicantManager *smgr,
guint32 new_state,
guint32 old_state,
gpointer user_data)
{
NMSupplicantInterface * self = NM_SUPPLICANT_INTERFACE (user_data);
switch (new_state) {
case NM_SUPPLICANT_MANAGER_STATE_DOWN:
/* The supplicant went away, likely the connection to it is also
* gone. Therefore, this interface must move to the DOWN state
* and be disposed of.
*/
nm_supplicant_interface_set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
break;
case NM_SUPPLICANT_MANAGER_STATE_IDLE:
/* Handle the supplicant now being available. */
nm_supplicant_interface_handle_supplicant_manager_idle_state (self);
break;
default:
nm_log_warn (LOGD_SUPPLICANT, "Unknown supplicant manager state!");
break;
}
}
static void
remove_network_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
{
@ -742,16 +690,13 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self)
if (!priv->iface_proxy)
return;
/* Don't try to disconnect if the supplicant interface is already
* disconnected.
*/
if (priv->con_state == NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED
|| priv->con_state == NM_SUPPLICANT_INTERFACE_CON_STATE_INACTIVE) {
/* Don't try to disconnect if the supplicant interface is already disconnected */
if ( priv->state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED
|| priv->state == NM_SUPPLICANT_INTERFACE_STATE_INACTIVE) {
if (priv->net_proxy) {
g_object_unref (priv->net_proxy);
priv->net_proxy = NULL;
}
return;
}
@ -1011,14 +956,6 @@ nm_supplicant_interface_set_config (NMSupplicantInterface * self,
return call != NULL;
}
const char *
nm_supplicant_interface_get_device (NMSupplicantInterface * self)
{
g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev;
}
static void
scan_request_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
{
@ -1067,24 +1004,30 @@ nm_supplicant_interface_get_state (NMSupplicantInterface * self)
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->state;
}
guint32
nm_supplicant_interface_get_connection_state (NMSupplicantInterface * self)
{
g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED);
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->con_state;
}
const char *
nm_supplicant_interface_state_to_string (guint32 state)
{
switch (state) {
case NM_SUPPLICANT_INTERFACE_STATE_INIT:
return "init";
case NM_SUPPLICANT_INTERFACE_STATE_STARTING:
return "starting";
case NM_SUPPLICANT_INTERFACE_STATE_READY:
return "ready";
case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED:
return "disconnected";
case NM_SUPPLICANT_INTERFACE_STATE_INACTIVE:
return "inactive";
case NM_SUPPLICANT_INTERFACE_STATE_SCANNING:
return "scanning";
case NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING:
return "associating";
case NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED:
return "associated";
case NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE:
return "4-way handshake";
case NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE:
return "group handshake";
case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED:
return "completed";
case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
return "down";
default:
@ -1094,35 +1037,28 @@ nm_supplicant_interface_state_to_string (guint32 state)
}
const char *
nm_supplicant_interface_connection_state_to_string (guint32 state)
nm_supplicant_interface_get_device (NMSupplicantInterface * self)
{
switch (state) {
case NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED:
return "disconnected";
case NM_SUPPLICANT_INTERFACE_CON_STATE_INACTIVE:
return "inactive";
case NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING:
return "scanning";
case NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATING:
return "associating";
case NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATED:
return "associated";
case NM_SUPPLICANT_INTERFACE_CON_STATE_4WAY_HANDSHAKE:
return "4-way handshake";
case NM_SUPPLICANT_INTERFACE_CON_STATE_GROUP_HANDSHAKE:
return "group handshake";
case NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED:
return "completed";
default:
break;
}
return "unknown";
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev;
}
const char *
nm_supplicant_interface_get_object_path (NMSupplicantInterface *self)
{
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL);
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->object_path;
}
const char *
nm_supplicant_interface_get_ifname (NMSupplicantInterface *self)
{
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE);
return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev;
}
@ -1147,14 +1083,15 @@ nm_supplicant_interface_new (NMSupplicantManager *smgr,
priv->smgr = g_object_ref (smgr);
id = g_signal_connect (priv->smgr,
"state",
G_CALLBACK (smgr_state_changed),
"notify::" NM_SUPPLICANT_MANAGER_RUNNING,
G_CALLBACK (smgr_running_cb),
self);
priv->smgr_state_sig_handler = id;
priv->smgr_running_id = id;
priv->dev = g_strdup (ifname);
priv->is_wireless = is_wireless;
nm_supplicant_interface_start (self);
interface_add (self, priv->is_wireless);
}
return self;
@ -1164,12 +1101,18 @@ static void
nm_supplicant_interface_init (NMSupplicantInterface * self)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
DBusGConnection *bus;
priv->state = NM_SUPPLICANT_INTERFACE_STATE_INIT;
priv->con_state = NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED;
priv->assoc_pcalls = nm_call_store_new ();
priv->other_pcalls = nm_call_store_new ();
priv->dbus_mgr = nm_dbus_manager_get ();
bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
priv->wpas_proxy = dbus_g_proxy_new_for_name (bus,
WPAS_DBUS_SERVICE,
WPAS_DBUS_PATH,
WPAS_DBUS_INTERFACE);
}
static void
@ -1195,9 +1138,6 @@ get_property (GObject *object,
case PROP_STATE:
g_value_set_uint (value, NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object)->state);
break;
case PROP_CONNECTION_STATE:
g_value_set_uint (value, NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object)->con_state);
break;
case PROP_SCANNING:
g_value_set_boolean (value, NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object)->scanning);
break;
@ -1211,7 +1151,6 @@ static void
dispose (GObject *object)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object);
guint32 sm_state;
if (priv->disposed) {
G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->dispose (object);
@ -1219,27 +1158,21 @@ dispose (GObject *object)
}
priv->disposed = TRUE;
/* Ask wpa_supplicant to remove this interface */
sm_state = nm_supplicant_manager_get_state (priv->smgr);
if (sm_state == NM_SUPPLICANT_MANAGER_STATE_IDLE) {
if (priv->object_path) {
try_remove_iface (nm_dbus_manager_get_connection (priv->dbus_mgr),
priv->object_path);
}
}
if (priv->iface_proxy)
g_object_unref (priv->iface_proxy);
if (priv->net_proxy)
g_object_unref (priv->net_proxy);
if (priv->wpas_proxy)
g_object_unref (priv->wpas_proxy);
if (priv->scan_results_timeout)
g_source_remove (priv->scan_results_timeout);
if (priv->smgr) {
g_signal_handler_disconnect (priv->smgr,
priv->smgr_state_sig_handler);
if (priv->smgr_running_id)
g_signal_handler_disconnect (priv->smgr, priv->smgr_running_id);
g_object_unref (priv->smgr);
}
@ -1338,15 +1271,6 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE, 1, G_TYPE_UINT);
signals[CONNECTION_STATE] =
g_signal_new ("connection-state",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NMSupplicantInterfaceClass, connection_state),
NULL, NULL,
_nm_marshal_VOID__UINT_UINT,
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
signals[CONNECTION_ERROR] =
g_signal_new ("connection-error",
G_OBJECT_CLASS_TYPE (object_class),

View file

@ -26,47 +26,25 @@
#include <dbus/dbus.h>
#include "nm-supplicant-types.h"
G_BEGIN_DECLS
/*
* Supplicant interface states
* The states are linear, ie INIT -> READY -> DOWN and state may only be
* changed in one direction. If an interface reaches the DOWN state, it
* cannot be re-initialized; it must be torn down and a new one created.
*
* INIT: interface has been created, but cannot be used yet; it is waiting
* for pending requests of the supplicant to complete.
* READY: interface is ready for use
* DOWN: interface has been removed or has otherwise been made invalid; it
* must be torn down.
*
* Note: LAST is an invalid state and only used for boundary checking.
* A mix of wpa_supplicant interface states and internal states.
*/
enum {
NM_SUPPLICANT_INTERFACE_STATE_INIT = 0,
NM_SUPPLICANT_INTERFACE_STATE_STARTING,
NM_SUPPLICANT_INTERFACE_STATE_READY,
NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED,
NM_SUPPLICANT_INTERFACE_STATE_INACTIVE,
NM_SUPPLICANT_INTERFACE_STATE_SCANNING,
NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING,
NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED,
NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE,
NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE,
NM_SUPPLICANT_INTERFACE_STATE_COMPLETED,
NM_SUPPLICANT_INTERFACE_STATE_DOWN,
NM_SUPPLICANT_INTERFACE_STATE_LAST
};
/*
* Supplicant interface connection states
* The wpa_supplicant state for the connection.
*/
enum {
NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED = 0,
NM_SUPPLICANT_INTERFACE_CON_STATE_INACTIVE,
NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING,
NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATING,
NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATED,
NM_SUPPLICANT_INTERFACE_CON_STATE_4WAY_HANDSHAKE,
NM_SUPPLICANT_INTERFACE_CON_STATE_GROUP_HANDSHAKE,
NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED,
NM_SUPPLICANT_INTERFACE_CON_STATE_LAST
};
#define NM_TYPE_SUPPLICANT_INTERFACE (nm_supplicant_interface_get_type ())
#define NM_SUPPLICANT_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterface))
#define NM_SUPPLICANT_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass))
@ -103,11 +81,6 @@ typedef struct {
void (*scan_results) (NMSupplicantInterface * iface,
guint num_bssids);
/* link state of the device's connection */
void (*connection_state) (NMSupplicantInterface * iface,
guint32 new_state,
guint32 old_state);
/* an error occurred during a connection request */
void (*connection_error) (NMSupplicantInterface * iface,
const char * name,
@ -128,20 +101,16 @@ void nm_supplicant_interface_disconnect (NMSupplicantInterface * iface);
const char * nm_supplicant_interface_get_device (NMSupplicantInterface * iface);
const char *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface);
gboolean nm_supplicant_interface_request_scan (NMSupplicantInterface * self);
guint32 nm_supplicant_interface_get_state (NMSupplicantInterface * self);
guint32 nm_supplicant_interface_get_connection_state (NMSupplicantInterface * self);
const char *nm_supplicant_interface_state_to_string (guint32 state);
const char *nm_supplicant_interface_connection_state_to_string (guint32 state);
gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self);
const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self);
G_END_DECLS
#endif /* NM_SUPPLICANT_INTERFACE_H */

View file

@ -26,19 +26,7 @@
#include "nm-supplicant-manager.h"
#include "nm-supplicant-interface.h"
#include "nm-dbus-manager.h"
#include "nm-marshal.h"
#include "nm-logging.h"
#include "nm-glib-compat.h"
#define SUPPLICANT_POKE_INTERVAL 120
typedef struct {
NMDBusManager * dbus_mgr;
guint32 state;
GHashTable * ifaces;
gboolean disposed;
guint poke_id;
} NMSupplicantManagerPrivate;
#define NM_SUPPLICANT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
NM_TYPE_SUPPLICANT_MANAGER, \
@ -46,84 +34,26 @@ typedef struct {
G_DEFINE_TYPE (NMSupplicantManager, nm_supplicant_manager, G_TYPE_OBJECT)
/* Signals */
/* Properties */
enum {
STATE, /* change in the manager's state */
LAST_SIGNAL
PROP_0 = 0,
PROP_RUNNING,
LAST_PROP
};
static guint signals[LAST_SIGNAL] = { 0 };
typedef struct {
NMDBusManager * dbus_mgr;
guint name_owner_id;
DBusGProxy * proxy;
gboolean running;
GHashTable * ifaces;
gboolean disposed;
} NMSupplicantManagerPrivate;
/********************************************************************/
static gboolean
poke_supplicant_cb (gpointer user_data)
{
NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data);
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
DBusGConnection *g_connection;
DBusGProxy *proxy;
const char *tmp = "ignoreme";
g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
proxy = dbus_g_proxy_new_for_name (g_connection,
WPAS_DBUS_SERVICE,
WPAS_DBUS_PATH,
WPAS_DBUS_INTERFACE);
if (!proxy) {
nm_log_warn (LOGD_SUPPLICANT, "Error: could not init wpa_supplicant proxy");
goto out;
}
nm_log_info (LOGD_SUPPLICANT, "Trying to start the supplicant...");
dbus_g_proxy_call_no_reply (proxy, "getInterface", G_TYPE_STRING, tmp, G_TYPE_INVALID);
g_object_unref (proxy);
out:
/* Reschedule the poke */
priv->poke_id = g_timeout_add_seconds (SUPPLICANT_POKE_INTERVAL,
poke_supplicant_cb,
(gpointer) self);
return FALSE;
}
guint32
nm_supplicant_manager_get_state (NMSupplicantManager * self)
{
g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), FALSE);
return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->state;
}
static void
set_state (NMSupplicantManager *self, guint32 new_state)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
guint32 old_state;
if (new_state != priv->state) {
old_state = priv->state;
priv->state = new_state;
g_signal_emit (self, signals[STATE], 0, priv->state, old_state);
}
}
static gboolean
startup (NMSupplicantManager * self)
{
gboolean running;
/* FIXME: convert to pending call */
running = nm_dbus_manager_name_has_owner (NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->dbus_mgr,
WPAS_DBUS_SERVICE);
if (running)
set_state (self, NM_SUPPLICANT_MANAGER_STATE_IDLE);
return running;
}
NMSupplicantInterface *
nm_supplicant_manager_get_iface (NMSupplicantManager * self,
nm_supplicant_manager_iface_get (NMSupplicantManager * self,
const char *ifname,
gboolean is_wireless)
{
@ -149,34 +79,37 @@ nm_supplicant_manager_get_iface (NMSupplicantManager * self,
}
void
nm_supplicant_manager_release_iface (NMSupplicantManager *self,
nm_supplicant_manager_iface_release (NMSupplicantManager *self,
NMSupplicantInterface *iface)
{
NMSupplicantManagerPrivate *priv;
const char *ifname;
const char *ifname, *op;
g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (self));
g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (iface));
priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
/* Ask wpa_supplicant to remove this interface */
op = nm_supplicant_interface_get_object_path (iface);
if (priv->running && priv->proxy && op) {
dbus_g_proxy_call_no_reply (priv->proxy, "removeInterface",
DBUS_TYPE_G_OBJECT_PATH, op,
G_TYPE_INVALID);
}
ifname = nm_supplicant_interface_get_ifname (iface);
g_assert (ifname);
g_hash_table_remove (priv->ifaces, ifname);
}
const char *
nm_supplicant_manager_state_to_string (guint32 state)
gboolean
nm_supplicant_manager_running (NMSupplicantManager *self)
{
switch (state) {
case NM_SUPPLICANT_MANAGER_STATE_DOWN:
return "down";
case NM_SUPPLICANT_MANAGER_STATE_IDLE:
return "idle";
default:
break;
}
return "unknown";
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), FALSE);
return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->running;
}
static void
@ -186,34 +119,23 @@ name_owner_changed (NMDBusManager *dbus_mgr,
const char *new_owner,
gpointer user_data)
{
NMSupplicantManager * self = (NMSupplicantManager *) user_data;
NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data);
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
gboolean old_owner_good = (old_owner && strlen (old_owner));
gboolean new_owner_good = (new_owner && strlen (new_owner));
/* Can't handle the signal if its not from the supplicant service */
/* We only care about the supplicant here */
if (strcmp (WPAS_DBUS_SERVICE, name) != 0)
return;
if (!old_owner_good && new_owner_good) {
gboolean running;
running = startup (self);
if (running && priv->poke_id) {
g_source_remove (priv->poke_id);
priv->poke_id = 0;
}
nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant started");
priv->running = TRUE;
g_object_notify (G_OBJECT (self), NM_SUPPLICANT_MANAGER_RUNNING);
} else if (old_owner_good && !new_owner_good) {
set_state (self, NM_SUPPLICANT_MANAGER_STATE_DOWN);
if (priv->poke_id)
g_source_remove (priv->poke_id);
/* Poke the supplicant so that it gets activated by dbus system bus
* activation.
*/
priv->poke_id = g_idle_add (poke_supplicant_cb, (gpointer) self);
nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant stopped");
priv->running = FALSE;
g_object_notify (G_OBJECT (self), NM_SUPPLICANT_MANAGER_RUNNING);
}
}
@ -237,24 +159,40 @@ static void
nm_supplicant_manager_init (NMSupplicantManager * self)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
gboolean running;
DBusGConnection *bus;
priv->state = NM_SUPPLICANT_MANAGER_STATE_DOWN;
priv->dbus_mgr = nm_dbus_manager_get ();
priv->poke_id = 0;
priv->name_owner_id = g_signal_connect (priv->dbus_mgr,
"name-owner-changed",
G_CALLBACK (name_owner_changed),
self);
priv->running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, WPAS_DBUS_SERVICE);
bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
priv->proxy = dbus_g_proxy_new_for_name (bus,
WPAS_DBUS_SERVICE,
WPAS_DBUS_PATH,
WPAS_DBUS_INTERFACE);
priv->ifaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}
running = startup (self);
static void
set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
g_signal_connect (priv->dbus_mgr,
"name-owner-changed",
G_CALLBACK (name_owner_changed),
self);
if (!running) {
/* Try to activate the supplicant */
priv->poke_id = g_idle_add (poke_supplicant_cb, (gpointer) self);
static void
get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
switch (prop_id) {
case PROP_RUNNING:
g_value_set_boolean (value, NM_SUPPLICANT_MANAGER_GET_PRIVATE (object)->running);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
@ -263,22 +201,22 @@ dispose (GObject *object)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object);
if (priv->disposed) {
G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
return;
}
if (priv->disposed)
goto out;
priv->disposed = TRUE;
if (priv->poke_id) {
g_source_remove (priv->poke_id);
priv->poke_id = 0;
}
if (priv->dbus_mgr) {
if (priv->name_owner_id)
g_signal_handler_disconnect (priv->dbus_mgr, priv->name_owner_id);
g_object_unref (G_OBJECT (priv->dbus_mgr));
priv->dbus_mgr = NULL;
}
g_hash_table_destroy (priv->ifaces);
if (priv->proxy)
g_object_unref (priv->proxy);
out:
/* Chain up to the parent class */
G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
}
@ -286,19 +224,19 @@ dispose (GObject *object)
static void
nm_supplicant_manager_class_init (NMSupplicantManagerClass *klass)
{
GObjectClass * object_class = G_OBJECT_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (object_class, sizeof (NMSupplicantManagerPrivate));
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->dispose = dispose;
/* Signals */
signals[STATE] = g_signal_new ("state",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NMSupplicantManagerClass, state),
NULL, NULL,
_nm_marshal_VOID__UINT_UINT,
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
g_object_class_install_property (object_class, PROP_RUNNING,
g_param_spec_boolean (NM_SUPPLICANT_MANAGER_RUNNING,
"Running",
"Running",
FALSE,
G_PARAM_READABLE));
}

View file

@ -33,23 +33,6 @@
G_BEGIN_DECLS
/*
* Supplicant manager states
* Either state may transition to the other state at any time.
*
* DOWN: supplicant manager has been created, but cannot be used; the supplicant
* is either not running or has not yet been fully initialized.
* IDLE: supplicant manager is ready for use
*
* Note: LAST is an invalid state and only used for boundary checking.
*/
enum {
NM_SUPPLICANT_MANAGER_STATE_DOWN = 0,
NM_SUPPLICANT_MANAGER_STATE_IDLE,
NM_SUPPLICANT_MANAGER_STATE_LAST
};
#define NM_TYPE_SUPPLICANT_MANAGER (nm_supplicant_manager_get_type ())
#define NM_SUPPLICANT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SUPPLICANT_MANAGER, NMSupplicantManager))
#define NM_SUPPLICANT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SUPPLICANT_MANAGER, NMSupplicantManagerClass))
@ -57,6 +40,8 @@ enum {
#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_RUNNING "running"
struct _NMSupplicantManager
{
GObject parent;
@ -65,24 +50,19 @@ struct _NMSupplicantManager
typedef struct
{
GObjectClass parent;
/* class members */
void (* state) (NMSupplicantManager * mgr, guint32 new_state, guint32 old_state);
} NMSupplicantManagerClass;
GType nm_supplicant_manager_get_type (void);
NMSupplicantManager * nm_supplicant_manager_get (void);
NMSupplicantManager *nm_supplicant_manager_get (void);
guint32 nm_supplicant_manager_get_state (NMSupplicantManager * mgr);
NMSupplicantInterface *nm_supplicant_manager_iface_get (NMSupplicantManager *mgr,
const char *ifname,
gboolean is_wireless);
NMSupplicantInterface * nm_supplicant_manager_get_iface (NMSupplicantManager * mgr,
const char *ifname,
gboolean is_wireless);
void nm_supplicant_manager_iface_release (NMSupplicantManager *mgr,
NMSupplicantInterface *iface);
void nm_supplicant_manager_release_iface (NMSupplicantManager * mgr,
NMSupplicantInterface * iface);
const char *nm_supplicant_manager_state_to_string (guint32 state);
gboolean nm_supplicant_manager_running (NMSupplicantManager *mgr);
#endif /* NM_SUPPLICANT_MANAGER_H */