diff options
Diffstat (limited to 'openbsc/src/chan_alloc.c')
-rw-r--r-- | openbsc/src/chan_alloc.c | 100 |
1 files changed, 76 insertions, 24 deletions
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 107abdc92..40d655409 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -33,8 +33,6 @@ #include <openbsc/debug.h> #include <openbsc/signal.h> -static void auto_release_channel(void *_lchan); - static int ts_is_usable(struct gsm_bts_trx_ts *ts) { /* FIXME: How does this behave for BS-11 ? */ @@ -225,7 +223,8 @@ _lc_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan) } /* Allocate a logical channel */ -struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) +struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type, + int allow_bigger) { struct gsm_lchan *lchan = NULL; enum gsm_phys_chan_config first, second; @@ -243,6 +242,19 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) lchan = _lc_find_bts(bts, first); if (lchan == NULL) lchan = _lc_find_bts(bts, second); + + /* allow to assign bigger channels */ + if (allow_bigger) { + if (lchan == NULL) { + lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H); + type = GSM_LCHAN_TCH_H; + } + + if (lchan == NULL) { + lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F); + type = GSM_LCHAN_TCH_F; + } + } break; case GSM_LCHAN_TCH_F: lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F); @@ -268,16 +280,13 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) /* clear multi rate config */ memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf)); + /* clear any msc reference */ + lchan->msc_data = NULL; + /* clear per MSC/BSC data */ memset(&lchan->conn, 0, sizeof(lchan->conn)); - - /* Configure the time and start it so it will be closed */ lchan->conn.lchan = lchan; lchan->conn.bts = lchan->ts->trx->bts; - lchan->conn.release_timer.cb = auto_release_channel; - lchan->conn.release_timer.data = lchan; - bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT); - } else { struct challoc_signal_data sig; sig.bts = bts; @@ -307,8 +316,6 @@ void lchan_free(struct gsm_lchan *lchan) lchan->conn.use_count = 0; } - /* stop the timer */ - bsc_del_timer(&lchan->conn.release_timer); bsc_del_timer(&lchan->T3101); /* clear cached measuement reports */ @@ -319,7 +326,6 @@ void lchan_free(struct gsm_lchan *lchan) } for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++) lchan->neigh_meas[i].arfcn = 0; - lchan->conn.silent_call = 0; sig.lchan = lchan; @@ -338,22 +344,43 @@ void lchan_free(struct gsm_lchan *lchan) void lchan_reset(struct gsm_lchan *lchan) { bsc_del_timer(&lchan->T3101); + bsc_del_timer(&lchan->T3111); + bsc_del_timer(&lchan->error_timer); lchan->type = GSM_LCHAN_NONE; lchan->state = LCHAN_S_NONE; } - -/* Consider releasing the channel now */ -int lchan_auto_release(struct gsm_lchan *lchan) +static int _lchan_release_next_sapi(struct gsm_lchan *lchan) { - if (lchan->conn.use_count > 0) { + 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; +} + +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; + /* Assume we have GSM04.08 running and send a release */ if (lchan->conn.subscr) { + ++lchan->conn.use_count; gsm48_send_rr_release(lchan); + --lchan->conn.use_count; } /* spoofed? message */ @@ -361,19 +388,44 @@ int lchan_auto_release(struct gsm_lchan *lchan) LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n", lchan->conn.use_count); - DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan)); + rsl_release_request(lchan, 0, lchan->release_reason); rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ); - rsl_release_request(lchan, 0); - return 1; } -/* Auto release the channel when the use count is zero */ -static void auto_release_channel(void *_lchan) +/* called from abis rsl */ +int rsl_lchan_rll_release(struct gsm_lchan *lchan, u_int8_t link_id) { - struct gsm_lchan *lchan = _lchan; + if (lchan->state != LCHAN_S_REL_REQ) + return -1; - if (!lchan_auto_release(lchan)) - bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT); + if ((link_id & 0x7) != 0) + _lchan_handle_release(lchan); + return 0; +} + + +/* + * Start the channel release procedure now. We will start by shutting + * down SAPI!=0, then we will deactivate the SACCH and finish by releasing + * the last SAPI at which point the RSL code will send the channel release + * for us. We should guard the whole shutdown by T3109 or similiar and then + * update the fixme inside gsm_04_08_utils.c + * When we request to release the RLL and we don't get an answer within T200 + * the BTS will send us an Error indication which we will handle by closing + * the channel and be done. + */ +int _lchan_release(struct gsm_lchan *lchan, u_int8_t release_reason) +{ + if (lchan->conn.use_count > 0) { + DEBUGP(DRLL, "BUG: _lchan_release called without zero use_count.\n"); + return 0; + } + + DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan)); + rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ); + lchan->release_reason = release_reason; + _lchan_handle_release(lchan); + return 1; } struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) { |