Merge remote branch 'origin/sup-rework'

This commit is contained in:
Dan Williams 2010-10-18 18:40:42 -05:00
commit b368b8fea3
6 changed files with 894 additions and 1501 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,18 @@ 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;
#define SUP_SIG_ID_LEN 5
typedef struct Supplicant {
NMSupplicantManager *mgr;
NMSupplicantInterface *iface;
/* signal handler ids */
guint mgr_state_id;
guint sig_ids[SUP_SIG_ID_LEN];
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 +183,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 +200,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 +599,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 +628,13 @@ static gboolean
supplicant_interface_acquire (NMDeviceWifi *self)
{
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
guint id, mgr_state;
guint id, i = 0;
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) {
@ -676,69 +643,41 @@ supplicant_interface_acquire (NMDeviceWifi *self)
return FALSE;
}
memset (priv->supplicant.sig_ids, 0, sizeof (priv->supplicant.sig_ids));
id = g_signal_connect (priv->supplicant.iface,
"state",
G_CALLBACK (supplicant_iface_state_cb),
self);
priv->supplicant.iface_state_id = id;
priv->supplicant.sig_ids[i++] = id;
id = g_signal_connect (priv->supplicant.iface,
"scanned-ap",
G_CALLBACK (supplicant_iface_scanned_ap_cb),
self);
priv->supplicant.iface_scanned_ap_id = id;
priv->supplicant.sig_ids[i++] = id;
id = g_signal_connect (priv->supplicant.iface,
"scan-req-result",
G_CALLBACK (supplicant_iface_scan_request_result_cb),
self);
priv->supplicant.iface_scan_request_result_id = id;
priv->supplicant.sig_ids[i++] = id;
id = g_signal_connect (priv->supplicant.iface,
"scan-results",
G_CALLBACK (supplicant_iface_scan_results_cb),
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;
priv->supplicant.sig_ids[i++] = id;
id = g_signal_connect (priv->supplicant.iface,
"notify::scanning",
G_CALLBACK (supplicant_iface_notify_scanning_cb),
self);
priv->supplicant.iface_notify_scanning_id = id;
priv->supplicant.sig_ids[i++] = id;
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)
{
@ -762,6 +701,7 @@ static void
supplicant_interface_release (NMDeviceWifi *self)
{
NMDeviceWifiPrivate *priv;
guint i;
g_return_if_fail (self != NULL);
@ -776,45 +716,18 @@ 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;
}
if (priv->supplicant.iface_scanned_ap_id > 0) {
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_scanned_ap_id);
priv->supplicant.iface_scanned_ap_id = 0;
}
if (priv->supplicant.iface_scan_request_result_id > 0) {
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_scan_request_result_id);
priv->supplicant.iface_scan_request_result_id = 0;
}
if (priv->supplicant.iface_scan_results_id > 0) {
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_scan_results_id);
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;
/* Clear supplicant interface signal handlers */
for (i = 0; i < SUP_SIG_ID_LEN; i++) {
if (priv->supplicant.sig_ids[i] > 0)
g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.sig_ids[i]);
}
memset (priv->supplicant.sig_ids, 0, sizeof (priv->supplicant.sig_ids));
if (priv->supplicant.iface) {
/* 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 +1750,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 +2354,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 +3602,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;

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2006 - 2008 Red Hat, Inc.
* Copyright (C) 2006 - 2010 Red Hat, Inc.
* Copyright (C) 2007 - 2008 Novell, Inc.
*/
@ -26,47 +26,26 @@
#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 +82,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,
@ -119,7 +93,8 @@ GType nm_supplicant_interface_get_type (void);
NMSupplicantInterface * nm_supplicant_interface_new (NMSupplicantManager * smgr,
const char *ifname,
gboolean is_wireless);
gboolean is_wireless,
gboolean start_now);
gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * iface,
NMSupplicantConfig * cfg);
@ -128,18 +103,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);
G_END_DECLS
const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self);
#endif /* NM_SUPPLICANT_INTERFACE_H */

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2006 - 2008 Red Hat, Inc.
* Copyright (C) 2006 - 2010 Red Hat, Inc.
* Copyright (C) 2007 - 2008 Novell, Inc.
*/
@ -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;
GSList * ifaces;
gboolean dispose_has_run;
guint poke_id;
} NMSupplicantManagerPrivate;
#define NM_SUPPLICANT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
NM_TYPE_SUPPLICANT_MANAGER, \
@ -46,252 +34,59 @@ typedef struct {
G_DEFINE_TYPE (NMSupplicantManager, nm_supplicant_manager, G_TYPE_OBJECT)
static void nm_supplicant_manager_name_owner_changed (NMDBusManager *dbus_mgr,
const char *name,
const char *old,
const char *new,
gpointer user_data);
static void nm_supplicant_manager_set_state (NMSupplicantManager * self,
guint32 new_state);
static gboolean nm_supplicant_manager_startup (NMSupplicantManager * self);
/* Signals */
/* Properties */
enum {
STATE, /* change in the manager's state */
LAST_SIGNAL
PROP_0 = 0,
PROP_AVAILABLE,
LAST_PROP
};
static guint nm_supplicant_manager_signals[LAST_SIGNAL] = { 0 };
typedef struct {
NMDBusManager * dbus_mgr;
guint name_owner_id;
DBusGProxy * proxy;
gboolean running;
GHashTable * ifaces;
guint die_count_reset_id;
guint die_count;
gboolean disposed;
} NMSupplicantManagerPrivate;
NMSupplicantManager *
nm_supplicant_manager_get (void)
/********************************************************************/
static inline gboolean
die_count_exceeded (guint32 count)
{
static NMSupplicantManager * singleton = NULL;
if (!singleton) {
singleton = NM_SUPPLICANT_MANAGER (g_object_new (NM_TYPE_SUPPLICANT_MANAGER, NULL));
} else {
g_object_ref (singleton);
}
g_assert (singleton);
return singleton;
}
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;
}
static void
nm_supplicant_manager_init (NMSupplicantManager * self)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
gboolean running;
priv->dispose_has_run = FALSE;
priv->state = NM_SUPPLICANT_MANAGER_STATE_DOWN;
priv->dbus_mgr = nm_dbus_manager_get ();
priv->poke_id = 0;
running = nm_supplicant_manager_startup (self);
g_signal_connect (priv->dbus_mgr,
"name-owner-changed",
G_CALLBACK (nm_supplicant_manager_name_owner_changed),
self);
if (!running) {
/* Try to activate the supplicant */
priv->poke_id = g_idle_add (poke_supplicant_cb, (gpointer) self);
}
}
static void
nm_supplicant_manager_dispose (GObject *object)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object);
if (priv->dispose_has_run) {
G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
return;
}
priv->dispose_has_run = TRUE;
if (priv->poke_id) {
g_source_remove (priv->poke_id);
priv->poke_id = 0;
}
if (priv->dbus_mgr) {
g_object_unref (G_OBJECT (priv->dbus_mgr));
priv->dbus_mgr = NULL;
}
/* Chain up to the parent class */
G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
}
static void
nm_supplicant_manager_class_init (NMSupplicantManagerClass *klass)
{
GObjectClass * object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (object_class, sizeof (NMSupplicantManagerPrivate));
object_class->dispose = nm_supplicant_manager_dispose;
/* Signals */
nm_supplicant_manager_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);
}
static void
nm_supplicant_manager_name_owner_changed (NMDBusManager *dbus_mgr,
const char *name,
const char *old_owner,
const char *new_owner,
gpointer user_data)
{
NMSupplicantManager * self = (NMSupplicantManager *) 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 */
if (strcmp (WPAS_DBUS_SERVICE, name) != 0)
return;
if (!old_owner_good && new_owner_good) {
gboolean running;
running = nm_supplicant_manager_startup (self);
if (running && priv->poke_id) {
g_source_remove (priv->poke_id);
priv->poke_id = 0;
}
} else if (old_owner_good && !new_owner_good) {
nm_supplicant_manager_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);
}
}
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
nm_supplicant_manager_set_state (NMSupplicantManager * self, guint32 new_state)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
guint32 old_state;
if (new_state == priv->state)
return;
old_state = priv->state;
priv->state = new_state;
g_signal_emit (self,
nm_supplicant_manager_signals[STATE],
0,
priv->state,
old_state);
}
static gboolean
nm_supplicant_manager_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)
nm_supplicant_manager_set_state (self, NM_SUPPLICANT_MANAGER_STATE_IDLE);
return running;
return count > 2;
}
NMSupplicantInterface *
nm_supplicant_manager_get_iface (NMSupplicantManager * self,
const char *ifname,
gboolean is_wireless)
nm_supplicant_manager_iface_get (NMSupplicantManager * self,
const char *ifname,
gboolean is_wireless)
{
NMSupplicantManagerPrivate *priv;
NMSupplicantInterface * iface = NULL;
GSList * elt;
NMSupplicantInterface *iface = NULL;
gboolean start_now;
g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL);
g_return_val_if_fail (ifname != NULL, NULL);
priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
/* Ensure we don't already have this interface */
for (elt = priv->ifaces; elt; elt = g_slist_next (elt)) {
NMSupplicantInterface * if_tmp = (NMSupplicantInterface *) elt->data;
if (!strcmp (ifname, nm_supplicant_interface_get_device (if_tmp))) {
iface = if_tmp;
break;
}
}
iface = g_hash_table_lookup (priv->ifaces, ifname);
if (!iface) {
/* If we're making the supplicant take a time out for a bit, don't
* let the supplicant interface start immediately, just let it hang
* around in INIT state until we're ready to talk to the supplicant
* again.
*/
start_now = !die_count_exceeded (priv->die_count);
nm_log_dbg (LOGD_SUPPLICANT, "(%s): creating new supplicant interface", ifname);
iface = nm_supplicant_interface_new (self, ifname, is_wireless);
iface = nm_supplicant_interface_new (self, ifname, is_wireless, start_now);
if (iface)
priv->ifaces = g_slist_append (priv->ifaces, iface);
g_hash_table_insert (priv->ifaces, g_strdup (ifname), iface);
} else {
nm_log_dbg (LOGD_SUPPLICANT, "(%s): returning existing supplicant interface", ifname);
}
@ -300,44 +95,222 @@ nm_supplicant_manager_get_iface (NMSupplicantManager * self,
}
void
nm_supplicant_manager_release_iface (NMSupplicantManager * self,
NMSupplicantInterface * iface)
nm_supplicant_manager_iface_release (NMSupplicantManager *self,
NMSupplicantInterface *iface)
{
NMSupplicantManagerPrivate *priv;
GSList * elt;
const char *ifname, *op;
g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (self));
g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (iface));
ifname = nm_supplicant_interface_get_ifname (iface);
g_assert (ifname);
priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
for (elt = priv->ifaces; elt; elt = g_slist_next (elt)) {
NMSupplicantInterface * if_tmp = (NMSupplicantInterface *) elt->data;
g_return_if_fail (g_hash_table_lookup (priv->ifaces, ifname) == iface);
if (if_tmp == iface) {
/* Remove the iface from the supplicant manager's list and
* dereference to match additional reference in get_iface.
*/
priv->ifaces = g_slist_remove_link (priv->ifaces, elt);
g_slist_free_1 (elt);
g_object_unref (iface);
break;
/* 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);
}
g_hash_table_remove (priv->ifaces, ifname);
}
gboolean
nm_supplicant_manager_available (NMSupplicantManager *self)
{
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), FALSE);
if (die_count_exceeded (NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->die_count))
return FALSE;
return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->running;
}
static void
set_running (NMSupplicantManager *self, gboolean now_running)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
gboolean old_available = nm_supplicant_manager_available (self);
priv->running = now_running;
if (old_available != nm_supplicant_manager_available (self))
g_object_notify (G_OBJECT (self), NM_SUPPLICANT_MANAGER_AVAILABLE);
}
static void
set_die_count (NMSupplicantManager *self, guint new_die_count)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
gboolean old_available = nm_supplicant_manager_available (self);
priv->die_count = new_die_count;
if (old_available != nm_supplicant_manager_available (self))
g_object_notify (G_OBJECT (self), NM_SUPPLICANT_MANAGER_AVAILABLE);
}
static gboolean
wpas_die_count_reset_cb (gpointer user_data)
{
NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data);
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
/* Reset the die count back to zero, which allows use of the supplicant again */
priv->die_count_reset_id = 0;
set_die_count (self, 0);
nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant die count reset");
return FALSE;
}
static void
name_owner_changed (NMDBusManager *dbus_mgr,
const char *name,
const char *old_owner,
const char *new_owner,
gpointer 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));
/* We only care about the supplicant here */
if (strcmp (WPAS_DBUS_SERVICE, name) != 0)
return;
if (!old_owner_good && new_owner_good) {
nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant started");
set_running (self, TRUE);
} else if (old_owner_good && !new_owner_good) {
nm_log_info (LOGD_SUPPLICANT, "wpa_supplicant stopped");
/* Reschedule the die count reset timeout. Every time the supplicant
* dies we wait 10 seconds before resetting the counter. If the
* supplicant died more than twice before the timer is reset, then
* we don't try to talk to the supplicant for a while.
*/
if (priv->die_count_reset_id)
g_source_remove (priv->die_count_reset_id);
priv->die_count_reset_id = g_timeout_add_seconds (10, wpas_die_count_reset_cb, self);
set_die_count (self, priv->die_count + 1);
if (die_count_exceeded (priv->die_count)) {
nm_log_info (LOGD_SUPPLICANT,
"wpa_supplicant die count %d; ignoring for 10 seconds",
priv->die_count);
}
set_running (self, FALSE);
}
}
const char *
nm_supplicant_manager_state_to_string (guint32 state)
/*******************************************************************/
NMSupplicantManager *
nm_supplicant_manager_get (void)
{
switch (state) {
case NM_SUPPLICANT_MANAGER_STATE_DOWN:
return "down";
case NM_SUPPLICANT_MANAGER_STATE_IDLE:
return "idle";
static NMSupplicantManager *singleton = NULL;
if (!singleton)
singleton = NM_SUPPLICANT_MANAGER (g_object_new (NM_TYPE_SUPPLICANT_MANAGER, NULL));
else
g_object_ref (singleton);
g_assert (singleton);
return singleton;
}
static void
nm_supplicant_manager_init (NMSupplicantManager * self)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
DBusGConnection *bus;
priv->dbus_mgr = nm_dbus_manager_get ();
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);
}
static void
set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
static void
get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
switch (prop_id) {
case PROP_AVAILABLE:
g_value_set_boolean (value, nm_supplicant_manager_available (NM_SUPPLICANT_MANAGER (object)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
return "unknown";
}
static void
dispose (GObject *object)
{
NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object);
if (priv->disposed)
goto out;
priv->disposed = TRUE;
if (priv->die_count_reset_id)
g_source_remove (priv->die_count_reset_id);
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));
}
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);
}
static void
nm_supplicant_manager_class_init (NMSupplicantManagerClass *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;
g_object_class_install_property (object_class, PROP_AVAILABLE,
g_param_spec_boolean (NM_SUPPLICANT_MANAGER_AVAILABLE,
"Available",
"Available",
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_AVAILABLE "available"
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_available (NMSupplicantManager *mgr);
#endif /* NM_SUPPLICANT_MANAGER_H */