aboutsummaryrefslogtreecommitdiffstats
path: root/tests/gsm23236/gsm23236_test.c
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2020-05-11 19:43:20 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2020-06-10 14:20:49 +0200
commit7dde1f40a293dbac575b294f82ba905d8f45b7b7 (patch)
treead78aff2307113c1d0906c4feaf0b40ecdace47c /tests/gsm23236/gsm23236_test.c
parent2908dbfddd0dd89df34e876d417fe1d8f085408d (diff)
add gsm23236: MSC pooling: TMSI and NRI utility functions
These utilities will be used by osmo-bsc to determine the Network Resource Indicator seen in the TMSI, and (potentially) by osmo-msc to compose a TMSI with a specific NRI, for osmo-bsc's load balancing between several MSCs. Add utility functions to: - extract an NRI value from a TMSI. - overwrite the NRI value in a TMSI. - limit an NRI in a (random) TMSI to a given list of ranges. - add NRI value ranges to a list. - remove them from a list. - match NRI value (range) to a list. - parse NRI values from string, for VTY. - common VTY functionality of adding/removing NRI values from argv. Add C tests for the above. Why we need public API for NRI ranges: In osmo-bsc alone, we need the same NRI API twice, 1: to manage/list NRI value ranges per-MSC, and 2: to manage/list NULL-NRI values. If we also consider (potentially) adding NRI support to osmo-msc, we need the same API twice again there. Hence it is useful to define re-used API up here in libosmocore. Related: OS#3682 Change-Id: Icb57a2dd9323c7ea11b34003eccc7e68a0247bf5
Diffstat (limited to 'tests/gsm23236/gsm23236_test.c')
-rw-r--r--tests/gsm23236/gsm23236_test.c620
1 files changed, 620 insertions, 0 deletions
diff --git a/tests/gsm23236/gsm23236_test.c b/tests/gsm23236/gsm23236_test.c
new file mode 100644
index 00000000..14c5ce38
--- /dev/null
+++ b/tests/gsm23236/gsm23236_test.c
@@ -0,0 +1,620 @@
+/*
+ * (C) 2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <strings.h>
+#include <string.h>
+
+#include <osmocom/gsm/gsm23236.h>
+#include <osmocom/core/utils.h>
+
+void *ctx;
+bool ok = true;
+
+void bitdump(uint8_t count, uint32_t val)
+{
+ uint32_t bit;
+ if (count < 1)
+ return;
+ for (bit = ((uint32_t)1) << (count - 1); bit; bit >>= 1)
+ printf("%c", (val & bit)? '1' : '0');
+}
+
+struct nri_v_get_set_test {
+ uint32_t tmsi;
+ uint8_t nri_bitlen;
+ int16_t expect_get_nri;
+ int expect_get_rc;
+ int16_t set_nri_v;
+ uint32_t expect_tmsi;
+ int expect_set_rc;
+};
+
+struct nri_v_get_set_test nri_v_get_set_tests[] = {
+ {
+ .tmsi = 0,
+ .nri_bitlen = 10,
+ .expect_get_nri = 0,
+ .set_nri_v = 0,
+ .expect_tmsi = 0,
+ },
+ {
+ .tmsi = 0,
+ .nri_bitlen = 10,
+ .expect_get_nri = 0,
+ .set_nri_v = 0x7fff,
+ .expect_tmsi = 0x00ffc000
+ },
+ {
+ .tmsi = 0xffffffff,
+ .nri_bitlen = 10,
+ .expect_get_nri = 0x3ff,
+ .set_nri_v = 0,
+ .expect_tmsi = 0xff003fff
+ },
+ {
+ .tmsi = 0xffffffff,
+ .nri_bitlen = 10,
+ .expect_get_nri = 0x3ff,
+ .set_nri_v = 0x7fff,
+ .expect_tmsi = 0xffffffff
+ },
+ {
+ .tmsi = 0,
+ .nri_bitlen = 5,
+ .expect_get_nri = 0,
+ .set_nri_v = 0,
+ .expect_tmsi = 0,
+ },
+ {
+ .tmsi = 0,
+ .nri_bitlen = 5,
+ .expect_get_nri = 0,
+ .set_nri_v = 0x7fff,
+ .expect_tmsi = 0x00f80000
+ },
+ {
+ .tmsi = 0xffffffff,
+ .nri_bitlen = 5,
+ .expect_get_nri = 0x1f,
+ .set_nri_v = 0,
+ .expect_tmsi = 0xff07ffff
+ },
+ {
+ .tmsi = 0xffffffff,
+ .nri_bitlen = 5,
+ .expect_get_nri = 0x1f,
+ .set_nri_v = 0x7fff,
+ .expect_tmsi = 0xffffffff
+ },
+ {
+ .tmsi = 0x01234567,
+ .nri_bitlen = 8,
+ .expect_get_nri = 0x23,
+ .set_nri_v = 0x42,
+ .expect_tmsi = 0x01424567
+ },
+ {
+ .tmsi = 0x01234567,
+ .nri_bitlen = 15,
+ .expect_get_nri = 0x2345 >> 1,
+ .set_nri_v = 0x7fff,
+ .expect_tmsi = 0x01ffff67
+ },
+ {
+ .tmsi = 0x01234567,
+ .nri_bitlen = 16,
+ .expect_get_rc = -1,
+ .expect_get_nri = -1,
+ .set_nri_v = 0x7fff,
+ .expect_set_rc = -1,
+ .expect_tmsi = 0x01234567,
+ },
+ {
+ .tmsi = 0x01234567,
+ .nri_bitlen = 0,
+ .expect_get_rc = -1,
+ .expect_get_nri = -1,
+ .set_nri_v = 0x7fff,
+ .expect_set_rc = -1,
+ .expect_tmsi = 0x01234567,
+ },
+};
+
+void test_nri_v_get_set()
+{
+ struct nri_v_get_set_test *t;
+
+ for (t = nri_v_get_set_tests; t < &nri_v_get_set_tests[ARRAY_SIZE(nri_v_get_set_tests)]; t++) {
+ int16_t nri_v = 0;
+ uint32_t tmsi2;
+ int rc;
+
+ rc = osmo_tmsi_nri_v_get(&nri_v, t->tmsi, t->nri_bitlen);
+ printf("\nosmo_tmsi_nri_v_get(0x%08x, %u) -> nri_v=0x%x rc=%d\n", t->tmsi, t->nri_bitlen, nri_v, rc);
+ if (!rc) {
+ printf("........|NRI->..................\n");
+ bitdump(32, t->tmsi);
+ printf(" tmsi nri_bitlen=%u\n", t->nri_bitlen);
+ printf(" ");
+ bitdump(t->nri_bitlen, nri_v);
+ printf(" = 0x%x", nri_v);
+ }
+ if (nri_v == t->expect_get_nri && rc == t->expect_get_rc) {
+ printf(" ok\n");
+ } else {
+ printf(" ERROR: expected nri_v=0x%x rc=%d\n", t->expect_get_nri, t->expect_get_rc);
+ ok = false;
+ }
+
+ tmsi2 = t->tmsi;
+ rc = osmo_tmsi_nri_v_set(&tmsi2, t->set_nri_v, t->nri_bitlen);
+ printf("osmo_tmsi_nri_v_set(0x%08x, 0x%x, %u) -> tmsi=0x%08x rc=%d\n", t->tmsi, t->set_nri_v, t->nri_bitlen,
+ tmsi2, rc);
+ if (!rc) {
+ printf(" ");
+ bitdump(t->nri_bitlen, t->set_nri_v);
+ printf("\n");
+ bitdump(32, tmsi2);
+ }
+ if (tmsi2 == t->expect_tmsi && rc == t->expect_set_rc) {
+ printf(" ok\n");
+ } else {
+ printf(" ERROR: expected tmsi=0x%08x rc=%d\n", t->expect_tmsi, t->expect_set_rc);
+ ok = false;
+ }
+ }
+}
+
+struct nri_validate_tc {
+ int16_t nri;
+ uint8_t nri_bitlen;
+ int expect_rc;
+};
+
+struct nri_validate_tc nri_validate_tests[] = {
+ { .nri = INT16_MIN, .nri_bitlen = 10, .expect_rc = -1 },
+ { .nri = -23, .nri_bitlen = 10, .expect_rc = -1 },
+ { .nri = -1, .nri_bitlen = 10, .expect_rc = -1 },
+ { .nri = 0, .nri_bitlen = 10, .expect_rc = 0 },
+ { .nri = (1 << 10) - 1, .nri_bitlen = 10, .expect_rc = 0 },
+ { .nri = (1 << 10), .nri_bitlen = 10, .expect_rc = 1 },
+ { .nri = INT16_MAX, .nri_bitlen = 10, .expect_rc = 1 },
+
+ { .nri = INT16_MIN, .nri_bitlen = 5, .expect_rc = -1 },
+ { .nri = -23, .nri_bitlen = 5, .expect_rc = -1 },
+ { .nri = -1, .nri_bitlen = 5, .expect_rc = -1 },
+ { .nri = 0, .nri_bitlen = 5, .expect_rc = 0 },
+ { .nri = (1 << 5) - 1, .nri_bitlen = 5, .expect_rc = 0 },
+ { .nri = (1 << 5), .nri_bitlen = 5, .expect_rc = 1 },
+ { .nri = INT16_MAX, .nri_bitlen = 5, .expect_rc = 1 },
+
+ { .nri = INT16_MIN, .nri_bitlen = 1, .expect_rc = -1 },
+ { .nri = -23, .nri_bitlen = 1, .expect_rc = -1 },
+ { .nri = -1, .nri_bitlen = 1, .expect_rc = -1 },
+ { .nri = 0, .nri_bitlen = 1, .expect_rc = 0 },
+ { .nri = 1, .nri_bitlen = 1, .expect_rc = 0 },
+ { .nri = 2, .nri_bitlen = 1, .expect_rc = 1 },
+ { .nri = INT16_MAX, .nri_bitlen = 1, .expect_rc = 1 },
+
+ { .nri = INT16_MIN, .nri_bitlen = 0, .expect_rc = -1 },
+ { .nri = -23, .nri_bitlen = 0, .expect_rc = -1 },
+ { .nri = -1, .nri_bitlen = 0, .expect_rc = -1 },
+ { .nri = 0, .nri_bitlen = 0, .expect_rc = 1 },
+ { .nri = 1, .nri_bitlen = 0, .expect_rc = 1 },
+ { .nri = INT16_MAX, .nri_bitlen = 0, .expect_rc = 1 },
+};
+
+void test_nri_validate()
+{
+ struct nri_validate_tc *t;
+ printf("\n%s()\n", __func__);
+ for (t = nri_validate_tests; (t - nri_validate_tests) < ARRAY_SIZE(nri_validate_tests); t++) {
+ int rc = osmo_nri_v_validate(t->nri, t->nri_bitlen);
+ printf("osmo_nri_v_validate(%d, %u) = %d ", t->nri, t->nri_bitlen, rc);
+ if (rc == t->expect_rc) {
+ printf("ok\n");
+ } else {
+ printf("ERROR, expected rc = %d\n", t->expect_rc);
+ ok = false;
+ }
+ }
+}
+
+struct nri_range_validate_tc {
+ struct osmo_nri_range range;
+ uint8_t nri_bitlen;
+ int expect_rc;
+};
+
+struct nri_range_validate_tc nri_range_validate_tests[] = {
+ { .range = { .first = INT16_MIN, .last = INT16_MIN }, .nri_bitlen = 10, .expect_rc = -1 },
+ { .range = { .first = -23, .last = -23 }, .nri_bitlen = 10, .expect_rc = -1 },
+ { .range = { .first = -1, .last = -1 }, .nri_bitlen = 10, .expect_rc = -1 },
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 10, .expect_rc = 0 },
+ { .range = { .first = (1 << 10) - 1, .last = (1 << 10) - 1 }, .nri_bitlen = 10, .expect_rc = 0 },
+ { .range = { .first = (1 << 10), .last = (1 << 10) }, .nri_bitlen = 10, .expect_rc = 1 },
+ { .range = { .first = INT16_MAX, .last = INT16_MAX }, .nri_bitlen = 10, .expect_rc = 1 },
+
+ { .range = { .first = INT16_MIN, .last = INT16_MIN }, .nri_bitlen = 5, .expect_rc = -1 },
+ { .range = { .first = -23, .last = -23 }, .nri_bitlen = 5, .expect_rc = -1 },
+ { .range = { .first = -1, .last = -1 }, .nri_bitlen = 5, .expect_rc = -1 },
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 5, .expect_rc = 0 },
+ { .range = { .first = (1 << 5) - 1, .last = (1 << 5) - 1 }, .nri_bitlen = 5, .expect_rc = 0 },
+ { .range = { .first = (1 << 5), .last = (1 << 5) }, .nri_bitlen = 5, .expect_rc = 1 },
+ { .range = { .first = INT16_MAX, .last = INT16_MAX }, .nri_bitlen = 5, .expect_rc = 1 },
+
+ { .range = { .first = INT16_MIN, .last = INT16_MIN }, .nri_bitlen = 1, .expect_rc = -1 },
+ { .range = { .first = -23, .last = -23 }, .nri_bitlen = 1, .expect_rc = -1 },
+ { .range = { .first = -1, .last = -1 }, .nri_bitlen = 1, .expect_rc = -1 },
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 1, .expect_rc = 0 },
+ { .range = { .first = 1, .last = 1 }, .nri_bitlen = 1, .expect_rc = 0 },
+ { .range = { .first = 2, .last = 2 }, .nri_bitlen = 1, .expect_rc = 1 },
+ { .range = { .first = INT16_MAX, .last = INT16_MAX }, .nri_bitlen = 1, .expect_rc = 1 },
+
+ { .range = { .first = INT16_MIN, .last = INT16_MIN }, .nri_bitlen = 0, .expect_rc = -1 },
+ { .range = { .first = -23, .last = -23 }, .nri_bitlen = 0, .expect_rc = -1 },
+ { .range = { .first = -1, .last = -1 }, .nri_bitlen = 0, .expect_rc = -1 },
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 0, .expect_rc = 1 },
+ { .range = { .first = 1, .last = 1 }, .nri_bitlen = 0, .expect_rc = 1 },
+ { .range = { .first = INT16_MAX, .last = INT16_MAX }, .nri_bitlen = 0, .expect_rc = 1 },
+
+
+ { .range = { .first = 0, .last = INT16_MIN }, .nri_bitlen = 10, .expect_rc = -2 },
+ { .range = { .first = 0, .last = -23 }, .nri_bitlen = 10, .expect_rc = -2 },
+ { .range = { .first = 0, .last = -1 }, .nri_bitlen = 10, .expect_rc = -2 },
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 10, .expect_rc = 0 },
+ { .range = { .first = 0, .last = (1 << 10) - 1 }, .nri_bitlen = 10, .expect_rc = 0 },
+ { .range = { .first = 0, .last = (1 << 10) }, .nri_bitlen = 10, .expect_rc = 2 },
+ { .range = { .first = 0, .last = INT16_MAX }, .nri_bitlen = 10, .expect_rc = 2 },
+
+ { .range = { .first = 0, .last = INT16_MIN }, .nri_bitlen = 5, .expect_rc = -2 },
+ { .range = { .first = 0, .last = -23 }, .nri_bitlen = 5, .expect_rc = -2 },
+ { .range = { .first = 0, .last = -1 }, .nri_bitlen = 5, .expect_rc = -2 },
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 5, .expect_rc = 0 },
+ { .range = { .first = 0, .last = (1 << 5) - 1 }, .nri_bitlen = 5, .expect_rc = 0 },
+ { .range = { .first = 0, .last = (1 << 5) }, .nri_bitlen = 5, .expect_rc = 2 },
+ { .range = { .first = 0, .last = INT16_MAX }, .nri_bitlen = 5, .expect_rc = 2 },
+
+ { .range = { .first = 0, .last = INT16_MIN }, .nri_bitlen = 1, .expect_rc = -2 },
+ { .range = { .first = 0, .last = -23 }, .nri_bitlen = 1, .expect_rc = -2 },
+ { .range = { .first = 0, .last = -1 }, .nri_bitlen = 1, .expect_rc = -2 },
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 1, .expect_rc = 0 },
+ { .range = { .first = 0, .last = 1 }, .nri_bitlen = 1, .expect_rc = 0 },
+ { .range = { .first = 0, .last = 2 }, .nri_bitlen = 1, .expect_rc = 2 },
+ { .range = { .first = 0, .last = INT16_MAX }, .nri_bitlen = 1, .expect_rc = 2 },
+
+ { .range = { .first = 0, .last = INT16_MIN }, .nri_bitlen = 0, .expect_rc = 1 },
+ { .range = { .first = 0, .last = -23 }, .nri_bitlen = 0, .expect_rc = 1 },
+ { .range = { .first = 0, .last = -1 }, .nri_bitlen = 0, .expect_rc = 1 },
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 0, .expect_rc = 1 },
+ { .range = { .first = 0, .last = 1 }, .nri_bitlen = 0, .expect_rc = 1 },
+ { .range = { .first = 0, .last = INT16_MAX }, .nri_bitlen = 0, .expect_rc = 1 },
+
+
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 10, .expect_rc = 0 },
+ { .range = { .first = 1, .last = 0 }, .nri_bitlen = 10, .expect_rc = -3 },
+ { .range = { .first = (1 << 10) - 1, .last = (1 << 10) - 1 }, .nri_bitlen = 10, .expect_rc = 0 },
+ { .range = { .first = (1 << 10) - 1, .last = (1 << 10) - 2 }, .nri_bitlen = 10, .expect_rc = -3 },
+ { .range = { .first = (1 << 10) - 1, .last = 0 }, .nri_bitlen = 10, .expect_rc = -3 },
+
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 5, .expect_rc = 0 },
+ { .range = { .first = 1, .last = 0 }, .nri_bitlen = 5, .expect_rc = -3 },
+ { .range = { .first = (1 << 5) - 1, .last = (1 << 5) - 1 }, .nri_bitlen = 5, .expect_rc = 0 },
+ { .range = { .first = (1 << 5) - 1, .last = (1 << 5) - 2 }, .nri_bitlen = 5, .expect_rc = -3 },
+ { .range = { .first = (1 << 5) - 1, .last = 0 }, .nri_bitlen = 5, .expect_rc = -3 },
+
+ { .range = { .first = 0, .last = 0 }, .nri_bitlen = 1, .expect_rc = 0 },
+ { .range = { .first = 1, .last = 1 }, .nri_bitlen = 1, .expect_rc = 0 },
+ { .range = { .first = 1, .last = 0 }, .nri_bitlen = 1, .expect_rc = -3 },
+
+};
+
+void test_nri_range_validate()
+{
+ struct nri_range_validate_tc *t;
+ printf("\n%s()\n", __func__);
+ for (t = nri_range_validate_tests; (t - nri_range_validate_tests) < ARRAY_SIZE(nri_range_validate_tests); t++) {
+ int rc = osmo_nri_range_validate(&t->range, t->nri_bitlen);
+ printf("osmo_nri_range_validate({%d,%d}, %u) = %d ", t->range.first, t->range.last, t->nri_bitlen, rc);
+ if (rc == t->expect_rc) {
+ printf("ok\n");
+ } else {
+ printf("ERROR, expected rc = %d\n", t->expect_rc);
+ ok = false;
+ }
+ }
+}
+
+void dump_list(const struct osmo_nri_ranges *nri_ranges)
+{
+ struct osmo_nri_range *r;
+ printf("nri_ranges = {\n");
+ llist_for_each_entry(r, &nri_ranges->entries, entry) {
+ printf(" { %d, %d },\n", r->first, r->last);
+ if (osmo_nri_range_validate(r, 255)) {
+ ok = false;
+ printf(" ^^^^^ ERROR: invalid range\n");
+ }
+ }
+ printf("};\n");
+}
+
+void test_nri_list()
+{
+ struct osmo_nri_ranges *nri_ranges = osmo_nri_ranges_alloc(ctx);
+ printf("\n%s()\n", __func__);
+
+#define ADD(FIRST, LAST) do { \
+ struct osmo_nri_range r = { .first = FIRST, .last = LAST }; \
+ int rc; \
+ rc = osmo_nri_ranges_add(nri_ranges, &r); \
+ printf("osmo_nri_ranges_add(%d, %d) -> %d\n", r.first, r.last, rc); \
+ dump_list(nri_ranges); \
+ } while(0)
+
+#define DEL(FIRST, LAST) do { \
+ struct osmo_nri_range r = { .first = FIRST, .last = LAST }; \
+ int rc; \
+ rc = osmo_nri_ranges_del(nri_ranges, &r); \
+ printf("osmo_nri_ranges_del(%d, %d) -> %d\n", r.first, r.last, rc); \
+ dump_list(nri_ranges); \
+ } while(0)
+
+#define MATCHES(NRI, EXPECT_MATCH) do { \
+ bool matches = osmo_nri_v_matches_ranges(NRI, nri_ranges); \
+ printf("osmo_nri_v_matches_ranges(%d) -> %s\n", NRI, matches ? "true" : "false"); \
+ if (matches != EXPECT_MATCH) { \
+ ok = false; \
+ printf(" ^ ERROR: expected " #EXPECT_MATCH "\n"); \
+ } \
+ } while(0)
+
+#define OVERLAPS(FIRST, LAST, EXPECT_OVERLAP) do { \
+ struct osmo_nri_range r = { .first = FIRST, .last = LAST }; \
+ bool overlaps = osmo_nri_range_overlaps_ranges(&r, nri_ranges); \
+ printf("osmo_nri_range_overlaps_ranges(%d, %d) -> %s\n", r.first, r.last, overlaps ? "true" : "false"); \
+ if (overlaps != EXPECT_OVERLAP) { \
+ ok = false; \
+ printf(" ^ ERROR: expected " #EXPECT_OVERLAP "\n"); \
+ } \
+ } while(0)
+
+ dump_list(nri_ranges);
+ MATCHES(INT16_MIN, false);
+ MATCHES(-1, false);
+ MATCHES(0, false);
+ MATCHES(INT16_MAX, false);
+ MATCHES(100, false);
+ OVERLAPS(INT16_MIN, -1, false);
+ OVERLAPS(-100, 100, false);
+ OVERLAPS(10, 20, false);
+
+ ADD(100, 200);
+ MATCHES(INT16_MIN, false);
+ MATCHES(-1, false);
+ MATCHES(0, false);
+ MATCHES(INT16_MAX, false);
+ MATCHES(99, false);
+ MATCHES(100, true);
+ MATCHES(101, true);
+ MATCHES(199, true);
+ MATCHES(200, true);
+ MATCHES(201, false);
+ OVERLAPS(INT16_MIN, -1, false);
+ OVERLAPS(-100, 100, true);
+ OVERLAPS(10, 20, false);
+ OVERLAPS(10, 99, false);
+ OVERLAPS(10, 100, true);
+ OVERLAPS(10, 150, true);
+ OVERLAPS(99, 99, false);
+ OVERLAPS(100, 100, true);
+ OVERLAPS(150, 300, true);
+ OVERLAPS(200, 300, true);
+ OVERLAPS(201, 300, false);
+
+ printf("\ndel from start:\n");
+ DEL(0, 110);
+ DEL(111, 111);
+ DEL(112, 199);
+ MATCHES(INT16_MIN, false);
+ MATCHES(-1, false);
+ MATCHES(0, false);
+ MATCHES(INT16_MAX, false);
+ MATCHES(199, false);
+ MATCHES(200, true);
+ MATCHES(201, false);
+ OVERLAPS(INT16_MIN, -1, false);
+ OVERLAPS(-1000, 1000, true);
+ OVERLAPS(0, 199, false);
+ OVERLAPS(0, 200, true);
+ OVERLAPS(0, 201, true);
+ OVERLAPS(0, 1000, true);
+ OVERLAPS(199, 199, false);
+ OVERLAPS(200, 200, true);
+ OVERLAPS(201, 201, false);
+
+ printf("\ndel from end:\n");
+ ADD(100, 200);
+ DEL(190, INT16_MAX);
+ DEL(189, 189);
+ DEL(101, 188);
+ MATCHES(INT16_MIN, false);
+ MATCHES(-1, false);
+ MATCHES(0, false);
+ MATCHES(INT16_MAX, false);
+ MATCHES(99, false);
+ MATCHES(100, true);
+ MATCHES(101, false);
+
+ printf("\ndel from middle:\n");
+ ADD(100, 200);
+ DEL(150, 160);
+ DEL(110, 120);
+ DEL(130, 130);
+ DEL(180, 190);
+ MATCHES(INT16_MIN, false);
+ MATCHES(-1, false);
+ MATCHES(0, false);
+ MATCHES(INT16_MAX, false);
+ MATCHES(99, false);
+ MATCHES(100, true);
+ MATCHES(109, true);
+ MATCHES(110, false);
+ MATCHES(120, false);
+ MATCHES(121, true);
+ MATCHES(129, true);
+ MATCHES(130, false);
+ MATCHES(131, true);
+ MATCHES(148, true);
+ MATCHES(149, true);
+ MATCHES(150, false);
+ MATCHES(160, false);
+ MATCHES(161, true);
+ MATCHES(170, true);
+ MATCHES(179, true);
+ MATCHES(180, false);
+ MATCHES(185, false);
+ MATCHES(190, false);
+ MATCHES(191, true);
+ MATCHES(195, true);
+ MATCHES(200, true);
+ MATCHES(201, false);
+ MATCHES(1000, false);
+ OVERLAPS(110, 120, false);
+ OVERLAPS(110, 130, true);
+ OVERLAPS(100, 200, true);
+
+ printf("\ndel across whole chunks:\n");
+ DEL(115, 185);
+ DEL(105, 195);
+ DEL(0, 1000);
+
+ printf("\nadd to join chunks:\n");
+ ADD(0, 100);
+ DEL(11, 19);
+ DEL(23, 23);
+ DEL(30, 41);
+ ADD(23, 23);
+ ADD(11, 41);
+ MATCHES(0, true);
+ MATCHES(10, true);
+ MATCHES(11, true);
+ MATCHES(24, true);
+ MATCHES(41, true);
+ MATCHES(42, true);
+ MATCHES(100, true);
+ MATCHES(101, false);
+
+ printf("\nborder cases:\n");
+ ADD(0, 0);
+ ADD(INT16_MAX, INT16_MAX);
+ ADD(1, INT16_MAX - 1);
+ MATCHES(INT16_MIN, false);
+ MATCHES(-1, false);
+ MATCHES(0, true);
+ MATCHES(INT16_MAX, true);
+ DEL(0, 0);
+ DEL(INT16_MAX, INT16_MAX);
+ DEL(1, INT16_MAX - 1);
+
+ printf("\nrange errors:\n");
+ ADD(-1, -1);
+ ADD(-20, -10);
+ ADD(100, 1);
+ ADD(0, INT16_MAX);
+ DEL(-1, -1);
+ DEL(-20, -10);
+ DEL(100, 1);
+}
+
+void test_nri_limit_by_ranges()
+{
+ const uint8_t nri_bitlen = 8;
+ const int16_t expect_nri_vals[] = { 10, 20, 21, 30, 31, 32 };
+ int i;
+ struct osmo_nri_ranges *nri_ranges = osmo_nri_ranges_alloc(ctx);
+ printf("\n%s()\n", __func__);
+
+ ADD(10, 10);
+ ADD(20, 21);
+ ADD(30, 32);
+
+ for (i = 0; i < 19; i++) {
+ int rc;
+ int16_t nri_v;
+ int16_t expect_nri_v = expect_nri_vals[i % ARRAY_SIZE(expect_nri_vals)];
+
+ nri_v = i;
+ rc = osmo_nri_v_limit_by_ranges(&nri_v, nri_ranges, nri_bitlen);
+ printf("osmo_nri_v_limit_by_ranges(%d) -> nri_v=%d rc=%d", i, nri_v, rc);
+ if (!rc && nri_v == expect_nri_v) {
+ printf(" ok\n");
+ } else {
+ printf(" ERROR: expected nri_v=%d rc=0\n", expect_nri_v);
+ ok = false;
+ }
+ }
+ for (i = 0; i < 19; i++) {
+ int rc;
+ int16_t nri_v;
+ uint32_t tmsi, tmsi2;
+ int16_t expect_nri_v = expect_nri_vals[i % ARRAY_SIZE(expect_nri_vals)];
+
+ tmsi = 0;
+ osmo_tmsi_nri_v_set(&tmsi, i, nri_bitlen);
+ tmsi2 = tmsi;
+ rc = osmo_tmsi_nri_v_limit_by_ranges(&tmsi2, nri_ranges, nri_bitlen);
+ osmo_tmsi_nri_v_get(&nri_v, tmsi2, nri_bitlen);
+ printf("osmo_tmsi_nri_v_limit_by_ranges(0x%08x, %u) -> tmsi=0x%08x nri_v=%d rc=%d",
+ tmsi, nri_bitlen, tmsi2, nri_v, rc);
+ if (!rc && nri_v == expect_nri_v) {
+ printf(" ok\n");
+ } else {
+ printf(" ERROR: expected nri_v=%d rc=0\n", expect_nri_v);
+ ok = false;
+ }
+ }
+}
+
+int main()
+{
+ ctx = talloc_named_const(NULL, 0, "nri_test");
+
+ test_nri_v_get_set();
+ test_nri_validate();
+ test_nri_range_validate();
+ test_nri_list();
+ test_nri_limit_by_ranges();
+
+ talloc_free(ctx);
+ if (!ok) {
+ printf("\nFAIL\n");
+ return -1;
+ }
+
+ printf("\npass\n");
+ return 0;
+}
+