fixeria has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/osmocom-bb/+/30745 )


Change subject: trxcon: add (optional) l1gprs_test binary for TTCN-3
......................................................................

trxcon: add (optional) l1gprs_test binary for TTCN-3

Change-Id: I36ceec4035b2ea593d47998f3f14f1415c606765
Related: OS#5500
---
M src/host/trxcon/.gitignore
M src/host/trxcon/configure.ac
M src/host/trxcon/src/Makefile.am
M src/host/trxcon/src/gprs.c
A src/host/trxcon/src/l1gprs_test.c
M src/host/trxcon/src/logging.c
6 files changed, 374 insertions(+), 4 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/45/30745/1

diff --git a/src/host/trxcon/.gitignore b/src/host/trxcon/.gitignore
index b5c3a99..da1a961 100644
--- a/src/host/trxcon/.gitignore
+++ b/src/host/trxcon/.gitignore
@@ -28,6 +28,7 @@
 *.la

 /src/trxcon
+/src/l1gprs_test

 # various
 .version
diff --git a/src/host/trxcon/configure.ac b/src/host/trxcon/configure.ac
index b22d1c8..dfaf97d 100644
--- a/src/host/trxcon/configure.ac
+++ b/src/host/trxcon/configure.ac
@@ -24,6 +24,14 @@
 dnl init libtool
 LT_INIT

