Blame opae-libs/libopae-c/pluginmgr.c

Packit 534379
// Copyright(c) 2018-2020, Intel Corporation
Packit 534379
//
Packit 534379
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
Packit 534379
// modification, are permitted provided that the following conditions are met:
Packit 534379
//
Packit 534379
// * Redistributions of  source code  must retain the  above copyright notice,
Packit 534379
//   this list of conditions and the following disclaimer.
Packit 534379
// * Redistributions in binary form must reproduce the above copyright notice,
Packit 534379
//   this list of conditions and the following disclaimer in the documentation
Packit 534379
//   and/or other materials provided with the distribution.
Packit 534379
// * Neither the name  of Intel Corporation  nor the names of its contributors
Packit 534379
//   may be used to  endorse or promote  products derived  from this  software
Packit 534379
//   without specific prior written permission.
Packit 534379
//
Packit 534379
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 534379
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
Packit 534379
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 534379
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
Packit 534379
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
Packit 534379
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
Packit 534379
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
Packit 534379
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
Packit 534379
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
Packit 534379
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
Packit 534379
// POSSIBILITY OF SUCH DAMAGE.
Packit 534379
Packit 534379
#ifdef HAVE_CONFIG_H
Packit 534379
#include <config.h>
Packit 534379
#endif /* HAVE_CONFIG_H */
Packit 534379
#define _GNU_SOURCE
Packit 534379
#include <stdio.h>
Packit 534379
#include <stdlib.h>
Packit 534379
#include <string.h>
Packit 534379
#include <stdint.h>
Packit 534379
#include <dlfcn.h>
Packit 534379
#include <sys/types.h>
Packit 534379
#include <dirent.h>
Packit 534379
#include <linux/limits.h>
Packit 534379
#include <pthread.h>
Packit 534379
#include <pwd.h>
Packit 534379
#include <unistd.h>
Packit 534379
Packit 534379
#include <json-c/json.h>
Packit 534379
Packit 534379
#include "pluginmgr.h"
Packit 534379
#include "opae_int.h"
Packit 534379
Packit 534379
#define OPAE_PLUGIN_CONFIGURE "opae_plugin_configure"
Packit 534379
typedef int (*opae_plugin_configure_t)(opae_api_adapter_table *, const char *);
Packit 534379
Packit 534379
typedef struct _platform_data {
Packit 534379
	uint16_t vendor_id;
Packit 534379
	uint16_t device_id;
Packit 534379
	const char *native_plugin;
Packit 534379
	uint32_t flags;
Packit 534379
#define OPAE_PLATFORM_DATA_DETECTED 0x00000001
Packit 534379
#define OPAE_PLATFORM_DATA_LOADED   0x00000002
Packit 534379
} platform_data;
Packit 534379
Packit 534379
static platform_data platform_data_table[] = {
Packit 534379
	{ 0x8086, 0xbcbd, "libxfpga.so", 0 },
Packit 534379
	{ 0x8086, 0xbcc0, "libxfpga.so", 0 },
Packit 534379
	{ 0x8086, 0xbcc1, "libxfpga.so", 0 },
Packit 534379
	{ 0x8086, 0x09c4, "libxfpga.so", 0 },
Packit 534379
	{ 0x8086, 0x09c5, "libxfpga.so", 0 },
Packit 534379
	{ 0x8086, 0x0b2b, "libxfpga.so", 0 },
Packit 534379
	{ 0x8086, 0x0b2c, "libxfpga.so", 0 },
Packit 534379
	{ 0x8086, 0x0b30, "libxfpga.so", 0 },
Packit 534379
	{ 0x8086, 0x0b31, "libxfpga.so", 0 },
Packit 534379
	{      0,      0,          NULL, 0 },
Packit 534379
};
Packit 534379
Packit 534379
static int initialized;
Packit 534379
static int finalizing;
Packit 534379
Packit 534379
STATIC opae_api_adapter_table *adapter_list = (void *)0;
Packit 534379
static pthread_mutex_t adapter_list_lock =
Packit 534379
	PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
