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);