[rsl] Introduce an error state for the lchan and set it on release

When we issue a RF Channel Release in case of a failure we receive
RLL release indications after the channel was tearn down and we
issue another RF Channel Release as a result. The channel allocator
might have already allocated this channel and we release the channel
again with another MS on it.

Make rsl_rf_chan_release take an error argument and make it set
a new state in case of an error and change the RF Channel Release
ack to not set the state back to none in case of an error but wait
for a timeout that is a bit higher than T3111.

I tested this with removing the battery during a phonecall and
waiting for the channel failure. With this test we only send the
release once.
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 39407e9..90e8fc0 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -205,6 +205,7 @@
 	LCHAN_S_ACT_REQ,	/* channel activatin requested */
 	LCHAN_S_ACTIVE,		/* channel is active and operational */
 	LCHAN_S_REL_REQ,	/* channel release has been requested */
+	LCHAN_S_REL_ERR,	/* channel is in an error state */
 	LCHAN_S_INACTIVE,	/* channel is set inactive */
 };
 
@@ -257,6 +258,7 @@
 
 	struct timer_list T3101;
 	struct timer_list T3111;
+	struct timer_list error_timer;
 
 	/* AMR bits */
 	struct gsm48_multi_rate_conf mr_conf;
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index d170ff7..79c8eeb 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -568,12 +568,33 @@
 	return abis_rsl_sendmsg(msg);
 }
 
+static void error_timeout_cb(void *data)
+{
+	struct gsm_lchan *lchan = data;
+	if (lchan->state != LCHAN_S_REL_ERR) {
+		LOGP(DRSL, LOGL_ERROR, "%s error timeout but not in error state: %d\n",
+		     gsm_lchan_name(lchan), lchan->state);
+		return;
+	}
+
+	/* go back to the none state */
+	LOGP(DRSL, LOGL_NOTICE, "%s is back in operation.\n", gsm_lchan_name(lchan));
+	lchan->state = LCHAN_S_NONE;
+}
+
 /* Chapter 8.4.14 / 4.7: Tell BTS to release the radio channel */
-int rsl_rf_chan_release(struct gsm_lchan *lchan)
+static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
 {
 	struct abis_rsl_dchan_hdr *dh;
-	struct msgb *msg = rsl_msgb_alloc();
+	struct msgb *msg;
 
+	if (lchan->state == LCHAN_S_REL_ERR) {
+		LOGP(DRSL, LOGL_NOTICE, "%s is in error state not sending release.\n",
+		     gsm_lchan_name(lchan));
+		return -1;
+	}
+
+	msg = rsl_msgb_alloc();
 	dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
 	init_dchan_hdr(dh, RSL_MT_RF_CHAN_REL);
 	dh->chan_nr = lchan2chan_nr(lchan);
@@ -581,7 +602,20 @@
 	msg->lchan = lchan;
 	msg->trx = lchan->ts->trx;
 
-	DEBUGP(DRSL, "%s RF Channel Release CMD\n", gsm_lchan_name(lchan));
+	DEBUGP(DRSL, "%s RF Channel Release CMD due error %d\n", gsm_lchan_name(lchan), error);
+
+	if (error) {
+		/*
+		 * the nanoBTS sends RLL release indications after the channel release. This can
+		 * be a problem when we have reassigned the channel to someone else and then can
+		 * not figure out who used this channel.
+		 */
+		lchan->state = LCHAN_S_REL_ERR;
+		lchan->error_timer.data = lchan;
+		lchan->error_timer.cb = error_timeout_cb;
+		bsc_schedule_timer(&lchan->error_timer,
+				   msg->trx->bts->network->T3111 + 2, 0);
+	}
 
 	/* BTS will respond by RF CHAN REL ACK */
 	return abis_rsl_sendmsg(msg);
@@ -811,7 +845,7 @@
 	LOGPC(DRSL, LOGL_NOTICE, "\n");
 	/* FIXME: only free it after channel release ACK */
 	counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail);
-	return rsl_rf_chan_release(msg->lchan);
+	return rsl_rf_chan_release(msg->lchan, 1);
 }
 
 static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru,
@@ -983,12 +1017,14 @@
 		break;
 	case RSL_MT_RF_CHAN_REL_ACK:
 		DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", ts_name);
-		if (msg->lchan->state != LCHAN_S_REL_REQ)
+		if (msg->lchan->state != LCHAN_S_REL_REQ && msg->lchan->state != LCHAN_S_REL_ERR)
 			LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n",
 				gsm_lchan_name(msg->lchan),
 				gsm_lchans_name(msg->lchan->state));
 		bsc_del_timer(&msg->lchan->T3111);
-		rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
+		/* we have an error timer pending to release that */
+		if (msg->lchan->state != LCHAN_S_REL_ERR)
+			rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
 		lchan_free(msg->lchan);
 		break;
 	case RSL_MT_MODE_MODIFY_ACK:
@@ -1080,7 +1116,7 @@
 {
 	struct gsm_lchan *lchan = data;
 
-	rsl_rf_chan_release(lchan);
+	rsl_rf_chan_release(lchan, 1);
 }
 
 /* If T3111 expires, we will send the RF Channel Request */
@@ -1088,7 +1124,7 @@
 {
 	struct gsm_lchan *lchan = data;
 
-	rsl_rf_chan_release(lchan);
+	rsl_rf_chan_release(lchan, 0);
 }
 
 /* MS has requested a channel on the RACH */
@@ -1261,7 +1297,7 @@
 
 	if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) {
 		counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err);
-		return rsl_rf_chan_release(msg->lchan);
+		return rsl_rf_chan_release(msg->lchan, 1);
 	}
 
 	return 0;
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index a10edad..9de4c1f 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -88,6 +88,7 @@
 	{ LCHAN_S_ACTIVE,	"ACTIVE" },
 	{ LCHAN_S_INACTIVE,	"INACTIVE" },
 	{ LCHAN_S_REL_REQ,	"RELEASE REQUESTED" },
+	{ LCHAN_S_REL_ERR,	"RELEASE DUE ERROR" },
 	{ 0,			NULL }
 };