Packit 534379
Packit 534379
#define MAX_PLUGINS PLUGIN_SUPPORTED_DEVICES_MAX
Packit 534379
STATIC plugin_cfg *opae_plugin_mgr_config_list;
Packit 534379
STATIC int opae_plugin_mgr_plugin_count;
Packit 534379
Packit 534379
#define CFG_PATH_MAX 64
Packit 534379
#define HOME_CFG_PATHS 3
Packit 534379
STATIC const char _opae_home_cfg_files[HOME_CFG_PATHS][CFG_PATH_MAX] = {
Packit 534379
	{ "/.local/opae.cfg" },
Packit 534379
	{ "/.local/opae/opae.cfg" },
Packit 534379
	{ "/.config/opae/opae.cfg" },
Packit 534379
};
Packit 534379
#define SYS_CFG_PATHS 2
Packit 534379
STATIC const char _opae_sys_cfg_files[SYS_CFG_PATHS][CFG_PATH_MAX] = {
Packit 534379
	{ "/usr/local/etc/opae/opae.cfg" },
Packit 534379
	{ "/etc/opae/opae.cfg" },
Packit 534379
};
Packit 534379
Packit 534379
Packit 534379
// Find the canonicalized configuration file. If null, the file was not found.
Packit 534379
// Otherwise, it's the first configuration file found from a list of possible
Packit 534379
// paths. Note: The char * returned is allocated here, caller must free.
Packit 534379
STATIC char *find_cfg(void)
Packit 534379
{
Packit 534379
	int i = 0;
Packit 534379
	char *file_name = NULL;
Packit 534379
	char home_cfg[PATH_MAX] = { 0, };
Packit 534379
	char *home_cfg_ptr = &home_cfg[0];
Packit 534379
	size_t len;
Packit 534379
Packit 534379
	// get the user's home directory
Packit 534379
	struct passwd *user_passwd = getpwuid(getuid());
Packit 534379
Packit 534379
	// first look in possible paths in the users home directory
Packit 534379
	for (i = 0; i < HOME_CFG_PATHS; ++i) {
Packit 534379
		len = strnlen(user_passwd->pw_dir,
Packit 534379
			      sizeof(home_cfg) - 1);
Packit 534379
		memcpy(home_cfg, user_passwd->pw_dir, len);
Packit 534379
		home_cfg[len] = '\0';
Packit 534379
Packit 534379
		home_cfg_ptr = home_cfg + strlen(home_cfg);
Packit 534379
Packit 534379
		len = strnlen(_opae_home_cfg_files[i], CFG_PATH_MAX);
Packit 534379
		memcpy(home_cfg_ptr, _opae_home_cfg_files[i], len);
Packit 534379
		home_cfg_ptr[len] = '\0';
Packit 534379
Packit 534379
		file_name = canonicalize_file_name(home_cfg);
Packit 534379
		if (file_name)
Packit 534379
			return file_name;
Packit 534379
Packit 534379
		home_cfg[0] = '\0';
Packit 534379
	}
Packit 534379
Packit 534379
	// now look in possible system paths
Packit 534379
	for (i = 0; i < SYS_CFG_PATHS; ++i) {
Packit 534379
		len = strnlen(_opae_sys_cfg_files[i], CFG_PATH_MAX);
Packit 534379
		memcpy(home_cfg, _opae_sys_cfg_files[i], len);
Packit 534379
		home_cfg[len] = '\0';
Packit 534379
Packit 534379
		file_name = canonicalize_file_name(home_cfg);
Packit 534379
		if (file_name)
Packit 534379
			return file_name;
Packit 534379
	}
Packit 534379
Packit 534379
	return NULL;
Packit 534379
}
Packit 534379
Packit 534379
STATIC void *opae_plugin_mgr_find_plugin(const char *lib_path)
Packit 534379
{
Packit 534379
	char plugin_path[PATH_MAX];
Packit 534379
	const char *search_paths[] = { OPAE_MODULE_SEARCH_PATHS };
Packit 534379
	unsigned i;
Packit 534379
	void *dl_handle;
Packit 534379
Packit 534379
	for (i = 0 ;
Packit 534379
		i < sizeof(search_paths) / sizeof(search_paths[0]) ; ++i) {
Packit 534379
Packit 534379
		snprintf(plugin_path, sizeof(plugin_path),
Packit 534379
			 "%s%s", search_paths[i], lib_path);
Packit 534379
Packit 534379
		dl_handle = dlopen(plugin_path, RTLD_LAZY | RTLD_LOCAL);
Packit 534379
Packit 534379
		if (dl_handle)
Packit 534379
			return dl_handle;
Packit 534379
	}
Packit 534379
Packit 534379
	return NULL;
Packit 534379
}
Packit 534379
Packit 534379
STATIC opae_api_adapter_table *opae_plugin_mgr_alloc_adapter(const char *lib_path)
Packit 534379
{
Packit 534379
	void *dl_handle;
Packit 534379
	opae_api_adapter_table *adapter;
Packit 534379
Packit 534379
	dl_handle = opae_plugin_mgr_find_plugin(lib_path);
Packit 534379
Packit 534379
	if (!dl_handle) {
Packit 534379
		char *err = dlerror();
Packit 534379
		OPAE_ERR("failed to load \"%s\" %s", lib_path, err ? err : "");
Packit 534379
		return NULL;
Packit 534379
	}
Packit 534379
Packit 534379
	adapter = (opae_api_adapter_table *)calloc(
Packit 534379
		1, sizeof(opae_api_adapter_table));
Packit 534379
Packit 534379
	if (!adapter) {
Packit 534379
		dlclose(dl_handle);
Packit 534379
		OPAE_ERR("out of memory");
Packit 534379
		return NULL;
Packit 534379
	}
Packit 534379
Packit 534379
	adapter->plugin.path = (char *)lib_path;
Packit 534379
	adapter->plugin.dl_handle = dl_handle;
Packit 534379
Packit 534379
	return adapter;
Packit 534379
}
Packit 534379
Packit 534379
STATIC int opae_plugin_mgr_free_adapter(opae_api_adapter_table *adapter)
Packit 534379
{
Packit 534379
	int res;
Packit 534379
	char *err;
Packit 534379
Packit 534379
	res = dlclose(adapter->plugin.dl_handle);
Packit 534379
Packit 534379
	if (res) {
Packit 534379
		err = dlerror();
Packit 534379
		OPAE_ERR("dlclose failed with %d %s", res, err ? err : "");
Packit 534379
	}
Packit 534379
Packit 534379
	free(adapter);
Packit 534379
Packit 534379
	return res;
Packit 534379
}
Packit 534379
Packit 534379
STATIC int opae_plugin_mgr_configure_plugin(opae_api_adapter_table *adapter,
Packit 534379
					    const char *config)
