lchan: Introduce T3109 handling for the release procedure

T3109 is started when the SACCH is deactivated. It is stopped when
the phones sends the DISC/UA/UM on LAPDm for the main signalling
link. In case of timeout the abnormal release procedure will be
initiated. Make sure to not issue the SACCH Deactivate twice to
avoid confusing the equipment.

This is still not fully spec compliant. In case of a timeout the
abnormal release handling will be started which involves starting
T3111+2. The error handling should be split out of the rf channel
release method, e.g. lchan_release should be called and check if
the channel release was already initiated.
diff --git a/openbsc/doc/channel_release.txt b/openbsc/doc/channel_release.txt
index bd707b4..c9cdfeb 100644
--- a/openbsc/doc/channel_release.txt
+++ b/openbsc/doc/channel_release.txt
@@ -61,7 +61,8 @@
 	* Release all SAPI's > 0 as local end (The BTS should send a
 	  REL_CONF a message)
 	* Send SACH Deactivate on SAPI=0 if required.
-	* It should start T3109 but it does not.
+	* Start T3109 (stop it when the main signalling link is disconnected)
+	  or when the channel released. On timeout start the error handling.
 	* abis_rsl.c schedules the RSL_MT_RF_CHAN_REL once all SAPI's are
 	  released and after T3111 has timed out or there is an error.
 
diff --git a/openbsc/doc/examples/osmo-nitb/bs11/openbsc-1bts-2trx-hopping.cfg b/openbsc/doc/examples/osmo-nitb/bs11/openbsc-1bts-2trx-hopping.cfg
index 654d397..36065e2 100644
--- a/openbsc/doc/examples/osmo-nitb/bs11/openbsc-1bts-2trx-hopping.cfg
+++ b/openbsc/doc/examples/osmo-nitb/bs11/openbsc-1bts-2trx-hopping.cfg
@@ -30,7 +30,7 @@
  timer t3103 0
  timer t3105 0
  timer t3107 0
- timer t3109 0
+ timer t3109 4
  timer t3111 0
  timer t3113 60
  timer t3115 0
diff --git a/openbsc/doc/examples/osmo-nitb/hsl/openbsc.cfg b/openbsc/doc/examples/osmo-nitb/hsl/openbsc.cfg
index 3d95748..b0af855 100644
--- a/openbsc/doc/examples/osmo-nitb/hsl/openbsc.cfg
+++ b/openbsc/doc/examples/osmo-nitb/hsl/openbsc.cfg
@@ -31,7 +31,7 @@
  timer t3103 0
  timer t3105 0
  timer t3107 0
- timer t3109 0
+ timer t3109 4
  timer t3111 0
  timer t3113 60
  timer t3115 0
diff --git a/openbsc/doc/examples/osmo-nitb/nanobts/openbsc-multitrx.cfg b/openbsc/doc/examples/osmo-nitb/nanobts/openbsc-multitrx.cfg
index 7a187f8..bea0b7d 100644
--- a/openbsc/doc/examples/osmo-nitb/nanobts/openbsc-multitrx.cfg
+++ b/openbsc/doc/examples/osmo-nitb/nanobts/openbsc-multitrx.cfg
@@ -30,7 +30,7 @@
  timer t3103 0
  timer t3105 0
  timer t3107 0
- timer t3109 0
+ timer t3109 4
  timer t3111 0
  timer t3113 60
  timer t3115 0
diff --git a/openbsc/doc/examples/osmo-nitb/nanobts/openbsc.cfg b/openbsc/doc/examples/osmo-nitb/nanobts/openbsc.cfg
index 78e9787..7a44308 100644
--- a/openbsc/doc/examples/osmo-nitb/nanobts/openbsc.cfg
+++ b/openbsc/doc/examples/osmo-nitb/nanobts/openbsc.cfg
@@ -30,7 +30,7 @@
  timer t3103 0
  timer t3105 0
  timer t3107 0
- timer t3109 0
+ timer t3109 4
  timer t3111 0
  timer t3113 60
  timer t3115 0
diff --git a/openbsc/doc/examples/osmo-nitb/rbs2308/openbsc.cfg b/openbsc/doc/examples/osmo-nitb/rbs2308/openbsc.cfg
index 7135042..97cd9df 100644
--- a/openbsc/doc/examples/osmo-nitb/rbs2308/openbsc.cfg
+++ b/openbsc/doc/examples/osmo-nitb/rbs2308/openbsc.cfg
@@ -29,7 +29,7 @@
  timer t3103 0
  timer t3105 0
  timer t3107 0
