From 5cd9b1e22fcb769eeac85bb16b09d3358ddc44f9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 2 Mar 2012 18:17:34 -0600 Subject: [PATCH] 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. --- src/nm-device-wifi.c | 41 ++++++++++++++++++- .../nm-supplicant-interface.c | 12 ++++++ .../nm-supplicant-interface.h | 5 +++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index 8a99005101..d5f79e8b2b 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -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) diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c index 042ef9ee07..f8ad8f18a9 100644 --- a/src/supplicant-manager/nm-supplicant-interface.c +++ b/src/supplicant-manager/nm-supplicant-interface.c @@ -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), diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h index dc55b3f10d..608ee0590f 100644 --- a/src/supplicant-manager/nm-supplicant-interface.h +++ b/src/supplicant-manager/nm-supplicant-interface.h @@ -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);