Packit 534379
{
Packit 534379
	opae_plugin_configure_t cfg;
Packit 534379
Packit 534379
	cfg = (opae_plugin_configure_t)dlsym(adapter->plugin.dl_handle,
Packit 534379
					     OPAE_PLUGIN_CONFIGURE);
Packit 534379
Packit 534379
	if (!cfg) {
Packit 534379
		OPAE_ERR("failed to find %s in \"%s\"", OPAE_PLUGIN_CONFIGURE,
Packit 534379
			 adapter->plugin.path);
Packit 534379
		return 1;
Packit 534379
	}
Packit 534379
Packit 534379
	return cfg(adapter, config);
Packit 534379
}
Packit 534379
Packit 534379
STATIC void opae_plugin_mgr_reset_cfg(void)
Packit 534379
{
Packit 534379
	plugin_cfg *ptr = opae_plugin_mgr_config_list;
Packit 534379
	plugin_cfg *tmp = NULL;
Packit 534379
	while (ptr) {
Packit 534379
		tmp = ptr;
Packit 534379
		ptr = ptr->next;
Packit 534379
		free(tmp->cfg);
Packit 534379
		free(tmp);
Packit 534379
	}
Packit 534379
	opae_plugin_mgr_config_list = NULL;
Packit 534379
	opae_plugin_mgr_plugin_count = 0;
Packit 534379
}
Packit 534379
Packit 534379
STATIC void opae_plugin_mgr_add_plugin(plugin_cfg *cfg)
Packit 534379
{
Packit 534379
	plugin_cfg *ptr = opae_plugin_mgr_config_list;
Packit 534379
	cfg->next = NULL;
Packit 534379
	if (!ptr) {
Packit 534379
		opae_plugin_mgr_config_list = cfg;
Packit 534379
	} else {
Packit 534379
		while (ptr->next) {
Packit 534379
			ptr = ptr->next;
Packit 534379
		}
Packit 534379
		ptr->next = cfg;
Packit 534379
	}
Packit 534379
	opae_plugin_mgr_plugin_count++;
Packit 534379
}
Packit 534379
Packit 534379
STATIC int opae_plugin_mgr_initialize_all(void)
Packit 534379
{
Packit 534379
	int res;
Packit 534379
	opae_api_adapter_table *aptr;
Packit 534379
	int errors = 0;
Packit 534379
Packit 534379
	for (aptr = adapter_list; aptr; aptr = aptr->next) {
Packit 534379
Packit 534379
		if (aptr->initialize) {
Packit 534379
			res = aptr->initialize();
Packit 534379
			if (res) {
Packit 534379
				OPAE_MSG("\"%s\" initialize() routine failed",
Packit 534379
					 aptr->plugin.path);
Packit 534379
				++errors;
Packit 534379
			}
Packit 534379
		}
Packit 534379
	}
Packit 534379
Packit 534379
	return errors;
Packit 534379
}
Packit 534379
Packit 534379
int opae_plugin_mgr_finalize_all(void)
Packit 534379
{
Packit 534379
	int res;
Packit 534379
	opae_api_adapter_table *aptr;
Packit 534379
	int errors = 0;
Packit 534379
	int i = 0;
Packit 534379
Packit 534379
	opae_mutex_lock(res, &adapter_list_lock);
Packit 534379
Packit 534379
	if (finalizing)
Packit 534379
		return 0;
Packit 534379
Packit 534379
	finalizing = 1;
Packit 534379
Packit 534379
	for (aptr = adapter_list; aptr;) {
Packit 534379
		opae_api_adapter_table *trash;
Packit 534379
Packit 534379
		if (aptr->finalize) {
Packit 534379
			res = aptr->finalize();
Packit 534379
			if (res) {
Packit 534379
				OPAE_MSG("\"%s\" finalize() routine failed",
Packit 534379
					 aptr->plugin.path);
Packit 534379
				++errors;
Packit 534379
			}
Packit 534379
		}
Packit 534379
Packit 534379
		trash = aptr;
Packit 534379
		aptr = aptr->next;
Packit 534379
Packit 534379
		if (opae_plugin_mgr_free_adapter(trash))
Packit 534379
			++errors;
Packit 534379
	}
Packit 534379
Packit 534379
	adapter_list = NULL;
Packit 534379
Packit 534379
	// reset platforms detected to 0
Packit 534379
	for (i = 0 ; platform_data_table[i].native_plugin ; ++i) {
Packit 534379
		platform_data_table[i].flags = 0;
Packit 534379
	}
Packit 534379
Packit 534379
	opae_plugin_mgr_reset_cfg();
Packit 534379
	initialized = 0;
Packit 534379
	finalizing = 0;
Packit 534379
	opae_mutex_unlock(res, &adapter_list_lock);
Packit 534379
Packit 534379
	return errors;
Packit 534379
}
Packit 534379
Packit 534379
#define JSON_GET(_jobj, _key, _jvar)                                           \
Packit 534379
	do {                                                                   \
Packit 534379
		if (!json_object_object_get_ex(_jobj, _key, _jvar)) {          \
Packit 534379
			OPAE_ERR("Error getting object: %s", _key);            \
Packit 534379
			return 1;                                              \
Packit 534379
		}                                                              \
Packit 534379
	} while (0)
