From 730f20b00a631353c7df15198b35691fa71002b4 Mon Sep 17 00:00:00 2001 From: Mazet Laurent Date: Fri, 2 May 2025 23:54:59 +0200 Subject: [PATCH] initial version of crypto module --- core.c | 119 ++++++++++++ core.h | 73 ++++++++ cryptomod.c | 511 ++++++++++++++++++++++++++++++++++++++++++++++++++++ cryptomod.h | 127 +++++++++++++ rdtsc.h | 45 +++++ task.c | 337 ++++++++++++++++++++++++++++++++++ task.h | 87 +++++++++ verbose.h | 4 +- 8 files changed, 1301 insertions(+), 2 deletions(-) create mode 100644 core.c create mode 100644 core.h create mode 100644 cryptomod.c create mode 100644 cryptomod.h create mode 100644 rdtsc.h create mode 100644 task.c create mode 100644 task.h diff --git a/core.c b/core.c new file mode 100644 index 0000000..0d0c7a6 --- /dev/null +++ b/core.c @@ -0,0 +1,119 @@ +/* + File name : core.c + Date of creation : 10/2/2008 + Version : 1.0 + Copyright : Soft'n'Design + Author : Laurent Mazet + + Description : Miscellaenous functions on core/thread management + + History : + - initial version from tools.h +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "rdtsc.h" +#include "verbose.h" + +#include "core.h" + +DECLARE_VERBOSE_LEVEL (coretools, 0); + +int get_cpu_number (void) +{ + int ncpu = 0; + char *procinfo = "processor"; + + FILE *F = fopen ("/proc/cpuinfo", "r"); + if (F) { + char line[256] = { '\0' }; + while (fgets (line, sizeof (line) - 1, F)) { + if (strncmp (line, procinfo, strlen (procinfo)) == 0) + ncpu++; + } + fclose (F); + } + + return (ncpu == 0) ? 1 : ncpu; +} + + +/* Thread management */ + +int enable_realtime (int prio) +{ + struct sched_param param; + + param.__sched_priority = prio; + return pthread_setschedparam (pthread_self (), SCHED_FIFO, ¶m); +} + +int cpu_setaffinity (const char *cpu_list) +{ + cpu_set_t cpuset; + char *save_ptr; + char *cpu; + char delim[] = "+, "; + + if (!cpu_list) return -1; + + char *copy_list = strdup(cpu_list); + + CPU_ZERO(&cpuset); + cpu = strtok_r(copy_list, delim, &save_ptr); + while (cpu) { + CPU_SET(atoi(cpu), &cpuset); + cpu = strtok_r(NULL, delim, &save_ptr); + } + + free(copy_list); + + return pthread_setaffinity_np(pthread_self (), sizeof(cpu_set_t), &cpuset); +} + +/** + Cpu clock +*/ +static double cpu_clock = 1; + + +/** + Internal funciton, executed at load time to calibrate cpu clock +*/ +void __attribute__((constructor)) _core_init_cpu_clock (void) +{ + struct timeval tv1, tv2; + long long int ts1, ts2; + + gettimeofday (&tv1, NULL); + ts1 = rdtsc (); + + usleep (100000); + + gettimeofday (&tv2, NULL); + ts2 = rdtsc (); + + double delta = ((double)tv2.tv_sec + tv2.tv_usec * 1e-6) - + ((double)tv1.tv_sec + tv1.tv_usec * 1e-6); + + cpu_clock = (ts2 - ts1) / delta; +} + +unsigned long long tsc2diff (unsigned long long tsc1, unsigned long long tsc2) +{ + return (tsc1 > tsc2) ? tsc1 - tsc2 : tsc2 + (~tsc1) + 1; +} + +float tsc2ms (unsigned long long delta_tsc) +{ + return (float) (delta_tsc / cpu_clock * 1e6f); +} + +/* vi:set tabstop=4 expandtab shiftwidth=4: this line set vi mode */ diff --git a/core.h b/core.h new file mode 100644 index 0000000..b9718ac --- /dev/null +++ b/core.h @@ -0,0 +1,73 @@ +/* + File name : core.h + Date of creation : 10/2/2008 + Version : 1.0 + Copyright : Soft'n'Design + Author : Laurent Mazet + + Description : Miscellaenous functions on core/thread management + + History : + - initial version from tools.h +*/ + +#ifndef __CORE_H__ +#define __CORE_H__ + +#include + +__BEGIN_DECLS + +/** + Declare a parameter or a variable unused. +*/ +#define UNUSED __attribute__ ((unused)) + +/** + Count number of CPU + + @return number of CPU +*/ +int get_cpu_number (void); + +/* Thread management */ + +/** + Set realtime priority + + @param prio priority + @return error code (from pthread_setschedparam) +*/ +int enable_realtime (int prio); + +/** + Set cpu (core) affinity + + @param cpu_list is a char string describing cpu affinity when core ids are separated by plus (+), comma (,) or space ( ) + @return error code (from pthread_setaffinity_np) +*/ +int cpu_setaffinity (const char *cpu_list); + +/** + Compute the difference between two cycle counters + + @param tsc1 initial cycle counter + @param tsc1 last cycle counter + @return cycle counter difference +*/ +unsigned long long tsc2diff (unsigned long long tsc1, unsigned long long tsc2); + +/** + Evaluation a number of cycles in milisecond + + @param delta_tsc number of cycles + @return number of miliseconds +*/ +float tsc2ms (unsigned long long delta_tsc); + +__END_DECLS + +#endif /* __CORE_H__ */ + + +/* vi:set tabstop=4 expandtab shiftwidth=4: this line set vi mode */ diff --git a/cryptomod.c b/cryptomod.c new file mode 100644 index 0000000..afeb71f --- /dev/null +++ b/cryptomod.c @@ -0,0 +1,511 @@ +/* + File name : cryptomod.c + Projet : MERLIN + Date of creation : 2025/05/0r2 + Version : 1.0 + Copyright : Thales SIX + Author : Laurent Mazet + + Description : Crypto Module + + History : + - initial version +*/ + +/* depend: */ +/* cflags: */ +/* linker: core.o morep.o parse.o pdu_channel.o pdu_encrypted_data.o pdu_prng_param.o pdu_status.o pdu_clear_data.o pdu_key.o pdu_raw_data.o task.o */ + +#include +#include +#include +#include +#include +#include +#include + +#include "def.h" +#include "cryptomod.h" +#include "morep.h" +#include "pdu_channel.h" +#include "pdu_encrypted_data.h" +#include "pdu_prng_param.h" +#include "pdu_status.h" +#include "pdu_clear_data.h" +#include "pdu_key.h" +#include "pdu_raw_data.h" +#include "pdu_raw_data.h" +#include "task.h" +#include "verbose.h" + +char *progname = NULL; + +int state = shutdowning_e; + +DECLARE_VERBOSE_LEVEL (morep, INFO); +DECLARE_VERBOSE_LEVEL (crypto, INFO); + +#define BUFMAX 4096 + +#define NBSERVICES 10 +char *services[NBSERVICES] = { + "CROSS_CRYPTO_R2B", + "LOCAL_CRYPTO_BLACK", + "LOCAL_CRYPTO_RED", + "PROVISIONING", + "PRNG_BLACK", + "PRNG_RED", + "BYPASS_B2R", + "BYPASS_R2B", + "CONTROL", +}; + +/* definition of all messages */ +message_t message_list[] = { + + /* Cross cryptographic B-2-R service */ + {"DECRYPT_CROSS_ASYNC", cross_crypto_b2r_e, 0x02, encrypted_data_e, decrypt_func_e}, + {"DECRYPTED_CROSS_ASYNC", cross_crypto_b2r_e, 0x03, clear_data_e, nofunc_e}, + + /* Cross cryptographic R-2-B service */ + {"ENCRYPT_CROSS_ASYNC", cross_crypto_r2b_e, 0x00, clear_data_e, encrypt_func_e}, + {"ENCRYPTED_CROSS_ASYNC", cross_crypto_r2b_e, 0x01, encrypted_data_e, nofunc_e}, + + /* Local cryptographic Black and Red services */ + {"ENCRYPT_LOCAL_REQ", local_crypto_e, 0x00, clear_data_e, encrypt_func_e}, + {"ENCRYPTED_LOCAL_RESP", local_crypto_e, 0x01, encrypted_data_e, nofunc_e}, + {"DECRYPT_LOCAL_REQ", local_crypto_e, 0x02, encrypted_data_e, decrypt_func_e}, + {"DECRYPTED_LOCAL_RESP", local_crypto_e, 0x03, clear_data_e, nofunc_e}, + + /* Provisioning service */ + {"LOAD_KEY_REQ", provisioning_e, 0x00, key_e, load_key_func_e}, + {"LOAD_KEY_RESP", provisioning_e, 0x01, status_e, nofunc_e}, + {"UNLOAD_KEY_REQ", provisioning_e, 0x02, key_e, unload_key_func_e}, + {"UNLOAD_KEY_RESP", provisioning_e, 0x03, status_e, nofunc_e}, + {"ERASE_KEY_REQ", provisioning_e, 0x04, key_e, erase_key_func_e}, + {"ERASE_KEY_RESP", provisioning_e, 0x05, status_e, nofunc_e}, + {"ASSOCIATE_CHANNEL_REQ", provisioning_e, 0x06, channel_e, associate_channel_e}, + {"ASSOCIATE_CHANNEL_RESP", provisioning_e, 0x07, status_e, nofunc_e}, + {"DISSOCIATE_CHANNEL_REQ", provisioning_e, 0x08, channel_e, dissociate_channel_e}, + {"DISSOCIATE_CHANNEL_RESP", provisioning_e, 0x09, status_e, nofunc_e}, + + /* Bypass B-2-R and R-2-B services */ + {"BYPASS_CROSS_ASYNC", bypass_e, 0x00, raw_data_e, bypass_func_e}, + {"BYPASSED_CROSS_ASYNC", bypass_e, 0x01, raw_data_e, nofunc_e}, + + /* PRNG Black and Red services */ + {"RANDOM_REQ", prng_e, 0x00, prng_param_e, random_func_e}, + {"RANDOM_RESP", prng_e, 0x01, raw_data_e, nofunc_e}, + + /* Control service */ + {"STATUS_REQ", control_e, 0x00, nopdu_e, status_func_e}, + {"STATUS_RESP", control_e, 0x01, status_e, nofunc_e}, + {"AUTHENTICATION_REQ", control_e, 0x02, raw_data_e, authentification_func_e}, + {"AUTHENTICATION_RESP", control_e, 0x03, raw_data_e, nofunc_e}, + {"REBOOT_REQ", control_e, 0x04, nopdu_e, reboot_func_e}, + {"REBOOT_RESP", control_e, 0x05, status_e, nofunc_e}, + {"ZEROIZE_REQ", control_e, 0x06, nopdu_e, zeroize_func_e}, + {"ZEROIZE_RESP", control_e, 0x07, status_e, nofunc_e}, + {"LOCK_CRYPTO_REQ", control_e, 0xFE, nopdu_e, lock_crypto_func_e}, + {"LOCK_CRYPTO_RESP", control_e, 0xFF, status_e, nofunc_e}, + + /* End of list */ + {"", noserv_e, 0x00, undef_pdu_e, nofunc_e} +}; + +/* definition of all services */ +service_t service_list[] = { + {"CROSS_CRYPTO_B2R", cross_crypto_b2r_e, NULL, NULL}, /* 809 */ + {"CROSS_CRYPTO_R2B", cross_crypto_r2b_e, NULL, NULL}, /* 809 */ + {"LOCAL_CRYPTO_BLACK", local_crypto_e, NULL, NULL}, /* 80a */ + {"LOCAL_CRYPTO_RED", local_crypto_e, NULL, NULL}, /* 80a */ + {"PROVISIONING", provisioning_e, NULL, NULL}, /* 80b */ + {"PRNG_BLACK", prng_e, NULL, NULL}, /* 80c */ + {"PRNG_RED", prng_e, NULL, NULL}, /* 80c */ + {"BYPASS_B2R", bypass_e, NULL, NULL}, /* 80d */ + {"BYPASS_R2B", bypass_e, NULL, NULL}, /* 80d */ + {"CONTROL", control_e, NULL, NULL}, /* 80e */ + {"", noserv_e, NULL, NULL} +}; + +/* various functions */ + +service_t *find_service (char *servname) +{ + service_t *serv = NULL; + for (int i = 0; ((service_list + i)->service_id != noserv_e) && (!serv); i++) { + service_t *s = service_list + i; + if ((s) && (servname) && (strcmp (s->name, servname) == 0)) { + serv = s; + } + } + return serv; +} + +/* main thread function */ + +int main_thread (sub_task_t *s, int id) +{ + if ((s == NULL) || (id != 0) || (id >= NBSERVICES)) { + VERBOSE (crypto, ERROR, PRINTF ("can't start thread '%d'\n", id)); + return -1; + } + + char *servname = services[id]; + service_t *serv = find_service (servname); + if (!serv) { + VERBOSE (crypto, ERROR, PRINTF ("can't find service '%s'\n", servname)); + return 1; + } + int in = MOREP_Connect (serv->rx); + if (in < 0) { + VERBOSE (crypto, ERROR, PRINTF ("can't open TX MOREP for service '%s'\n", servname)); + return 1; + } + int out = MOREP_Connect (serv->tx); + if (in < 0) { + VERBOSE (crypto, ERROR, PRINTF ("can't open RX MOREP for service '%s'\n", servname)); + MOREP_Close (in); + return 1; + } + + CHANNEL_t pdu_channel = {0}; + CLEAR_DATA_t pdu_clear_data = {0}; + ENCRYPTED_DATA_t pdu_encrypted_data = {0}; + KEY_t pdu_key = {0}; + PRNG_PARAM_t pdu_prng_param = {0}; + RAW_DATA_t pdu_raw_data = {0}; + STATUS_t pdu_status = {0}; + int rc = 0; + + while (1) { + + /* listen a message */ + uint8_t msgtype = 0; + uint8_t payload[MOREP_PAYLOAD] = {0}; + int len = 0; + int seqnum = MOREP_Receive (in, &msgtype, payload, &len); + + /* check service/msgtype */ + message_t *msg = NULL; + for (int i = 0; ((message_list + i)->service_id) && (!msg); i++) { + message_t *m = message_list + i; + if ((m->service_id == serv->service_id) && (m->msgtype == msgtype)) { + msg = m; + } + } + + /* check msg type */ + if (msg == NULL) { + VERBOSE (crypto, WARNING, PRINTF ("R:%s [SEQ=%d MSG=%d LEN=%d] message type is not allowed for this service\n", serv->name, seqnum, msgtype, len)); + continue; + } + + /* deserialize message */ + rc = 1; + switch (msg->pdu) { + case nopdu_e: + rc = 0; + break; + case channel_e: + rc = deserial_channel (payload, len, &pdu_channel); + break; + case clear_data_e: + rc = deserial_clear_data (payload, len, &pdu_clear_data); + break; + case encrypted_data_e: + rc = deserial_encrypted_data (payload, len, &pdu_encrypted_data); + break; + case key_e: + rc = deserial_key (payload, len, &pdu_key); + break; + case prng_param_e: + rc = deserial_prng_param (payload, len, &pdu_prng_param); + break; + case raw_data_e: + rc = deserial_raw_data (payload, len, &pdu_raw_data); + break; + case status_e: + rc = deserial_status (payload, len, &pdu_status); + break; + default: + } + if (rc) { + VERBOSE (crypto, WARNING, PRINTF ("can't deserialize message %s\n", msg->name)); + continue; + } + + /* log received message */ + VERBOSE (crypto, INFO, PRINTF ("R:%s [SEQ=%d MSG=%d LEN=%d PDU=%d] %s\n", serv->name, seqnum, msgtype, len, msg->pdu, msg->name)); + + /* process message */ + rc = 1; + switch (msg->func) { + case nofunc_e: + break; + case encrypt_func_e: + rc = encrypt_func (&pdu_clear_data, &pdu_encrypted_data); + break; + case decrypt_func_e: + rc = decrypt_func (&pdu_encrypted_data, &pdu_clear_data); + break; + case load_key_func_e: + rc = load_key_func (&pdu_key, &pdu_status); + break; + case unload_key_func_e: + rc = unload_key_func (&pdu_key, &pdu_status); + break; + case erase_key_func_e: + rc = erase_key_func (&pdu_key, &pdu_status); + break; + case associate_channel_e: + rc = associate_channel_func (&pdu_channel, &pdu_status); + break; + case dissociate_channel_e: + rc = dissociate_channel_func (&pdu_channel, &pdu_status); + break; + case bypass_func_e: + //rc = bypass_func (&pdu_raw_data, &pdu_raw_data); + rc = 0; + break; + case random_func_e: + rc = random_func (&pdu_prng_param, &pdu_raw_data); + break; + case status_func_e: + rc = random_func (NULL, &pdu_status); + break; + case authentification_func_e: + rc = authentification_func (&pdu_raw_data, &pdu_raw_data); + break; + case reboot_func_e: + rc = reboot_func (NULL, &pdu_status); + break; + case zeroize_func_e: + rc = zeroize_func (NULL, &pdu_status); + break; + case lock_crypto_func_e: + rc = lock_crypto_func (NULL, &pdu_status); + break; + } + if (rc) { + VERBOSE (crypto, WARNING, PRINTF ("can't process message %s\n", msg->name)); + continue; + } + + /* prepare message for transmission */ + msgtype++; + + /* check service/msgtype */ + msg = NULL; + for (int i = 0; ((message_list + i)->service_id) && (!msg); i++) { + message_t *m = message_list + i; + if ((m->service_id == serv->service_id) && (m->msgtype == msgtype)) { + msg = m; + } + } + + /* check msg type */ + if (msg == NULL) { + VERBOSE (crypto, WARNING, PRINTF ("T:%s [SEQ=%d MSG=%d] message type is not allowed for this service\n", serv->name, seqnum, msgtype)); + continue; + } + + /* serialize message */ + len = -1; + switch (msg->pdu) { + case nopdu_e: + len = 0; + break; + case channel_e: + len = serial_channel (&pdu_channel, payload, sizeof (payload)); + break; + case clear_data_e: + len = serial_clear_data (&pdu_clear_data, payload, sizeof (payload)); + break; + case encrypted_data_e: + len = serial_encrypted_data (&pdu_encrypted_data, payload, sizeof (payload)); + break; + case key_e: + len = serial_key (&pdu_key, payload, sizeof (payload)); + break; + case prng_param_e: + len = serial_prng_param (&pdu_prng_param, payload, sizeof (payload)); + break; + case raw_data_e: + len = serial_raw_data (&pdu_raw_data, payload, sizeof (payload)); + break; + case status_e: + len = serial_status (&pdu_status, payload, sizeof (payload)); + break; + default: + } + if (len < 0) { + VERBOSE (crypto, WARNING, PRINTF ("can't serialize message %s\n", msg->name)); + } + + /* send message */ + seqnum = MOREP_Send (out, msgtype, payload, len); + + /* log transmitted message */ + VERBOSE (crypto, INFO, PRINTF ("T:%s [SEQ=%d MSG=%d PDU=%d] %s\n", serv->name, seqnum, msgtype, msg->pdu, msg->name)); + } + + return 0; +} + +/* signal handler */ +void sig_handler (int sig) +{ + switch (sig) { + case SIGINT: + exit (0); + break; + case SIGTERM: + exit (0); + break; + } +} + +/* usage function */ +void usage (void) { + printf ("usage: %s [-h] [-l log] [-r url] [-s srv] [-t url] [-v lvl] [-V lvl]\n", progname); + printf (" -h : help message\n"); + printf (" -l log: log all message into a file or stdout if -\n"); + printf (" -r url: set MOREP url for a receveiving service\n"); + printf (" -s srv: define a service\n"); + printf (" -t url: set MOREP url for a transmiting service\n"); + printf (" -v lvl: verbose level for MOREP functions (%d)\n", GET_VERBOSE_LEVEL(morep)); + printf (" -V lvl: verbose level for crypto modul functions (%d)\n", GET_VERBOSE_LEVEL(crypto)); +} + +/* main function */ +int main (int argc, char **argv) +{ + + /* get basename */ + char *ptr = progname = argv[0]; + while (*ptr) { + if ((*ptr == '/') || (*ptr == '\\')) { + progname = ptr + 1; + } + ptr++; + } + + /* process argument */ + char *logname = NULL; + char *servname = NULL; + while (argc-- > 1) { + char *url = NULL; + int mode = -1; + + char *arg = *(++argv); + if (arg[0] != '-') { + usage (); + return 1; + } + char c = arg[1]; + switch (c) { + case 'l': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (crypto, ERROR, PRINTF ("%s: log file not specified\n", progname)); + return 1; + } + logname = arg; + break; + case 'r': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (crypto, ERROR, PRINTF ("%s: receiver url not specified\n", progname)); + return 1; + } + url = arg; + mode = 0; + break; + case 's': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (crypto, ERROR, PRINTF ("%s: service not specified\n", progname)); + return 1; + } + servname = arg; + break; + case 't': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (crypto, ERROR, PRINTF ("%s: transmitter url not specified\n", progname)); + return 1; + } + url = arg; + mode = 1; + break; + case 'v': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (crypto, ERROR, PRINTF ("%s: morep verbose level not specified\n", progname)); + return 1; + } + CHANGE_VERBOSE_LEVEL (morep, atoi (arg)); + break; + case 'V': + arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL; + if (arg == NULL) { + VERBOSE (crypto, ERROR, PRINTF ("%s: cryptomod verbose level not specified\n", progname)); + return 1; + } + CHANGE_VERBOSE_LEVEL (crypto, atoi (arg)); + break; + case 'h': + default: + usage (); + return (c != 'h'); + } + + /* init communication channel */ + if (mode != -1) { + service_t *serv = find_service (servname); + if (serv) { + if (mode) { + serv->rx = url; + } else { + serv->tx = url; + } + } else { + VERBOSE (crypto, WARNING, PRINTF ("can't find service '%s'\n", servname)); + } + mode = -1; + } + } + + /* signals */ + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + /* main loop */ + + while (state != shutdowning_e) { + + /* booting and starting */ + state = booting_e; + + task_t *task = create_async_task ("CRYPTOMOD", main_thread, 0, NBSERVICES, NULL); + + } + + /* cleaning */ + //if ((log) && (log != stdout)) { + // fclose (log); + //} + + return 0; +} + +/* test: cryptomod.exe -h | grep usage */ +/* test: cryptomod.exe -l | grep 'log file not specified' */ +/* test: cryptomod.exe -r | grep 'url not specified' */ +/* test: cryptomod.exe -s | grep 'service not specified' */ +/* test: cryptomod.exe -t | grep 'url not specified' */ +/* test: cryptomod.exe -v | grep 'morep verbose level not specified' */ +/* test: cryptomod.exe -V | grep 'cryptomod verbose level not specified' */ + +/* vim: set ts=4 sw=4 si et: */ diff --git a/cryptomod.h b/cryptomod.h new file mode 100644 index 0000000..64661fe --- /dev/null +++ b/cryptomod.h @@ -0,0 +1,127 @@ +/* + File name : cryptomode.h + Projet : MERLIN + Date of creation : 2025/05/02 + Version : 1.0 + Copyright : Thales SIX + Author : Laurent Mazet + + Description : This file defines crypto module types + + History : + - initial version +*/ + +#ifndef __CRYPTOMOD_H__ +#define __CRYPTOMOD_H__ + +#include +#include + +__BEGIN_DECLS + +/** + @defgroup CRYPTOMOD Public API of Crypto module + +*/ + +/** + @ingroup CRYPTOMOD + + Service enumarate values +*/ +typedef enum { + noserv_e = 0, /**< no service defined */ + cross_crypto_r2b_e, /**< cross cryptographic R-2-B service */ + cross_crypto_b2r_e, /**< cross cryptographic B-2-R service */ + local_crypto_e, /**< local cryptographic Black and Red services */ + provisioning_e, /**< provisioning service */ + prng_e, /**< PRNG Black and Red services */ + bypass_e, /**< bypass B-2-R and R-2-B services */ + control_e /**< controlservice */ +} service_id_t; + +/** + @ingroup CRYPTOMOD + + PDU enumarate values +*/ +typedef enum { + undef_pdu_e = 0, /**< undefined PDU */ + channel_e, /**< CHANNEL_t PDU */ + clear_data_e, /**< CLEAR_DATA_t PDU */ + encrypted_data_e, /**< ENCRYPTED_DATA_t PDU */ + key_e, /**< KEY_t PDU */ + prng_param_e, /**< PRNG_PARAM_t PDU */ + raw_data_e, /**< RAW_DATA_t PDU */ + status_e, /**< STATUS_t PDU */ + nopdu_e /**< no PDU */ +} pdu_t; + +/** + @ingroup CRYPTOMOD + + Function type +*/ +typedef enum { + nofunc_e = 0, /**< undefined function */ + encrypt_func_e, /**< encrypt function */ + decrypt_func_e, /**< decrypt function */ + load_key_func_e, /**< load key function */ + unload_key_func_e, /**< unload key function */ + erase_key_func_e, /**< erase key function */ + associate_channel_e, /**< associate channel function */ + dissociate_channel_e, /**< dissociate channel function */ + bypass_func_e, /**< bypass function */ + random_func_e, /**< random function */ + status_func_e, /**< get status function */ + authentification_func_e, /**< authentification function */ + reboot_func_e, /**< reboot function */ + zeroize_func_e, /** + + Description : This file contains rdtsc inline function + + History : + - initial version +*/ + +#ifndef __RDTSC_H__ +#define __RDTSC_H__ + +#include +#include + +__BEGIN_DECLS + +/** + Get RDTSC counter + + @return counter +*/ +#ifdef __i386 +static __inline__ int64_t rdtsc (void) { + int64_t x; + __asm__ volatile ("rdtsc" : "=A" (x)); + return x; +} +#elif __amd64 +static __inline__ int64_t rdtsc (void) { + int64_t a, d; + __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d)); + return (d << 32) | a; +} +#endif + +__END_DECLS + +#endif /* __RDTSC_H__ */ + +/* vi:set tabstop=4 expandtab shiftwidth=4: this line set vi mode */ diff --git a/task.c b/task.c new file mode 100644 index 0000000..fcfbf87 --- /dev/null +++ b/task.c @@ -0,0 +1,337 @@ +/* + File name : task.c + Date of creation : 25/01/2010 + Version : 1.0 + Copyright : Soft'n'Design + Author : Laurent Mazet + + Description : Task management + + History : + - initial version +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "rdtsc.h" +#include "verbose.h" + +#include "task.h" + +long long tsc_start; + +void task_stat (task_t * t, int condensed) +{ + if (!t->is_sync) return; + + pthread_mutex_lock(&t->stats_mutex); + + if (condensed) { + printf ("%s=[%lu]", t->name, (unsigned long) tsc2ms (t->current_exec_time)); + } else { + printf ("task %s prio=%d cpu=%s last run in %lu µs [count=%d overtimes=%lu overloads=%lu, min=%lu average=%lu max=%lu]\n", + t->name, t->priority, t->cpu_list, + (unsigned long) tsc2ms (t->current_exec_time), t->count, t->overtimes, + t->overloads, (unsigned long) tsc2ms (t->min_exec_time), + t->count ? (unsigned long) tsc2ms (t->cumul_exec_time / t->count) : 0, + (unsigned long) tsc2ms (t->max_exec_time)); + } + + pthread_mutex_unlock(&t->stats_mutex); +} + +void *task_sync_runner (void *param) +{ + sub_task_t *s = (sub_task_t *) param; + task_t *t = s->task; + + cpu_setaffinity(t->cpu_list); + + if (t->priority) { + enable_realtime (t->priority); + } + pthread_mutex_init (&s->condition_mutex, NULL); + pthread_cond_init (&s->condition_cond, NULL); + + /* potential init function */ + if (t->init) t->init (s, s->sub_task_id); + pthread_mutex_unlock (&t->init_mutex); + + while (1) { + // Wait for the trigger + pthread_mutex_lock (&s->condition_mutex); + while (s->trigger == 0) { + pthread_cond_wait (&s->condition_cond, &s->condition_mutex); + } + pthread_mutex_unlock (&s->condition_mutex); + + // Run the task and measure the execution time + + long long tsc1, tsc2; + + tsc1 = rdtsc (); + t->task (s, s->sub_task_id); + tsc2 = rdtsc (); + + // Update performances indicators + + pthread_mutex_lock (&t->stats_mutex); + + t->current_exec_time = tsc2diff (tsc2, tsc1); + t->cumul_exec_time += t->current_exec_time; + t->count++; + s->count++; + + if (s->start_time_us) *(s->start_time_us) = tsc2ms(tsc2diff (tsc1, tsc_start)); + if (s->exec_time_us) *(s->exec_time_us) = tsc2ms(t->current_exec_time); + + if (t->current_exec_time > t->max_exec_time) + t->max_exec_time = t->current_exec_time; + if (t->current_exec_time / 10 > t->min_exec_time) + t->min_exec_time = 0; // To avoid min=0 + if ((t->current_exec_time < t->min_exec_time) || (t->min_exec_time == 0)) + t->min_exec_time = t->current_exec_time; + + if (t->current_exec_time > t->max_allowed_time) { + VERBOSE (coretools, 1, printf ("Warning: task %s[%d] too slow %luus\n", t->name, s->sub_task_id, (unsigned long) tsc2ms (t->current_exec_time))); + t->overtimes++; + } + + if (s->count > 10 && t->current_exec_time > 10*t->max_allowed_time) { + char ascii_time[80]; + time_t my_time = time(NULL); + strftime(ascii_time, sizeof(ascii_time), "%T", localtime(&my_time)); + VERBOSE (coretools, 0, printf ("%s: task %s[%d], big overtime %luus\n", ascii_time, t->name, s->sub_task_id, (unsigned long) tsc2ms (t->current_exec_time))); + } + + pthread_mutex_unlock (&t->stats_mutex); + + pthread_mutex_lock (&s->condition_mutex); + s->trigger = 0; + pthread_cond_signal (&s->condition_cond); + pthread_mutex_unlock (&s->condition_mutex); + } + + return NULL; +} + +int task_trig (task_t * t) +{ + assert (t != NULL); + int i; + for (i=0; inb_sub_tasks; i++) { + sub_task_t *s = &t->sub_task_list[i]; + pthread_mutex_lock (&s->condition_mutex); + while (s->trigger != 0) { + pthread_cond_wait (&s->condition_cond, &s->condition_mutex); + } + s->trigger = 1; + pthread_cond_signal (&s->condition_cond); + pthread_mutex_unlock (&s->condition_mutex); + } + return 0; +} + +int task_end (task_t * t) +{ + assert (t != NULL); + int i; + for (i=0; inb_sub_tasks; i++) { + sub_task_t *s = &t->sub_task_list[i]; + pthread_mutex_lock (&s->condition_mutex); + while (s->trigger != 0) { + pthread_cond_wait (&s->condition_cond, &s->condition_mutex); + } + pthread_mutex_unlock (&s->condition_mutex); + } + return 0; +} + +int task_selective_run (task_t * t, int run_list[]) +{ + assert (t != NULL); + int i; + + // Start all selected sub-tasks + + for (i=0; inb_sub_tasks; i++) { + if (!run_list[i]) continue; + sub_task_t *s = &t->sub_task_list[i]; + pthread_mutex_lock (&s->condition_mutex); + while (s->trigger != 0) { + pthread_cond_wait (&s->condition_cond, &s->condition_mutex); + } + s->trigger = 1; + pthread_cond_signal (&s->condition_cond); + pthread_mutex_unlock (&s->condition_mutex); + + } + + // Wait end of all selected sub-tasks + + for (i=0; inb_sub_tasks; i++) { + if (!run_list[i]) continue; + sub_task_t *s = &t->sub_task_list[i]; + pthread_mutex_lock (&s->condition_mutex); + while (s->trigger != 0) { + pthread_cond_wait (&s->condition_cond, &s->condition_mutex); + } + pthread_mutex_unlock (&s->condition_mutex); + } + + return 0; +} + +int task_try_trig (task_t * t) +{ + assert (t != NULL); + + int i; + int nb_running = 0; + for (i=0; inb_sub_tasks; i++) nb_running += t->sub_task_list[i].trigger ? 1 : 0; + + if (nb_running != 0) { + t->overloads++; + return -1; + } + + task_trig(t); + + return 0; +} + +task_t *create_sync_task (const char *name, int (*task) (sub_task_t *, int), + float max_allowed_time_us, int (*init) (sub_task_t *, int), + int priority, int nb_sub_tasks, const char *cpu_list) +{ + int i; + + task_t *t = calloc (1, sizeof (*t)); + assert (t); + + t->name = strdup (name); + t->is_sync = 1; + t->task = task; + t->max_allowed_time = (long long) (max_allowed_time_us / tsc2ms (1)); + t->init = init; + t->priority = priority; + if (cpu_list) { + t->cpu_list = strdup(cpu_list); + for (i = 0; t->cpu_list[i] != 0; i++) { + if (t->cpu_list[i] == ':') { + t->cpu_list[i] = 0; + int nb = atoi (t->cpu_list + i + 1); + if (nb > 0) + nb_sub_tasks = nb; + } + } + } + pthread_mutex_init (&t->stats_mutex, NULL); + pthread_mutex_init (&t->init_mutex, NULL); + + t->sub_task_list = calloc (nb_sub_tasks, sizeof (sub_task_t)); + assert (t->sub_task_list); + t->nb_sub_tasks = nb_sub_tasks; + + printf("Creating task %s[%d] prio=%d cpu=%s ttl=%d\n", t->name, t->nb_sub_tasks, t->priority, t->cpu_list, (int)(max_allowed_time_us)); + + pthread_attr_t tattr; + int ret = 0; + + size_t size = 1024 * 1024; + + /* initialized with default attributes */ + ret |= pthread_attr_init (&tattr); + + /* setting the size of the stack also */ + ret |= pthread_attr_setstacksize (&tattr, size); + + for (i=0; isub_task_list[i].task = t; + t->sub_task_list[i].sub_task_id = i; + pthread_mutex_lock (&t->init_mutex); + pthread_create (&t->sub_task_list[i].thread, &tattr, task_sync_runner, &t->sub_task_list[i]); + } + + return t; +} + +void *task_async_runner (void *param) +{ + sub_task_t *s = (sub_task_t *) param; + task_t *t = s->task; + + cpu_setaffinity(t->cpu_list); + + if (t->priority) { + enable_realtime (t->priority); + } + pthread_mutex_init (&s->condition_mutex, NULL); + pthread_cond_init (&s->condition_cond, NULL); + + while (1) { + t->task (s, s->sub_task_id); + } + + return NULL; +} + +task_t *create_async_task (const char *name, int (*task) (sub_task_t *, int), + int priority, int nb_sub_tasks, const char *cpu_list) +{ + int i; + + task_t *t = calloc (1, sizeof (*t)); + assert (t); + + t->name = strdup (name); + t->is_sync = 0; + t->task = task; + t->priority = priority; + if (cpu_list) { + t->cpu_list = strdup(cpu_list); + for (i = 0; t->cpu_list[i] != 0; i++) { + if (t->cpu_list[i] == ':') { + t->cpu_list[i] = 0; + int nb = atoi (t->cpu_list + i + 1); + if (nb > 0) + nb_sub_tasks = nb; + } + } + } + + t->sub_task_list = calloc (nb_sub_tasks, sizeof (sub_task_t)); + assert (t->sub_task_list); + t->nb_sub_tasks = nb_sub_tasks; + + printf("Creating task %s[%d] prio=%d cpu=%s\n", t->name, t->nb_sub_tasks, t->priority, t->cpu_list); + + pthread_attr_t tattr; + int ret = 0; + + size_t size = 1024 * 1024; + + /* initialized with default attributes */ + ret |= pthread_attr_init (&tattr); + + /* setting the size of the stack also */ + ret |= pthread_attr_setstacksize (&tattr, size); + + for (i = 0; i < nb_sub_tasks; i++) { + t->sub_task_list[i].task = t; + t->sub_task_list[i].sub_task_id = i; + pthread_create (&t->sub_task_list[i].thread, &tattr, task_async_runner, &t->sub_task_list[i]); + } + + return t; +} + +/* vi:set tabstop=4 expandtab shiftwidth=4: this line set vi mode */ diff --git a/task.h b/task.h new file mode 100644 index 0000000..76e4b6f --- /dev/null +++ b/task.h @@ -0,0 +1,87 @@ +/* + File name : task.h + Date of creation : 25/01/2010 + Version : 1.0 + Copyright : Soft'n'Design + Author : Laurent Mazet + + Description : Task management + + History : + - initial version +*/ + +#ifndef __TASK_H__ +#define __TASK_H__ + +#include + +__BEGIN_DECLS + +struct _task_t; + +typedef struct { + pthread_t thread; + pthread_mutex_t condition_mutex; + pthread_cond_t condition_cond; + int trigger; + struct _task_t *task; + int sub_task_id; + + int count; + + unsigned long *start_time_us; + unsigned long *exec_time_us; +} sub_task_t; + + +typedef struct _task_t { + char *name; + int is_sync; + int priority; + char *cpu_list; + + int (*task) (sub_task_t *s, int subtask_id); + long long max_allowed_time; + + sub_task_t *sub_task_list; + int nb_sub_tasks; + + // Init function + + int (*init) (sub_task_t *s, int subtask_id); + pthread_mutex_t init_mutex; + + // Statistics section + + pthread_mutex_t stats_mutex; + + int count; + long long min_exec_time; + long long max_exec_time; + long long current_exec_time; + unsigned long long cumul_exec_time; + unsigned long int overtimes; + unsigned long int overloads; +} task_t; + +task_t *create_sync_task (const char *name, int (*task) (sub_task_t *, int), + float max_allowed_time_us, int (*init) (sub_task_t *, int), + int priority, int nb_sub_tasks, const char *cpu_list); + +task_t *create_async_task (const char *name, int (*task) (sub_task_t *, int), + int priority, int nb_sub_tasks, const char *cpu_list); + +int task_trig (task_t * t); + +int task_try_trig (task_t * t); + +int task_end (task_t * t); + +int task_selective_run (task_t * t, int run_list[]); + +void task_stat (task_t * t, int condensed); + +#endif /* __TASK_H__ */ + +/* vi:set tabstop=4 expandtab shiftwidth=4: this line set vi mode */ diff --git a/verbose.h b/verbose.h index 09daadf..0f91e24 100644 --- a/verbose.h +++ b/verbose.h @@ -132,9 +132,9 @@ __END_DECLS Get error and waring call number. @param module module name - @param level verbose level + @return level verbose level */ -#define GET_VERBOSE_ERRORS(module) verbose_errors_##module +#define GET_VERBOSE_LEVEL(module) verbose_errors_##module #endif /* __VERBOSE_H__ */ -- 2.30.2