From 8d96e10622c52040e4049102457189560eb8c6ce Mon Sep 17 00:00:00 2001
From: Harald Welte <laforge@gnumonks.org>
Date: Mon, 27 Jun 2016 18:56:01 +0200
Subject: [PATCH] RACH decoding: Use BER threshold for RACH ghost detection

When decoding RACH bursts, we should use a BER threshold in order to
help distinguish 'ghost' RACH bursts from real RACH bursts.

The theoretical ideal threshold according to some papers is 7 out of 41
bits qhich aquals to Eb/N0 of 0 dB = 0.1707 (17.07%)

We add a new 'ber10k' parameter to the RACH indication l1sap primitive
(needs separate change for libosmocore), and then fill this value from
osmo-bts-{sysmo,lc15,trx,octphy}.  The common part above L1SAP then
applies the threshold, which can be changed from vty using the
	"max-ber10k-rach <0-10000>"
command available at the BTS node.  The unit is BER in 1/10000, i.e. a
value of 100 equals 1% bit error rate.

Change-Id: Ic41c11f6312a36baa2738547e8dcec80829457f8
---
 include/osmo-bts/gsm_data.h       |  1 +
 src/common/bts.c                  |  1 +
 src/common/l1sap.c                |  7 +++++++
 src/common/vty.c                  | 16 ++++++++++++++++
 src/osmo-bts-litecell15/l1_if.c   |  1 +
 src/osmo-bts-octphy/l1_if.c       |  2 ++
 src/osmo-bts-sysmo/l1_if.c        |  1 +
 src/osmo-bts-trx/gsm0503_coding.c |  6 ++++--
 src/osmo-bts-trx/gsm0503_coding.h |  3 ++-
 src/osmo-bts-trx/scheduler_trx.c  | 11 ++++++++++-
 10 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h
index 7a48667..de20e36 100644
--- a/include/osmo-bts/gsm_data.h
+++ b/include/osmo-bts/gsm_data.h
@@ -107,6 +107,7 @@ struct gsm_bts_role_bts {
 
 	float min_qual_rach;	/* minimum quality for RACH bursts */
 	float min_qual_norm;	/* minimum quality for normal daata */
+	uint16_t max_ber10k_rach;	/* Maximum permitted RACH BER in 0.01% */
 
 	struct {
 		char *sock_path;
diff --git a/src/common/bts.c b/src/common/bts.c
index 6f621c4..6681994 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -118,6 +118,7 @@ int bts_init(struct gsm_bts *bts)
 	btsb->t3105_ms = 300;
 	btsb->min_qual_rach = MIN_QUAL_RACH;
 	btsb->min_qual_norm = MIN_QUAL_NORM;
+	btsb->max_ber10k_rach = 1707; /* 7 of 41 bits is Eb/N0 of 0 dB = 0.1707 */
 	btsb->pcu.sock_path = talloc_strdup(btsb, PCU_SOCK_DEFAULT);
 	for (i = 0; i < ARRAY_SIZE(btsb->t200_ms); i++)
 		btsb->t200_ms[i] = oml_default_t200_ms[i];
diff --git a/src/common/l1sap.c b/src/common/l1sap.c
index 5ea2a2c..4e1e352 100644
--- a/src/common/l1sap.c
+++ b/src/common/l1sap.c
@@ -936,6 +936,13 @@ static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx,
 
 	lc = &trx->ts[0].lchan[4].lapdm_ch;
 
+	/* check for RACH exceeding BER threshold (ghost RACH) */
+	if (rach_ind->ber10k > btsb->max_ber10k_rach) {
+		DEBUGP(DL1C, "ignoring RACH request: %u > %u (max BER)\n",
+			rach_ind->ber10k, btsb->max_ber10k_rach);
+		return 0;
+	}
+
 	/* check for under/overflow / sign */
 	if (!check_acc_delay(rach_ind, btsb, &acc_delay)) {
 		LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n",
diff --git a/src/common/vty.c b/src/common/vty.c
index b4aa616..34dc581 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -304,6 +304,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
 		VTY_NEWLINE);
 	vty_out(vty, " min-qual-norm %.0f%s", btsb->min_qual_norm * 10.0f,
 		VTY_NEWLINE);
+	vty_out(vty, " max-ber10k-rach %u%s", btsb->max_ber10k_rach,
+		VTY_NEWLINE);
 	if (strcmp(btsb->pcu.sock_path, PCU_SOCK_DEFAULT))
 		vty_out(vty, " pcu-socket %s%s", btsb->pcu.sock_path, VTY_NEWLINE);
 
@@ -603,6 +605,19 @@ DEFUN(cfg_bts_min_qual_norm, cfg_bts_min_qual_norm_cmd,
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_bts_max_ber_rach, cfg_bts_max_ber_rach_cmd,
+	"max-ber10k-rach <0-10000>",
+	"Set the maximum BER for valid RACH requests\n"
+	"BER in 1/10000 units (0=no BER; 100=1% BER)\n")
+{
+	struct gsm_bts *bts = vty->index;
+	struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
+
+	btsb->max_ber10k_rach = strtoul(argv[0], NULL, 10);
+
+	return CMD_SUCCESS;
+}
+
 DEFUN(cfg_bts_pcu_sock, cfg_bts_pcu_sock_cmd,
 	"pcu-socket PATH",
 	"Configure the PCU socket file/path name\n")
@@ -1093,6 +1108,7 @@ int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat)
 	install_element(BTS_NODE, &cfg_bts_ul_power_target_cmd);
 	install_element(BTS_NODE, &cfg_bts_min_qual_rach_cmd);
 	install_element(BTS_NODE, &cfg_bts_min_qual_norm_cmd);
+	install_element(BTS_NODE, &cfg_bts_max_ber_rach_cmd);
 	install_element(BTS_NODE, &cfg_bts_pcu_sock_cmd);
 
 	install_element(BTS_NODE, &cfg_trx_gsmtap_sapi_cmd);
diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c
index 2af2481..e7aaae5 100644
--- a/src/osmo-bts-litecell15/l1_if.c
+++ b/src/osmo-bts-litecell15/l1_if.c
@@ -964,6 +964,7 @@ static int handle_ph_ra_ind(struct lc15l1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind,
 	l1sap->u.rach_ind.ra = ra;
 	l1sap->u.rach_ind.acc_delay = acc_delay;
 	l1sap->u.rach_ind.fn = fn;
+	l1sap->u.rach_ind.ber10k = (uint16_t) (ra_ind->measParam.fBer * 100);
 	if (!lchan || lchan->ts->pchan == GSM_PCHAN_CCCH ||
 	    lchan->ts->pchan == GSM_PCHAN_CCCH_SDCCH4)
 		l1sap->u.rach_ind.chan_nr = 0x88;
diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c
index 760c988..9af1bb0 100644
--- a/src/osmo-bts-octphy/l1_if.c
+++ b/src/osmo-bts-octphy/l1_if.c
@@ -1087,6 +1087,8 @@ static int handle_ph_rach_ind(struct octphy_hdl *fl1,
 	l1sap->u.rach_ind.ra = ra;
 	l1sap->u.rach_ind.acc_delay = acc_delay;
 	l1sap->u.rach_ind.fn = fn;
+	l1sap->u.rach_ind.ber10k = (unsigned int)
+			(ra_ind->MeasuremenetInfo.usBERCnt * 100);
 	if (!lchan || lchan->ts->pchan == GSM_PCHAN_CCCH ||
 	    lchan->ts->pchan == GSM_PCHAN_CCCH_SDCCH4)
 		l1sap->u.rach_ind.chan_nr = 0x88;
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index 355507d..3e8d802 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -960,6 +960,7 @@ static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind,
 	l1sap->u.rach_ind.ra = ra;
 	l1sap->u.rach_ind.acc_delay = acc_delay;
 	l1sap->u.rach_ind.fn = fn;
+	l1sap->u.rach_ind.ber10k = (uint16_t) (ra_ind->measParam.fBer * 100);
 	if (!lchan || lchan->ts->pchan == GSM_PCHAN_CCCH ||
 	    lchan->ts->pchan == GSM_PCHAN_CCCH_SDCCH4)
 		l1sap->u.rach_ind.chan_nr = 0x88;
diff --git a/src/osmo-bts-trx/gsm0503_coding.c b/src/osmo-bts-trx/gsm0503_coding.c
index fde020e..ad7b36b 100644
--- a/src/osmo-bts-trx/gsm0503_coding.c
+++ b/src/osmo-bts-trx/gsm0503_coding.c
@@ -1628,12 +1628,14 @@ static int rach_apply_bsic(ubit_t *d, uint8_t bsic)
 	return 0;
 }
 
-int rach_decode(uint8_t *ra, sbit_t *burst, uint8_t bsic)
+int rach_decode(uint8_t *ra, sbit_t *burst, uint8_t bsic,
+		int *n_errors, int *n_bits_total)
 {
 	ubit_t conv[14];
 	int rv;
 
-	osmo_conv_decode(&gsm0503_conv_rach, burst, conv);
+	osmo_conv_decode_ber(&gsm0503_conv_rach, burst, conv,
+				n_errors, n_bits_total);
 
 	rach_apply_bsic(conv, bsic);
 
diff --git a/src/osmo-bts-trx/gsm0503_coding.h b/src/osmo-bts-trx/gsm0503_coding.h
index a454d8f..cf87e3d 100644
--- a/src/osmo-bts-trx/gsm0503_coding.h
+++ b/src/osmo-bts-trx/gsm0503_coding.h
@@ -45,7 +45,8 @@ int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
 int tch_ahs_encode(ubit_t *bursts, uint8_t *tch_data, int len,
 	int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft,
 	uint8_t cmr);
-int rach_decode(uint8_t *ra, sbit_t *burst, uint8_t bsic);
+int rach_decode(uint8_t *ra, sbit_t *burst, uint8_t bsic,
+		int *n_errors, int *n_bits_total);
 int rach_encode(ubit_t *burst, uint8_t *ra, uint8_t bsic);
 int sch_decode(uint8_t *sb_info, sbit_t *burst);
 int sch_encode(ubit_t *burst, uint8_t *sb_info);
diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c
index 9a6a59c..297403f 100644
--- a/src/osmo-bts-trx/scheduler_trx.c
+++ b/src/osmo-bts-trx/scheduler_trx.c
@@ -703,6 +703,12 @@ send_burst:
 }
 
 
+unsigned int compute_ber10k(int n_errors, int n_bits_total)
+{
+	float ber = n_bits_total == 0 ? 1.0 :
+			(float)n_errors / (float)n_bits_total;
+	return (int) (ber * 10000.0f);
+}
 /*
  * RX on uplink (indication to upper layer)
  */
@@ -714,6 +720,7 @@ int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 	uint8_t chan_nr;
 	struct osmo_phsap_prim l1sap;
 	uint8_t ra;
+	int n_errors, n_bits_total;
 	int rc;
 
 	chan_nr = trx_chan_desc[chan].chan_nr | tn;
@@ -722,7 +729,8 @@ int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 		trx_chan_desc[chan].name, fn, toa);
 
 	/* decode */
-	rc = rach_decode(&ra, bits + 8 + 41, l1t->trx->bts->bsic);
+	rc = rach_decode(&ra, bits + 8 + 41, l1t->trx->bts->bsic,
+			 &n_errors, &n_bits_total);
 	if (rc) {
 		LOGP(DL1C, LOGL_NOTICE, "Received bad AB frame at fn=%u "
 			"(%u/51)\n", fn, fn % 51);
@@ -742,6 +750,7 @@ int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
 #endif
 	l1sap.u.rach_ind.acc_delay = (toa >= 0) ? toa : 0;
 	l1sap.u.rach_ind.fn = fn;
+	l1sap.u.rach_ind.ber10k = compute_ber10k(n_errors, n_bits_total);
 
 	/* forward primitive */
 	l1sap_up(l1t->trx, &l1sap);
-- 
2.8.1

