From 4d2b71151e4cdfae67aaa9d25cb439a77aa7702a Mon Sep 17 00:00:00 2001
From: Holger Hans Peter Freyther <zecke@selfish.org>
Date: Tue, 17 Nov 2009 20:42:09 +0100
Subject: [PATCH] [lchan] Release the channel ones its' usecount drops to zero

Remove the timer handling from the LCHAN and release the
channel ones the use count is dropping to zero.

Change code that was sending/using the lchan after the
release and change the send data method to warn in case
the lchan is used after it has been freed.
---
 openbsc/include/openbsc/chan_alloc.h |   26 ++++++++++++++++++++++++--
 openbsc/include/openbsc/gsm_data.h   |   23 -----------------------
 openbsc/src/abis_rsl.c               |    4 ++++
 openbsc/src/chan_alloc.c             |   26 ++++----------------------
 openbsc/src/gsm_04_08.c              |    5 ++---
 openbsc/src/gsm_subscriber_base.c    |    1 +
 openbsc/src/transaction.c            |    7 ++++---
 openbsc/tests/channel/channel_test.c |    1 +
 8 files changed, 40 insertions(+), 53 deletions(-)

diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h
index 38855d1..ef42fe1 100644
--- a/openbsc/include/openbsc/chan_alloc.h
+++ b/openbsc/include/openbsc/chan_alloc.h
@@ -23,6 +23,28 @@
 
 #include "gsm_subscriber.h"
 
+/*
+ * Refcounting for the lchan. If the refcount drops to zero
+ * the channel will send a RSL release request.
+ */
+#define use_lchan(lchan) \
+	do {	lchan->use_count++; \
+		DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \
+			lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
+			lchan->nr, lchan->use_count); \
+	} while(0);
+
+#define put_lchan(lchan) \
+	do { lchan->use_count--; \
+		DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \
+			lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
+			lchan->nr, lchan->use_count); \
+	    if (lchan->use_count <= 0) \
+		_lchan_release(lchan); \
+	} while(0);
+
+
+
 /* Special allocator for C0 of BTS */
 struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
 				   enum gsm_phys_chan_config pchan);
@@ -46,7 +68,7 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type);
 /* Free a logical channel (SDCCH, TCH, ...) */
 void lchan_free(struct gsm_lchan *lchan);
 
-/* Consider releasing the channel */
-int lchan_auto_release(struct gsm_lchan *lchan);
+/* internal.. do not use */
+int _lchan_release(struct gsm_lchan *lchan);
 
 #endif /* _CHAN_ALLOC_H */
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index c1b7b05..008427b 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -85,26 +85,6 @@ typedef int gsm_cbfn(unsigned int hooknum,
 		     struct msgb *msg,
 		     void *data, void *param);
 
-/*
- * Use the channel. As side effect the lchannel recycle timer
- * will be started.
- */
-#define LCHAN_RELEASE_TIMEOUT 20, 0
-#define use_lchan(lchan) \
-	do {	lchan->use_count++; \
-		DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \
-			lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
-			lchan->nr, lchan->use_count); \
-		bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); } while(0);
-
-#define put_lchan(lchan) \
-	do { lchan->use_count--; \
-		DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \
-			lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
-			lchan->nr, lchan->use_count); \
-	} while(0);
-
-
 /* communications link with a BTS */
 struct gsm_bts_link {
 	struct gsm_bts *bts;
@@ -167,9 +147,6 @@ struct gsm_lchan {
 	/* To whom we are allocated at the moment */
 	struct gsm_subscriber *subscr;
 
-	/* Timer started to release the channel */
-	struct timer_list release_timer;
-
 	struct timer_list T3101;
 
 	/* Established data link layer services */
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index 2d00603..1af39b5 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -832,6 +832,10 @@ int rsl_data_request(struct msgb *msg, u_int8_t link_id)
 		return -EINVAL;
 	}
 
+	if (msg->lchan->use_count <= 0) {
+		DEBUGP(DRSL, "BUG: Trying to send data on unused lchan\n");
+	}
+
 	/* First push the L3 IE tag and length */
 	msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
 
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index 7464aa9..10da135 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -33,8 +33,6 @@
 #include <openbsc/debug.h>
 #include <openbsc/signal.h>
 
-static void auto_release_channel(void *_lchan);
-
 struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
 				   enum gsm_phys_chan_config pchan)
 {
@@ -214,11 +212,6 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type)
 
 		/* clear sapis */
 		memset(lchan->sapis, 0, sizeof(lchan->sapis));
-
-		/* Configure the time and start it so it will be closed */
-		lchan->release_timer.cb = auto_release_channel;
-		lchan->release_timer.data = lchan;
-		bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
 	}
 
 	return lchan;
