aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/abis_rsl.c
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-05-31 21:38:24 +0800
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-05-31 21:39:23 +0800
commit4b4dd100f8ca079134b780e0ca0879c1ab3e5ebb (patch)
tree08c3d37b638e6b1b1610681e4fb17263995bc21e /openbsc/src/abis_rsl.c
parentf30c0dca0d82ff738a0b4e228f055181416bd7c6 (diff)
[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.
Diffstat (limited to 'openbsc/src/abis_rsl.c')
-rw-r--r--openbsc/src/abis_rsl.c54
1 files changed, 45 insertions, 9 deletions
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index d170ff78..79c8eeb3 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -568,12 +568,33 @@ int rsl_deact_sacch(struct gsm_lchan *lchan)
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 @@ int rsl_rf_chan_release(struct gsm_lchan *lchan)
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 @@ static int rsl_rx_conn_fail(struct msgb *msg)
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 @@ static int abis_rsl_rx_dchan(struct msgb *msg)
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 @@ static void t3101_expired(void *data)
{
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 @@ static void t3111_expired(void *data)
{
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 @@ static int rsl_rx_rll_err_ind(struct msgb *msg)
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;