pespin has uploaded this change for review. (
https://gerrit.osmocom.org/c/libosmo-gprs/+/34044 )
Change subject: rlcmac: Fix rfn->fn calculation
......................................................................
rlcmac: Fix rfn->fn calculation
Change-Id: I00741289333853a8db472950ee2ac38dc2c74fd3
---
M include/osmocom/gprs/rlcmac/rlcmac_dec.h
M src/rlcmac/rlcmac_dec.c
M tests/rlcmac/Makefile.am
A tests/rlcmac/rlcmac_types_test.c
A tests/rlcmac/rlcmac_types_test.err
A tests/rlcmac/rlcmac_types_test.ok
M tests/testsuite.at
7 files changed, 189 insertions(+), 6 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-gprs refs/changes/44/34044/1
diff --git a/include/osmocom/gprs/rlcmac/rlcmac_dec.h
b/include/osmocom/gprs/rlcmac/rlcmac_dec.h
index f707dcb..d07a9df 100644
--- a/include/osmocom/gprs/rlcmac/rlcmac_dec.h
+++ b/include/osmocom/gprs/rlcmac/rlcmac_dec.h
@@ -47,6 +47,13 @@
struct bitvec *bits, int *bsn_begin, int *bsn_end,
struct gprs_rlcmac_rlc_ul_window *ulw);
+#define RFN_MODULUS 42432
+
+static inline uint16_t fn2rfn(uint32_t fn)
+{
+ return fn % RFN_MODULUS;
+}
+
uint32_t TBF_StartingTime_to_fn(const StartingTime_t *tbf_start_time, uint32_t curr_fn);
uint32_t TBF_Starting_Frame_Number_to_fn(const Starting_Frame_Number_t *tbf_start_fn,
uint32_t curr_fn);
diff --git a/src/rlcmac/rlcmac_dec.c b/src/rlcmac/rlcmac_dec.c
index d607aae..56d444c 100644
--- a/src/rlcmac/rlcmac_dec.c
+++ b/src/rlcmac/rlcmac_dec.c
@@ -429,15 +429,57 @@
return num_blocks;
}
+#define RFN_THRESHOLD (RFN_MODULUS / 2)
+/* Determine the full frame number from a relative frame number */
+static uint32_t rfn_to_fn(uint32_t rfn, uint32_t curr_fn)
+{
+ uint32_t curr_rfn;
+ uint32_t fn_rounded;
+
+ /* Ensure that all following calculations are performed with the
+ * relative frame number */
+ OSMO_ASSERT(rfn < RFN_MODULUS);
+
+ /* Compute an internal relative frame number from the full internal
+ frame number */
+ curr_rfn = fn2rfn(curr_fn);
+
+ /* Compute a "rounded" version of the internal frame number, which
+ * exactly fits in the RFN_MODULUS raster */
+ fn_rounded = GSM_TDMA_FN_SUB(curr_fn, curr_rfn);
+
+ /* If the delta between the internal and the external relative frame
+ * number exceeds a certain limit, we need to assume that the incoming
+ * request belongs to a the previous rfn period. To correct this,
+ * we roll back the rounded frame number by one RFN_MODULUS */
+ if (GSM_TDMA_FN_DIFF(rfn, curr_rfn) > RFN_THRESHOLD) {
+ LOGRLCMAC(LOGL_DEBUG, "Race condition between rfn (%u) and m_cur_fn (%u) detected:
"
+ "rfn belongs to the previous modulus %u cycle, wrapping...\n",
+ rfn, curr_fn, RFN_MODULUS);
+ if (fn_rounded < RFN_MODULUS) {
+ LOGRLCMAC(LOGL_DEBUG, "Cornercase detected: wrapping crosses %u border\n",
+ GSM_MAX_FN);
+ fn_rounded = GSM_TDMA_FN_SUB(GSM_MAX_FN, (GSM_TDMA_FN_SUB(RFN_MODULUS, fn_rounded)));
+ } else {
+ fn_rounded = GSM_TDMA_FN_SUB(fn_rounded, RFN_MODULUS);
+ }
+ }
+
+ /* The real frame number is the sum of the rounded frame number and the
+ * relative framenumber computed via RACH */
+ return GSM_TDMA_FN_SUM(fn_rounded, rfn);
+}
+
/* 12.21 Starting Frame Number Description */
uint32_t TBF_StartingTime_to_fn(const StartingTime_t *tbf_start_time, uint32_t curr_fn)
{
- const struct gsm_time g_time = {
- .t1 = tbf_start_time->N32,
- .t2 = tbf_start_time->N51,
- .t3 = tbf_start_time->N26
- };
- return gsm_gsmtime2fn(&g_time);
+ const uint8_t t1 = tbf_start_time->N32;
+ const uint8_t t3 = tbf_start_time->N51;
+ const uint8_t t2 = tbf_start_time->N26;
+ const uint16_t rfn = (51 * ((t3 - t2) % 26)) + t3 + 51 * 26 * t1;
+ const uint32_t fn = rfn_to_fn(rfn, curr_fn);
+ LOGRLCMAC(LOGL_DEBUG, "curr_fn=%u + RFN=%u -> FN=%u\n", curr_fn, rfn, fn);
+ return fn;
}
diff --git a/tests/rlcmac/Makefile.am b/tests/rlcmac/Makefile.am
index 9d1f5b0..c13d179 100644
--- a/tests/rlcmac/Makefile.am
+++ b/tests/rlcmac/Makefile.am
@@ -16,6 +16,7 @@
csn1_ts_44_018_test \
csn1_ts_44_060_test \
rlcmac_prim_test \
+ rlcmac_types_test \
$(NULL)
EXTRA_DIST = \
@@ -25,6 +26,8 @@
csn1_ts_44_060_test.err \
rlcmac_prim_test.ok \
rlcmac_prim_test.err \
+ rlcmac_types_test.ok \
+ rlcmac_types_test.err \
$(NULL)
# Common LDADD entries
@@ -44,3 +47,6 @@
rlcmac_prim_test_SOURCES = rlcmac_prim_test.c
rlcmac_prim_test_LDADD = $(LDADD)
+
+rlcmac_types_test_SOURCES = rlcmac_types_test.c
+rlcmac_types_test_LDADD = $(LDADD)
\ No newline at end of file
diff --git a/tests/rlcmac/rlcmac_types_test.c b/tests/rlcmac/rlcmac_types_test.c
new file mode 100644
index 0000000..18ecda9
--- /dev/null
+++ b/tests/rlcmac/rlcmac_types_test.c
@@ -0,0 +1,87 @@
+/* rlcmac_types_test.c
+ *
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ *
+ * 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 <stdint.h>
+#include <stdio.h>
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/select.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/gsm48_rest_octets.h>
+
+#include <osmocom/gprs/rlcmac/rlcmac.h>
+#include <osmocom/gprs/rlcmac/csn1_defs.h>
+#include <osmocom/gprs/rlcmac/rlcmac_dec.h>
+
+static void *tall_ctx = NULL;
+
+
+/* SGSN->PCU->BTS --PCH--> MS containing "Paging Request Type 1"
asking for PS services.
+ * RLCMAC will send GMMRR-PAGE.ind to GMM layer, which is in charge of orchestrating the
response. */
+static void test_tbf_starting_time_to_fn(const uint32_t cur_fn, const uint32_t fn)
+{
+ const uint16_t rfn = fn2rfn(fn);
+ StartingTime_t st;
+
+ printf("=== %s(cur_fn=%u, fn=%u) start ===\n", __func__, cur_fn, fn);
+
+ /* TBF_STARTING_TIME -- same as 3GPP TS 44.018 §10.5.2.38 Starting Time without tag: */
+ st.N32 = (rfn / (26 * 51)) % 32;
+ st.N51 = rfn % 51;
+ st.N26 = rfn % 26;
+
+ printf("cur_fn=%u fn=%u rfn=%u [T1'=%u T3=%u T2=%u]\n",
+ cur_fn, fn, rfn, st.N32, st.N51, st.N26);
+
+ uint32_t res_fn = TBF_StartingTime_to_fn(&st, cur_fn);
+ printf("res_fn=%u\n", res_fn);
+ OSMO_ASSERT(res_fn == fn);
+
+ printf("=== %s(cur_fn=%u, fn=%u) end ===\n", __func__, cur_fn, fn);
+}
+
+static const struct log_info_cat test_log_categories[] = { };
+static const struct log_info test_log_info = {
+ .cat = test_log_categories,
+ .num_cat = ARRAY_SIZE(test_log_categories),
+};
+
+int main(int argc, char *argv[])
+{
+ tall_ctx = talloc_named_const(NULL, 1, __FILE__);
+
+ osmo_init_logging2(tall_ctx, &test_log_info);
+ log_parse_category_mask(osmo_stderr_target, "DLGLOBAL,1:");
+ osmo_fsm_log_addr(false);
+
+ log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
+ 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_use_color(osmo_stderr_target, 0);
+
+ test_tbf_starting_time_to_fn(0, 0);
+ test_tbf_starting_time_to_fn(0, 4);
+ test_tbf_starting_time_to_fn(2229729, 2229786);
+ test_tbf_starting_time_to_fn(2229777, 2229786);
+ test_tbf_starting_time_to_fn(1320458, 1320462);
+
+ talloc_free(tall_ctx);
+}
diff --git a/tests/rlcmac/rlcmac_types_test.err b/tests/rlcmac/rlcmac_types_test.err
new file mode 100644
index 0000000..fd860eb
--- /dev/null
+++ b/tests/rlcmac/rlcmac_types_test.err
@@ -0,0 +1,5 @@
+DLGLOBAL DEBUG curr_fn=0 + RFN=0 -> FN=0
+DLGLOBAL DEBUG curr_fn=0 + RFN=4 -> FN=4
+DLGLOBAL DEBUG curr_fn=2229729 + RFN=23322 -> FN=2229786
+DLGLOBAL DEBUG curr_fn=2229777 + RFN=23322 -> FN=2229786
+DLGLOBAL DEBUG curr_fn=1320458 + RFN=5070 -> FN=1320462
diff --git a/tests/rlcmac/rlcmac_types_test.ok b/tests/rlcmac/rlcmac_types_test.ok
new file mode 100644
index 0000000..2075682
--- /dev/null
+++ b/tests/rlcmac/rlcmac_types_test.ok
@@ -0,0 +1,20 @@
+=== test_tbf_starting_time_to_fn(cur_fn=0, fn=0) start ===
+cur_fn=0 fn=0 rfn=0 [T1'=0 T3=0 T2=0]
+res_fn=0
+=== test_tbf_starting_time_to_fn(cur_fn=0, fn=0) end ===
+=== test_tbf_starting_time_to_fn(cur_fn=0, fn=4) start ===
+cur_fn=0 fn=4 rfn=4 [T1'=0 T3=4 T2=4]
+res_fn=4
+=== test_tbf_starting_time_to_fn(cur_fn=0, fn=4) end ===
+=== test_tbf_starting_time_to_fn(cur_fn=2229729, fn=2229786) start ===
+cur_fn=2229729 fn=2229786 rfn=23322 [T1'=17 T3=15 T2=0]
+res_fn=2229786
+=== test_tbf_starting_time_to_fn(cur_fn=2229729, fn=2229786) end ===
+=== test_tbf_starting_time_to_fn(cur_fn=2229777, fn=2229786) start ===
+cur_fn=2229777 fn=2229786 rfn=23322 [T1'=17 T3=15 T2=0]
+res_fn=2229786
+=== test_tbf_starting_time_to_fn(cur_fn=2229777, fn=2229786) end ===
+=== test_tbf_starting_time_to_fn(cur_fn=1320458, fn=1320462) start ===
+cur_fn=1320458 fn=1320462 rfn=5070 [T1'=3 T3=21 T2=0]
+res_fn=1320462
+=== test_tbf_starting_time_to_fn(cur_fn=1320458, fn=1320462) end ===
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 74fd43a..ce51e35 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -64,6 +64,13 @@
AT_CHECK([$abs_top_builddir/tests/rlcmac/rlcmac_prim_test], [0], [expout], [experr])
AT_CLEANUP
+AT_SETUP([rlcmac/rlcmac_types])
+AT_KEYWORDS([rlcmac rlcmac_types])
+cat $abs_srcdir/rlcmac/rlcmac_types_test.ok > expout
+cat $abs_srcdir/rlcmac/rlcmac_types_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/rlcmac/rlcmac_types_test], [0], [expout], [experr])
+AT_CLEANUP
+
AT_SETUP([sm/sm_prim])
AT_KEYWORDS([sm sm_prim])
cat $abs_srcdir/sm/sm_prim_test.ok > expout
--
To view, visit
https://gerrit.osmocom.org/c/libosmo-gprs/+/34044
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: libosmo-gprs
Gerrit-Branch: master
Gerrit-Change-Id: I00741289333853a8db472950ee2ac38dc2c74fd3
Gerrit-Change-Number: 34044
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: newchange