chan_alloc: Change Channel Release to release SAPIs, then the channel
Currently every SAPI release indication will trigger the channel. It was possible that we had SAPI=3 and SAPI=0 allocated and we tried to release the channel by sending a RF Channel Release, the BTS answered with a RF Channel Release ACK but also sent the SAPI Release Indication which triggered a channel release here. So it was possible that we would have released a newly allocated channel because of the SAPI release of the old connection. This code now works by releasing all SAPIs from highest to lowest, then sending a SACH Deactivate and finally releasing the channel. This approach is in use on the on-waves/bsc-master.
This commit is contained in:
parent
aeb45f5186
commit
4b85a32360
|
@ -75,6 +75,7 @@ int rsl_lchan_set_state(struct gsm_lchan *lchan, int);
|
||||||
/* to be provided by external code */
|
/* to be provided by external code */
|
||||||
int abis_rsl_sendmsg(struct msgb *msg);
|
int abis_rsl_sendmsg(struct msgb *msg);
|
||||||
int rsl_deact_sacch(struct gsm_lchan *lchan);
|
int rsl_deact_sacch(struct gsm_lchan *lchan);
|
||||||
|
int rsl_lchan_rll_release(struct gsm_lchan *lchan, u_int8_t link_id);
|
||||||
|
|
||||||
/* BCCH related code */
|
/* BCCH related code */
|
||||||
int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf);
|
int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf);
|
||||||
|
|
|
@ -278,6 +278,8 @@ struct gsm_lchan {
|
||||||
|
|
||||||
/* Established data link layer services */
|
/* Established data link layer services */
|
||||||
u_int8_t sapis[8];
|
u_int8_t sapis[8];
|
||||||
|
int sach_deact;
|
||||||
|
int release_reason;
|
||||||
|
|
||||||
/* GSM Random Access data */
|
/* GSM Random Access data */
|
||||||
struct gsm48_req_ref *rqd_ref;
|
struct gsm48_req_ref *rqd_ref;
|
||||||
|
|
|
@ -1356,11 +1356,21 @@ static int rsl_rx_rll_err_ind(struct msgb *msg)
|
||||||
|
|
||||||
static void rsl_handle_release(struct gsm_lchan *lchan)
|
static void rsl_handle_release(struct gsm_lchan *lchan)
|
||||||
{
|
{
|
||||||
|
int sapi;
|
||||||
struct gsm_bts *bts;
|
struct gsm_bts *bts;
|
||||||
|
|
||||||
|
/* maybe we have only brought down one RLL */
|
||||||
if (lchan->state != LCHAN_S_REL_REQ)
|
if (lchan->state != LCHAN_S_REL_REQ)
|
||||||
LOGP(DRSL, LOGL_ERROR, "RF release on %s but state %s\n",
|
return;
|
||||||
gsm_lchan_name(lchan),
|
|
||||||
gsm_lchans_name(lchan->state));
|
for (sapi = 0; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) {
|
||||||
|
if (lchan->sapis[sapi] == LCHAN_SAPI_UNUSED)
|
||||||
|
continue;
|
||||||
|
LOGP(DRSL, LOGL_NOTICE, "%s waiting for SAPI=%d to be released.\n",
|
||||||
|
gsm_lchan_name(lchan), sapi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* wait a bit to send the RF Channel Release */
|
/* wait a bit to send the RF Channel Release */
|
||||||
|
@ -1422,6 +1432,7 @@ static int abis_rsl_rx_rll(struct msgb *msg)
|
||||||
rll_indication(msg->lchan, rllh->link_id,
|
rll_indication(msg->lchan, rllh->link_id,
|
||||||
BSC_RLLR_IND_REL_IND);
|
BSC_RLLR_IND_REL_IND);
|
||||||
rsl_handle_release(msg->lchan);
|
rsl_handle_release(msg->lchan);
|
||||||
|
rsl_lchan_rll_release(msg->lchan, rllh->link_id);
|
||||||
break;
|
break;
|
||||||
case RSL_MT_REL_CONF:
|
case RSL_MT_REL_CONF:
|
||||||
/* BTS informs us of having received UA from MS,
|
/* BTS informs us of having received UA from MS,
|
||||||
|
@ -1429,6 +1440,7 @@ static int abis_rsl_rx_rll(struct msgb *msg)
|
||||||
DEBUGPC(DRLL, "RELEASE CONFIRMATION\n");
|
DEBUGPC(DRLL, "RELEASE CONFIRMATION\n");
|
||||||
msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED;
|
msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED;
|
||||||
rsl_handle_release(msg->lchan);
|
rsl_handle_release(msg->lchan);
|
||||||
|
rsl_lchan_rll_release(msg->lchan, rllh->link_id);
|
||||||
break;
|
break;
|
||||||
case RSL_MT_ERROR_IND:
|
case RSL_MT_ERROR_IND:
|
||||||
rc = rsl_rx_rll_err_ind(msg);
|
rc = rsl_rx_rll_err_ind(msg);
|
||||||
|
|
|
@ -328,6 +328,9 @@ void lchan_free(struct gsm_lchan *lchan)
|
||||||
lchan->conn = NULL;
|
lchan->conn = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lchan->sach_deact = 0;
|
||||||
|
lchan->release_reason = 0;
|
||||||
|
|
||||||
/* FIXME: ts_free() the timeslot, if we're the last logical
|
/* FIXME: ts_free() the timeslot, if we're the last logical
|
||||||
* channel using it */
|
* channel using it */
|
||||||
}
|
}
|
||||||
|
@ -352,18 +355,62 @@ void lchan_reset(struct gsm_lchan *lchan)
|
||||||
lchan->state = LCHAN_S_NONE;
|
lchan->state = LCHAN_S_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* release the next allocated SAPI or return 0 */
|
||||||
|
static int _lchan_release_next_sapi(struct gsm_lchan *lchan)
|
||||||
|
{
|
||||||
|
int sapi;
|
||||||
|
|
||||||
|
for (sapi = 1; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) {
|
||||||
|
u_int8_t link_id;
|
||||||
|
if (lchan->sapis[sapi] == LCHAN_SAPI_UNUSED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
link_id = sapi;
|
||||||
|
if (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H)
|
||||||
|
link_id |= 0x40;
|
||||||
|
rsl_release_request(lchan, link_id, lchan->release_reason);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drive the release process of the lchan */
|
||||||
|
static void _lchan_handle_release(struct gsm_lchan *lchan)
|
||||||
|
{
|
||||||
|
/* Ask for SAPI != 0 to be freed first and stop if we need to wait */
|
||||||
|
if (_lchan_release_next_sapi(lchan) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (lchan->sach_deact) {
|
||||||
|
gsm48_send_rr_release(lchan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rsl_release_request(lchan, 0, lchan->release_reason);
|
||||||
|
rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called from abis rsl */
|
||||||
|
int rsl_lchan_rll_release(struct gsm_lchan *lchan, u_int8_t link_id)
|
||||||
|
{
|
||||||
|
if (lchan->state != LCHAN_S_REL_REQ)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((link_id & 0x7) != 0)
|
||||||
|
_lchan_handle_release(lchan);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Consider releasing the channel now */
|
/* Consider releasing the channel now */
|
||||||
int lchan_release(struct gsm_lchan *lchan, int sach_deact, int reason)
|
int lchan_release(struct gsm_lchan *lchan, int sach_deact, int reason)
|
||||||
{
|
{
|
||||||
/* Assume we have GSM04.08 running and send a release */
|
DEBUGP(DRLL, "%s starting release sequence\n", gsm_lchan_name(lchan));
|
||||||
if (sach_deact) {
|
|
||||||
gsm48_send_rr_release(lchan);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
|
|
||||||
rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
|
rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
|
||||||
rsl_release_request(lchan, 0, 0);
|
|
||||||
|
lchan->release_reason = reason;
|
||||||
|
lchan->sach_deact = sach_deact;
|
||||||
|
_lchan_handle_release(lchan);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue