Blame src/devices/nm-device-factory.c

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