Add basic SI2quater support

* support for sending arbitrary static SI2quater.
* vty interface for neightbor EARFCNs specific to SI2quater.
* dynamic generation of SI2quater messages.
* unit test for SI2quater messages.

Fixes: OS#1630
diff --git a/openbsc/tests/gsm0408/Makefile.am b/openbsc/tests/gsm0408/Makefile.am
index 1c29ece..ee04102 100644
--- a/openbsc/tests/gsm0408/Makefile.am
+++ b/openbsc/tests/gsm0408/Makefile.am
@@ -7,6 +7,7 @@
 gsm0408_test_SOURCES = gsm0408_test.c
 gsm0408_test_LDADD =	$(top_builddir)/src/libbsc/libbsc.a \
 			$(top_builddir)/src/libmsc/libmsc.a \
+			$(top_builddir)/src/libtrau/libtrau.a \
 			$(top_builddir)/src/libbsc/libbsc.a \
 			$(top_builddir)/src/libcommon/libcommon.a \
-			$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -ldbi
+			$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOABIS_LIBS) -ldbi
diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c
index 781ef61..d6abce6 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.c
+++ b/openbsc/tests/gsm0408/gsm0408_test.c
@@ -29,7 +29,11 @@
 #include <openbsc/gsm_subscriber.h>
 #include <openbsc/debug.h>
 #include <openbsc/arfcn_range_encode.h>
+#include <openbsc/system_information.h>
+#include <openbsc/abis_rsl.h>
+
 #include <osmocom/core/application.h>
+#include <osmocom/gsm/sysinfo.h>
 
 #define COMPARE(result, op, value) \
     if (!((result) op (value))) {\
@@ -79,6 +83,70 @@
     COMPARE(lai48.lac, ==, htons(0x000f));
 }
 
+static inline void add_arfcn_b(struct osmo_earfcn_si2q *e, uint16_t earfcn,
+			       uint8_t bw)
+{
+	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)
+{
+	int r = gsm_generate_si(bts, SYSINFO_TYPE_2quater);
+	if (r > 0)
+		printf("generated SI2quater: [%d] %s\n", r,
+		       osmo_hexdump(bts->si_buf[SYSINFO_TYPE_2quater], r));
+	else
+		printf("failed to generate SI2quater: %s\n", strerror(-r));
+}
+
+static inline void test_si2q(void)
+{
+	struct gsm_bts *bts;
+	struct gsm_network *network = gsm_network_init(1, 1, NULL);
+	printf("Testing SYSINFO_TYPE_2quater generation:\n");
+
+	if (!network)
+		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.length = MAX_EARFCN_LIST;
+	bts->si_common.si2quater_neigh_list.thresh_hi = 5;
+
+	osmo_earfcn_init(&bts->si_common.si2quater_neigh_list);
+
+	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);
+}
+
 static void test_mi_functionality(void)
 {
 	const char *imsi_odd  = "987654321098763";
@@ -486,6 +554,7 @@
 	test_range_encoding();
 	test_gsm411_rp_ref_wrap();
 
+	test_si2q();
 	printf("Done.\n");
 	return EXIT_SUCCESS;
 }
diff --git a/openbsc/tests/gsm0408/gsm0408_test.ok b/openbsc/tests/gsm0408/gsm0408_test.ok
index 058563a..59319bf 100644
--- a/openbsc/tests/gsm0408/gsm0408_test.ok
+++ b/openbsc/tests/gsm0408/gsm0408_test.ok
@@ -62,4 +62,12 @@
 Allocated reference: 255
 Allocated reference: 0
 Allocated reference: 1
+Testing SYSINFO_TYPE_2quater generation:
+added EARFCN 1917 - generated 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 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 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 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 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
 Done.