pespin has submitted this change. ( 
https://gerrit.osmocom.org/c/osmocom-bb/+/30870 )

Change subject: modem: passive decoding of SI{3,4,13} and IA Rest Octets
......................................................................

modem: passive decoding of SI{3,4,13} and IA Rest Octets

Use the existing application skeleton from '$(top_srcdir)/src/common/'.
Use the LAPDm glue from '$(top_srcdir)/src/misc/rslms.c'.
This is what the misc applications like ccch_scan are using.

Change-Id: I8566a3cdc9f818bed7e28ea4b1957dce735c298b
Related: SYS#5500
---
M src/host/layer23/src/modem/Makefile.am
A src/host/layer23/src/modem/app_modem.c
D src/host/layer23/src/modem/modem_main.c
3 files changed, 330 insertions(+), 170 deletions(-)

Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, but someone else must approve
  pespin: Looks good to me, approved



diff --git a/src/host/layer23/src/modem/Makefile.am 
b/src/host/layer23/src/modem/Makefile.am
index 4fb3c11..522456a 100644
--- a/src/host/layer23/src/modem/Makefile.am
+++ b/src/host/layer23/src/modem/Makefile.am
@@ -13,7 +13,11 @@

 bin_PROGRAMS = modem

-modem_SOURCES = modem_main.c
+modem_SOURCES = \
+       $(top_srcdir)/src/common/main.c \
+       $(top_srcdir)/src/misc/rslms.c \
+       app_modem.c \
+       $(NULL)
 modem_LDADD = \
        $(top_builddir)/src/common/liblayer23.a \
        $(LIBOSMOCORE_LIBS) \
diff --git a/src/host/layer23/src/modem/app_modem.c 
b/src/host/layer23/src/modem/app_modem.c
new file mode 100644
index 0000000..48c216d
--- /dev/null
+++ b/src/host/layer23/src/modem/app_modem.c
@@ -0,0 +1,325 @@
+/* modem app (gprs) */
+
+/* (C) 2022 by sysmocom - s.m.f.c. GmbH <[email protected]>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/lienses/>.
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/signal.h>
+#include <osmocom/core/application.h>
+
+#include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/gsm48_ie.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gprs/rlcmac/gprs_rlcmac.h>
+
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/common/l1ctl.h>
+#include <osmocom/bb/common/l23_app.h>
+#include <osmocom/bb/common/sysinfo.h>
+#include <osmocom/bb/misc/rslms.h>
+#include <osmocom/bb/misc/layer3.h>
+
+#include <l1ctl_proto.h>
+
+static struct {
+       enum ccch_mode ccch_mode;
+       struct gsm48_sysinfo si;
+} app_data;
+
+static int handle_si1(struct osmocom_ms *ms, struct msgb *msg)
+{
+       int rc;
+
+       if (msgb_l3len(msg) != GSM_MACBLOCK_LEN)
+               return -EINVAL;
+       if (!memcmp(&app_data.si.si1_msg[0], msgb_l3(msg), msgb_l3len(msg)))
+               return 0; /* this message is already handled */
+
+       rc = gsm48_decode_sysinfo1(&app_data.si, msgb_l3(msg), msgb_l3len(msg));
+       if (rc != 0) {
+               LOGP(DRR, LOGL_ERROR, "Failed to decode SI1 message\n");
+               return rc;
+       }
+
+       return 0;
+}
+
+static int handle_si3(struct osmocom_ms *ms, struct msgb *msg)
+{
+       int rc;
+
+       if (msgb_l3len(msg) != GSM_MACBLOCK_LEN)
+               return -EINVAL;
+       if (!memcmp(&app_data.si.si3_msg[0], msgb_l3(msg), msgb_l3len(msg)))
+               return 0; /* this message is already handled */
+
+       rc = gsm48_decode_sysinfo3(&app_data.si, msgb_l3(msg), msgb_l3len(msg));
+       if (rc != 0) {
+               LOGP(DRR, LOGL_ERROR, "Failed to decode SI3 message\n");
+               return rc;
+       }
+
+       if (app_data.ccch_mode == CCCH_MODE_NONE) {
+               if (app_data.si.ccch_conf == RSL_BCCH_CCCH_CONF_1_C)
+                       app_data.ccch_mode = CCCH_MODE_COMBINED;
+               else
+                       app_data.ccch_mode = CCCH_MODE_NON_COMBINED;
+               l1ctl_tx_ccch_mode_req(ms, app_data.ccch_mode);
+       }
+
+       if (!app_data.si.gprs.supported) {
+               LOGP(DRR, LOGL_NOTICE, "SI3 Rest Octets IE contains no GPRS 
Indicator\n");
+               return 0;
+       }
+
+       LOGP(DRR, LOGL_NOTICE, "Found GPRS Indicator (RA Colour %u, SI13 on 
BCCH %s)\n",
+            app_data.si.gprs.ra_colour, app_data.si.gprs.si13_pos ? "Ext" : 
"Norm");
+
+       return 0;
+}
+
+static int handle_si4(struct osmocom_ms *ms, struct msgb *msg)
+{
+       int rc;
+
+       if (msgb_l3len(msg) != GSM_MACBLOCK_LEN)
+               return -EINVAL;
+       if (!memcmp(&app_data.si.si4_msg[0], msgb_l3(msg), msgb_l3len(msg)))
+               return 0; /* this message is already handled */
+
+       rc = gsm48_decode_sysinfo4(&app_data.si, msgb_l3(msg), msgb_l3len(msg));
+       if (rc != 0) {
+               LOGP(DRR, LOGL_ERROR, "Failed to decode SI4 message\n");
+               return rc;
+       }
+
+       if (!app_data.si.gprs.supported) {
+               LOGP(DRR, LOGL_NOTICE, "SI4 Rest Octets IE contains no GPRS 
Indicator\n");
+               return 0;
+       }
+
+       LOGP(DRR, LOGL_NOTICE, "Found GPRS Indicator (RA Colour %u, SI13 on 
BCCH %s)\n",
+            app_data.si.gprs.ra_colour, app_data.si.gprs.si13_pos ? "Ext" : 
"Norm");
+
+       return 0;
+}
+
+static int handle_si13(struct osmocom_ms *ms, struct msgb *msg)
+{
+       int rc;
+
+       if (msgb_l3len(msg) != GSM_MACBLOCK_LEN)
+               return -EINVAL;
+       if (!memcmp(&app_data.si.si13_msg[0], msgb_l3(msg), msgb_l3len(msg)))
+               return 0; /* this message is already handled */
+
+       rc = gsm48_decode_sysinfo13(&app_data.si, msgb_l3(msg), 
msgb_l3len(msg));
+       if (rc != 0)
+               return rc;
+
+       return 0;
+}
+
+int gsm48_rx_bcch(struct msgb *msg, struct osmocom_ms *ms)
+{
+       const struct gsm48_system_information_type_header *si_hdr = 
msgb_l3(msg);
+       const uint8_t si_type = si_hdr->system_information;
+
+       LOGP(DRR, LOGL_INFO, "BCCH message (type=0x%02x): %s\n",
+            si_type, gsm48_rr_msg_name(si_type));
+
+       switch (si_type) {
+       case GSM48_MT_RR_SYSINFO_1:
+               return handle_si1(ms, msg);
+       case GSM48_MT_RR_SYSINFO_3:
+               return handle_si3(ms, msg);
+       case GSM48_MT_RR_SYSINFO_4:
+               return handle_si4(ms, msg);
+       case GSM48_MT_RR_SYSINFO_13:
+               return handle_si13(ms, msg);
+       default:
+               return 0;
+       };
+}
+
+static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
+{
+       const struct gsm48_imm_ass *ia = msgb_l3(msg);
+       uint8_t ch_type, ch_subch, ch_ts;
+       int rc;
+
+       /* Discard CS channel assignment */
+       if ((ia->page_mode >> 4) == 0)
+               return 0;
+
+       if (rsl_dec_chan_nr(ia->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts) 
!= 0) {
+               LOGP(DRR, LOGL_ERROR,
+                    "%s(): rsl_dec_chan_nr(chan_nr=0x%02x) failed\n",
+                    __func__, ia->chan_desc.chan_nr);
+               return -EINVAL;
+       }
+
+       if (!ia->chan_desc.h0.h) {
+               /* Non-hopping */
+               uint16_t arfcn;
+
+               arfcn = ia->chan_desc.h0.arfcn_low | 
(ia->chan_desc.h0.arfcn_high << 8);
+
+               LOGP(DRR, LOGL_INFO, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, 
"
+                    "ARFCN=%u, TS=%u, SS=%u, TSC=%u)\n", ia->req_ref.ra,
+                    ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
+                    ia->chan_desc.h0.tsc);
+       } else {
+               /* Hopping */
+               uint8_t maio, hsn;
+
+               hsn = ia->chan_desc.h1.hsn;
+               maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high 
<< 2);
+
+               LOGP(DRR, LOGL_INFO, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, 
"
+                    "HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u)\n", ia->req_ref.ra,
+                    ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
+                    ia->chan_desc.h1.tsc);
+       }
+
+       const uint8_t *data = msgb_l3(msg) + sizeof(*ia) + ia->mob_alloc_len;
+       size_t data_len = msgb_l3len(msg) - (sizeof(*ia) + ia->mob_alloc_len);
+       IA_RestOctets_t iaro;
+
+       rc = osmo_gprs_rlcmac_decode_imm_ass_ro(&iaro, data, data_len);
+       if (rc != 0) {
+               LOGP(DRR, LOGL_ERROR, "Failed to decode IA Rest Octets IE\n");
+               return rc;
+       }
+
+       return 0;
+}
+
+/* Dummy Paging Request 1 with "no identity" */
+static const uint8_t paging_fill[] = {
+       0x15, 0x06, 0x21, 0x00, 0x01, 0xf0, 0x2b,
+       /* The rest part may be randomized */
+};
+
+/* LAPDm func=UI fill frame (for the BTS side) */
+static const uint8_t lapdm_fill[] = {
+       0x03, 0x03, 0x01, 0x2b,
+       /* The rest part may be randomized */
+};
+
+/* TODO: share / generalize this code */
+static bool is_fill_frame(const struct msgb *msg)
+{
+       const uint8_t *l2 = msgb_l3(msg);
+
+       if (!memcmp(l2, paging_fill, sizeof(paging_fill)))
+               return true;
+       if (!memcmp(l2, lapdm_fill, sizeof(lapdm_fill)))
+               return true;
+
+       return false;
+}
+
+int gsm48_rx_ccch(struct msgb *msg, struct osmocom_ms *ms)
+{
+       const struct gsm48_system_information_type_header *sih = msgb_l3(msg);
+
+       /* Skip frames with wrong length */
+       if (msgb_l3len(msg) != GSM_MACBLOCK_LEN) {
+               LOGP(DRR, LOGL_ERROR, "Rx CCCH message with odd length=%u: 
%s\n",
+                    msgb_l3len(msg), msgb_hexdump_l3(msg));
+               return -EINVAL;
+       }
+
+       /* Skip dummy (fill) frames */
+       if (is_fill_frame(msg))
+               return 0;
+
+       if (sih->rr_protocol_discriminator != GSM48_PDISC_RR) {
+               LOGP(DRR, LOGL_ERROR, "PCH pdisc (%s) != RR\n",
+                    gsm48_pdisc_name(sih->rr_protocol_discriminator));
+       }
+
+       switch (sih->system_information) {
+       case GSM48_MT_RR_IMM_ASS:
+               return gsm48_rx_imm_ass(msg, ms);
+       default:
+               return 0;
+       }
+}
+
+void layer3_app_reset(void)
+{
+       memset(&app_data, 0x00, sizeof(app_data));
+}
+
+static int signal_cb(unsigned int subsys, unsigned int signal,
+                    void *handler_data, void *signal_data)
+{
+       struct osmocom_ms *ms;
+
+       if (subsys != SS_L1CTL)
+               return 0;
+
+       switch (signal) {
+       case S_L1CTL_RESET:
+               ms = signal_data;
+               layer3_app_reset();
+               return l1ctl_tx_fbsb_req(ms, ms->test_arfcn,
+                                        L1CTL_FBSB_F_FB01SB, 100, 0,
+                                        CCCH_MODE_NONE, dbm2rxlev(-85));
+       }
+
+       return 0;
+}
+
+
+int l23_app_init(struct osmocom_ms *ms)
+{
+       log_set_category_filter(osmo_stderr_target, DLGLOBAL, 1, LOGL_DEBUG);
+       log_set_category_filter(osmo_stderr_target, DLCSN1, 1, LOGL_DEBUG);
+       log_set_category_filter(osmo_stderr_target, DRR, 1, LOGL_INFO);
+
+       osmo_signal_register_handler(SS_L1CTL, &signal_cb, NULL);
+       l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
+
+       return layer3_init(ms);
+}
+
+static int l23_cfg_supported(void)
+{
+       return L23_OPT_ARFCN | L23_OPT_TAP | L23_OPT_DBG;
+}
+
+static struct l23_app_info info = {
+       .copyright = "Copyright (C) 2022 by sysmocom - s.m.f.c. GmbH 
<[email protected]>\n",
+       .cfg_supported = &l23_cfg_supported,
+};
+
+struct l23_app_info *l23_app_info(void)
+{
+       return &info;
+}
diff --git a/src/host/layer23/src/modem/modem_main.c 
b/src/host/layer23/src/modem/modem_main.c
deleted file mode 100644
index 438c1fe..0000000
--- a/src/host/layer23/src/modem/modem_main.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/* modem app (gprs) */
-
-/* (C) 2022 by sysmocom - s.m.f.c. GmbH <[email protected]>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/lienses/>.
- *
- */
-
-#include <osmocom/bb/common/osmocom_data.h>
-#include <osmocom/bb/common/logging.h>
-#include <osmocom/bb/modem/modem.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/signal.h>
-#include <osmocom/core/application.h>
-
-#include <arpa/inet.h>
-
-#define _GNU_SOURCE
-#include <getopt.h>
-
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-
-void *tall_modem_ctx = NULL;
-int daemonize = 0;
-
-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.\n");
-       printf("  -D --daemonize        Run as daemon\n");
-}
-
-static int 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'},
-                       {"daemonize", 0, 0, 'D'},
-                       {0, 0, 0, 0},
-               };
-
-               c = getopt_long(argc, argv, "hi:u:c:v:d:Dm",
-                               long_options, &option_index);
-               if (c == -1)
-                       break;
-
-               switch (c) {
-               case 'h':
-                       print_usage(argv[0]);
-                       print_help();
-                       exit(0);
-                       break;
-               case 'd':
-                       log_parse_category_mask(osmo_stderr_target, optarg);
-                       break;
-               case 'D':
-                       daemonize = 1;
-                       break;
-               default:
-                       /* Unknown parameter passed */
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-
-void signal_handler(int signum)
-{
-       fprintf(stdout, "signal %u received\n", signum);
-
-       switch (signum) {
-       case SIGINT:
-       case SIGTERM:
-               exit(0);
-               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_modem_ctx, stderr);
-               signal(SIGABRT, SIG_DFL);
-               raise(SIGABRT);
-               break;
-       case SIGUSR1:
-               talloc_report(tall_modem_ctx, stderr);
-               break;
-       case SIGUSR2:
-               talloc_report_full(tall_modem_ctx, stderr);
-               break;
-       default:
-               break;
-       }
-}
-
-int modem_start(void)
-{
-       printf("Nothing to be done yet\n");
-       return 0;
-}
-
-int main(int argc, char **argv)
-{
-       int rc;
-
-       tall_modem_ctx = talloc_named_const(NULL, 1, "modem");
-       msgb_talloc_ctx_init(tall_modem_ctx, 0);
-       osmo_signal_talloc_ctx_init(tall_modem_ctx);
-
-       osmo_init_logging2(tall_modem_ctx, &log_info);
-
-       rc = handle_options(argc, argv);
-       if (rc) { /* Abort in case of parsing errors */
-               fprintf(stderr, "Error in command line options. Exiting.\n");
-               return 1;
-       }
-
-       signal(SIGINT, &signal_handler);
-       signal(SIGTERM, &signal_handler);
-       signal(SIGABRT, &signal_handler);
-       signal(SIGUSR1, &signal_handler);
-       signal(SIGUSR2, &signal_handler);
-       osmo_init_ignore_signals();
-
-       if (daemonize) {
-               printf("Running as daemon\n");
-               rc = osmo_daemonize();
-               if (rc)
-                       fprintf(stderr, "Failed to run as daemon\n");
-       }
-
-       modem_start();
-
-       while (!osmo_select_shutdown_done()) {
-               osmo_select_main_ctx(0);
-       }
-
-       talloc_report_full(tall_modem_ctx, stderr);
-       return 0;
-}

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

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: I8566a3cdc9f818bed7e28ea4b1957dce735c298b
Gerrit-Change-Number: 30870
Gerrit-PatchSet: 5
Gerrit-Owner: fixeria <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to