summary refs log tree commit diff
path: root/src/devices/nm-device-factory.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/nm-device-factory.c')
-rw-r--r--src/devices/nm-device-factory.c593
1 files changed, 306 insertions, 287 deletions
diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c
index a7db2669..a238ce1b 100644
--- a/src/devices/nm-device-factory.c
+++ b/src/devices/nm-device-factory.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright (C) 2014 - 2018 Red Hat, Inc.
  */
@@ -20,375 +20,394 @@
 
 /*****************************************************************************/
 
-enum {
-	DEVICE_ADDED,
-	LAST_SIGNAL
-};
+enum { DEVICE_ADDED, LAST_SIGNAL };
 
-static guint signals[LAST_SIGNAL] = { 0 };
+static guint signals[LAST_SIGNAL] = {0};
 
-G_DEFINE_ABSTRACT_TYPE (NMDeviceFactory, nm_device_factory, G_TYPE_OBJECT)
+G_DEFINE_ABSTRACT_TYPE(NMDeviceFactory, nm_device_factory, G_TYPE_OBJECT)
 
 /*****************************************************************************/
 
 static void
-nm_device_factory_get_supported_types (NMDeviceFactory *factory,
-                                       const NMLinkType **out_link_types,
-                                       const char *const**out_setting_types)
+nm_device_factory_get_supported_types(NMDeviceFactory *   factory,
+                                      const NMLinkType ** out_link_types,
+                                      const char *const **out_setting_types)
 {
-	g_return_if_fail (NM_IS_DEVICE_FACTORY (factory));
+    g_return_if_fail(NM_IS_DEVICE_FACTORY(factory));
 
-	NM_DEVICE_FACTORY_GET_CLASS (factory)->get_supported_types (factory,
-	                                                            out_link_types,
-	                                                            out_setting_types);
+    NM_DEVICE_FACTORY_GET_CLASS(factory)->get_supported_types(factory,
+                                                              out_link_types,
+                                                              out_setting_types);
 }
 
 void
-nm_device_factory_start (NMDeviceFactory *factory)
+nm_device_factory_start(NMDeviceFactory *factory)
 {
-	g_return_if_fail (factory != NULL);
+    g_return_if_fail(factory != NULL);
 
-	if (NM_DEVICE_FACTORY_GET_CLASS (factory)->start)
-		NM_DEVICE_FACTORY_GET_CLASS (factory)->start (factory);
+    if (NM_DEVICE_FACTORY_GET_CLASS(factory)->start)
+        NM_DEVICE_FACTORY_GET_CLASS(factory)->start(factory);
 }
 
 NMDevice *
-nm_device_factory_create_device (NMDeviceFactory *factory,
-                                 const char *iface,
-                                 const NMPlatformLink *plink,
-                                 NMConnection *connection,
-                                 gboolean *out_ignore,
-                                 GError **error)
+nm_device_factory_create_device(NMDeviceFactory *     factory,
+                                const char *          iface,
+                                const NMPlatformLink *plink,
+                                NMConnection *        connection,
+                                gboolean *            out_ignore,
+                                GError **             error)
 {
-	NMDeviceFactoryClass *klass;
-	NMDevice *device;
-	gboolean ignore = FALSE;
-
-	g_return_val_if_fail (factory, NULL);
-	g_return_val_if_fail (iface && *iface, NULL);
-	if (plink) {
-		g_return_val_if_fail (!connection, NULL);
-		g_return_val_if_fail (strcmp (iface, plink->name) == 0, NULL);
-		nm_assert (factory == nm_device_factory_manager_find_factory_for_link_type (plink->type));
-	} else if (connection)
-		nm_assert (factory == nm_device_factory_manager_find_factory_for_connection (connection));
-	else
-		g_return_val_if_reached (NULL);
-
-	klass = NM_DEVICE_FACTORY_GET_CLASS (factory);
-	if (!klass->create_device) {
-		g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
-		             "Device factory %s cannot manage new devices",
-		             G_OBJECT_TYPE_NAME (factory));
-		NM_SET_OUT (out_ignore, FALSE);
-		return NULL;
-	}
-
-	device = klass->create_device (factory, iface, plink, connection, &ignore);
-	NM_SET_OUT (out_ignore, ignore);
-	if (!device) {
-		if (ignore) {
-			g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
-			             "Device factory %s ignores device %s",
-			             G_OBJECT_TYPE_NAME (factory), iface);
-		} else {
-			g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
-			             "Device factory %s failed to create device %s",
-			             G_OBJECT_TYPE_NAME (factory), iface);
-		}
-	}
-	return device;
+    NMDeviceFactoryClass *klass;
+    NMDevice *            device;
+    gboolean              ignore = FALSE;
+
+    g_return_val_if_fail(factory, NULL);
+    g_return_val_if_fail(iface && *iface, NULL);
+    if (plink) {
+        g_return_val_if_fail(!connection, NULL);
+        g_return_val_if_fail(strcmp(iface, plink->name) == 0, NULL);
+        nm_assert(factory == nm_device_factory_manager_find_factory_for_link_type(plink->type));
+    } else if (connection)
+        nm_assert(factory == nm_device_factory_manager_find_factory_for_connection(connection));
+    else
+        g_return_val_if_reached(NULL);
+
+    klass = NM_DEVICE_FACTORY_GET_CLASS(factory);
+    if (!klass->create_device) {
+        g_set_error(error,
+                    NM_MANAGER_ERROR,
+                    NM_MANAGER_ERROR_FAILED,
+                    "Device factory %s cannot manage new devices",
+                    G_OBJECT_TYPE_NAME(factory));
+        NM_SET_OUT(out_ignore, FALSE);
+        return NULL;
+    }
+
+    device = klass->create_device(factory, iface, plink, connection, &ignore);
+    NM_SET_OUT(out_ignore, ignore);
+    if (!device) {
+        if (ignore) {
+            g_set_error(error,
+                        NM_MANAGER_ERROR,
+                        NM_MANAGER_ERROR_FAILED,
+                        "Device factory %s ignores device %s",
+                        G_OBJECT_TYPE_NAME(factory),
+                        iface);
+        } else {
+            g_set_error(error,
+                        NM_MANAGER_ERROR,
+                        NM_MANAGER_ERROR_FAILED,
+                        "Device factory %s failed to create device %s",
+                        G_OBJECT_TYPE_NAME(factory),
+                        iface);
+        }
+    }
+    return device;
 }
 
 const char *
-nm_device_factory_get_connection_parent (NMDeviceFactory *factory,
-                                         NMConnection *connection)
+nm_device_factory_get_connection_parent(NMDeviceFactory *factory, NMConnection *connection)
 {
-	g_return_val_if_fail (factory != NULL, NULL);
-	g_return_val_if_fail (connection != NULL, NULL);
+    g_return_val_if_fail(factory != NULL, NULL);
+    g_return_val_if_fail(connection != NULL, NULL);
 
-	if (!nm_connection_is_virtual (connection))
-		return NULL;
+    if (!nm_connection_is_virtual(connection))
+        return NULL;
 
-	if (NM_DEVICE_FACTORY_GET_CLASS (factory)->get_connection_parent)
-		return NM_DEVICE_FACTORY_GET_CLASS (factory)->get_connection_parent (factory, connection);
-	return NULL;
+    if (NM_DEVICE_FACTORY_GET_CLASS(factory)->get_connection_parent)
+        return NM_DEVICE_FACTORY_GET_CLASS(factory)->get_connection_parent(factory, connection);
+    return NULL;
 }
 
 char *
-nm_device_factory_get_connection_iface (NMDeviceFactory *factory,
-                                        NMConnection *connection,
-                                        const char *parent_iface,
-                                        GError **error)
+nm_device_factory_get_connection_iface(NMDeviceFactory *factory,
+                                       NMConnection *   connection,
+                                       const char *     parent_iface,
+                                       GError **        error)
 {
-	NMDeviceFactoryClass *klass;
-	char *ifname;
+    NMDeviceFactoryClass *klass;
+    char *                ifname;
 
-	g_return_val_if_fail (factory != NULL, NULL);
-	g_return_val_if_fail (connection != NULL, NULL);
-	g_return_val_if_fail (!error || !*error, NULL);
+    g_return_val_if_fail(factory != NULL, NULL);
+    g_return_val_if_fail(connection != NULL, NULL);
+    g_return_val_if_fail(!error || !*error, NULL);
 
-	klass = NM_DEVICE_FACTORY_GET_CLASS (factory);
+    klass = NM_DEVICE_FACTORY_GET_CLASS(factory);
 
-	ifname = g_strdup (nm_connection_get_interface_name (connection));
-	if (!ifname && klass->get_connection_iface)
-		ifname = klass->get_connection_iface (factory, connection, parent_iface);
+    ifname = g_strdup(nm_connection_get_interface_name(connection));
+    if (!ifname && klass->get_connection_iface)
+        ifname = klass->get_connection_iface(factory, connection, parent_iface);
 
-	if (!ifname) {
-		g_set_error (error,
-		             NM_MANAGER_ERROR,
-		             NM_MANAGER_ERROR_FAILED,
-		             "failed to determine interface name: error determine name for %s",
-		             nm_connection_get_connection_type (connection));
-		return NULL;
-	}
+    if (!ifname) {
+        g_set_error(error,
+                    NM_MANAGER_ERROR,
+                    NM_MANAGER_ERROR_FAILED,
+                    "failed to determine interface name: error determine name for %s",
+                    nm_connection_get_connection_type(connection));
+        return NULL;
+    }
 
-	return ifname;
+    return ifname;
 }
 
 /*****************************************************************************/
 
 static void
-nm_device_factory_init (NMDeviceFactory *self)
-{
-}
+nm_device_factory_init(NMDeviceFactory *self)
+{}
 
 static void
-nm_device_factory_class_init (NMDeviceFactoryClass *klass)
+nm_device_factory_class_init(NMDeviceFactoryClass *klass)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-	signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED,
-	                                      G_OBJECT_CLASS_TYPE (object_class),
-	                                      G_SIGNAL_RUN_FIRST,
-	                                      0, NULL, NULL, NULL,
-	                                      G_TYPE_NONE, 1, NM_TYPE_DEVICE);
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    signals[DEVICE_ADDED] = g_signal_new(NM_DEVICE_FACTORY_DEVICE_ADDED,
+                                         G_OBJECT_CLASS_TYPE(object_class),
+                                         G_SIGNAL_RUN_FIRST,
+                                         0,
+                                         NULL,
+                                         NULL,
+                                         NULL,
+                                         G_TYPE_NONE,
+                                         1,
+                                         NM_TYPE_DEVICE);
 }
 
 /*****************************************************************************/
 
-static GHashTable *factories_by_link = NULL;
+static GHashTable *factories_by_link    = NULL;
 static GHashTable *factories_by_setting = NULL;
 
-static void __attribute__((destructor))
-_cleanup (void)
+static void __attribute__((destructor)) _cleanup(void)
 {
-	nm_clear_pointer (&factories_by_link, g_hash_table_unref);
-	nm_clear_pointer (&factories_by_setting, g_hash_table_unref);
+    nm_clear_pointer(&factories_by_link, g_hash_table_unref);
+    nm_clear_pointer(&factories_by_setting, g_hash_table_unref);
 }
 
 NMDeviceFactory *
-nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type)
+nm_device_factory_manager_find_factory_for_link_type(NMLinkType link_type)
 {
-	g_return_val_if_fail (factories_by_link, NULL);
+    g_return_val_if_fail(factories_by_link, NULL);
 
-	return g_hash_table_lookup (factories_by_link, GUINT_TO_POINTER (link_type));
+    return g_hash_table_lookup(factories_by_link, GUINT_TO_POINTER(link_type));
 }
 
 NMDeviceFactory *
