initial version of crypto module
authorMazet Laurent <laurent.mazet@thalesgroup.com>
Fri, 2 May 2025 21:54:59 +0000 (23:54 +0200)
committerMazet Laurent <laurent.mazet@thalesgroup.com>
Fri, 2 May 2025 21:54:59 +0000 (23:54 +0200)
core.c [new file with mode: 0644]
core.h [new file with mode: 0644]
cryptomod.c [new file with mode: 0644]
cryptomod.h [new file with mode: 0644]
rdtsc.h [new file with mode: 0644]
task.c [new file with mode: 0644]
task.h [new file with mode: 0644]
verbose.h

diff --git a/core.c b/core.c
new file mode 100644 (file)
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 <mazet@softndesign.org>
+
+  Description      : Miscellaenous functions on core/thread management
+
+  History          :
+  - initial version from tools.h
+*/
+
+#define _GNU_SOURCE
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#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, &param);
+}
+
+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 (file)
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 <mazet@softndesign.org>
+
+  Description      : Miscellaenous functions on core/thread management
+
+  History          :
+  - initial version from tools.h
+*/
+
+#ifndef __CORE_H__
+#define __CORE_H__
+
+#include <sys/cdefs.h>
+
+__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 (file)
index 0000000..afeb71f
--- /dev/null
@@ -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 <laurent.mazet@thalesgroup.com>
+
+  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 <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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 (file)
index 0000000..64661fe
--- /dev/null
@@ -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 <laurent.mazet@thalesgroup.com>
+
+  Description      : This file defines crypto module types
+
+  History          :
+  - initial version
+*/
+
+#ifndef __CRYPTOMOD_H__
+#define __CRYPTOMOD_H__
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__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, /**<zeroize function */
+    lock_crypto_func_e /**< lock crypto module function */
+} func_t;
+
+/**
+   @ingroup CRYPTOMOD
+
+   Message type
+*/
+typedef struct {
+    char *name; /**< message name */
+    service_id_t service_id; /**< associated service id */
+    uint8_t msgtype; /**< message id */
+    pdu_t pdu; /**< associated PDU type */
+    func_t func; /**< function type */
+} message_t;
+
+/**
+   @ingroup CRYPTOMOD
+
+   Service type
+*/
+typedef struct {
+    char *name; /**< service name */
+    service_id_t service_id; /**< service id */
+    char *tx; /**< URL for associated TX communication channel */
+    char *rx; /**< URL for assiciated RX communication channel */
+} service_t;
+
+/**
+   @ingroup CRYPTOMOD
+
+   Module states
+*/
+typedef enum {
+    ok_e = 0, /**< ok/idle state */
+    booting_e, /**< booting state */
+    starting_e, /**< starting state */
+    initializing_e, /**< initializing state */
+    ready_e, /**< ready state */
+    working_e, /**< working state */
+    shutdowning_e, /**< shutdowning state */
+    error_e = 255 /**< error state */
+} state_t;
+
+#endif /* __CRYPTOMOD_H__ */
+
+/* vim: set ts=4 sw=4 si et: */
diff --git a/rdtsc.h b/rdtsc.h
new file mode 100644 (file)
index 0000000..f03e1f8
--- /dev/null
+++ b/rdtsc.h
@@ -0,0 +1,45 @@
+/*
+  File name        : rdtsc.h
+  Date of creation : 26/1/2012
+  Version          : 1.0
+  Copyright        : Soft'n'design
+  Author           : Laurent Mazet <mazet@softndesign.org>
+
+  Description      : This file contains rdtsc inline function
+
+  History          :
+  - initial version
+*/
+
+#ifndef __RDTSC_H__
+#define __RDTSC_H__
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__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 (file)
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 <mazet@softndesign,org>
+
+  Description      : Task management
+
+  History          :
+  - initial version
+*/
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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; i<t->nb_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; i<t->nb_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; i<t->nb_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; i<t->nb_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; i<t->nb_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; i<nb_sub_tasks; i++) {
+        t->sub_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 (file)
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 <mazet@softndesign,org>
+
+  Description      : Task management
+
+  History          :
+  - initial version
+*/
+
+#ifndef __TASK_H__
+#define __TASK_H__
+
+#include <pthread.h>
+
+__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 */
index 09daadfcfd64dc997fd41e8b2b94c13f440bf3ca..0f91e2456c4470cc14101209d5ed0233f7d56053 100644 (file)
--- 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__ */