system_information: use bitvec to generate frequency lists

We use a 1024-bit-sized bitvec to generate the BA and neighbor frequency list.

This bitvec is still generated from the list of all BTS's inside the BSC, but
this patch is the first step to generalize this, i.e. generate arbitrary
neighbor lists.
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 9bddd7a..52c6a03 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -60,6 +60,7 @@
 #include <openbsc/abis_rsl.h>
 #include <openbsc/mncc.h>
 #include <openbsc/tlv.h>
+#include <openbsc/bitvec.h>
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
@@ -381,6 +382,13 @@
 		struct gsm48_cell_sel_par cell_sel_par;
 		struct gsm48_cell_options cell_options;
 		struct gsm48_control_channel_descr chan_desc;
+		struct bitvec neigh_list;
+		struct bitvec cell_alloc;
+		struct {
+			/* bitmask large enough for all possible ARFCN's */
+			u_int8_t neigh_list[1024/8];
+			u_int8_t cell_alloc[1024/8];
+		} data;
 	} si_common;
 
 	/* ip.accesss Unit ID's have Site/BTS/TRX layout */
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index cdaba9e..3cf9e3c 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -169,6 +169,12 @@
 	bts->ms_max_power = 15;	/* dBm */
 	bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */
 	bts->si_common.cell_sel_par.rxlev_acc_min = 0;
+	bts->si_common.neigh_list.data = bts->si_common.data.neigh_list;
+	bts->si_common.neigh_list.data_len =
+				sizeof(bts->si_common.data.neigh_list);
+	bts->si_common.cell_alloc.data = bts->si_common.data.cell_alloc;
+	bts->si_common.cell_alloc.data_len =
+				sizeof(bts->si_common.data.cell_alloc);
 
 	for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
 		bts->gprs.nsvc[i].bts = bts;
diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c
index 60a8219..2d4ba20 100644
--- a/openbsc/src/system_information.c
+++ b/openbsc/src/system_information.c
@@ -23,6 +23,7 @@
 
 #include <errno.h>
 #include <string.h>
+#include <stdio.h>
 #include <sys/types.h>
 #include <netinet/in.h>
 
@@ -30,6 +31,7 @@
 #include <openbsc/gsm_data.h>
 #include <openbsc/abis_rsl.h>
 #include <openbsc/rest_octets.h>
+#include <openbsc/bitvec.h>
 
 #define GSM48_CELL_CHAN_DESC_SIZE	16
 #define GSM_MACBLOCK_LEN 		23
@@ -38,7 +40,7 @@
 /* Frequency Lists as per TS 04.08 10.5.2.13 */
 
 /* 10.5.2.13.2: Bit map 0 format */
-static int cchan_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn)
+static int freq_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn)
 {
 	unsigned int byte, bit;
 
@@ -57,7 +59,7 @@
 }
 
 /* 10.5.2.13.7: Variable bit map format */
-static int cchan_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn)
+static int freq_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn)
 {
 	unsigned int byte, bit;
 	unsigned int min_arfcn;
@@ -86,20 +88,23 @@
 }
 
 /* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
-static int generate_cell_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts)
+static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv,
+			    const struct gsm_bts *bts)
 {
-	struct gsm_bts_trx *trx;
-	int rc, min = 1024, max = 0;
+	int i, rc, min = 1024, max = 0;
 
 	memset(chan_list, 0, 16);
 
 	/* GSM900-only handsets only support 'bit map 0 format' */
 	if (bts->band == GSM_BAND_900) {
 		chan_list[0] = 0;
-		llist_for_each_entry(trx, &bts->trx_list, list) {
-			rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn);
-			if (rc < 0)
-				return rc;
+
+		for (i = 0; i < bv->data_len*8; i++) {
+			if (bitvec_get_bit_pos(bv, i)) {
+				rc = freq_list_bm0_set_arfcn(chan_list, i);
+				if (rc < 0)
+					return rc;
+			}
 		}
 		return 0;
 	}
@@ -107,11 +112,13 @@
 	/* We currently only support the 'Variable bitmap format' */
 	chan_list[0] = 0x8e;
 
-	llist_for_each_entry(trx, &bts->trx_list, list) {
-		if (trx->arfcn < min)
-			min = trx->arfcn;
-		if (trx->arfcn > max)
-			max = trx->arfcn;
+	for (i = 0; i < bv->data_len*8; i++) {
+		if (bitvec_get_bit_pos(bv, i)) {
+			if (i < min)
+				min = i;
+			if (i > max)
+				max = i;
+		}
 	}
 
 	if ((max - min) > 111)
@@ -121,8 +128,8 @@
 	chan_list[1] = (min >> 1);
 	chan_list[2] = (min & 1) << 7;
 
-	llist_for_each_entry(trx, &bts->trx_list, list) {
-		rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn);
+	for (i = 0; i < bv->data_len*8; i++) {
+		rc = freq_list_bmrel_set_arfcn(chan_list, i);
 		if (rc < 0)
 			return rc;
 	}
@@ -131,61 +138,37 @@
 }
 
 /* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
-static int generate_bcch_chan_list(u_int8_t *chan_list, const struct gsm_bts *bts)
+static int generate_cell_chan_list(u_int8_t *chan_list, struct gsm_bts *bts)
 {
-	struct gsm_bts *cur_bts;
 	struct gsm_bts_trx *trx;
-	int rc, min = 1024, max = 0;
+	struct bitvec *bv = &bts->si_common.cell_alloc;
 
-	memset(chan_list, 0, 16);
+	/* first we generate a bitvec of all TRX ARFCN's in our BTS */
+	llist_for_each_entry(trx, &bts->trx_list, list)
+		bitvec_set_bit_pos(bv, trx->arfcn, 1);
 
-	/* GSM900-only handsets only support 'bit map 0 format' */
-	if (bts->band == GSM_BAND_900) {
-		chan_list[0] = 0;
-		llist_for_each_entry(cur_bts, &bts->list, list) {
-			if (&cur_bts->list == &bts->network->bts_list)
-				continue;
-			trx = cur_bts->c0;
-			rc = cchan_list_bm0_set_arfcn(chan_list, trx->arfcn);
-			if (rc < 0)
-				return rc;
-		}
-		return 0;
-	}
-
-	/* We currently only support the 'Variable bitmap format' */
-	chan_list[0] = 0x8e;
-
-	llist_for_each_entry(cur_bts, &bts->list, list) {
-		if (&cur_bts->list == &bts->network->bts_list)
-			continue;
-		trx = cur_bts->c0;
-		if (trx->arfcn < min)
-			min = trx->arfcn;
-		if (trx->arfcn > max)
-			max = trx->arfcn;
-	}
-
-	if ((max - min) > 111)
-		return -EINVAL;
-
-	chan_list[0] |= (min >> 9) & 1;
-	chan_list[1] = (min >> 1);
-	chan_list[2] = (min & 1) << 7;
-
-	llist_for_each_entry(cur_bts, &bts->list, list) {
-		if (&cur_bts->list == &bts->network->bts_list)
-			continue;
-		trx = cur_bts->c0;
-		rc = cchan_list_bmrel_set_arfcn(chan_list, trx->arfcn);
-		if (rc < 0)
-			return rc;
-	}
-
-	return 0;
+	/* then we generate a GSM 04.08 frequency list from the bitvec */
+	return bitvec2freq_list(chan_list, bv, bts);
 }
 
-static int generate_si1(u_int8_t *output, const struct gsm_bts *bts)
+/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
+static int generate_bcch_chan_list(u_int8_t *chan_list, struct gsm_bts *bts)
+{
+	struct gsm_bts *cur_bts;
+	struct bitvec *bv = &bts->si_common.neigh_list;
+
+	/* first we generate a bitvec of the BCCH ARFCN's in our BSC */
+	llist_for_each_entry(cur_bts, &bts->network->bts_list, list) {
+		if (cur_bts == bts)
+			continue;
+		bitvec_set_bit_pos(bv, cur_bts->c0->arfcn, 1);
+	}
+
+	/* then we generate a GSM 04.08 frequency list from the bitvec */
+	return bitvec2freq_list(chan_list, bv, bts);
+}
+
+static int generate_si1(u_int8_t *output, struct gsm_bts *bts)
 {
 	int rc;
 	struct gsm48_system_information_type_1 *si1 =
@@ -210,7 +193,7 @@
 	return GSM_MACBLOCK_LEN;
 }
 
-static int generate_si2(u_int8_t *output, const struct gsm_bts *bts)
+static int generate_si2(u_int8_t *output, struct gsm_bts *bts)
 {
 	int rc;
 	struct gsm48_system_information_type_2 *si2 =
@@ -257,7 +240,7 @@
 	.break_ind = 0,
 };
 
-static int generate_si3(u_int8_t *output, const struct gsm_bts *bts)
+static int generate_si3(u_int8_t *output, struct gsm_bts *bts)
 {
 	struct gsm48_system_information_type_3 *si3 =
 		(struct gsm48_system_information_type_3 *) output;
@@ -287,7 +270,7 @@
 	return GSM_MACBLOCK_LEN;
 }
 
-static int generate_si4(u_int8_t *output, const struct gsm_bts *bts)
+static int generate_si4(u_int8_t *output, struct gsm_bts *bts)
 {
 	struct gsm48_system_information_type_4 *si4 =
 		(struct gsm48_system_information_type_4 *) output;
@@ -319,7 +302,7 @@
 	return GSM_MACBLOCK_LEN;
 }
 
-static int generate_si5(u_int8_t *output, const struct gsm_bts *bts)
+static int generate_si5(u_int8_t *output, struct gsm_bts *bts)
 {
 	struct gsm48_system_information_type_5 *si5 =
 		(struct gsm48_system_information_type_5 *) output;
@@ -339,7 +322,7 @@
 	return 18;
 }
 
-static int generate_si6(u_int8_t *output, const struct gsm_bts *bts)
+static int generate_si6(u_int8_t *output, struct gsm_bts *bts)
 {
 	struct gsm48_system_information_type_6 *si6 =
 		(struct gsm48_system_information_type_6 *) output;
@@ -390,7 +373,7 @@
 	},
 };
 
-static int generate_si13(u_int8_t *output, const struct gsm_bts *bts)
+static int generate_si13(u_int8_t *output, struct gsm_bts *bts)
 {
 	struct gsm48_system_information_type_13 *si13 =
 		(struct gsm48_system_information_type_13 *) output;