Introduce new ACT_REQ state to prevent race condition during channel allocation
When we allocate a channel, we send the RSL CHAN ACT REQ and wait until we get
a CHAN ACT ACK. Only the ACK will change the state, so there is a race where
we allocate that same channel to a different channel request before we get
the ACT ACK.
Introducing a new ACT_REQ state resolves this issue.
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 0b60542..37c9ff2 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -170,6 +170,7 @@
/* state of a logical channel */
enum gsm_lchan_state {
LCHAN_S_NONE, /* channel is not active */
+ LCHAN_S_ACT_REQ, /* channel activatin requested */
LCHAN_S_ACTIVE, /* channel is active and operational */
LCHAN_S_INACTIVE, /* channel is set inactive */
};
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index a1b20a4..26da704 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -939,12 +939,15 @@
return -EINVAL;
rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
- if (TLVP_PRESENT(&tp, RSL_IE_CAUSE))
- print_rsl_cause(LOGL_ERROR, TLVP_VAL(&tp, RSL_IE_CAUSE),
+ if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) {
+ const u_int8_t *cause = TLVP_VAL(&tp, RSL_IE_CAUSE);
+ print_rsl_cause(LOGL_ERROR, cause,
TLVP_LEN(&tp, RSL_IE_CAUSE));
-
- msg->lchan->state = LCHAN_S_NONE;
-
+ if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
+ msg->lchan->state = LCHAN_S_NONE;
+ } else
+ msg->lchan->state = LCHAN_S_NONE;
+
LOGPC(DRSL, LOGL_ERROR, "\n");
dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan);
@@ -1277,6 +1280,8 @@
return -ENOMEM;
}
+ lchan->state = LCHAN_S_ACT_REQ;
+
ts_number = lchan->ts->nr;
arfcn = lchan->ts->trx->arfcn;
subch = lchan->nr;
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index 4bdf722..abf4de8 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -175,7 +175,8 @@
/* check if all sub-slots are allocated yet */
for (ss = 0; ss < subslots_per_pchan[pchan]; ss++) {
struct gsm_lchan *lc = &ts->lchan[ss];
- if (lc->type == GSM_LCHAN_NONE)
+ if (lc->type == GSM_LCHAN_NONE &&
+ lc->state == LCHAN_S_NONE)
return lc;
}
}