Restructure SI2quater generation

In preparation for extended SI2q messages:

* add SI2q-specific accessor macro
* add *_offset variables to gsm_bts struct
* internalize memory check while generating rest octets - introduce
  budget concept (number of bits available in a given message)
* internalize *arfcn_size() functions as they are not needed outside of
  si2q_num() anymore
* change rest octets generation to work with gsm_bts struct directly
* do not generate rest octets if no SI2q is necessary
* adjust unit tests accordingly (cosmetic changes only to avoid
  regressions)

Requires: I92e12e91605bdab9916a3f665705287572434f74 in libosmocore

Change-Id: Ib554cf7ffc949a321571e1ae2ada1160e1b35fa6
Related: RT#8792
diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c
index 81dc177..265e4b2 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.c
+++ b/openbsc/tests/gsm0408/gsm0408_test.c
@@ -84,18 +84,12 @@
     COMPARE(lai48.lac, ==, htons(0x000f));
 }
 
-static inline void add_arfcn_b(struct osmo_earfcn_si2q *e, uint16_t earfcn,
-			       uint8_t bw)
+static inline void gen(struct gsm_bts *bts, const char *s)
 {
-	int r = osmo_earfcn_add(e, earfcn, bw);
-	if (r)
-		printf("failed to add EARFCN %u: %s\n", earfcn, strerror(-r));
-	else
-		printf("added EARFCN %u - ", earfcn);
-}
-
-static inline void gen(struct gsm_bts *bts)
-{
+	bts->u_offset = 0;
+	bts->e_offset = 0;
+	bts->si2q_index = 0;
+	bts->si2q_count = 0;
 	bts->si_valid = 0;
 	bts->si_valid |= (1 << SYSINFO_TYPE_2quater);
 	/* should be no-op as entire buffer is filled with padding: */
@@ -106,17 +100,32 @@
 		printf("generated %s SI2quater: [%d] %s\n",
 		       v ? "valid" : "invalid", r, osmo_hexdump(GSM_BTS_SI(bts, SYSINFO_TYPE_2quater), r));
 	else
-		printf("failed to generate SI2quater: %s\n", strerror(-r));
+		printf("%s() failed to generate SI2quater: %s\n", s, strerror(-r));
 }
 
-static inline void _bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn,
-			      uint16_t scramble, bool diversity)
+static inline void add_earfcn_b(struct gsm_bts *bts, uint16_t earfcn, uint8_t bw)
 {
-	int r = bts_uarfcn_add(bts, arfcn, scramble, diversity);
+	struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list;
+	int r = osmo_earfcn_add(e, earfcn, bw);
+	if (r)
+		printf("failed to add EARFCN %u: %s\n", earfcn, strerror(-r));
+	else
+		printf("added EARFCN %u - ", earfcn);
+
+	gen(bts, __func__);
+}
+
+static inline void _bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble, bool diversity)
+{
+	int r;
+
+	bts->u_offset = 0;
+
+	r = bts_uarfcn_add(bts, arfcn, scramble, diversity);
 	if (r < 0)
 		printf("failed to add UARFCN to SI2quater: %s\n", strerror(-r));
 	else
-		gen(bts);
+		gen(bts, __func__);
 }
 
 static inline void test_si2q_segfault(void)
@@ -131,7 +140,7 @@
 
 	_bts_uarfcn_add(bts, 10564, 319, 0);
 	_bts_uarfcn_add(bts, 10612, 319, 0);
-	gen(bts);
+	gen(bts, __func__);
 }
 
 static inline void test_si2q_mu(void)
@@ -151,7 +160,7 @@
 	_bts_uarfcn_add(bts, 10613, 64, 0);
 	_bts_uarfcn_add(bts, 10613, 164, 0);
 	_bts_uarfcn_add(bts, 10613, 14, 0);
-	gen(bts);
+	gen(bts, __func__);
 }
 
 static inline void test_si2q_u(void)
@@ -165,7 +174,7 @@
 	bts = gsm_bts_alloc(network);
 
 	/* first generate invalid SI as no UARFCN added */
-	gen(bts);
+	gen(bts, __func__);
 	/* subsequent calls should produce valid SI if there's enough memory */
 	_bts_uarfcn_add(bts, 1982, 13, 1);
 	_bts_uarfcn_add(bts, 1982, 44, 0);
@@ -178,7 +187,7 @@
 	_bts_uarfcn_add(bts, 1982, 223, 1);
 	_bts_uarfcn_add(bts, 1982, 14, 0);
 	_bts_uarfcn_add(bts, 1982, 88, 0);
-	gen(bts);
+	gen(bts, __func__);
 }
 
 static inline void test_si2q_e(void)