Packit 534379
Packit 534379
#define MAX_PLUGIN_CFG_SIZE 8192
Packit 534379
STATIC int process_plugin(const char *name, json_object *j_config)
Packit 534379
{
Packit 534379
	json_object *j_plugin = NULL;
Packit 534379
	json_object *j_plugin_cfg = NULL;
Packit 534379
	json_object *j_enabled = NULL;
Packit 534379
	const char *stringified = NULL;
Packit 534379
	size_t len;
Packit 534379
Packit 534379
	JSON_GET(j_config, "plugin", &j_plugin);
Packit 534379
	JSON_GET(j_config, "configuration", &j_plugin_cfg);
Packit 534379
	JSON_GET(j_config, "enabled", &j_enabled);
Packit 534379
	if (json_object_get_string_len(j_plugin) > PLUGIN_NAME_MAX) {
Packit 534379
		OPAE_ERR("plugin name too long");
Packit 534379
		return 1;
Packit 534379
	}
Packit 534379
Packit 534379
	plugin_cfg *cfg = malloc(sizeof(plugin_cfg));
Packit 534379
	if (!cfg) {
Packit 534379
		OPAE_ERR("Could not allocate memory for plugin cfg");
Packit 534379
		return 1;
Packit 534379
	}
Packit 534379
Packit 534379
	stringified = json_object_to_json_string_ext(j_plugin_cfg, JSON_C_TO_STRING_PLAIN);
Packit 534379
	if (!stringified) {
Packit 534379
		OPAE_ERR("error getting plugin configuration");
Packit 534379
		free(cfg);
Packit 534379
		return 1;
Packit 534379
	}
Packit 534379
Packit 534379
	cfg->cfg_size = strlen(stringified) + 1;
Packit 534379
Packit 534379
	if (cfg->cfg_size >= MAX_PLUGIN_CFG_SIZE) {
Packit 534379
		OPAE_ERR("plugin config too large");
Packit 534379
		free(cfg);
Packit 534379
		return 1;
Packit 534379
	}
Packit 534379
Packit 534379
	cfg->cfg = malloc(cfg->cfg_size);
Packit 534379
	if (!cfg->cfg) {
Packit 534379
		OPAE_ERR("error allocating memory for plugin configuration");
Packit 534379
		cfg->cfg_size = 0;
Packit 534379
		free(cfg);
Packit 534379
		return 1;
Packit 534379
	}
Packit 534379
Packit 534379
	len = strnlen(stringified, cfg->cfg_size - 1);
Packit 534379
	memcpy(cfg->cfg, stringified, len);
Packit 534379
	cfg->cfg[len] = '\0';
Packit 534379
Packit 534379
	len = strnlen(name, PLUGIN_NAME_MAX - 1);
Packit 534379
	memcpy(cfg->name, name, len);
Packit 534379
	cfg->name[len] = '\0';
Packit 534379
Packit 534379
	len = strnlen(json_object_get_string(j_plugin), PLUGIN_NAME_MAX - 1);
Packit 534379
	memcpy(cfg->plugin, json_object_get_string(j_plugin), len);
Packit 534379
	cfg->plugin[len] = '\0';
Packit 534379
Packit 534379
	cfg->enabled = json_object_get_boolean(j_enabled);
Packit 534379
Packit 534379
	opae_plugin_mgr_add_plugin(cfg);
Packit 534379
Packit 534379
	return 0;
Packit 534379
}
Packit 534379
Packit 534379
STATIC int process_cfg_buffer(const char *buffer, const char *filename)
Packit 534379
{
Packit 534379
	int num_plugins = 0;
Packit 534379
	int num_errors = 0;
Packit 534379
	int i = 0;
Packit 534379
	int res = 1;
Packit 534379
	json_object *root = NULL;
Packit 534379
	json_object *j_plugins = NULL;
Packit 534379
	json_object *j_configs = NULL;
Packit 534379
	json_object *j_plugin = NULL;
Packit 534379
	json_object *j_config = NULL;
Packit 534379
	const char *plugin_name = NULL;
Packit 534379
	enum json_tokener_error j_err = json_tokener_success;
Packit 534379
Packit 534379
	root = json_tokener_parse_verbose(buffer, &j_err);
Packit 534379
	if (!root) {
Packit 534379
		OPAE_ERR("Error parsing config file: '%s' - %s", filename,
Packit 534379
			 json_tokener_error_desc(j_err));
Packit 534379
		goto out_free;
Packit 534379
	}
Packit 534379
Packit 534379
	if (!json_object_object_get_ex(root, "plugins", &j_plugins)) {
Packit 534379
		OPAE_ERR("Error parsing config file: '%s' - missing 'plugins'", filename);
Packit 534379
		goto out_free;
Packit 534379
	}
Packit 534379
	if (!json_object_object_get_ex(root, "configurations", &j_configs)) {
Packit 534379
		OPAE_ERR("Error parsing config file: '%s' - missing 'configs'", filename);
Packit 534379
		goto out_free;
Packit 534379
	}
Packit 534379
Packit 534379
	if (!json_object_is_type(j_plugins, json_type_array)) {
Packit 534379
		OPAE_ERR("'plugins' JSON object not array type");
Packit 534379
		goto out_free;
Packit 534379
	}
Packit 534379
Packit 534379
	num_plugins = json_object_array_length(j_plugins);
Packit 534379
	num_errors = 0;
Packit 534379
	for (i = 0; i < num_plugins; ++i) {
Packit 534379
		j_plugin = json_object_array_get_idx(j_plugins, i);
Packit 534379
		plugin_name = json_object_get_string(j_plugin);
Packit 534379
Packit 534379
		if (json_object_object_get_ex(j_configs, plugin_name, &j_config)) {
Packit 534379
			num_errors += process_plugin(plugin_name, j_config);
Packit 534379
		} else {
Packit 534379
			OPAE_ERR("Could not find plugin configuration for '%s'", plugin_name);
Packit 534379
			num_errors += 1;
Packit 534379
		}
Packit 534379
	}
Packit 534379
	res = num_errors;
Packit 534379
Packit 534379
out_free:
Packit 534379
	if (root)
Packit 534379
		json_object_put(root);
Packit 534379
	return res;
Packit 534379
}
Packit 534379
Packit 534379
#define MAX_CFG_SIZE 4096
Packit 534379
STATIC int opae_plugin_mgr_parse_config(const char *filename)
Packit 534379
{
Packit 534379
	char buffer[MAX_CFG_SIZE] = { 0 };
Packit 534379
	char *ptr = &buffer[0];
Packit 534379
	size_t bytes_read = 0, total_read = 0;
Packit 534379
	FILE *fp = NULL;
Packit 534379
	if (filename) {
Packit 534379
		fp = fopen(filename, "r");
Packit 534379
	} else {
Packit 534379
		OPAE_MSG("config file is NULL");
Packit 534379
		return 1;
Packit 534379
	}
Packit 534379
Packit 534379
	if (!fp) {
Packit 534379
		OPAE_ERR("Error opening config file: %s", filename);
Packit 534379
		return 1;
Packit 534379
	}
Packit 534379
Packit 534379
	while ((bytes_read = fread(ptr + total_read, 1, 1, fp))
Packit 534379
	       && total_read < MAX_CFG_SIZE) {
Packit 534379
		total_read += bytes_read;
Packit 534379
	}
Packit 534379
Packit 534379
	if (ferror(fp)) {
Packit 534379
		OPAE_ERR("Error reading config file: %s - %s", filename, strerror(errno));
Packit 534379
		goto out_err;
Packit 534379
	}
Packit 534379
	if (!feof(fp)) {
Packit 534379
		OPAE_ERR("Unknown error reading config file: %s", filename);
Packit 534379
		goto out_err;
Packit 534379
	}
Packit 534379
	fclose(fp);
Packit 534379
	fp = NULL;
Packit 534379
Packit 534379
	return process_cfg_buffer(buffer, filename);
Packit 534379
out_err:
Packit 534379
	fclose(fp);
Packit 534379
	fp = NULL;
Packit 534379
	return 1;
Packit 534379
}
Packit 534379
Packit 534379
STATIC int opae_plugin_mgr_register_adapter(opae_api_adapter_table *adapter)
Packit 534379
{
Packit 534379
	opae_api_adapter_table *aptr;
Packit 534379
Packit 534379
	adapter->next = NULL;
Packit 534379
Packit 534379
	if (!adapter_list) {
Packit 534379
		adapter_list = adapter;
Packit 534379
		return 0;
Packit 534379
	}
Packit 534379
Packit 534379
	// new entries go to the end of the list.
Packit 534379
	for (aptr = adapter_list; aptr->next; aptr = aptr->next)
Packit 534379
		/* find the last entry */;
Packit 534379
Packit 534379
	aptr->next = adapter;
Packit 534379
Packit 534379
	return 0;
Packit 534379
}
Packit 534379
Packit 534379
STATIC void opae_plugin_mgr_detect_platform(uint16_t vendor, uint16_t device)
Packit 534379
{
Packit 534379
	int i;
Packit 534379
Packit 534379
	for (i = 0 ; platform_data_table[i].native_plugin ; ++i) {
Packit 534379
Packit 534379
		if (platform_data_table[i].vendor_id == vendor &&
Packit 534379
		    platform_data_table[i].device_id == device) {
Packit 534379
			OPAE_DBG("platform detected: vid=0x%04x did=0x%04x -> %s",
Packit 534379
					vendor, device,
Packit 534379
					platform_data_table[i].native_plugin);
Packit 534379
Packit 534379
			platform_data_table[i].flags |= OPAE_PLATFORM_DATA_DETECTED;
Packit 534379
		}
Packit 534379
Packit 534379
	}
Packit 534379
}
Packit 534379
Packit 534379
STATIC int opae_plugin_mgr_detect_platforms(void)
Packit 534379
{
Packit 534379
	DIR *dir;
Packit 534379
	char base_dir[PATH_MAX];
Packit 534379
	char file_path[PATH_MAX];
Packit 534379
	struct dirent *dirent;
Packit 534379
	int errors = 0;
Packit 534379
Packit 534379
	// Iterate over the directories in /sys/bus/pci/devices.
Packit 534379
	// This directory contains symbolic links to device directories
Packit 534379
	// where 'vendor' and 'device' files exist.
Packit 534379
Packit 534379
	memcpy(base_dir, "/sys/bus/pci/devices", 21);
Packit 534379
Packit 534379
	dir = opendir(base_dir);
Packit 534379
	if (!dir) {
Packit 534379
		OPAE_ERR("Failed to open %s. Aborting platform detection.", base_dir);
Packit 534379
		return 1;
Packit 534379
	}
Packit 534379
Packit 534379
	while ((dirent = readdir(dir)) != NULL) {
Packit 534379
		FILE *fp;
Packit 534379
		unsigned vendor = 0;
Packit 534379
		unsigned device = 0;
Packit 534379
Packit 534379
		if (!strcmp(dirent->d_name, ".") ||
Packit 534379
		    !strcmp(dirent->d_name, ".."))
Packit 534379
			continue;
Packit 534379
Packit 534379
		// Read the 'vendor' file.
Packit 534379
		if (snprintf(file_path, sizeof(file_path),
Packit 534379
			     "%s/%s/vendor",
Packit 534379
			     base_dir,
Packit 534379
			     dirent->d_name) < 0) {
Packit 534379
			OPAE_ERR("snprintf buffer overflow");
Packit 534379
			++errors;
Packit 534379
			goto out_close;
Packit 534379
		}
Packit 534379
Packit 534379
		fp = fopen(file_path, "r");
Packit 534379
		if (!fp) {
Packit 534379
			OPAE_ERR("Failed to open %s. Aborting platform detection.", file_path);
Packit 534379
			++errors;
Packit 534379
			goto out_close;
Packit 534379
		}
Packit 534379
Packit 534379
		if (EOF == fscanf(fp, "%x", &vendor)) {
Packit 534379
			OPAE_ERR("Failed to read %s. Aborting platform detection.", file_path);
Packit 534379
			fclose(fp);
Packit 534379
			++errors;
Packit 534379
			goto out_close;
Packit 534379
		}
Packit 534379
Packit 534379
		fclose(fp);
Packit 534379
Packit 534379
		// Read the 'device' file.
Packit 534379
		if (snprintf(file_path, sizeof(file_path),
Packit 534379
			     "%s/%s/device",
Packit 534379
			     base_dir,
Packit 534379
			     dirent->d_name) < 0) {
Packit 534379
			OPAE_ERR("snprintf buffer overflow");
Packit 534379
			++errors;
Packit 534379
			goto out_close;
Packit 534379
		}
Packit 534379
Packit 534379
		fp = fopen(file_path, "r");
Packit 534379
		if (!fp) {
Packit 534379
			OPAE_ERR("Failed to open %s. Aborting platform detection.", file_path);
Packit 534379
			++errors;
Packit 534379
			goto out_close;
Packit 534379
		}
Packit 534379
Packit 534379
		if (EOF == fscanf(fp, "%x", &device)) {
Packit 534379
			OPAE_ERR("Failed to read %s. Aborting platform detection.", file_path);
Packit 534379
			fclose(fp);
Packit 534379
			++errors;
Packit 534379
			goto out_close;
Packit 534379
		}
Packit 534379
Packit 534379
		fclose(fp);
Packit 534379
Packit 534379
		// Detect platform for this (vendor, device).
Packit 534379
		opae_plugin_mgr_detect_platform((uint16_t) vendor, (uint16_t) device);
Packit 534379
	}
Packit 534379
Packit 534379
out_close:
Packit 534379
	closedir(dir);
Packit 534379
	return errors;
Packit 534379
}
Packit 534379
Packit 534379
STATIC int opae_plugin_mgr_load_cfg_plugin(plugin_cfg *cfg)
Packit 534379
{
Packit 534379
	int res = 0;
Packit 534379
	opae_api_adapter_table *adapter = NULL;
Packit 534379
Packit 534379
	if (cfg->enabled && cfg->cfg && cfg->cfg_size) {
Packit 534379
		adapter = opae_plugin_mgr_alloc_adapter(cfg->plugin);
Packit 534379
		if (!adapter) {
Packit 534379
			OPAE_ERR("malloc failed");
Packit 534379
			return 1;
Packit 534379
		}
Packit 534379
		res = opae_plugin_mgr_configure_plugin(adapter, cfg->cfg);
Packit 534379
		if (res) {
Packit 534379
			opae_plugin_mgr_free_adapter(adapter);
Packit 534379
			OPAE_ERR("failed to configure plugin \"%s\"",
Packit 534379
				 cfg->name);
Packit 534379
			return 1;
Packit 534379
		}
Packit 534379
Packit 534379
		res = opae_plugin_mgr_register_adapter(adapter);
Packit 534379
		if (res) {
Packit 534379
			opae_plugin_mgr_free_adapter(adapter);
Packit 534379
			OPAE_ERR("Failed to register \"%s\"", cfg->name);
Packit 534379
			return 1;
Packit 534379
		}
Packit 534379
Packit 534379
	}
Packit 534379
Packit 534379
	return 0;
Packit 534379
}
Packit 534379
Packit 534379
STATIC int opae_plugin_mgr_load_cfg_plugins(void)
Packit 534379
{
Packit 534379
	plugin_cfg *ptr = opae_plugin_mgr_config_list;
Packit 534379
	int errors = 0;
Packit 534379
	while (ptr) {
Packit 534379
		errors += opae_plugin_mgr_load_cfg_plugin(ptr);
Packit 534379
		ptr = ptr->next;
Packit 534379
	}
Packit 534379
	return errors;
Packit 534379
}
Packit 534379
Packit 534379
STATIC int opae_plugin_mgr_load_dflt_plugins(int *platforms_detected)
Packit 534379
{
Packit 534379
	int i = 0, j = 0;
Packit 534379
	int res = 0;
Packit 534379
	opae_api_adapter_table *adapter = NULL;
Packit 534379
	int errors = opae_plugin_mgr_detect_platforms();
Packit 534379
	if (errors)
Packit 534379
		return errors;
Packit 534379
	// Load each of the native plugins that were detected.
Packit 534379
	*platforms_detected = 0;
Packit 534379
Packit 534379
	for (i = 0 ; platform_data_table[i].native_plugin ; ++i) {
Packit 534379
		const char *native_plugin;
Packit 534379
		int already_loaded;
Packit 534379
Packit 534379
		if (!(platform_data_table[i].flags & OPAE_PLATFORM_DATA_DETECTED))
Packit 534379
			continue; // This platform was not detected.
Packit 534379
Packit 534379
		native_plugin = platform_data_table[i].native_plugin;
Packit 534379
		(*platforms_detected)++;
Packit 534379
Packit 534379
		// Iterate over the table again to prevent multiple loads
Packit 534379
		// of the same native plugin.
Packit 534379
		already_loaded = 0;
Packit 534379
		for (j = 0 ; platform_data_table[j].native_plugin ; ++j) {
Packit 534379
Packit 534379
			if (!strcmp(native_plugin, platform_data_table[j].native_plugin) &&
Packit 534379
			    (platform_data_table[j].flags & OPAE_PLATFORM_DATA_LOADED)) {
Packit 534379
				already_loaded = 1;
Packit 534379
				break;
Packit 534379
			}
Packit 534379
Packit 534379
		}
Packit 534379
Packit 534379
		if (already_loaded)
Packit 534379
			continue;
Packit 534379
Packit 534379
		adapter = opae_plugin_mgr_alloc_adapter(native_plugin);
Packit 534379
Packit 534379
		if (!adapter) {
Packit 534379
			OPAE_ERR("malloc failed");
Packit 534379
			return ++errors;
Packit 534379
		}
Packit 534379
Packit 534379
		// TODO: pass serialized json for native plugin
Packit 534379
		res = opae_plugin_mgr_configure_plugin(adapter, "");
Packit 534379
		if (res) {
Packit 534379
			opae_plugin_mgr_free_adapter(adapter);
Packit 534379
			OPAE_ERR("failed to configure plugin \"%s\"",
Packit 534379
				 native_plugin);
Packit 534379
			++errors;
Packit 534379
			continue; // Keep going.
Packit 534379
		}
Packit 534379
Packit 534379
		res = opae_plugin_mgr_register_adapter(adapter);
Packit 534379
		if (res) {
Packit 534379
			opae_plugin_mgr_free_adapter(adapter);
Packit 534379
			OPAE_ERR("Failed to register \"%s\"", native_plugin);
Packit 534379
			++errors;
Packit 534379
			continue; // Keep going.
Packit 534379
		}
Packit 534379
Packit 534379
		platform_data_table[i].flags |= OPAE_PLATFORM_DATA_LOADED;
Packit 534379
	}
Packit 534379
	return errors;
Packit 534379
}
Packit 534379
Packit 534379
int opae_plugin_mgr_initialize(const char *cfg_file)
Packit 534379
{
Packit 534379
	int res;
Packit 534379
	int errors = 0;
Packit 534379
	int platforms_detected = 0;
Packit 534379
	opae_plugin_mgr_plugin_count = 0;
Packit 534379
	char *found_cfg = NULL;
Packit 534379
	const char *use_cfg = NULL;
Packit 534379
Packit 534379
	opae_mutex_lock(res, &adapter_list_lock);
Packit 534379
Packit 534379
	if (initialized) { // prevent multiple init.
Packit 534379
		opae_mutex_unlock(res, &adapter_list_lock);
Packit 534379
		return 0;
Packit 534379
	}
Packit 534379
	found_cfg = find_cfg();
Packit 534379
	use_cfg = cfg_file ? cfg_file : found_cfg;
Packit 534379
	if (use_cfg) {
Packit 534379
		opae_plugin_mgr_parse_config(use_cfg);
Packit 534379
		if (found_cfg) {
Packit 534379
			free(found_cfg);
Packit 534379
		}
Packit 534379
	}
Packit 534379
Packit 534379
	if (opae_plugin_mgr_plugin_count) {
Packit 534379
		errors = opae_plugin_mgr_load_cfg_plugins();
Packit 534379
	} else {
Packit 534379
		// fail-safe, try to detect plugins based on supported devices
Packit 534379
		errors = opae_plugin_mgr_load_dflt_plugins(&platforms_detected);
Packit 534379
	}
Packit 534379
Packit 534379
	if (errors)
Packit 534379
		goto out_unlock;
Packit 534379
Packit 534379
	// Call each plugin's initialization routine.
Packit 534379
	errors += opae_plugin_mgr_initialize_all();
Packit 534379
Packit 534379
	if (!errors && (opae_plugin_mgr_plugin_count || platforms_detected))
Packit 534379
		initialized = 1;
Packit 534379
Packit 534379
out_unlock:
Packit 534379
	opae_mutex_unlock(res, &adapter_list_lock);
Packit 534379
Packit 534379
	return errors;
Packit 534379
}
Packit 534379
Packit 534379
int opae_plugin_mgr_for_each_adapter
Packit 534379
	(int (*callback)(const opae_api_adapter_table *, void *), void *context)
Packit 534379
{
Packit 534379
	int res;
Packit 534379
	int cb_res = OPAE_ENUM_CONTINUE;
Packit 534379
	opae_api_adapter_table *aptr;
Packit 534379
Packit 534379
	if (!callback) {
Packit 534379
		OPAE_ERR("NULL callback passed to %s()", __func__);
Packit 534379
		return OPAE_ENUM_STOP;
Packit 534379
	}
Packit 534379
Packit 534379
	opae_mutex_lock(res, &adapter_list_lock);
Packit 534379
Packit 534379
	for (aptr = adapter_list; aptr; aptr = aptr->next) {
Packit 534379
		cb_res = callback(aptr, context);
Packit 534379
		if (cb_res)
Packit 534379
			break;
Packit 534379
	}
Packit 534379
Packit 534379
	opae_mutex_unlock(res, &adapter_list_lock);
Packit 534379
Packit 534379
	return cb_res;
Packit 534379
}