pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/34145 )
Change subject: gsm: Introduce functions to convert between FN and RFN (Reduced FN) ......................................................................
gsm: Introduce functions to convert between FN and RFN (Reduced FN)
Implementation ported from osmo-pcu.git e98b315d12fb009359410809f4169f9380f3d933, function bts_rfn_to_fn().
This functionality can be used by osmo-pcu, libosmo-gprs or any other related code which needs to handle RFNs.
Change-Id: Ib71e8da976f6cc84c3a4ab17b0a8c2101492e243 --- M include/osmocom/gsm/gsm_utils.h M src/gsm/gsm_utils.c M src/gsm/libosmogsm.map M tests/gsm0408/gsm0408_test.c 4 files changed, 90 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/45/34145/1
diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h index 721456d..b250c59 100644 --- a/include/osmocom/gsm/gsm_utils.h +++ b/include/osmocom/gsm/gsm_utils.h @@ -188,6 +188,14 @@ char *osmo_dump_gsmtime_buf(char *buf, size_t buf_len, const struct gsm_time *tm); char *osmo_dump_gsmtime_c(const void *ctx, const struct gsm_time *tm);
+/* Reduced Frame Number (3GPP TS 44.018 §10.5.2.38) */ +#define GSM_RFN_MODULUS 42432 +uint32_t gsm_rfn2fn(uint16_t rfn, uint32_t curr_fn); +static inline uint16_t gsm_fn2rfn(uint32_t fn) +{ + return fn % GSM_RFN_MODULUS; +} + /* GSM TS 03.03 Chapter 2.6 */ enum gprs_tlli_type { TLLI_LOCAL, diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c index 06b2406..bb40339 100644 --- a/src/gsm/gsm_utils.c +++ b/src/gsm/gsm_utils.c @@ -80,6 +80,7 @@ #include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/meas_rep.h> #include <osmocom/gsm/protocol/gsm_04_08.h> +#include <osmocom/gsm/gsm0502.h>
#include <stdlib.h> #include <stdint.h> @@ -924,6 +925,45 @@ return osmo_dump_gsmtime_buf(buf, 64, tm); }
+#define GSM_RFN_THRESHOLD (GSM_RFN_MODULUS / 2) +uint32_t gsm_rfn2fn(uint16_t rfn, uint32_t curr_fn) +{ + uint32_t curr_rfn; + uint32_t fn_rounded; + const uint32_t rfn32 = rfn; /* used as 32bit for calculations */ + + /* Ensure that all following calculations are performed with the + * relative frame number */ + OSMO_ASSERT(rfn32 < GSM_RFN_MODULUS); + + /* Compute an internal relative frame number from the full internal + frame number */ + curr_rfn = gsm_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(rfn32, curr_rfn) > GSM_RFN_THRESHOLD) { + /* Race condition between rfn and curr_fn detected: rfn belongs + to the previous RFN_MODULUS cycle, wrapping... */ + if (fn_rounded < GSM_RFN_MODULUS) { + /* Corner case detected: wrapping crosses GSM_MAX_FN border */ + fn_rounded = GSM_TDMA_FN_SUB(GSM_MAX_FN, (GSM_TDMA_FN_SUB(GSM_RFN_MODULUS, fn_rounded))); + } else { + fn_rounded = GSM_TDMA_FN_SUB(fn_rounded, GSM_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, rfn32); +} + /*! append range1024 encoded data to bit vector * \param[out] bv Caller-provided output bit-vector * \param[in] r Input Range1024 sructure */ diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 951cbcb..49db282 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -544,6 +544,7 @@ osmo_dump_gsmtime; osmo_dump_gsmtime_buf; osmo_dump_gsmtime_c; +gsm_rfn2fn;
gsm_milenage; gsm_septet_encode; diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c index f4353e2..5b3f5cd 100644 --- a/tests/gsm0408/gsm0408_test.c +++ b/tests/gsm0408/gsm0408_test.c @@ -1946,6 +1946,31 @@ } }
+static void test_gsm_rfn2fn(void) +{ + unsigned int i; + struct { + uint32_t curr_fn; + uint16_t rfn; + uint32_t exp_fn; + } input[] = { + { .curr_fn = 0, .rfn = 0, .exp_fn = 0 }, + { .curr_fn = 0, .rfn = 4, .exp_fn = 4 }, + { .curr_fn = 2229729, .rfn = 23322, .exp_fn = 2229786 }, + { .curr_fn = 2229777, .rfn = 23322, .exp_fn = 2229786 }, + { .curr_fn = 1320458, .rfn = 5070, .exp_fn = 1320462 }, + }; + + for (i = 0; i < ARRAY_SIZE(input); i++) { + uint32_t fn = gsm_rfn2fn(input[i].rfn, input[i].curr_fn); + if (fn != input[i].exp_fn) { + printf("Wrong frame number computed! curr_fn=%u, rfn=%u ==> fn=%u, expected fn=%u\n", + input[i].curr_fn, input[i].rfn, fn, input[i].exp_fn); + OSMO_ASSERT(false); + } + } +} + int main(int argc, char **argv) { test_bearer_cap(); @@ -1967,6 +1992,7 @@ test_power_ctrl(); test_rach_tx_integer_raw2val(); test_gsm_gsmtime2fn(); + test_gsm_rfn2fn();
return EXIT_SUCCESS; }