-nm_device_factory_manager_find_factory_for_connection (NMConnection *connection)
+nm_device_factory_manager_find_factory_for_connection(NMConnection *connection)
 {
-	NMDeviceFactoryClass *klass;
-	NMDeviceFactory *factory;
-	const char *type;
-	GSList *list;
+    NMDeviceFactoryClass *klass;
+    NMDeviceFactory *     factory;
+    const char *          type;
+    GSList *              list;
 
-	g_return_val_if_fail (factories_by_setting, NULL);
+    g_return_val_if_fail(factories_by_setting, NULL);
 
-	type = nm_connection_get_connection_type (connection);
-	list = g_hash_table_lookup (factories_by_setting, type);
+    type = nm_connection_get_connection_type(connection);
+    list = g_hash_table_lookup(factories_by_setting, type);
 
-	for (; list; list = g_slist_next (list)) {
-		factory = list->data;
-		klass = NM_DEVICE_FACTORY_GET_CLASS (factory);
-		if (!klass->match_connection || klass->match_connection (factory, connection))
-			return factory;
-	}
+    for (; list; list = g_slist_next(list)) {
+        factory = list->data;
+        klass   = NM_DEVICE_FACTORY_GET_CLASS(factory);
+        if (!klass->match_connection || klass->match_connection(factory, connection))
+            return factory;
+    }
 
-	return NULL;
+    return NULL;
 }
 
 void
-nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc callback,
-                                            gpointer user_data)
+nm_device_factory_manager_for_each_factory(NMDeviceFactoryManagerFactoryFunc callback,
+                                           gpointer                          user_data)
 {
-	GHashTableIter iter;
-	NMDeviceFactory *factory;
-	GSList *list_iter, *list = NULL;
-
-	if (factories_by_link) {
-		g_hash_table_iter_init (&iter, factories_by_link);
-		while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) {
-			if (!g_slist_find (list, factory))
-				list = g_slist_prepend (list, factory);
-		}
-	}
-
-	if (factories_by_setting) {
-		g_hash_table_iter_init (&iter, factories_by_setting);
-		while (g_hash_table_iter_next (&iter, NULL, (gpointer) &list_iter)) {
-			for (; list_iter; list_iter = g_slist_next (list_iter)) {
-				if (!g_slist_find (list, list_iter->data))
-					list = g_slist_prepend (list, list_iter->data);
-			}
-		}
-	}
-
-	for (list_iter = list; list_iter; list_iter = list_iter->next)
-		callback (list_iter->data, user_data);
-
-	g_slist_free (list);
+    GHashTableIter   iter;
+    NMDeviceFactory *factory;
+    GSList *         list_iter, *list = NULL;
+
+    if (factories_by_link) {
+        g_hash_table_iter_init(&iter, factories_by_link);
+        while (g_hash_table_iter_next(&iter, NULL, (gpointer) &factory)) {
+            if (!g_slist_find(list, factory))
+                list = g_slist_prepend(list, factory);
+        }
+    }
+
+    if (factories_by_setting) {
+        g_hash_table_iter_init(&iter, factories_by_setting);
+        while (g_hash_table_iter_next(&iter, NULL, (gpointer) &list_iter)) {
+            for (; list_iter; list_iter = g_slist_next(list_iter)) {
+                if (!g_slist_find(list, list_iter->data))
+                    list = g_slist_prepend(list, list_iter->data);
+            }
+        }
+    }
+
+    for (list_iter = list; list_iter; list_iter = list_iter->next)
+        callback(list_iter->data, user_data);
+
+    g_slist_free(list);
 }
 
 static gboolean
-_add_factory (NMDeviceFactory *factory,
-              const char *path,
-              NMDeviceFactoryManagerFactoryFunc callback,
-              gpointer user_data)
+_add_factory(NMDeviceFactory *                 factory,
+             const char *                      path,
+             NMDeviceFactoryManagerFactoryFunc callback,
+             gpointer                          user_data)
 {
-	const NMLinkType *link_types = NULL;
-	const char *const*setting_types = NULL;
-	GSList *list, *list2;
-	int i;
-
-	g_return_val_if_fail (factories_by_link, FALSE);
-	g_return_val_if_fail (factories_by_setting, FALSE);
-
-	nm_device_factory_get_supported_types (factory, &link_types, &setting_types);
-
-	g_return_val_if_fail (   (link_types && link_types[0] > NM_LINK_TYPE_UNKNOWN)
-	                      || (setting_types && setting_types[0]),
-	                      FALSE);
-
-	for (i = 0; link_types && link_types[i] > NM_LINK_TYPE_UNKNOWN; i++)
-		g_hash_table_insert (factories_by_link, GUINT_TO_POINTER (link_types[i]), g_object_ref (factory));
-	for (i = 0; setting_types && setting_types[i]; i++) {
-		list = g_hash_table_lookup (factories_by_setting, (char *) setting_types[i]);
-		if (list) {
-			list2 = g_slist_append (list, g_object_ref (factory));
-			nm_assert (list == list2);
-		} else {
-			list = g_slist_append (list, g_object_ref (factory));
-			g_hash_table_insert (factories_by_setting, (char *) setting_types[i], list);
-		}
-	}
-
-	callback (factory, user_data);
-
-	nm_log (path ? LOGL_INFO : LOGL_DEBUG,
-	        LOGD_PLATFORM,
-	        NULL, NULL,
-	        "Loaded device plugin: %s (%s)",
-	        G_OBJECT_TYPE_NAME (factory),
-	        path ?: "internal");
-	return TRUE;
+    const NMLinkType * link_types    = NULL;
+    const char *const *setting_types = NULL;
+    GSList *           list, *list2;
+    int                i;
+
+    g_return_val_if_fail(factories_by_link, FALSE);
+    g_return_val_if_fail(factories_by_setting, FALSE);
+
+    nm_device_factory_get_supported_types(factory, &link_types, &setting_types);
+
+    g_return_val_if_fail((link_types && link_types[0] > NM_LINK_TYPE_UNKNOWN)
+                             || (setting_types && setting_types[0]),
+                         FALSE);
+
+    for (i = 0; link_types && link_types[i] > NM_LINK_TYPE_UNKNOWN; i++)
+        g_hash_table_insert(factories_by_link,
+                            GUINT_TO_POINTER(link_types[i]),
+                            g_object_ref(factory));
+    for (i = 0; setting_types && setting_types[i]; i++) {
+        list = g_hash_table_lookup(factories_by_setting, (char *) setting_types[i]);
+        if (list) {
+            list2 = g_slist_append(list, g_object_ref(factory));
+            nm_assert(list == list2);
+        } else {
+            list = g_slist_append(list, g_object_ref(factory));
+            g_hash_table_insert(factories_by_setting, (char *) setting_types[i], list);
+        }
+    }
+
+    callback(factory, user_data);
+
+    nm_log(path ? LOGL_INFO : LOGL_DEBUG,
+           LOGD_PLATFORM,
+           NULL,
+           NULL,
+           "Loaded device plugin: %s (%s)",
+           G_OBJECT_TYPE_NAME(factory),
+           path ?: "internal");
+    return TRUE;
 }
 
 static void
-_load_internal_factory (GType factory_gtype,
-                        NMDeviceFactoryManagerFactoryFunc callback,
-                        gpointer user_data)
+_load_internal_factory(GType                             factory_gtype,
+                       NMDeviceFactoryManagerFactoryFunc callback,
+                       gpointer                          user_data)
 {
-	gs_unref_object NMDeviceFactory *factory = NULL;
+    gs_unref_object NMDeviceFactory *factory = NULL;
 
-	factory = (NMDeviceFactory *) g_object_new (factory_gtype, NULL);
-	_add_factory (factory, NULL, callback, user_data);
+    factory = (NMDeviceFactory *) g_object_new(factory_gtype, NULL);
+    _add_factory(factory, NULL, callback, user_data);
 }
 
 static void
-factories_list_unref (GSList *list)
+factories_list_unref(GSList *list)
 {
-	g_slist_free_full (list, g_object_unref);
+    g_slist_free_full(list, g_object_unref);
 }
 
 static void
-load_factories_from_dir (const char *dirname,
-                         NMDeviceFactoryManagerFactoryFunc callback,
-                         gpointer user_data)
+load_factories_from_dir(const char *                      dirname,
+                        NMDeviceFactoryManagerFactoryFunc callback,
+                        gpointer                          user_data)
 {
-	NMDeviceFactory *factory;
-	GError *error = NULL;
-	char **path, **paths;
-
-	paths = nm_utils_read_plugin_paths (dirname, PLUGIN_PREFIX);
-	if (!paths)
-		return;
-
-	for (path = paths; *path; path++) {
-		GModule *plugin;
-		NMDeviceFactoryCreateFunc create_func;
-		const char *item;
-
-		item = strrchr (*path, '/');
-		g_assert (item);
-
-		plugin = g_module_open (*path, G_MODULE_BIND_LOCAL);
-
-		if (!plugin) {
-			nm_log_warn (LOGD_PLATFORM, "(%s): failed to load plugin: %s", item, g_module_error ());
-			continue;
-		}
-
-		if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) {
-			nm_log_warn (LOGD_PLATFORM, "(%s): failed to find device factory creator: %s", item, g_module_error ());
-			g_module_close (plugin);
-			continue;
-		}
-
-		/* after loading glib types from the plugin, we cannot unload the library anymore.
-		 * Make it resident. */
-		g_module_make_resident (plugin);
-
-		factory = create_func (&error);
-		if (!factory) {
-			nm_log_warn (LOGD_PLATFORM, "(%s): failed to initialize device factory: %s",
-			             item, NM_G_ERROR_MSG (error));
-			g_clear_error (&error);
-			continue;
-		}
-		g_clear_error (&error);
-
-		_add_factory (factory, g_module_name (plugin), callback, user_data);
-
-		g_object_unref (factory);
-	}
-	g_strfreev (paths);
+    NMDeviceFactory *factory;
+    GError *         error = NULL;
+    char **          path, **paths;
+
+    paths = nm_utils_read_plugin_paths(dirname, PLUGIN_PREFIX);
+    if (!paths)
+        return;
+
+    for (path = paths; *path; path++) {
+        GModule *                 plugin;
+        NMDeviceFactoryCreateFunc create_func;
+        const char *              item;
+
+        item = strrchr(*path, '/');
+        g_assert(item);
+
+        plugin = g_module_open(*path, G_MODULE_BIND_LOCAL);
+
+        if (!plugin) {
+            nm_log_warn(LOGD_PLATFORM, "(%s): failed to load plugin: %s", item, g_module_error());
+            continue;
+        }
+
+        if (!g_module_symbol(plugin, "nm_device_factory_create", (gpointer) &create_func)) {
+            nm_log_warn(LOGD_PLATFORM,
+                        "(%s): failed to find device factory creator: %s",
+                        item,
+                        g_module_error());
+            g_module_close(plugin);
+            continue;
+        }
+
+        /* after loading glib types from the plugin, we cannot unload the library anymore.
+         * Make it resident. */
+        g_module_make_resident(plugin);
+
+        factory = create_func(&error);
+        if (!factory) {
+            nm_log_warn(LOGD_PLATFORM,
+                        "(%s): failed to initialize device factory: %s",
+                        item,
+                        NM_G_ERROR_MSG(error));
+            g_clear_error(&error);
+            continue;
+        }
+        g_clear_error(&error);
+
+        _add_factory(factory, g_module_name(plugin), callback, user_data);
+
+        g_object_unref(factory);
+    }
+    g_strfreev(paths);
 }
 
 void
-nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback,
-                                          gpointer user_data)
+nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callback,
+                                         gpointer                          user_data)
 {
-	g_return_if_fail (factories_by_link == NULL);
-	g_return_if_fail (factories_by_setting == NULL);
-
-	factories_by_link = g_hash_table_new_full (nm_direct_hash, NULL, NULL, g_object_unref);
-	factories_by_setting = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, (GDestroyNotify) factories_list_unref);
-
-#define _ADD_INTERNAL(get_type_fcn) \
-	G_STMT_START { \
-		GType get_type_fcn (void); \
-		_load_internal_factory (get_type_fcn (), \
-		                        callback, user_data); \
-	} G_STMT_END
-
-	_ADD_INTERNAL (nm_6lowpan_device_factory_get_type);
-	_ADD_INTERNAL (nm_bond_device_factory_get_type);
-	_ADD_INTERNAL (nm_bridge_device_factory_get_type);
-	_ADD_INTERNAL (nm_dummy_device_factory_get_type);
-	_ADD_INTERNAL (nm_ethernet_device_factory_get_type);
-	_ADD_INTERNAL (nm_infiniband_device_factory_get_type);
-	_ADD_INTERNAL (nm_ip_tunnel_device_factory_get_type);
-	_ADD_INTERNAL (nm_macsec_device_factory_get_type);
-	_ADD_INTERNAL (nm_macvlan_device_factory_get_type);
-	_ADD_INTERNAL (nm_ppp_device_factory_get_type);
-	_ADD_INTERNAL (nm_tun_device_factory_get_type);
-	_ADD_INTERNAL (nm_veth_device_factory_get_type);
-	_ADD_INTERNAL (nm_vlan_device_factory_get_type);
-	_ADD_INTERNAL (nm_vrf_device_factory_get_type);
-	_ADD_INTERNAL (nm_vxlan_device_factory_get_type);
-	_ADD_INTERNAL (nm_wireguard_device_factory_get_type);
-	_ADD_INTERNAL (nm_wpan_device_factory_get_type);
-
-	load_factories_from_dir (NMPLUGINDIR, callback, user_data);
+    g_return_if_fail(factories_by_link == NULL);
+    g_return_if_fail(factories_by_setting == NULL);
+
+    factories_by_link    = g_hash_table_new_full(nm_direct_hash, NULL, NULL, g_object_unref);
+    factories_by_setting = g_hash_table_new_full(nm_str_hash,
+                                                 g_str_equal,
+                                                 NULL,
+                                                 (GDestroyNotify) factories_list_unref);
+
+#define _ADD_INTERNAL(get_type_fcn)                                  \
+    G_STMT_START                                                     \
+    {                                                                \
+        GType get_type_fcn(void);                                    \
+        _load_internal_factory(get_type_fcn(), callback, user_data); \
+    }                                                                \
+    G_STMT_END
+
+    _ADD_INTERNAL(nm_6lowpan_device_factory_get_type);
+    _ADD_INTERNAL(nm_bond_device_factory_get_type);
+    _ADD_INTERNAL(nm_bridge_device_factory_get_type);
+    _ADD_INTERNAL(nm_dummy_device_factory_get_type);
+    _ADD_INTERNAL(nm_ethernet_device_factory_get_type);
+    _ADD_INTERNAL(nm_infiniband_device_factory_get_type);
+    _ADD_INTERNAL(nm_ip_tunnel_device_factory_get_type);
+    _ADD_INTERNAL(nm_macsec_device_factory_get_type);
+    _ADD_INTERNAL(nm_macvlan_device_factory_get_type);
+    _ADD_INTERNAL(nm_ppp_device_factory_get_type);
+    _ADD_INTERNAL(nm_tun_device_factory_get_type);
+    _ADD_INTERNAL(nm_veth_device_factory_get_type);
+    _ADD_INTERNAL(nm_vlan_device_factory_get_type);
+    _ADD_INTERNAL(nm_vrf_device_factory_get_type);
+    _ADD_INTERNAL(nm_vxlan_device_factory_get_type);
+    _ADD_INTERNAL(nm_wireguard_device_factory_get_type);
+    _ADD_INTERNAL(nm_wpan_device_factory_get_type);
+
+    load_factories_from_dir(NMPLUGINDIR, callback, user_data);
 }