fixeria has uploaded this change for review. (
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
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, 324 insertions(+), 170 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/70/30870/1
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..c19bfda
--- /dev/null
+++ b/src/host/layer23/src/modem/app_modem.c
@@ -0,0 +1,319 @@
+/* modem app (gprs) */
+
+/* (C) 2022 by sysmocom - s.m.f.c. GmbH <info(a)sysmocom.de>
+ * 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 struct l23_app_info info = {
+ .copyright = "Copyright (C) 2022 by sysmocom - s.m.f.c. GmbH
<info(a)sysmocom.de>\n"gt;\n",
+};
+
+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 <info(a)sysmocom.de>
- * 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: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange