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@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