@@ -191,40 +200,22 @@
 		exit(1);
 	bts = gsm_bts_alloc(network);
 
-	bts->si_common.si2quater_neigh_list.arfcn =
-		bts->si_common.data.earfcn_list;
-	bts->si_common.si2quater_neigh_list.meas_bw =
-		bts->si_common.data.meas_bw_list;
+	bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list;
+	bts->si_common.si2quater_neigh_list.meas_bw = bts->si_common.data.meas_bw_list;
 	bts->si_common.si2quater_neigh_list.length = MAX_EARFCN_LIST;
 	bts->si_common.si2quater_neigh_list.thresh_hi = 5;
 
 	osmo_earfcn_init(&bts->si_common.si2quater_neigh_list);
 	/* first generate invalid SI as no EARFCN added */
-	gen(bts);
+	gen(bts, __func__);
 	/* subsequent calls should produce valid SI if there's enough memory */
-	add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1917, 1);
-	gen(bts);
-
-	add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1932,
-		    OSMO_EARFCN_MEAS_INVALID);
-	gen(bts);
-
-	add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1937, 2);
-	gen(bts);
-
-	add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1945,
-		    OSMO_EARFCN_MEAS_INVALID);
-	gen(bts);
-
-	add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1965,
-		    OSMO_EARFCN_MEAS_INVALID);
-	gen(bts);
-
-	add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1967, 4);
-	gen(bts);
-
-	add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1982, 3);
-	gen(bts);
+	add_earfcn_b(bts, 1917, 1);
+	add_earfcn_b(bts, 1932, OSMO_EARFCN_MEAS_INVALID);
+	add_earfcn_b(bts, 1937, 2);
+	add_earfcn_b(bts, 1945, OSMO_EARFCN_MEAS_INVALID);
+	add_earfcn_b(bts, 1965, OSMO_EARFCN_MEAS_INVALID);
+	add_earfcn_b(bts, 1967, 4);
+	add_earfcn_b(bts, 1982, 3);
 }
 
 static void test_mi_functionality(void)
diff --git a/openbsc/tests/gsm0408/gsm0408_test.ok b/openbsc/tests/gsm0408/gsm0408_test.ok
index 1c02dfd..5f9398b 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.ok
+++ b/openbsc/tests/gsm0408/gsm0408_test.ok
@@ -67,16 +67,16 @@
 generated valid SI2quater: [23] 59 06 07 c0 00 25 52 e8 0a 7f 52 88 0a 7e 10 99 64 00 0b 2b 2b 2b 2b 
 generated valid SI2quater: [23] 59 06 07 c0 00 25 52 e8 0a 7f 52 88 0a 7e 10 99 64 00 0b 2b 2b 2b 2b 
 Testing SYSINFO_TYPE_2quater EARFCN generation:
-generated invalid SI2quater: [23] 59 06 07 c0 00 04 86 59 0a 03 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
+generated invalid SI2quater: [23] ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae 
 added EARFCN 1917 - generated valid SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be c8 50 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
 added EARFCN 1932 - generated valid SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 30 14 03 2b 2b 2b 2b 2b 2b 2b 2b 
 added EARFCN 1937 - generated valid SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a0 a0 2b 2b 2b 2b 2b 2b 
 added EARFCN 1945 - generated valid SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a8 3c c8 28 0b 2b 2b 2b 
 added EARFCN 1965 - generated valid SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a8 3c ca 0f 5a 0a 03 2b 
-added EARFCN 1967 - failed to generate SI2quater: Cannot allocate memory
-added EARFCN 1982 - failed to generate SI2quater: Cannot allocate memory
+added EARFCN 1967 - add_earfcn_b() failed to generate SI2quater: Cannot allocate memory
+added EARFCN 1982 - add_earfcn_b() failed to generate SI2quater: Cannot allocate memory
 Testing SYSINFO_TYPE_2quater UARFCN generation:
-generated invalid SI2quater: [23] 59 06 07 c0 00 04 86 59 00 03 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 
+generated invalid SI2quater: [23] ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae ae 
 generated valid SI2quater: [23] 59 06 07 c0 00 25 0f 7c 0c 1a 10 99 64 00 0b 2b 2b 2b 2b 2b 2b 2b 2b 
 generated valid SI2quater: [23] 59 06 07 c0 00 25 0f 7c 14 1a 1f 00 44 b2 00 03 2b 2b 2b 2b 2b 2b 2b 
 generated valid SI2quater: [23] 59 06 07 c0 00 25 0f 7c 18 58 12 f0 84 86 59 00 03 2b 2b 2b 2b 2b 2b