// SPDX-License-Identifier: BSD-2-Clause
/*
  Copyright (c) Matthias Schiffer <mschiffer@universe-factory.net>
  All rights reserved.
*/

/**
   \file

   Generated lists of MACs and their implementations
*/


#include "crypto.h"
#include "fastd.h"


extern const fastd_mac_info_t fastd_mac_info_ghash;
extern const fastd_mac_t fastd_mac_ghash_pclmulqdq;
extern const fastd_mac_t fastd_mac_ghash_builtin;
extern const fastd_mac_info_t fastd_mac_info_uhash;
extern const fastd_mac_t fastd_mac_uhash_builtin;


/** A MAC implementation */
typedef struct fastd_mac_impl {
	const char *name;			/**< The name of the MAC implementation */
	const fastd_mac_t *impl;		/**< The MAC implementation */
} fastd_mac_impl_t;

/** A MAC */
typedef struct mac_entry {
	const char *name;			/**< The name of the MAC */
	const fastd_mac_info_t *info;		/**< The associated MAC information */
	const fastd_mac_impl_t *impls;		/**< NULL-terminated array of MAC implementations */
} mac_entry_t;

static const fastd_mac_impl_t mac_ghash_impls[] = {
{"pclmulqdq", &fastd_mac_ghash_pclmulqdq},
{"builtin", &fastd_mac_ghash_builtin},
{NULL, NULL}
};
static const fastd_mac_impl_t mac_uhash_impls[] = {
{"builtin", &fastd_mac_uhash_builtin},
{NULL, NULL}
};


/** The list of supported MACs */
static const mac_entry_t macs[] = {
	{"ghash", &fastd_mac_info_ghash, mac_ghash_impls},
{"uhash", &fastd_mac_info_uhash, mac_uhash_impls},

};

/** The list of chosen MAC implementations */
static const fastd_mac_t *mac_conf[array_size(macs)] = {};


/** Checks if a MAC implementation is available on the runtime platform */
static inline bool mac_available(const fastd_mac_t *mac) {
	return (!mac->available) || mac->available();
}

void fastd_mac_init(void) {
	size_t i, j;
	for (i = 0; i < array_size(macs); i++) {
		for (j = 0; macs[i].impls[j].impl; j++) {
			if (mac_available(macs[i].impls[j].impl))
				break;
		}

		mac_conf[i] = macs[i].impls[j].impl;
	}
}

bool fastd_mac_config(const char *name, const char *impl) {
	size_t i;
	for (i = 0; i < array_size(macs); i++) {
		if (!strcmp(macs[i].name, name)) {
			size_t j;
			for (j = 0; macs[i].impls[j].impl; j++) {
				if (!strcmp(macs[i].impls[j].name, impl)) {
					if (!mac_available(macs[i].impls[j].impl))
						return false;

					mac_conf[i] = macs[i].impls[j].impl;
					return true;
				}
			}

			return false;
		}
	}

	return false;
}

const fastd_mac_info_t * fastd_mac_info_get_by_name(const char *name) {
	size_t i;
	for (i = 0; i < array_size(macs); i++) {
		if (strcmp(macs[i].name, name))
			continue;

		if (mac_conf[i])
			return macs[i].info;

		break;
	}

	return NULL;
}

const fastd_mac_t * fastd_mac_get(const fastd_mac_info_t *info) {
	size_t i;
	for (i = 0; i < array_size(macs); i++) {
		if (macs[i].info == info)
			return mac_conf[i];
	}

	return NULL;
}
