Recylce a gsm_lchan when the refcount drops to zero
When a channel is allocated, start a timeout, when a lchan_use
is used the timer will be restarted, when the timeout fires
we will try to recycle or restart the timer.
diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h
index d9974a7..986f331 100644
--- a/include/openbsc/gsm_data.h
+++ b/include/openbsc/gsm_data.h
@@ -13,6 +13,18 @@
#define HARDCODED_ARFCN 123
+/*
+ * Use the channel. As side effect the lchannel recycle timer
+ * will be started.
+ */
+#define LCHAN_RELEASE_TIMEOUT 4, 0
+#define use_lchan(lchan) \
+ do { lchan->use_count++; \
+ schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); } while(0);
+
+#define put_lchan(lchan) \
+ do { lchan->use_count--; } while(0);
+
/* communications link with a BTS */
struct gsm_bts_link {
struct gsm_bts *bts;
@@ -79,8 +91,10 @@
enum gsm_chan_t type;
/* To whom we are allocated at the moment */
struct gsm_subscriber *subscr;
- /* Universal timer, undefined use ;) */
- struct timer_list timer;
+
+ /* Timer started to release the channel */
+ struct timer_list release_timer;
+ struct timer_list updating_timer;
/* local end of a call, if any */
struct gsm_call call;
diff --git a/src/chan_alloc.c b/src/chan_alloc.c
index 3ef8b4d..d76c929 100644
--- a/src/chan_alloc.c
+++ b/src/chan_alloc.c
@@ -1,6 +1,7 @@
/* GSM Channel allocation routines
*
* (C) 2008 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
*
* All Rights Reserved
*
@@ -28,6 +29,9 @@
#include <openbsc/gsm_data.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/abis_nm.h>
+#include <openbsc/debug.h>
+
+static void auto_release_channel(struct gsm_lchan* lchan);
struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
enum gsm_phys_chan_config pchan)
@@ -164,8 +168,15 @@
fprintf(stderr, "Unknown gsm_chan_t %u\n", type);
}
- if (lchan)
+ if (lchan) {
lchan->type = type;
+ lchan->use_count = 0;
+
+ /* Configure the time and start it so it will be closed */
+ lchan->release_timer.cb = auto_release_channel;
+ lchan->release_timer.data = lchan;
+ schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
+ }
return lchan;
}
@@ -174,6 +185,35 @@
void lchan_free(struct gsm_lchan *lchan)
{
lchan->type = GSM_LCHAN_NONE;
+
+ /* stop the timer */
+ del_timer(&lchan->release_timer);
+
/* FIXME: ts_free() the timeslot, if we're the last logical
* channel using it */
}
+
+/*
+ * Auto release the channel when the use count is zero
+ */
+static void auto_release_channel(struct gsm_lchan* lchan)
+{
+ /*
+ * Busy...
+ */
+ if (lchan->use_count > 0) {
+ schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
+ return;
+ }
+
+ /*
+ * spoofed? message
+ */
+ if (lchan->use_count < 0) {
+ DEBUGP(DRLL, "Channel count is negative: %d\n", lchan->use_count);
+ }
+
+ DEBUGP(DRLL, "Recylcing the channel with: %d (%x)\n", lchan->nr, lchan->nr);
+ rsl_chan_release(lchan);
+}
+
diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c
index 1f4f4f0..7dccb14 100644
--- a/src/gsm_04_08.c
+++ b/src/gsm_04_08.c
@@ -323,6 +323,11 @@
DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
mi_type, mi_string);
+ /*
+ * Rogue messages could trick us but so is life
+ */
+ put_lchan(lchan);
+
switch (mi_type) {
case GSM_MI_TYPE_IMSI:
if (!lchan->subscr)
@@ -362,10 +367,10 @@
static void schedule_reject(struct gsm_lchan *lchan)
{
- lchan->timer.cb = loc_upd_rej_cb;
- lchan->timer.data = lchan;
+ lchan->updating_timer.cb = loc_upd_rej_cb;
+ lchan->updating_timer.data = lchan;
lchan->pending_update_request = 0;
- schedule_timer(&lchan->timer, 1, 0);
+ schedule_timer(&lchan->updating_timer, 1, 0);
}
#define MI_SIZE 32
@@ -392,17 +397,22 @@
switch (mi_type) {
case GSM_MI_TYPE_IMSI:
/* we always want the IMEI, too */
+ use_lchan(lchan);
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEISV);
+
/* look up subscriber based on IMSI */
subscr = db_create_subscriber(mi_string);
break;
case GSM_MI_TYPE_TMSI:
/* we always want the IMEI, too */
+ use_lchan(lchan);
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEISV);
+
/* look up the subscriber based on TMSI, request IMSI if it fails */
subscr = subscr_get_by_tmsi(lu->mi);
if (!subscr) {
/* send IDENTITY REQUEST message to get IMSI */
+ use_lchan(lchan);
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
}
break;