NetworkManager 1.2 Has Better Wi-Fi Scanning

Almost since the beginning of time, NetworkManager kept an internal list of access points found in the last 3 scans.  Since the background scan were triggered at least every two minutes, an access point could stay in the list for up to 6 minutes.  This was a compromise between mobility, unreliable drivers, and an unreliable medium (eg, air).  Even when you’re not moving the closest access point may not show up in every scan.  So NetworkManager attempted to compensate by keeping access points around for a longer time.

Obviously that approach has problems if you’re driving, on a train, or on a bus.  You can end up with a huge list of access points that are obviously no longer in range.  If you turn off an access point, it could stay in the list a long time.

Ubuntu contributed a patch that exposes the “last seen time” for each access point, which allows the user-interface to decide for itself which access points to show.  A location service (like Firefox or Geoclue) may want a more complete list of access points than the live Wi-Fi network list does, for example, which is why NetworkManager keeps the list in the first place instead of only showing the results of the most recent (and potentially unreliable) scan.

But in the end this behavior needed to change, and with recent versions of wpa_supplicant it was possible to make NetworkManager’s scanning behavior better.  The supplicant also contains a scan list from which NetworkManager built it’s.  Wouldn’t it be great if there was one list instead of two?

So we threw away the internal NetworkManager list and just followed the supplicant’s list.  When the supplicant decides that an access point is no longer visible, NetworkManager removes it too.  This works better because the supplicant has more information than NetworkManager does and can make smarter decisions.  NetworkManager tweaks the supplicant’s behavior through the BSSExpireAge and BSSExpireCount properties so that any access point seen more than 4 minutes ago, or not seen in the past two scans, will be dropped.

When scans happen more often, like when a Wi-Fi network list is displayed, the two-scan limit removes access points after 20 or 30 seconds in the best case.  The supplicant performs backgrounds scans to facilitate faster roaming, which can be triggered on signal strength, which also helps remove old access points when they are out of range.

Tracking the Current BSS

Along with the scanning cleanup, NetworkManager delegates tracking the access point you’re currently associated with to wpa_supplicant’s CurrentBSS property.  Previously NetworkManager periodically asked the Wi-Fi driver what the current access point was, but this was inconsistently implemented between drivers and required hacky workarounds to smooth out intermittent results.

The supplicant’s CurrentBSS property tracks the access point the supplicant wants to be associated with, not what the driver currently is associated with, but these are almost always the same thing, and there’s no point in telling the user that they are momentarily disconnected from their access point during a scan when there is no actual interruption in traffic due to 802.11 protocol mechanisms like powersave buffering.  This was another huge cleanup in the NetworkManager codebase.

Death of dbus-glib

Finally, along with these changes all communication with wpa_supplicant was switched to use GDBus instead of the old, deprecated, and unmaintained dbus-glib library.  This advances our goal of removing all use of dbus-glib from NetworkManager, which was one of the first major users of the library in 2004, and is likely the last one too.  GDBus provides much better integration with glib and the GIO model, is fully supported, and has an saner API.

And even better, through the painstaking work of Dan Winship, Jirka Klimes, Thomas Haller, Lubomir Rintel, me, and others, all of NetworkManager 1.2 was ported to GDBus without changing our public D-Bus API.  Welcome to the future!