aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2018-07-20 05:35:47 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2018-07-28 12:18:23 +0200
commitd5df9a1d0d996acf0d090793231cae3346f6fbd4 (patch)
tree654097bdc38dbbc46fb97e21dfdd1162dc8a89e8
parentac85b34476afc341af7e09e9eca368835cd9d68b (diff)
lchan_fsm: add in_release_handler flag
If a release event is being handled, ignore other ricocheting release events until that release handling has concluded. For example, if an lchan is regularly released, it signals the lchan RTP FSM to release, which then calls back to say "RTP is released" on termination -- this should not trigger other state changes than the initial release intends. Change-Id: Iec41e006b6ab9d0f618d36925341f9536353e5d8
-rw-r--r--include/osmocom/bsc/gsm_data.h4
-rw-r--r--src/osmo-bsc/lchan_fsm.c24
2 files changed, 21 insertions, 7 deletions
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 12bc5c354..448924c06 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -525,6 +525,10 @@ struct gsm_lchan {
/* RSL error code, RSL_ERR_* */
uint8_t rsl_error_cause;
+ /* If a release event is being handled, ignore other ricocheting release events until that
+ * release handling has concluded. */
+ bool in_release_handler;
+
/* The logical channel type */
enum gsm_chan_t type;
/* RSL channel mode */
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index 1ecec7c3a..940afe8de 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -521,7 +521,7 @@ static void lchan_fsm_wait_ts_ready(struct osmo_fsm_inst *fi, uint32_t event, vo
case LCHAN_EV_RTP_RELEASED:
case LCHAN_EV_RTP_ERROR:
- if (lchan->release_requested) {
+ if (lchan->in_release_handler) {
/* Already in release, the RTP is not the initial cause of failure.
* Just ignore. */
return;
@@ -581,6 +581,7 @@ static void lchan_fsm_wait_activ_ack(struct osmo_fsm_inst *fi, uint32_t event, v
break;
case LCHAN_EV_RSL_CHAN_ACTIV_NACK:
+ lchan->in_release_handler = true;
if (data) {
uint32_t next_state;
lchan->rsl_error_cause = *(uint8_t*)data;
@@ -599,11 +600,12 @@ static void lchan_fsm_wait_activ_ack(struct osmo_fsm_inst *fi, uint32_t event, v
lchan->release_in_error = true;
lchan_fail_to(LCHAN_ST_BORKEN, "Chan Activ NACK without cause IE");
}
+ lchan->in_release_handler = false;
break;
case LCHAN_EV_RTP_RELEASED:
case LCHAN_EV_RTP_ERROR:
- if (lchan->release_requested) {
+ if (lchan->in_release_handler) {
/* Already in release, the RTP is not the initial cause of failure.
* Just ignore. */
return;
@@ -715,7 +717,7 @@ static void lchan_fsm_wait_rll_rtp_establish(struct osmo_fsm_inst *fi, uint32_t
case LCHAN_EV_RTP_RELEASED:
case LCHAN_EV_RTP_ERROR:
- if (lchan->release_requested) {
+ if (lchan->in_release_handler) {
/* Already in release, the RTP is not the initial cause of failure.
* Just ignore. */
return;
@@ -826,7 +828,7 @@ static void lchan_fsm_established(struct osmo_fsm_inst *fi, uint32_t event, void
case LCHAN_EV_RTP_RELEASED:
case LCHAN_EV_RTP_ERROR:
- if (lchan->release_requested) {
+ if (lchan->in_release_handler) {
/* Already in release, the RTP is not the initial cause of failure.
* Just ignore. */
return;
@@ -1201,6 +1203,11 @@ void lchan_release(struct gsm_lchan *lchan, bool sacch_deact,
{
if (!lchan || !lchan->fi)
return;
+
+ if (lchan->in_release_handler)
+ return;
+ lchan->in_release_handler = true;
+
struct osmo_fsm_inst *fi = lchan->fi;
lchan->release_in_error = err;
lchan->rsl_error_cause = cause_rr;
@@ -1223,13 +1230,13 @@ void lchan_release(struct gsm_lchan *lchan, bool sacch_deact,
if (lchan->deact_sacch)
rsl_deact_sacch(lchan);
lchan_fsm_state_chg(LCHAN_ST_WAIT_RF_RELEASE_ACK);
- return;
+ goto exit_release_handler;
case LCHAN_ST_WAIT_TS_READY:
lchan_fsm_state_chg(LCHAN_ST_WAIT_RLL_RTP_RELEASED);
- return;
+ goto exit_release_handler;
case LCHAN_ST_WAIT_RF_RELEASE_ACK:
case LCHAN_ST_BORKEN:
- return;
+ goto exit_release_handler;
}
}
@@ -1237,6 +1244,9 @@ void lchan_release(struct gsm_lchan *lchan, bool sacch_deact,
* is: */
if (fi->state == LCHAN_ST_ESTABLISHED)
lchan_fsm_state_chg(LCHAN_ST_WAIT_RLL_RTP_RELEASED);
+
+exit_release_handler:
+ lchan->in_release_handler = false;
}
void lchan_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)