wifi: handle unsolicited supplicant scans

With supplicant patches, this allows NM to figure out when the supplicant
is performing an unsolicited scan, and thus to not run periodic_update()
when the supplicant is scanning.

This fixes some of the causes of "roaming to none", especially in hidden
SSID networks.  In those cases, after NM had requested a broadcast scan,
the hidden SSID AP would likely not show up in the scan results, leading
to the supplicant performing a specific SSID scan that NetworkManager
was unaware of.  While that specific SSID scan was going on, NM could
run periodic_update() and pull the wrong frequency off the card,
leading to the "roaming to none" message when the associated AP with
the wrong frequency could not be found in the scan list.
This commit is contained in:
Dan Williams
2009-05-13 11:16:29 -04:00
parent 027ef78682
commit 57a04fa59d
3 changed files with 97 additions and 20 deletions

View File

@@ -152,7 +152,6 @@ struct _NMDeviceWifiPrivate {
gboolean enabled; /* rfkilled or not */
guint state_to_disconnected_id;
gboolean scanning;
glong scheduled_scan_time;
guint8 scan_interval; /* seconds */
guint pending_scan_id;
@@ -461,7 +460,6 @@ nm_device_wifi_init (NMDeviceWifi * self)
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
priv->dispose_has_run = FALSE;
priv->scanning = FALSE;
priv->ap_list = NULL;
priv->we_version = 0;
@@ -966,7 +964,7 @@ nm_device_wifi_periodic_update (gpointer data)
if (state != NM_DEVICE_STATE_ACTIVATED)
goto out;
if (priv->scanning)
if (nm_supplicant_interface_get_scanning (priv->supplicant.iface))
goto out;
periodic_update (self);
@@ -2362,6 +2360,7 @@ supplicant_iface_connection_state_cb_handler (gpointer 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. */
@@ -2373,7 +2372,7 @@ supplicant_iface_connection_state_cb_handler (gpointer user_data)
nm_supplicant_interface_connection_state_to_string (task->old_state),
nm_supplicant_interface_connection_state_to_string (task->new_state));
priv->scanning = (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING);
scanning = nm_supplicant_interface_get_scanning (priv->supplicant.iface);
if (task->new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED) {
remove_supplicant_interface_error_handler (self);
@@ -2399,7 +2398,7 @@ supplicant_iface_connection_state_cb_handler (gpointer user_data)
* while to scan.
*/
if (!priv->link_timeout_id) {
priv->link_timeout_id = g_timeout_add_seconds (priv->scanning ? 30 : 15,
priv->link_timeout_id = g_timeout_add_seconds (scanning ? 30 : 15,
link_timeout_cb, self);
}
}

View File

@@ -92,6 +92,7 @@ enum {
PROP_DEVICE,
PROP_STATE,
PROP_CONNECTION_STATE,
PROP_SCANNING,
LAST_PROP
};
@@ -110,6 +111,7 @@ typedef struct
NMCallStore * other_pcalls;
guint32 con_state;
gboolean scanning;
DBusGProxy * iface_proxy;
DBusGProxy * net_proxy;
@@ -243,12 +245,6 @@ nm_supplicant_interface_set_property (GObject * object,
/* Construct-only */
priv->dev = g_strdup (g_value_get_string (value));
break;
case PROP_STATE:
/* warn on setting read-only property */
break;
case PROP_CONNECTION_STATE:
/* warn on setting read-only property */
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -276,6 +272,9 @@ nm_supplicant_interface_get_property (GObject * object,
case PROP_CONNECTION_STATE:
g_value_set_uint (value, priv->con_state);
break;
case PROP_SCANNING:
g_value_set_boolean (value, priv->scanning);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -395,6 +394,14 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
NM_SUPPLICANT_INTERFACE_STATE_INIT,
G_PARAM_READABLE));
g_object_class_install_property (object_class,
PROP_SCANNING,
g_param_spec_boolean ("scanning",
"Scanning",
"Scanning",
FALSE,
G_PARAM_READABLE));
/* Signals */
nm_supplicant_interface_signals[STATE] =
g_signal_new ("state",
@@ -601,23 +608,22 @@ wpas_state_string_to_enum (const char * str_state)
{
guint32 enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED;
if (!strcmp (str_state, "DISCONNECTED")) {
if (!strcmp (str_state, "DISCONNECTED"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED;
} else if (!strcmp (str_state, "INACTIVE")) {
else if (!strcmp (str_state, "INACTIVE"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_INACTIVE;
} else if (!strcmp (str_state, "SCANNING")) {
else if (!strcmp (str_state, "SCANNING"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING;
} else if (!strcmp (str_state, "ASSOCIATING")) {
else if (!strcmp (str_state, "ASSOCIATING"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATING;
} else if (!strcmp (str_state, "ASSOCIATED")) {
else if (!strcmp (str_state, "ASSOCIATED"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATED;
} else if (!strcmp (str_state, "4WAY_HANDSHAKE")) {
else if (!strcmp (str_state, "4WAY_HANDSHAKE"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_4WAY_HANDSHAKE;
} else if (!strcmp (str_state, "GROUP_HANDSHAKE")) {
else if (!strcmp (str_state, "GROUP_HANDSHAKE"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_GROUP_HANDSHAKE;
} else if (!strcmp (str_state, "COMPLETED")) {
else if (!strcmp (str_state, "COMPLETED"))
enum_state = NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED;
}
return enum_state;
}
@@ -681,6 +687,68 @@ wpas_iface_get_state (NMSupplicantInterface *self)
nm_supplicant_info_set_call (info, call);
}
static void
iface_scanning_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
{
NMSupplicantInfo *info = (NMSupplicantInfo *) user_data;
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface);
gboolean scanning = FALSE;
if (dbus_g_proxy_end_call (proxy, call_id, NULL,
G_TYPE_BOOLEAN, &scanning,
G_TYPE_INVALID)) {
if (scanning != priv->scanning) {
priv->scanning = scanning;
g_object_notify (G_OBJECT (info->interface), "scanning");
}
}
}
static void
wpas_iface_get_scanning (NMSupplicantInterface *self)
{
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
NMSupplicantInfo *info;
DBusGProxyCall *call;
info = nm_supplicant_info_new (self, priv->iface_proxy, priv->other_pcalls);
call = dbus_g_proxy_begin_call (priv->iface_proxy, "scanning",
iface_scanning_cb,
info,
nm_supplicant_info_destroy,
G_TYPE_INVALID);
nm_supplicant_info_set_call (info, call);
}
static void
wpas_iface_handle_scanning (DBusGProxy *proxy,
gboolean scanning,
gpointer user_data)
{
NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
if (scanning != priv->scanning) {
priv->scanning = scanning;
g_object_notify (G_OBJECT (self), "scanning");
}
}
gboolean
nm_supplicant_interface_get_scanning (NMSupplicantInterface *self)
{
NMSupplicantInterfacePrivate *priv;
g_return_val_if_fail (self != NULL, FALSE);
priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
if (priv->scanning)
return TRUE;
if (priv->con_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING)
return TRUE;
return FALSE;
}
static void
nm_supplicant_interface_add_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
{
@@ -732,8 +800,16 @@ nm_supplicant_interface_add_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpoi
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);
}
}

View File

@@ -138,6 +138,8 @@ 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
#endif /* NM_SUPPLICANT_INTERFACE_H */