[BSC] Generate MA for each timeslot that has hopping enabled

The MA is used in 04.08 channel assignment related messages
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 8cb09d2..170ebab 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -338,11 +338,15 @@
 	u_int8_t nm_chan_comb;
 
 	struct {
+		/* Parameters below are configured by VTY */
 		int enabled;
 		u_int8_t maio;
 		u_int8_t hsn;
 		struct bitvec arfcns;
 		u_int8_t arfcns_data[1024/8];
+		/* This is the pre-computed MA for channel assignments */
+		struct bitvec ma;
+		u_int8_t ma_data[8];	/* 10.5.2.21: max 8 bytes value part */
 	} hopping;
 
 	/* To which E1 subslot are we connected */
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index ddb53ba..b69aebd 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -915,14 +915,58 @@
 	}
 }
 
+/* Produce a MA as specified in 10.5.2.21 */
+static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts)
+{
+	/* we have three bitvecs: the per-timeslot ARFCNs, the cell chan ARFCNs
+	 * and the MA */
+	struct bitvec *cell_chan = &ts->trx->bts->si_common.cell_alloc;
+	struct bitvec *ts_arfcn = &ts->hopping.arfcns;
+	struct bitvec *ma = &ts->hopping.ma;
+	int i;
+
+	/* re-set the MA to all-zero */
+	ma->cur_bit = 0;
+	memset(ma->data, 0, ma->data_len);
+
+	if (!ts->hopping.enabled)
+		return 0;
+
+	for (i = 1; i < 1024; i++) {
+		if (!bitvec_get_bit_pos(cell_chan, i))
+			continue;
+		/* append a bit to the MA */
+		if (bitvec_get_bit_pos(ts_arfcn, i))
+			bitvec_set_bit(ma, 1);
+		else
+			bitvec_set_bit(ma, 0);
+	}
+
+	/* ARFCN 0 is special: It is coded last in the bitmask */
+	if (bitvec_get_bit_pos(cell_chan, 0)) {
+		/* append a bit to the MA */
+		if (bitvec_get_bit_pos(ts_arfcn, 0))
+			bitvec_set_bit(ma, 1);
+		else
+			bitvec_set_bit(ma, 0);
+	}
+
+	return 0;
+}
+
 static void bootstrap_rsl(struct gsm_bts_trx *trx)
 {
+	unsigned int i;
+
 	LOGP(DRSL, LOGL_NOTICE, "bootstrapping RSL for BTS/TRX (%u/%u) "
 		"on ARFCN %u using MCC=%u MNC=%u LAC=%u CID=%u BSIC=%u TSC=%u\n",
 		trx->bts->nr, trx->nr, trx->arfcn, bsc_gsmnet->country_code,
 		bsc_gsmnet->network_code, trx->bts->location_area_code,
 		trx->bts->cell_identity, trx->bts->bsic, trx->bts->tsc);
 	set_system_infos(trx);
+
+	for (i = 0; i < ARRAY_SIZE(trx->ts); i++)
+		generate_ma_for_ts(&trx->ts[i]);
 }
 
 void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index bbf150a..de3a08d 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -156,6 +156,8 @@
 
 		ts->hopping.arfcns.data_len = sizeof(ts->hopping.arfcns_data);
 		ts->hopping.arfcns.data = ts->hopping.arfcns_data;
+		ts->hopping.ma.data_len = sizeof(ts->hopping.ma_data);
+		ts->hopping.ma.data = ts->hopping.ma_data;
 
 		for (l = 0; l < TS_MAX_LCHAN; l++) {
 			struct gsm_lchan *lchan;