From c6ea9dbebaf2329be078f62723f2455bc010065a Mon Sep 17 00:00:00 2001 From: Holger Freyther Date: Tue, 30 Dec 2008 19:18:21 +0000 Subject: [PATCH] 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. --- include/openbsc/gsm_data.h | 18 ++++++++++++++-- src/chan_alloc.c | 42 +++++++++++++++++++++++++++++++++++++- src/gsm_04_08.c | 16 ++++++++++++--- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h index d9974a767..986f33127 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 @@ struct gsm_lchan { 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 3ef8b4d24..d76c92913 100644 --- a/src/chan_alloc.c +++ b/src/chan_alloc.c @@ -1,6 +1,7 @@ /* GSM Channel allocation routines * * (C) 2008 by Harald Welte + * (C) 2008 by Holger Hans Peter Freyther * * All Rights Reserved * @@ -28,6 +29,9 @@ #include #include #include +#include + +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 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) 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 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) 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 1f4f4f015..7dccb14e4 100644 --- a/src/gsm_04_08.c +++ b/src/gsm_04_08.c @@ -323,6 +323,11 @@ static int mm_rx_id_resp(struct msgb *msg) 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 loc_upd_rej_cb(void *data) 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 @@ static int mm_rx_loc_upd_req(struct msgb *msg) 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;