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.
This commit is contained in:

committed by
Thomas Haller

parent
abc6177448
commit
43fd93d8f4
@@ -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));
|
||||
}
|
||||
@@ -2693,7 +2695,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) {
|
||||
|
@@ -975,7 +975,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;
|
||||
@@ -1007,6 +1028,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 int
|
||||
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,
|
||||
};
|
||||
int rank_a = G_N_ELEMENTS(interface_order);
|
||||
int 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)
|
||||
{
|
||||
@@ -1062,6 +1137,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);
|
||||
|
||||
|
Reference in New Issue
Block a user