Move D-Bus export/unexport handling into NMExportedObject and remove
type-specific export/get_path methods (export paths are now specified
at the class level, and NMExportedObject handles the counters for all
exported types automatically).
Since all exportable objects now use the same get_path() method, we
can also add some helper methods to simplify get_property()
implementations for object-path and object-path-array properties.
Add NMExportedObject, make it the base class of all D-Bus-exported
types, and move the nm-properties-changed-signal logic into it. (Also,
make NMSettings use the same properties-changed code as everything
else, which it was not previously doing, presumably for historical
reasons).
(This is mostly just shuffling code around at this point, but
NMExportedObject will be more important in the gdbus port, since
gdbus-codegen doesn't do a very good job of supporting objects that
export multiple interfaces [as each NMDevice subclass does, for
example], so we will need more glue/helper code in NMExportedObject
then.)
Rather than randomly including one or more of <glib.h>,
<glib-object.h>, and <gio/gio.h> everywhere (and forgetting to include
"nm-glib-compat.h" most of the time), rename nm-glib-compat.h to
nm-glib.h, include <gio/gio.h> from there, and then change all .c
files in NM to include "nm-glib.h" rather than including the glib
headers directly.
(Public headers files still have to include the real glib headers,
since nm-glib.h isn't installed...)
Also, remove glib includes from header files that are already
including a base object header file (which must itself already include
the glib headers).
Instead of hacky stuff in the Manager, let plugins themselves indicate
which links should be ignored (because they are really child links that
are controlled by a different device that the plugin handles).
Ethernet, WiFi, and VLAN used the same implementation for initial address.
Ethernet and WiFi used the same implementation (and duplicated code) for
permanent MAC address, plus they both used ethtool in what should be
generic code, which is better done in the platform.
Instead of looping over all plugins and asking each plugin whether it
can handle a link or a connection, have them advertise the link and
connection types they support, and use that when creating new devices.
NM never removes the current AP from the AP list, to prevent NM from
indicating that it's connected, but to nothing. But the supplicant
can remove that AP from its list at any time (out of range, turned off,
etc), leading to a priv->current_ap that is no longer known to the
supplicant but still exists in the NM AP list. Since the supplicant
has forgotten it, NM will never receive a removal signal for it.
To ensure that a supplicant-forgotten priv->current_ap is removed
from the NM AP list when priv->current_ap is cleared or changed, mark
any AP removed by the supplicant as 'fake'. It will then always be
removed in set_current_ap() and not linger in the AP list forever like
a zombie.
Instead of tricky logic to merge APs and age them, just tell the
supplicant what our aging parameters are, and rely on it to handle
removal from the list. Notable behavioral changes are:
* APs will now be removed when they haven't been seen for two
consecutive scans in which they would have been included. This
means that when the scan interval is short, out-of-range APs will
be removed much more quickly than the previous 360 seconds.
* APs now live at most 250 seconds (twice our longest scan interval)
instead of the previous 360 seconds.
* The problem with wpa_supplicant < 2.3 not notifying that a BSS has
been seen in the scan if none of its properties actually changed is
now avoided, because an AP is only removed when the supplicant removes it
In general these changes should make the scan list more responsive, at
the cost of slightly more instability in the list due to the unreliability
of WiFi scanning. But it also removes a layer of complexity and
abstraction from NetworkManager, pushing the scan results list closer
to that which the hardware reports.
Most nm_platform_*() functions operate on the platform
singleton nm_platform_get(). That made sense because the
NMPlatform instance was mainly to hook fake platform for
testing.
While the implicit argument saved some typing, I think explicit is
better. Especially, because NMPlatform could become a more usable
object then just a hook for testing.
With this change, NMPlatform instances can be used individually, not
only as a singleton instance.
Before this change, the constructor of NMLinuxPlatform could not
call any nm_platform_*() functions because the singleton was not
yet initialized. We could only instantiate an incomplete instance,
register it via nm_platform_setup(), and then complete initialization
via singleton->setup().
With this change, we can create and fully initialize NMPlatform instances
before/without setting them up them as singleton.
Also, currently there is no clear distinction between functions
that operate on the NMPlatform instance, and functions that can
be used stand-alone (e.g. nm_platform_ip4_address_to_string()).
The latter can not be mocked for testing. With this change, the
distinction becomes obvious. That is also useful because it becomes
clearer which functions make use of the platform cache and which not.
Inside nm-linux-platform.c, continue the pattern that the
self instance is named @platform. That makes sense because
its type is NMPlatform, and not NMLinuxPlatform what we
would expect from a paramter named @self.
This is a major diff that causes some pain when rebasing. Try
to rebase to the parent commit of this commit as a first step.
Then rebase on top of this commit using merge-strategy "ours".
Some dual-band access points use the same BSSID in both the 5GHz
and 2.4GHz bands, so obviously frequency must be taken into account
when matching. But no AP should ever use the same SSID/BSSID pair
concurrently in the same band on different frequencies.
Some APs also dynamically channel hop when they detect interference,
or when they restart, they do so on a different channel after finding
the channel with the lowest interference. To assure that we don't
end up with stale scan list entries when the AP has switched to
another channel in the same band, fall back to band matching
when merging new scan results.
The only reason to allow lazy matching was to update a fake
current AP when its real scan result comes in. Now that NM
tracks the current AP based on the the supplicant's current
BSS, a fake current AP will be replaced when the real scan
result arrives. So it's pointless to update the fake one
when it'll just be removed soon.
Instead of keeping track of it internally, and attempting to fuzzy-match
access points and stuff, just use the supplicant's information. If the
supplicant doesn't know what AP it's talking to, then we've got more
problems than just NM code.
The theory here is that when starting activation, we'll use the given
access point from the scan list that the supplicant already knows about.
If there isn't one yet (adhoc, hidden, or AP mode) then we'll create
a fake AP and add it to the scan list.
Once the supplicant has associated to the AP, it'll notify about the
current BSS which we then look up in the scan list, and set
priv->current AP to that. If for some reason the given AP isn't yet
in our scan list (which often happens for adhoc/AP) then we'll just
live with the fake AP until we get the scan result, which should happen
very soon.
We don't need to do any fuzzy-matching to find the current AP because
it will either always be one the supplicant knows about, or a fake one
that the supplicant doesn't know about that will be replaced soon anyway.
A few places in the NMSupplicantInterface API and in NMDeviceWifi's
use of it were still using "GHashTable *properties" where they should
have been using "GVariant *properties". (This didn't cause any actual
problems because nothing was looking at those arguments.)
(Also fix a comment typo.)
It was confusing to understand the difference between calling nm_device_connection_is_available()
and check_connection_available(), they behaved similar, but not really
the same. Especially nm_device_connection_is_available() would look
first into @available_connetions, and might call check_connection_available()
itself. Whereas @available_connetions was also populated by testing
check_connection_available(). This interrelation makes it hard to
understand when nm_device_connection_is_available() returned true.
Rename nm_device_connection_is_available() to nm_device_check_connection_available()
and remove all direct calls of check_connection_available() in favor of
the wrapper nm_device_check_connection_available().
Now we only call nm_device_check_connection_available() with different
parameters (@flags and @specific_object). We also have the additional
guarantee that specifying more @flags will widen the result and making
a connection "more" available, while specifying a @specific_object will
restrict it.
This also changes behavior in several cases. For example before
nm_device_connection_is_available() for user-requests would always
declare matching connections available on Wi-Fi devices (only)
regardless of the device state. Now the device state gets consistently
considered.
For default-unmanaged devices it also changes behavior in complicated
ways, because before we would put connections into @available_connetions
for every device-state, but nm_device_connection_is_available() had a
special over-ride only for unmanaged-state.
This also fixes a bug, that user can activate an unavailable Wi-Fi
device:
nmcli radio wifi off
nmcli connection up wlan0
Having logging statements in a simple getter (or is_*()) means
you cannot call these functions without cluttering the log.
Another approach would be to add an @out_reason argument, and
callers who actually care log the reason. For now, just get rid
of the messages.
nm_device_get_hw_address() may return NULL and nm_platform_link_get_type may
return NM_LINK_TYPE_NONE. While it might be a good idea to check for such cases
at the init time it seems easier to just ignore it and prevent blowing up in
subsequent deactivation.
A quick test case:
# while :; do ip link add moo0 type veth peer moo1; ip link del moo0 ; done
Yields:
NetworkManager:ERROR:devices/nm-device-ethernet.c:268:constructor:
assertion failed: (link_type == NM_LINK_TYPE_ETHERNET ||
link_type == NM_LINK_TYPE_VETH)
nm_device_set_hw_addr: assertion 'addr != NULL' failed
https://bugzilla.gnome.org/show_bug.cgi?id=740992
config.h should be included from every .c file, and it should be
included before any other include. Fix that.
(As a side effect of how I did this, this also changes us to
consistently use "config.h" rather than <config.h>. To the extent that
it matters [which is not much], quotes are more correct anyway, since
we're talking about a file in our own build tree, not a system
include.)