summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Zaborowski <andrew.zaborowski@intel.com>2020-11-04 01:35:21 +0100
committerThomas Haller <thaller@redhat.com>2020-11-12 15:38:02 +0100
commitfde2757b2d1a8081c3d13daa02fcc3e0d5a9a618 (patch)
treefb60737eb9f1d4cff9f4adeace78a04c2e41b9e2
parentde423080fc86bda9d88b8d0f6ea54aeda09ff5e6 (diff)
downloadNetworkManager-fde2757b2d1a8081c3d13daa02fcc3e0d5a9a618.tar.gz
iwd: Order objects from g_dbus_object_manager_get_objects
Before we call interface_added for all interfaces and objects returned from g_dbus_object_manager_get_objects(), order the objects based on the interfaces present on them. This is to avoid processing Network.KnownNetwork properties referring to KnownNetwork objects that we haven't processed yet, and new Station.ConnectedNetwork properties referring to Network objects we haven't processed yet. In NMDeviceIwd make sure we don't emit unnecessary re-checks if device is not yet enabled because now we're always going to be adding the APs (representing IWD Network objects) before the device is enabled, i.e. before the nm_device_iwd_set_dbus_object() call, when NM first connects to IWD.
-rw-r--r--src/devices/wifi/nm-device-iwd.c6
-rw-r--r--src/devices/wifi/nm-iwd-manager.c76
2 files changed, 80 insertions, 2 deletions
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index 0e4afc9ee1..8cd7091e3a 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -136,7 +136,9 @@ ap_add_remove(NMDeviceIwd *self,
nm_dbus_object_clear_and_unexport(&ap);
}
- nm_device_emit_recheck_auto_activate(NM_DEVICE(self));
+ if (priv->enabled)
+ nm_device_emit_recheck_auto_activate(NM_DEVICE(self));
+
if (recheck_available_connections)
nm_device_recheck_available_connections(NM_DEVICE(self));
}
@@ -2695,7 +2697,7 @@ nm_device_iwd_network_add_remove(NMDeviceIwd *self, GDBusProxy *network, bool ad
* can skip recheck-available if we're currently scanning or in the middle
* of a GetOrderedNetworks() call as that will trigger the recheck too.
*/
- recheck = !priv->scanning && !priv->networks_requested;
+ recheck = priv->enabled && !priv->scanning && !priv->networks_requested;
if (!add) {
if (ap) {
diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c
index b4f567d3c6..6eebccbba4 100644
--- a/src/devices/wifi/nm-iwd-manager.c
+++ b/src/devices/wifi/nm-iwd-manager.c
@@ -982,7 +982,28 @@ device_added(NMManager *manager, NMDevice *device, gpointer user_data)
if (!priv->running)
return;
+ /* Here we handle a potential scenario where IWD's DBus objects for the
+ * new device popped up before the NMDevice. The
+ * interface_added/object_added signals have been received already and
+ * the handlers couldn't do much because the NMDevice wasn't there yet
+ * so now we go over the Network and Device interfaces again. In this
+ * exact order for "object path" property consistency -- see reasoning
+ * in object_compare_interfaces.
+ */
objects = g_dbus_object_manager_get_objects(priv->object_manager);
+
+ for (iter = objects; iter; iter = iter->next) {
+ GDBusObject * object = G_DBUS_OBJECT(iter->data);
+ gs_unref_object GDBusInterface *interface = NULL;
+
+ interface = g_dbus_object_get_interface(object, NM_IWD_NETWORK_INTERFACE);
+ if (!interface)
+ continue;
+
+ if (NM_DEVICE_IWD(device) == get_device_from_network(self, (GDBusProxy *) interface))
+ nm_device_iwd_network_add_remove(NM_DEVICE_IWD(device), (GDBusProxy *) interface, TRUE);
+ }
+
for (iter = objects; iter; iter = iter->next) {
GDBusObject * object = G_DBUS_OBJECT(iter->data);
gs_unref_object GDBusInterface *interface = NULL;
@@ -1014,6 +1035,60 @@ device_removed(NMManager *manager, NMDevice *device, gpointer user_data)
priv->last_agent_call_device = NULL;
}
+/* This is used to sort the list of objects returned by GetManagedObjects()
+ * based on the DBus interfaces available on these objects in such a way that
+ * the interface_added calls happen in the right order. The order is defined
+ * by how some DBus interfaces point to interfaces on other objects using
+ * DBus properties of the type "object path" ("o" signature). This creates
+ * "dependencies" between objects.
+ *
+ * When NM and IWD are running, the InterfacesAdded signals should come in
+ * an order that ensures consistency of those object paths. For example
+ * when a Network interface is added with a KnownNetwork property, or that
+ * property is assigned a new value, the KnownNetwork object pointed to by
+ * it will have been added in an earlier InterfacesAdded signal. Similarly
+ * Station.ConnectedNetwork and Station.GetOrdereNetworks() only point to
+ * existing Network objects. (There may be circular dependencies but during
+ * initialization we only need a subset of those properties that doesn't
+ * have this problem.)
+ *
+ * But GetManagedObjects doesn't guarantee this kind of consistency so we
+ * order the returned object list ourselves to simplify the job of
+ * interface_added(). Objects that don't have any interfaces listed in
+ * interface_order are moved to the end of the list.
+ */
+static gint
+object_compare_interfaces(gconstpointer a, gconstpointer b)
+{
+ static const char *interface_order[] = {
+ NM_IWD_KNOWN_NETWORK_INTERFACE,
+ NM_IWD_NETWORK_INTERFACE,
+ NM_IWD_DEVICE_INTERFACE,
+ };
+ gint rank_a = G_N_ELEMENTS(interface_order);
+ gint rank_b = G_N_ELEMENTS(interface_order);
+ guint pos;
+
+ for (pos = 0; interface_order[pos]; pos++) {
+ GDBusInterface *iface_a;
+ GDBusInterface *iface_b;
+
+ if (rank_a == G_N_ELEMENTS(interface_order)
+ && (iface_a = g_dbus_object_get_interface(G_DBUS_OBJECT(a), interface_order[pos]))) {
+ rank_a = pos;
+ g_object_unref(iface_a);
+ }
+
+ if (rank_b == G_N_ELEMENTS(interface_order)
+ && (iface_b = g_dbus_object_get_interface(G_DBUS_OBJECT(b), interface_order[pos]))) {
+ rank_b = pos;
+ g_object_unref(iface_b);
+ }
+ }
+
+ return rank_a - rank_b;
+}
+
static void
got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data)
{
@@ -1069,6 +1144,7 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data)
g_hash_table_remove_all(priv->known_networks);
objects = g_dbus_object_manager_get_objects(object_manager);
+ objects = g_list_sort(objects, object_compare_interfaces);
for (iter = objects; iter; iter = iter->next)
object_added(NULL, G_DBUS_OBJECT(iter->data), self);