From 4b85a323600a623afc7728f9d3433e4745765a7c Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 29 Jul 2010 17:09:36 +0800 Subject: [PATCH] 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. --- openbsc/include/openbsc/abis_rsl.h | 1 + openbsc/include/openbsc/gsm_data.h | 2 + openbsc/src/abis_rsl.c | 18 +++++++-- openbsc/src/chan_alloc.c | 61 ++++++++++++++++++++++++++---- 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index 4a334108b..0b732d9fd 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -75,6 +75,7 @@ int rsl_lchan_set_state(struct gsm_lchan *lchan, int); /* to be provided by external code */ int abis_rsl_sendmsg(struct msgb *msg); 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 */ int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf); diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index e276e1eee..14d801459 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -278,6 +278,8 @@ struct gsm_lchan { /* Established data link layer services */ u_int8_t sapis[8]; + int sach_deact; + int release_reason; /* GSM Random Access data */ struct gsm48_req_ref *rqd_ref; diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 7b19d7f43..706842225 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1356,11 +1356,21 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) static void rsl_handle_release(struct gsm_lchan *lchan) { + int sapi; struct gsm_bts *bts; + + /* maybe we have only brought down one RLL */ if (lchan->state != LCHAN_S_REL_REQ) - LOGP(DRSL, LOGL_ERROR, "RF release on %s but state %s\n", - gsm_lchan_name(lchan), - gsm_lchans_name(lchan->state)); + return; + + 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 */ @@ -1422,6 +1432,7 @@ static int abis_rsl_rx_rll(struct msgb *msg) rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_REL_IND); rsl_handle_release(msg->lchan); + rsl_lchan_rll_release(msg->lchan, rllh->link_id); break; case RSL_MT_REL_CONF: /* 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"); msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED; rsl_handle_release(msg->lchan); + rsl_lchan_rll_release(msg->lchan, rllh->link_id); break; case RSL_MT_ERROR_IND: rc = rsl_rx_rll_err_ind(msg); diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index b061fc798..5325dc08a 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -328,6 +328,9 @@ void lchan_free(struct gsm_lchan *lchan) lchan->conn = NULL; } + lchan->sach_deact = 0; + lchan->release_reason = 0; + /* FIXME: ts_free() the timeslot, if we're the last logical * channel using it */ } @@ -352,18 +355,62 @@ void lchan_reset(struct gsm_lchan *lchan) 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 */ int lchan_release(struct gsm_lchan *lchan, int sach_deact, int reason) { - /* Assume we have GSM04.08 running and send a release */ - if (sach_deact) { - gsm48_send_rr_release(lchan); - } - - DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan)); + DEBUGP(DRLL, "%s starting release sequence\n", gsm_lchan_name(lchan)); 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; }