@@ -239,17 +232,15 @@ void lchan_free(struct gsm_lchan *lchan)
 		lchan->use_count = 0;
 	}
 
-	/* stop the timer */
-	bsc_del_timer(&lchan->release_timer);
-
 	/* FIXME: ts_free() the timeslot, if we're the last logical
 	 * channel using it */
 }
 
 /* Consider releasing the channel now */
-int lchan_auto_release(struct gsm_lchan *lchan)
+int _lchan_release(struct gsm_lchan *lchan)
 {
 	if (lchan->use_count > 0) {
+		DEBUGP(DRLL, "BUG: _lchan_release called without zero use_count.\n");
 		return 0;
 	}
 
@@ -260,23 +251,14 @@ int lchan_auto_release(struct gsm_lchan *lchan)
 
 	/* spoofed? message */
 	if (lchan->use_count < 0) {
-		DEBUGP(DRLL, "Channel count is negative: %d\n", lchan->use_count);
+		DEBUGP(DRLL, "BUG: channel count is negative: %d\n", lchan->use_count);
 	}
 
-	DEBUGP(DRLL, "Recycling the channel with: %d (%x)\n", lchan->nr, lchan->nr);
+	DEBUGP(DRLL, "Releasing the channel with: %d (%x)\n", lchan->nr, lchan->nr);
 	rsl_release_request(lchan, 0);
 	return 1;
 }
 
-/* Auto release the channel when the use count is zero */
-static void auto_release_channel(void *_lchan)
-{
-	struct gsm_lchan *lchan = _lchan;
-
-	if (!lchan_auto_release(lchan))
-		bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
-}
-
 struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
 	struct gsm_bts_trx *trx;
 	int ts_no, lchan_no; 
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index 7a8bcbd..a5ecb8a 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -296,13 +296,13 @@ static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
 		int rc;
 
 		db_subscriber_alloc_tmsi(lchan->subscr);
-		release_loc_updating_req(lchan);
 		rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi);
 		/* call subscr_update after putting the loc_upd_acc
 		 * in the transmit queue, since S_SUBSCR_ATTACHED might
 		 * trigger further action like SMS delivery */
 		subscr_update(lchan->subscr, msg->trx->bts,
 			      GSM_SUBSCRIBER_UPDATE_ATTACHED);
+		release_loc_updating_req(lchan);
 		return rc;
 	}
 
@@ -972,9 +972,8 @@ static void loc_upd_rej_cb(void *data)
 {
 	struct gsm_lchan *lchan = data;
 
-	release_loc_updating_req(lchan);
 	gsm0408_loc_upd_rej(lchan, reject_cause);
-	lchan_auto_release(lchan);
+	release_loc_updating_req(lchan);
 }
 
 static void schedule_reject(struct gsm_lchan *lchan)
diff --git a/openbsc/src/gsm_subscriber_base.c b/openbsc/src/gsm_subscriber_base.c
index 48374ea..7fb96fd 100644
--- a/openbsc/src/gsm_subscriber_base.c
+++ b/openbsc/src/gsm_subscriber_base.c
@@ -32,6 +32,7 @@
 #include <openbsc/paging.h>
 #include <openbsc/debug.h>
 #include <openbsc/paging.h>
+#include <openbsc/chan_alloc.h>
 
 LLIST_HEAD(active_subscribers);
 void *tall_subscr_ctx;
diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c
index 04eaa3c..03735d4 100644
--- a/openbsc/src/transaction.c
+++ b/openbsc/src/transaction.c
@@ -28,6 +28,7 @@
 #include <openbsc/gsm_04_08.h>
 #include <openbsc/mncc.h>
 #include <openbsc/paging.h>
+#include <openbsc/chan_alloc.h>
 
 void *tall_trans_ctx;
 
@@ -95,14 +96,14 @@ void trans_free(struct gsm_trans *trans)
 		break;
 	}
 
-	if (trans->lchan)
-		put_lchan(trans->lchan);
-
 	if (!trans->lchan && trans->subscr && trans->subscr->net) {
 		/* Stop paging on all bts' */
 		paging_request_stop(NULL, trans->subscr, NULL);
 	}
 
+	if (trans->lchan)
+		put_lchan(trans->lchan);
+
 	if (trans->subscr)
 		subscr_put(trans->subscr);
 
diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c
index 1b01878..ed0f3ad 100644
--- a/openbsc/tests/channel/channel_test.c
+++ b/openbsc/tests/channel/channel_test.c
@@ -76,4 +76,5 @@ int main(int argc, char** argv)
 void nm_state_event() {}
 void input_event() {}
 void sms_alloc() {}
+void _lchan_release() {}
 
-- 
1.6.3.3

