wifi: don't remove APs still known to the supplicant

Because the supplicant doesn't have a BSS property for "last seen"
we have to fake that by listening to PropertiesChanged events for
stuff like signal strength, which usually changes a bit from scan
to scan.  But in case it doesn't change, we'll never get that PC
signal, and thus we'll never update our internal 'last seen'
timestamp, and thus the AP will get removed from the NM scan list
even if it was in the supplicant's last scan results.

So, if the AP if we haven't receieved a BssRemoved signal for the
AP yet don't remove it from the NM scan list.  One caveat is that
if the supplicant's DEFAULT_BSS_EXPIRATION_AGE value is greater
than NM's AP expiration age, NM will by consequence use the
supplicant's value instead.  At the moment the supplicant sets
DEFAULT_BSS_EXPIRATION_AGE to 180 seconds while NM's is 360.
This commit is contained in:
Dan Williams 2012-03-02 18:17:34 -06:00
parent fb06cda723
commit 5cd9b1e22f
3 changed files with 57 additions and 1 deletions

View file

@ -105,7 +105,7 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
#define SUP_SIG_ID_LEN 5
#define SUP_SIG_ID_LEN 6
typedef struct Supplicant {
NMSupplicantManager *mgr;
@ -179,6 +179,10 @@ static void supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface,
GHashTable *properties,
NMDeviceWifi *self);
static void supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface,
const char *object_path,
NMDeviceWifi *self);
static void supplicant_iface_scan_done_cb (NMSupplicantInterface * iface,
gboolean success,
NMDeviceWifi * self);
@ -370,6 +374,12 @@ supplicant_interface_acquire (NMDeviceWifi *self)
self);
priv->supplicant.sig_ids[i++] = id;
id = g_signal_connect (priv->supplicant.iface,
NM_SUPPLICANT_INTERFACE_BSS_REMOVED,
G_CALLBACK (supplicant_iface_bss_removed_cb),
self);
priv->supplicant.sig_ids[i++] = id;
id = g_signal_connect (priv->supplicant.iface,
NM_SUPPLICANT_INTERFACE_SCAN_DONE,
G_CALLBACK (supplicant_iface_scan_done_cb),
@ -1696,6 +1706,8 @@ merge_scanned_ap (NMDeviceWifi *self,
}
}
#define WPAS_REMOVED_TAG "supplicant-removed"
static gboolean
cull_scan_list (NMDeviceWifi *self)
{
@ -1722,6 +1734,17 @@ cull_scan_list (NMDeviceWifi *self)
if (ap == priv->current_ap || nm_ap_get_fake (ap))
continue;
/* Don't cull APs still known to the supplicant. Since the supplicant
* doesn't yet emit property updates for "last seen" we have to rely
* on changing signal strength for updating "last seen". But if the
* AP's strength doesn't change we won't get any updates for the AP,
* and we'll end up here even if the AP was still found by the
* supplicant in the last scan.
*/
if ( nm_ap_get_supplicant_path (ap)
&& g_object_get_data (G_OBJECT (ap), WPAS_REMOVED_TAG) == NULL)
continue;
if (nm_ap_get_last_seen (ap) + prune_interval_s < now.tv_sec)
outdated_list = g_slist_append (outdated_list, ap);
}
@ -1815,6 +1838,7 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface,
GTimeVal now;
g_return_if_fail (self != NULL);
g_return_if_fail (object_path != NULL);
g_return_if_fail (properties != NULL);
/* Ignore new APs when unavailable or unamnaged */
@ -1833,6 +1857,21 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface,
schedule_scanlist_cull (self);
}
static void
supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface,
const char *object_path,
NMDeviceWifi *self)
{
NMAccessPoint *ap;
g_return_if_fail (self != NULL);
g_return_if_fail (object_path != NULL);
ap = get_ap_by_supplicant_path (self, object_path);
if (ap)
g_object_set_data (G_OBJECT (ap), WPAS_REMOVED_TAG, GUINT_TO_POINTER (TRUE));
}
static void
cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect)

View file

@ -60,6 +60,7 @@ enum {
REMOVED, /* interface was removed by the supplicant */
NEW_BSS, /* interface saw a new access point from a scan */
BSS_UPDATED, /* a BSS property changed */
BSS_REMOVED, /* supplicant removed BSS from its scan list */
SCAN_DONE, /* wifi scan is complete */
CONNECTION_ERROR, /* an error occurred during a connection request */
CREDENTIALS_REQUEST, /* 802.1x identity or password requested */
@ -356,6 +357,8 @@ wpas_iface_bss_removed (DBusGProxy *proxy,
NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data);
NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);
g_signal_emit (self, signals[BSS_REMOVED], 0, object_path);
g_hash_table_remove (priv->bss_proxies, object_path);
}
@ -1450,6 +1453,15 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
_nm_marshal_VOID__STRING_POINTER,
G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
signals[BSS_REMOVED] =
g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_REMOVED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NMSupplicantInterfaceClass, bss_removed),
NULL, NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
signals[SCAN_DONE] =
g_signal_new (NM_SUPPLICANT_INTERFACE_SCAN_DONE,
G_OBJECT_CLASS_TYPE (object_class),

View file

@ -58,6 +58,7 @@ enum {
#define NM_SUPPLICANT_INTERFACE_REMOVED "removed"
#define NM_SUPPLICANT_INTERFACE_NEW_BSS "new-bss"
#define NM_SUPPLICANT_INTERFACE_BSS_UPDATED "bss-updated"
#define NM_SUPPLICANT_INTERFACE_BSS_REMOVED "bss-removed"
#define NM_SUPPLICANT_INTERFACE_SCAN_DONE "scan-done"
#define NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR "connection-error"
#define NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST "credentials-request"
@ -89,6 +90,10 @@ typedef struct {
const char *object_path,
GHashTable *props);
/* supplicant removed a BSS from its scan list */
void (*bss_removed) (NMSupplicantInterface *iface,
const char *object_path);
/* wireless scan is done */
void (*scan_done) (NMSupplicantInterface *iface,
gboolean success);