- timer t3109 0
+ timer t3109 4
  timer t3111 0
  timer t3113 60
  timer t3115 0
diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h
index 45af4a6..4f2b6b5 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -99,6 +99,7 @@
 
 int rsl_release_sapis_from(struct gsm_lchan *lchan, int start,
 				enum rsl_rel_mode release_mode);
+int rsl_start_t3109(struct gsm_lchan *lchan);
 
 #endif /* RSL_MT_H */
 
diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h
index 21fa645..ba431da 100644
--- a/openbsc/include/openbsc/gsm_data_shared.h
+++ b/openbsc/include/openbsc/gsm_data_shared.h
@@ -217,6 +217,7 @@
 
 #ifdef ROLE_BSC
 	struct osmo_timer_list T3101;
+	struct osmo_timer_list T3109;
 	struct osmo_timer_list T3111;
 	struct osmo_timer_list error_timer;
 	struct osmo_timer_list act_timer;
diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c
index 04d5c61..6e1ce78 100644
--- a/openbsc/src/libbsc/abis_rsl.c
+++ b/openbsc/src/libbsc/abis_rsl.c
@@ -46,6 +46,11 @@
 #define RSL_ALLOC_SIZE		1024
 #define RSL_ALLOC_HEADROOM	128
 
+enum sacch_deact {
+	SACCH_NONE,
+	SACCH_DEACTIVATE,
+};
+
 static int rsl_send_imm_assignment(struct gsm_lchan *lchan);
 
 static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan,
@@ -644,12 +649,16 @@
 static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan);
 
 /* Chapter 8.4.14 / 4.7: Tell BTS to release the radio channel */
-static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
+static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error,
+				enum sacch_deact deact_sacch)
 {
 	struct abis_rsl_dchan_hdr *dh;
 	struct msgb *msg;
 	int rc;
 
+	/* Stop timers that should lead to a channel release */
+	osmo_timer_del(&lchan->T3109);
+
 	if (lchan->state == LCHAN_S_REL_ERR) {
 		LOGP(DRSL, LOGL_NOTICE, "%s is in error state not sending release.\n",
 		     gsm_lchan_name(lchan));
@@ -688,7 +697,8 @@
 		/*
 		 * sacch de-activate and "local end release"
 		 */
-		rsl_deact_sacch(lchan);
+		if (deact_sacch == SACCH_DEACTIVATE)
+			rsl_deact_sacch(lchan);
 		rsl_release_sapis_from(lchan, 0, RSL_REL_LOCAL_END);
 
 		/*
@@ -939,7 +949,7 @@
 		if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
 			rsl_lchan_set_state(msg->lchan, LCHAN_S_BROKEN);
 		else
-			rsl_rf_chan_release(msg->lchan, 1);
+			rsl_rf_chan_release(msg->lchan, 1, SACCH_DEACTIVATE);
 
 	} else
 		rsl_lchan_set_state(msg->lchan, LCHAN_S_BROKEN);
@@ -969,7 +979,7 @@
 	LOGPC(DRSL, LOGL_NOTICE, "\n");
 	/* FIXME: only free it after channel release ACK */
 	osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail);
-	return rsl_rf_chan_release(msg->lchan, 1);
+	return rsl_rf_chan_release(msg->lchan, 1, SACCH_DEACTIVATE);
 }
 
 static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru,
@@ -1250,7 +1260,7 @@
 {
 	struct gsm_lchan *lchan = data;
 
-	rsl_rf_chan_release(lchan, 1);
+	rsl_rf_chan_release(lchan, 1, SACCH_DEACTIVATE);
 }
 
 /* If T3111 expires, we will send the RF Channel Request */
@@ -1258,7 +1268,17 @@
 {
 	struct gsm_lchan *lchan = data;
 
-	rsl_rf_chan_release(lchan, 0);
+	rsl_rf_chan_release(lchan, 0, SACCH_NONE);
+}
+
+/* If T3109 expires the MS has not send a UA/UM do the error release */
+static void t3109_expired(void *data)
+{
+	struct gsm_lchan *lchan = data;
+
+	LOGP(DRSL, LOGL_ERROR,
+		"%s SACCH deactivation timeout.\n", gsm_lchan_name(lchan));
+	rsl_rf_chan_release(lchan, 1, SACCH_NONE);
 }
 
 #define GSM48_LEN2PLEN(a)	(((a) << 2) | 1)