+AC_ARG_WITH(l1gprs_test, [
+       AS_HELP_STRING(
+               [--with-l1gprs-test],
+               [Enable building l1gprs_test binary])
+       ])
+
+AM_CONDITIONAL(ENABLE_L1GPRS_TEST, [test "x$with_l1gprs_test" = "xyes"])
+
 AC_ARG_ENABLE(sanitize,
        [AS_HELP_STRING(
                [--enable-sanitize],
diff --git a/src/host/trxcon/src/Makefile.am b/src/host/trxcon/src/Makefile.am
index 44546d1..f1db13f 100644
--- a/src/host/trxcon/src/Makefile.am
+++ b/src/host/trxcon/src/Makefile.am
@@ -53,6 +53,21 @@
        $(NULL)


+if ENABLE_L1GPRS_TEST
+noinst_PROGRAMS = l1gprs_test
+
+l1gprs_test_SOURCES = \
+       l1ctl_server.c \
+       l1gprs_test.c \
+       logging.c \
+       $(NULL)
+
+l1gprs_test_LDADD = \
+       libl1gprs.la \
+       $(NULL)
+endif
+
+
 bin_PROGRAMS = trxcon

 trxcon_SOURCES = \
diff --git a/src/host/trxcon/src/gprs.c b/src/host/trxcon/src/gprs.c
index a550946..a5e4c5d 100644
--- a/src/host/trxcon/src/gprs.c
+++ b/src/host/trxcon/src/gprs.c
@@ -133,6 +133,9 @@
 {
        const enum osmo_gprs_cs cs = 
osmo_gprs_dl_cs_by_block_bytes(ind->data_len);

+       LOGP_PDCH(pdch, LOGL_DEBUG, "Rx PDTCH/D block (fn=%u, len=%zu): %s\n",
+                 ind->frame_nr, ind->data_len, osmo_hexdump(ind->data, 
ind->data_len));
+
        if (!pdch->enabled) {
                LOGP_PDCH(pdch, LOGL_ERROR, "Rx PDTCH/D block for disabled 
PDCH\n");
                return -ENODEV;
@@ -158,6 +161,9 @@
 int l1gprs_handle_ptcch_ind(struct l1gprs_pdch *pdch,
                            const struct l1gprs_prim_data_ind *ind)
 {
+       LOGP_PDCH(pdch, LOGL_DEBUG, "Rx PTCCH/D block (fn=%u, len=%zu): %s\n",
+                 ind->frame_nr, ind->data_len, osmo_hexdump(ind->data, 
ind->data_len));
+
        if (!pdch->enabled) {
                LOGP_PDCH(pdch, LOGL_ERROR, "Rx PTCCH/D block for disabled 
PDCH\n");
                return -ENODEV;
@@ -170,8 +176,5 @@
                return -EINVAL;
        }

-       LOGP_PDCH(pdch, LOGL_INFO, "Rx PTCCH/D block: %s\n",
-                 osmo_hexdump(ind->data, ind->data_len));
-
        return 0;
 }
diff --git a/src/host/trxcon/src/l1gprs_test.c 
b/src/host/trxcon/src/l1gprs_test.c
new file mode 100644
index 0000000..315e99d
--- /dev/null
+++ b/src/host/trxcon/src/l1gprs_test.c
@@ -0,0 +1,343 @@
+/*
+ * MS side L1 GPRS implementation (testing gate)
+ *
+ * (C) 2022 by sysmocom - s.f.m.c. GmbH <[email protected]>
+ * Author: Vadim Yanitskiy <[email protected]>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <time.h>
+
+#include <arpa/inet.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/signal.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/gsmtap_util.h>
+#include <osmocom/core/gsmtap.h>
+
+#include <osmocom/bb/trxcon/l1ctl_server.h>
+#include <osmocom/bb/trxcon/l1ctl_proto.h>
+#include <osmocom/bb/trxcon/logging.h>
+
+#include <osmocom/bb/l1gprs/l1gprs.h>
+#include <osmocom/bb/l1gprs/logging.h>
+
+#define COPYRIGHT \
+       "Copyright (C) 2022 by sysmocom - s.f.m.c. GmbH <[email protected]>\n" \
+       "License GPLv2+: GNU GPL version 2 or later " \
+       "<http://gnu.org/licenses/gpl.html>\n" \
+       "This is free software: you are free to change and redistribute it.\n" \
+       "There is NO WARRANTY, to the extent permitted by law.\n\n"
+
+static struct {
+       const char *debug_mask;
+       int daemonize;
+       int quit;
+
+       /* L1CTL specific */
+       unsigned int max_clients;
+       const char *bind_socket;
+
+       /* GSMTAP specific */
+       struct gsmtap_inst *gsmtap;
+       const char *gsmtap_ip;
+} app_data = {
+       .max_clients = 1, /* only one L1CTL client by default */
+       .bind_socket = "/tmp/osmocom_l2",
+};
+
+static void *tall_ctx = NULL;
+
+static int l1ctl_rx_cb(struct l1ctl_client *l1c, struct msgb *msg)
+{
+       struct l1gprs_grr_inst *grr = l1c->priv;
+       struct l1ctl_hdr *l1h = (struct l1ctl_hdr *)msg->l1h;
+
+       switch (l1h->msg_type) {
+       case L1CTL_RESET_REQ:
+       {
+               LOGP_GRR(grr, LOGL_NOTICE, "Resetting GRR state\n");
+
+               for (unsigned int tn = 0; tn < ARRAY_SIZE(grr->pdch); tn++)
+                       l1gprs_pdch_disable(&grr->pdch[tn]);
+
+               /* Reuse the original msgb for sending RESET.cnf */
+               l1h->msg_type = L1CTL_RESET_CONF;
+               return l1ctl_client_send(l1c, msg);
+       }
+       case L1CTL_DM_EST_REQ: /* PDCH activation */
+       case L1CTL_DM_REL_REQ: /* PDCH deactivation */
+       {
+               const struct l1ctl_info_ul *ulh = (void *)l1h->data;
+               struct l1gprs_pdch *pdch = &grr->pdch[ulh->chan_nr & 0x07];
+
+               if (l1h->msg_type == L1CTL_DM_EST_REQ) {
+                       if (l1gprs_pdch_enable(pdch) != 0)
+                               LOGP_PDCH(pdch, LOGL_ERROR, "failed to 
enable\n");
+               } else {
+                       if (l1gprs_pdch_disable(pdch) != 0)
+                               LOGP_PDCH(pdch, LOGL_ERROR, "failed to 
disable\n");
+               }
+               break;
+       }
+       case L1CTL_DATA_IND:
+       {
+               const struct l1ctl_info_dl *dlh = (void *)l1h->data;
+               struct l1gprs_pdch *pdch = &grr->pdch[dlh->chan_nr & 0x07];
+               const struct l1gprs_prim_data_ind grr_ind = {
+                       .frame_nr = ntohl(dlh->frame_nr),
+                       .data_len = msg->tail - dlh->payload,
+                       .data = &dlh->payload[0],
+               };
+
+               if (dlh->link_id == 0x00)
+                       l1gprs_handle_pdtch_ind(pdch, &grr_ind);
+               else
+                       l1gprs_handle_ptcch_ind(pdch, &grr_ind);
+
+               /* TODO: send over GSMTAP */
+               break;
+       }
+       default:
+               LOGP(DAPP, LOGL_ERROR,
+                    "%sL1CTL message 0x%02x is not supported\n",
+                    grr->log_prefix, l1h->msg_type);
+               break;
+       }
+
+       msgb_free(msg);
+       return 0;
+}
+
+static void l1ctl_conn_accept_cb(struct l1ctl_client *l1c)
+{
+       struct l1gprs_grr_inst *grr;
+
+       grr = l1gprs_grr_inst_alloc(l1c, NULL, l1c);
+       if (grr == NULL) {
+               LOGP(DAPP, LOGL_ERROR, "l1gprs_grr_inst_alloc() failed\n");
+               l1ctl_client_conn_close(l1c);
+               return;
+       }
+
+       l1c->log_prefix = talloc_asprintf(l1c, "l1c[%p]: ", l1c);
+       l1c->priv = grr;
+}
+
+static void l1ctl_conn_close_cb(struct l1ctl_client *l1c)
+{
+       struct l1gprs_grr_inst *grr = l1c->priv;
+
+       l1gprs_grr_inst_free(grr);
+}
+
+static void print_usage(const char *app)
+{
+       printf("Usage: %s\n", app);
+}
+
+static void print_help(void)
+{
+       printf(" Some help...\n");
+       printf("  -h --help         this text\n");
+       printf("  -d --debug        Change debug flags (e.g. DL1C:DSCH)\n");
+       printf("  -s --socket       Listening socket for layer23 (default 
/tmp/osmocom_l2)\n");
+       printf("  -g --gsmtap-ip    The destination IP used for GSMTAP 
(disabled by default)\n");
+       printf("  -D --daemonize    Run as daemon\n");
+}
+
+static void handle_options(int argc, char **argv)
+{
+       while (1) {
+               int option_index = 0, c;
+               static struct option long_options[] = {
+                       {"help", 0, 0, 'h'},
+                       {"debug", 1, 0, 'd'},
+                       {"socket", 1, 0, 's'},
+                       {"gsmtap-ip", 1, 0, 'g'},
+                       {"daemonize", 0, 0, 'D'},
+                       {0, 0, 0, 0}
+               };
+
+               c = getopt_long(argc, argv, "d:s:g:Dh",
+                               long_options, &option_index);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_usage(argv[0]);
+                       print_help();
+                       exit(0);
+                       break;
+               case 'd':
+                       app_data.debug_mask = optarg;
+                       break;
+               case 's':
+                       app_data.bind_socket = optarg;
+                       break;
+               case 'g':
+                       app_data.gsmtap_ip = optarg;
+                       break;
+               case 'D':
+                       app_data.daemonize = 1;
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void signal_handler(int signum)
+{
+       fprintf(stderr, "signal %u received\n", signum);
+
+       switch (signum) {
+       case SIGINT:
+       case SIGTERM:
+               app_data.quit++;
+               break;
+       case SIGABRT:
+               /* in case of abort, we want to obtain a talloc report and
+                * then run default SIGABRT handler, who will generate coredump
+                * and abort the process. abort() should do this for us after we
+                * return, but program wouldn't exit if an external SIGABRT is
+                * received.
+                */
+               talloc_report_full(tall_ctx, stderr);
+               signal(SIGABRT, SIG_DFL);
+               raise(SIGABRT);
+               break;
+       case SIGUSR1:
+       case SIGUSR2:
+               talloc_report_full(tall_ctx, stderr);
+               break;
+       default:
+               break;
+       }
+}
+
+int main(int argc, char **argv)
+{
+       struct l1ctl_server_cfg server_cfg;
+       struct l1ctl_server *server = NULL;
+       int rc = 0;
+
+       printf("%s", COPYRIGHT);
+       handle_options(argc, argv);
+
+       /* Track the use of talloc NULL memory contexts */
+       talloc_enable_null_tracking();
+
+       /* Init talloc memory management system */
+       tall_ctx = talloc_init("l1gprs_test context");
+       msgb_talloc_ctx_init(tall_ctx, 0);
+
+       /* Setup signal handlers */
+       signal(SIGINT, &signal_handler);
+       signal(SIGTERM, &signal_handler);
+       signal(SIGABRT, &signal_handler);
+       signal(SIGUSR1, &signal_handler);
+       signal(SIGUSR2, &signal_handler);
+       osmo_init_ignore_signals();
+
+       /* Init logging system */
+       trxcon_logging_init(tall_ctx, app_data.debug_mask);
+       l1gprs_logging_init(DGRR);
+
+       log_set_category_filter(osmo_stderr_target, DLCSN1, 1, LOGL_DEBUG);
+
+       /* Configure pretty logging */
+       log_set_print_extended_timestamp(osmo_stderr_target, 1);
+       log_set_print_category_hex(osmo_stderr_target, 0);
+       log_set_print_category(osmo_stderr_target, 1);
+       log_set_print_level(osmo_stderr_target, 1);
+
+       log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
+       log_set_print_filename_pos(osmo_stderr_target, 
LOG_FILENAME_POS_LINE_END);
+
+       /* Optional GSMTAP  */
+       if (app_data.gsmtap_ip != NULL) {
+               app_data.gsmtap = gsmtap_source_init(app_data.gsmtap_ip, 
GSMTAP_UDP_PORT, 1);
+               if (!app_data.gsmtap) {
+                       LOGP(DAPP, LOGL_ERROR, "Failed to init GSMTAP\n");
+                       goto exit;
+               }
+               /* Suppress ICMP "destination unreachable" errors */
+               gsmtap_source_add_sink(app_data.gsmtap);
+       }
+
+       /* Start the L1CTL server */
+       server_cfg = (struct l1ctl_server_cfg) {
+               .sock_path = app_data.bind_socket,
+               .num_clients_max = app_data.max_clients,
+               .conn_read_cb = &l1ctl_rx_cb,
+               .conn_accept_cb = &l1ctl_conn_accept_cb,
+               .conn_close_cb = &l1ctl_conn_close_cb,
+       };
+
+       server = l1ctl_server_alloc(tall_ctx, &server_cfg);
+       if (server == NULL) {
+               rc = EXIT_FAILURE;
+               goto exit;
+       }
+
+       LOGP(DAPP, LOGL_NOTICE, "Init complete\n");
+
+       if (app_data.daemonize) {
+               rc = osmo_daemonize();
+               if (rc < 0) {
+                       perror("Error during daemonize");
+                       goto exit;
+               }
+       }
+
+       /* Initialize pseudo-random generator */
+       srand(time(NULL));
+
+       while (!app_data.quit)
+               osmo_select_main(0);
+
+exit:
+       if (server != NULL)
+               l1ctl_server_free(server);
+
+       /* Deinitialize logging */
+       log_fini();
+
+       /**
+        * Print report for the root talloc context in order
+        * to be able to find and fix potential memory leaks.
+        */
+       talloc_report_full(tall_ctx, stderr);
+       talloc_free(tall_ctx);
+
+       /* Make both Valgrind and ASAN happy */
+       talloc_report_full(NULL, stderr);
+       talloc_disable_null_tracking();
+
+       return rc;
+}
diff --git a/src/host/trxcon/src/logging.c b/src/host/trxcon/src/logging.c
index e98d79a..c0803f6 100644
--- a/src/host/trxcon/src/logging.c
+++ b/src/host/trxcon/src/logging.c
@@ -69,7 +69,7 @@
        [DGRR] = {
                .name = "DGRR",
                .description = "GPRS RR",
-               .color = "\033[1;36m",
+               .color = "\033[0;96m",
                .enabled = 1, .loglevel = LOGL_DEBUG,
        },
 };

--
To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/30745
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: I36ceec4035b2ea593d47998f3f14f1415c606765
Gerrit-Change-Number: 30745
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <[email protected]>
Gerrit-MessageType: newchange

Reply via email to