@@ -1516,7 +1536,7 @@
 
 	if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) {
 		osmo_counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err);
-		return rsl_rf_chan_release(msg->lchan, 1);
+		return rsl_rf_chan_release(msg->lchan, 1, SACCH_DEACTIVATE);
 	}
 
 	return 0;
@@ -1544,8 +1564,8 @@
 	}
 
 
-
-	/* wait a bit to send the RF Channel Release */
+	/* Stop T3109 and wait for T3111 before re-using the channel */
+	osmo_timer_del(&lchan->T3109);
 	lchan->T3111.cb = t3111_expired;
 	lchan->T3111.data = lchan;
 	bts = lchan->ts->trx->bts;
@@ -2107,3 +2127,17 @@
 
 	return no_sapi;
 }
+
+int rsl_start_t3109(struct gsm_lchan *lchan)
+{
+	struct gsm_bts *bts = lchan->ts->trx->bts;
+
+	/* Disabled, mostly legacy code */
+	if (bts->network->T3109 == 0)
+		return -1;
+
+	lchan->T3109.cb = t3109_expired;
+	lchan->T3109.data = lchan;
+	osmo_timer_schedule(&lchan->T3109, bts->network->T3109, 0);
+	return 0;
+}
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 61b0911..dfe80c9 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -1379,7 +1379,7 @@
 DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.\n")
 DECLARE_TIMER(3105, "Set the timer for repetition of PHYSICAL INFORMATION.\n")
 DECLARE_TIMER(3107, "Currently not used.\n")
-DECLARE_TIMER(3109, "Currently not used.\n")
+DECLARE_TIMER(3109, "Set the RSL SACCH deactivation timeout.\n")
 DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.\n")
 DECLARE_TIMER(3113, "Set the time to try paging a subscriber.\n")
 DECLARE_TIMER(3115, "Currently not used.\n")
diff --git a/openbsc/src/libbsc/chan_alloc.c b/openbsc/src/libbsc/chan_alloc.c
index a8b15d1..9b59d5d 100644
--- a/openbsc/src/libbsc/chan_alloc.c
+++ b/openbsc/src/libbsc/chan_alloc.c
@@ -362,6 +362,7 @@
 void lchan_reset(struct gsm_lchan *lchan)
 {
 	osmo_timer_del(&lchan->T3101);
+	osmo_timer_del(&lchan->T3109);
 	osmo_timer_del(&lchan->T3111);
 	osmo_timer_del(&lchan->error_timer);
 
@@ -376,7 +377,7 @@
 
 /* Drive the release process of the lchan */
 static void _lchan_handle_release(struct gsm_lchan *lchan,
-				  int sach_deact, int mode)
+				  int sacch_deact, int mode)
 {
 	/* Release all SAPIs on the local end and continue */
 	rsl_release_sapis_from(lchan, 1, RSL_REL_LOCAL_END);
@@ -386,10 +387,15 @@
 	 * release indication from the BTS or just take it down (e.g.
 	 * on assignment requests)
 	 */
-	if (sach_deact)
+	if (sacch_deact) {
 		gsm48_send_rr_release(lchan);
-	else
+
+		/* Deactivate the SACCH on the BTS side */
+		rsl_deact_sacch(lchan);
+		rsl_start_t3109(lchan);
+	} else {
 		rsl_release_request(lchan, 0, mode);
+	}
 }
 
 /* Consider releasing the channel now */
diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c
index 968e62e..de596de 100644
--- a/openbsc/src/libbsc/gsm_04_08_utils.c
+++ b/openbsc/src/libbsc/gsm_04_08_utils.c
@@ -231,11 +231,7 @@
 		lchan->nr, lchan->type);
 
 	/* Send actual release request to MS */
-	gsm48_sendmsg(msg);
-	/* FIXME: Start Timer T3109 */
-
-	/* Deactivate the SACCH on the BTS side */
-	return rsl_deact_sacch(lchan);
+	return gsm48_sendmsg(msg);
 }
 
 int send_siemens_mrpci(struct gsm_lchan *lchan,