aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2020-08-21 22:40:23 +0200
committerDaniel Willmann <dwillmann@sysmocom.de>2020-08-31 09:36:55 +0200
commitbe027ad003625b01a731333d2acd78c01295cdcb (patch)
treed4c866c8aeab2bc10f01e8ba36b8dfe956c39f88
parent43a00c945ba47a32264dbfe292275bc7bdfe7490 (diff)
abis_rsl: prioritize emergency calls over regular callsdaniel/emerg
when an emergency call arrives while all TCH are busy, the BSC should pick an arbitrary (preferably the longest lasting) call / lchan and release it in favor of the incoming emergancy call. The release of the existing call is a process that can not be done synchronously while the ChanRQD is handled sonce multiple messages are exchanged between BTS and MSC and multiple FSMs need to do their work. To be able to release one lchan while handling a ChanRQD a queue is implemented in which the incomming channel requests are collected. The queue is checked regulary for incoming requests. If one of the requests is for an emergency call and if all channels are busy one channel is picked and released. It is also made sure that the incoming emergency call directly gets the TCH that was just released. Change-Id: If8651265928797dbda9f528b544931dcfa4a0b36 Related: OS#4549
-rw-r--r--include/osmocom/bsc/abis_rsl.h2
-rw-r--r--include/osmocom/bsc/bts.h2
-rw-r--r--include/osmocom/bsc/lchan_fsm.h2
-rw-r--r--include/osmocom/bsc/lchan_select.h1
-rw-r--r--src/ipaccess/ipaccess-config.c1
-rw-r--r--src/ipaccess/ipaccess-proxy.c1
-rw-r--r--src/osmo-bsc/abis_rsl.c241
-rw-r--r--src/osmo-bsc/bts.c14
-rw-r--r--src/osmo-bsc/lchan_fsm.c7
-rw-r--r--src/osmo-bsc/lchan_select.c36
-rw-r--r--src/utils/bs11_config.c1
-rw-r--r--src/utils/meas_json.c1
-rw-r--r--tests/abis/abis_test.c1
-rw-r--r--tests/acc/acc_test.c3
-rw-r--r--tests/bsc/bsc_test.c1
-rw-r--r--tests/gsm0408/gsm0408_test.c3
-rw-r--r--tests/nanobts_omlattr/nanobts_omlattr_test.c1
17 files changed, 271 insertions, 47 deletions
diff --git a/include/osmocom/bsc/abis_rsl.h b/include/osmocom/bsc/abis_rsl.h
index 2611a3d00..146c63683 100644
--- a/include/osmocom/bsc/abis_rsl.h
+++ b/include/osmocom/bsc/abis_rsl.h
@@ -118,5 +118,7 @@ int ipacc_payload_type(enum gsm48_chan_mode tch_mode, enum gsm_chan_t type);
int rsl_tx_rf_chan_release(struct gsm_lchan *lchan);
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts);
+
#endif /* RSL_MT_H */
diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h
index 16053a3bb..693fb804a 100644
--- a/include/osmocom/bsc/bts.h
+++ b/include/osmocom/bsc/bts.h
@@ -495,6 +495,8 @@ struct gsm_bts {
struct osmo_timer_list etws_timer; /* when to stop ETWS PN */
struct llist_head oml_fail_rep;
+ struct llist_head chan_rqd_queue;
+ struct osmo_timer_list chan_rqd_queue_timer;
};
#define GSM_BTS_SI2Q(bts, i) (struct gsm48_system_information_type_2quater *)((bts)->si_buf[SYSINFO_TYPE_2quater][i])
diff --git a/include/osmocom/bsc/lchan_fsm.h b/include/osmocom/bsc/lchan_fsm.h
index d935b5281..7a09db344 100644
--- a/include/osmocom/bsc/lchan_fsm.h
+++ b/include/osmocom/bsc/lchan_fsm.h
@@ -74,3 +74,5 @@ bool lchan_may_receive_data(struct gsm_lchan *lchan);
void lchan_forget_conn(struct gsm_lchan *lchan);
void lchan_set_last_error(struct gsm_lchan *lchan, const char *fmt, ...);
+
+void lchan_fsm_skip_error(struct gsm_lchan *lchan);
diff --git a/include/osmocom/bsc/lchan_select.h b/include/osmocom/bsc/lchan_select.h
index 865181bf5..7a828d98c 100644
--- a/include/osmocom/bsc/lchan_select.h
+++ b/include/osmocom/bsc/lchan_select.h
@@ -4,3 +4,4 @@
struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type);
struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,
enum gsm48_chan_mode chan_mode, enum channel_rate chan_rate);
+bool lchan_select_avail(struct gsm_bts *bts, enum gsm_chan_t type);
diff --git a/src/ipaccess/ipaccess-config.c b/src/ipaccess/ipaccess-config.c
index c9264d723..be5f6a8a3 100644
--- a/src/ipaccess/ipaccess-config.c
+++ b/src/ipaccess/ipaccess-config.c
@@ -1142,3 +1142,4 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type, const uint8_t *data
int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len)
{ return 0; }
int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type si_type) { return 0; }
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) { return 0; }
diff --git a/src/ipaccess/ipaccess-proxy.c b/src/ipaccess/ipaccess-proxy.c
index d5dd8d4d5..fec866a75 100644
--- a/src/ipaccess/ipaccess-proxy.c
+++ b/src/ipaccess/ipaccess-proxy.c
@@ -1260,3 +1260,4 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type, const uint8_t *data
int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len)
{ return 0; }
int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type si_type) { return 0; }
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) { return 0; }
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index 42f3a4226..64c4af50c 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -1322,77 +1322,219 @@ int rsl_tx_imm_ass_rej(struct gsm_bts *bts, struct gsm48_req_ref *rqd_ref)
return rsl_send_imm_ass_rej(bts, rqd_ref, wait_ind);
}
+struct chan_rqd {
+ struct llist_head list;
+ struct gsm_bts *bts;
+ struct gsm48_req_ref ref;
+ enum gsm_chreq_reason_t reason;
+ uint8_t ta;
+ bool relasing;
+ struct gsm_lchan *lchan;
+};
+
/* Handle packet channel rach requests */
-static int rsl_rx_pchan_rqd(struct msgb *msg, struct gsm_bts *bts)
+static int rsl_rx_pchan_rqd(struct chan_rqd *rqd)
{
- struct gsm48_req_ref *rqd_ref;
- struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg);
- rqd_ref = (struct gsm48_req_ref *) &rqd_hdr->data[1];
- uint8_t ra = rqd_ref->ra;
uint8_t t1, t2, t3;
uint32_t fn;
uint8_t rqd_ta;
uint8_t is_11bit;
/* Process rach request and forward contained information to PCU */
- if (ra == 0x7F) {
+ if (rqd->ref.ra == 0x7F) {
is_11bit = 1;
/* FIXME: Also handle 11 bit rach requests */
- LOGP(DRSL, LOGL_ERROR, "BTS %d eleven bit access burst not supported yet!\n",bts->nr);
+ LOGP(DRSL, LOGL_ERROR, "BTS %d eleven bit access burst not supported yet!\n",rqd->bts->nr);
return -EINVAL;
} else {
is_11bit = 0;
- t1 = rqd_ref->t1;
- t2 = rqd_ref->t2;
- t3 = rqd_ref->t3_low | (rqd_ref->t3_high << 3);
+ t1 = rqd->ref.t1;
+ t2 = rqd->ref.t2;
+ t3 = rqd->ref.t3_low | (rqd->ref.t3_high << 3);
fn = (51 * ((t3-t2) % 26) + t3 + 51 * 26 * t1);
-
- rqd_ta = rqd_hdr->data[sizeof(struct gsm48_req_ref)+2];
+ rqd_ta = rqd->ta;
}
- return pcu_tx_rach_ind(bts, rqd_ta, ra, fn, is_11bit,
+ return pcu_tx_rach_ind(rqd->bts, rqd_ta, rqd->ref.ra, fn, is_11bit,
GSM_L1_BURST_TYPE_ACCESS_0);
}
/* MS has requested a channel on the RACH */
static int rsl_rx_chan_rqd(struct msgb *msg)
{
- struct lchan_activate_info info;
struct e1inp_sign_link *sign_link = msg->dst;
struct gsm_bts *bts = sign_link->trx->bts;
struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg);
- struct gsm48_req_ref *rqd_ref;
- enum gsm_chan_t lctype;
- enum gsm_chreq_reason_t chreq_reason;
- struct gsm_lchan *lchan;
- uint8_t rqd_ta;
+ struct chan_rqd *rqd;
+
+ rqd = talloc_zero(bts, struct chan_rqd);
+ OSMO_ASSERT(rqd);
+
+ rqd->bts = bts;
/* parse request reference to be used in immediate assign */
- if (rqd_hdr->data[0] != RSL_IE_REQ_REFERENCE)
+ if (rqd_hdr->data[0] != RSL_IE_REQ_REFERENCE) {
+ talloc_free(rqd);
return -EINVAL;
-
- rqd_ref = (struct gsm48_req_ref *) &rqd_hdr->data[1];
+ }
+ memcpy(&rqd->ref, &rqd_hdr->data[1], sizeof(rqd->ref));
/* parse access delay and use as TA */
- if (rqd_hdr->data[sizeof(struct gsm48_req_ref)+1] != RSL_IE_ACCESS_DELAY)
+ if (rqd_hdr->data[sizeof(struct gsm48_req_ref)+1] != RSL_IE_ACCESS_DELAY) {
+ talloc_free(rqd);
return -EINVAL;
- rqd_ta = rqd_hdr->data[sizeof(struct gsm48_req_ref)+2];
+ }
+ rqd->ta = rqd_hdr->data[sizeof(struct gsm48_req_ref)+2];
/* Determine channel request cause code */
- chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci);
+ rqd->reason = get_reason_by_chreq(rqd->ref.ra, bts->network->neci);
LOG_BTS(bts, DRSL, LOGL_INFO, "CHAN RQD: reason: %s (ra=0x%02x, neci=0x%02x, chreq_reason=0x%02x)\n",
- get_value_string(gsm_chreq_descs, chreq_reason), rqd_ref->ra, bts->network->neci, chreq_reason);
+ get_value_string(gsm_chreq_descs, rqd->reason), rqd->ref.ra, bts->network->neci, rqd->reason);
+
+ rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_TOTAL]);
+
+ /* Enqueue request */
+ llist_add_tail(&rqd->list, &bts->chan_rqd_queue);
+ return 0;
+}
+
+/* Find any busy TCH/H or TCH/F lchan, prefer established and old lchans */
+static struct gsm_lchan *get_any_lchan(struct gsm_bts *bts)
+{
+ int trx_nr;
+ int ts_nr;
+ struct gsm_bts_trx *trx;
+ struct gsm_bts_trx_ts *ts;
+ struct gsm_lchan *lchan_est = NULL;
+ struct gsm_lchan *lchan_any = NULL;
+ struct gsm_lchan *lchan;
+
+ for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
+ trx = gsm_bts_trx_num(bts, trx_nr);
+ for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
+ ts = &trx->ts[ts_nr];
+ ts_for_each_lchan(lchan, ts) {
+ if (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H) {
+ if (bts->chan_alloc_reverse) {
+ if (lchan->fi->state == LCHAN_ST_ESTABLISHED)
+ lchan_est = lchan;
+ else
+ lchan_any = lchan;
+ } else {
+ if (lchan->fi->state == LCHAN_ST_ESTABLISHED) {
+ if (!lchan_est)
+ lchan_est = lchan;
+ } else {
+ if (!lchan_any)
+ lchan_any = lchan;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (lchan_est)
+ return lchan_est;
+ else if (lchan_any)
+ return lchan_any;
+ return NULL;
+}
+
+/* Ensure that an incoming emergency call gets priority, if all voice channels
+ * are busy, terminate one regular call */
+static int handle_emergency_call(struct chan_rqd *rqd)
+{
+ /* If the request is not about an emergency call, we may exit early,
+ * without doing anything. */
+ if(rqd->reason != GSM_CHREQ_REASON_EMERG)
+ return 0;
+
+ /* First check the situation on the BTS, if we still have TCH/H or
+ * TCH/F resources available, then not action is required. */
+ if (lchan_select_avail(rqd->bts, GSM_LCHAN_TCH_F)) {
+ LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE,
+ "CHAN RQD/EMERGENCY-PRIORITY: at least one TCH/F is (now) available!\n");
+ return 0;
+ }
+ if (lchan_select_avail(rqd->bts, GSM_LCHAN_TCH_H)) {
+ LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE,
+ "CHAN RQD/EMERGENCY-PRIORITY: at least one TCH/H is (now) available!\n");
+ return 0;
+ }
+
+ if (!rqd->relasing) {
+ /* Pick any busy TCH/F or TCH/H lchan and inititate a channel
+ * release to make room for the incoming emergency call */
+ rqd->lchan = get_any_lchan(rqd->bts);
+ if (!rqd->lchan) {
+ /* It can not happen that we first find out that there
+ * is no TCH/H or TCH/F available and at the same time
+ * we ware unable to find any busy TCH/H or TCH/F. In
+ * this case, the BTS probably does not have any
+ * voice channels configured? */
+ LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE,
+ "CHAN RQD/EMERGENCY-PRIORITY: no TCH/H or TCH/F available - check VTY config!\n");
+ return 0;
+ }
+
+ LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE,
+ "CHAN RQD/EMERGENCY-PRIORITY: inducing termination of lchan %s (state:%s) in favor of incoming EMERGENCY CALL!\n",
+ gsm_lchan_name(rqd->lchan), osmo_fsm_inst_state_name(rqd->lchan->fi));
+
+ lchan_release(rqd->lchan, !!(rqd->lchan->conn), true, 0);
+ rqd->relasing = true;
+ } else {
+ if (!rqd->lchan->fi) {
+ LOG_BTS(rqd->bts, DRSL, LOGL_ERROR,
+ "CHAN RQD/EMERGENCY-PRIORITY: lchan %s has lost its FSM - skipping!\n",
+ gsm_lchan_name(rqd->lchan));
+ return 0;
+ }
+
+ LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE,
+ "CHAN RQD/EMERGENCY-PRIORITY: still terminating lchan %s (state:%s) in favor of incoming EMERGENCY CALL!\n",
+ gsm_lchan_name(rqd->lchan), osmo_fsm_inst_state_name(rqd->lchan->fi));
+
+ /* If the channel was released in error (not established), the
+ * lchan FSM automatically blocks the LCHAN for a short time.
+ * This is not acceptable in an emergency situation, so we skip
+ * this waiting period. */
+ if (rqd->lchan->fi->state == LCHAN_ST_WAIT_AFTER_ERROR)
+ lchan_fsm_skip_error(rqd->lchan);
+ }
+
+ return -1;
+}
+
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts)
+{
+ struct lchan_activate_info info;
+ enum gsm_chan_t lctype;
+ struct gsm_lchan *lchan;
+ struct llist_head *lh_rqd;
+ struct chan_rqd *rqd;
+
+ if (llist_empty(&bts->chan_rqd_queue)) {
+ return 0;
+ }
+ lh_rqd = bts->chan_rqd_queue.next;
+ if(!lh_rqd)
+ return 0;
+ rqd = llist_entry(lh_rqd, struct chan_rqd, list);
/* Handle PDCH related rach requests (in case of BSC-co-located-PCU */
- if (chreq_reason == GSM_CHREQ_REASON_PDCH)
- return rsl_rx_pchan_rqd(msg, bts);
+ if (rqd->reason == GSM_CHREQ_REASON_PDCH)
+ return rsl_rx_pchan_rqd(rqd);
+
+ /* Ensure that emergency calls will get priority over regular calls */
+ if (handle_emergency_call(rqd) < 0)
+ return 0;
/* determine channel type (SDCCH/TCH_F/TCH_H) based on
* request reference RA */
- lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra);
-
- rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_TOTAL]);
+ lctype = get_ctype_by_chreq(bts->network, rqd->ref.ra);
/* check availability / allocate channel
*
@@ -1402,30 +1544,45 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
* - If there is still no channel available, try a TCH/F.
*
*/
- if (chreq_reason == GSM_CHREQ_REASON_EMERG) {
+ if (rqd->reason == GSM_CHREQ_REASON_EMERG) {
if (bts->si_common.rach_control.t2 & 0x4) {
LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD: MS attempts EMERGENCY CALL although EMERGENCY CALLS "
"are not allowed in sysinfo (spec violation by MS!)\n");
- rsl_tx_imm_ass_rej(bts, rqd_ref);
+ rsl_tx_imm_ass_rej(bts, &rqd->ref);
+ llist_del(lh_rqd);
+ talloc_free(rqd);
return -EINVAL;
}
}
- lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH);
+
+ lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_F);
+
+ /* If an emergency call is incoming, the preemption logic already
+ * has made sure that there is at least one TCH/F or TCH/H available,
+ * so we refrain from assigning an SDCCH first, assigning the TCH
+ * dirrectly is faster and safer in this case */
+ if (rqd->reason == GSM_CHREQ_REASON_EMERG)
+ lchan = NULL;
+ else
+ lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH);
+
if (!lchan) {
LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD: no resources for %s 0x%x, retrying with %s\n",
- gsm_lchant_name(GSM_LCHAN_SDCCH), rqd_ref->ra, gsm_lchant_name(GSM_LCHAN_TCH_H));
+ gsm_lchant_name(GSM_LCHAN_SDCCH), rqd->ref.ra, gsm_lchant_name(GSM_LCHAN_TCH_H));
lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_H);
}
if (!lchan) {
LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD: no resources for %s 0x%x, retrying with %s\n",
- gsm_lchant_name(GSM_LCHAN_SDCCH), rqd_ref->ra, gsm_lchant_name(GSM_LCHAN_TCH_F));
+ gsm_lchant_name(GSM_LCHAN_SDCCH), rqd->ref.ra, gsm_lchant_name(GSM_LCHAN_TCH_F));
lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_F);
}
if (!lchan) {
LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD: no resources for %s 0x%x\n",
- gsm_lchant_name(lctype), rqd_ref->ra);
+ gsm_lchant_name(lctype), rqd->ref.ra);
rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_NO_CHANNEL]);
- rsl_tx_imm_ass_rej(bts, rqd_ref);
+ rsl_tx_imm_ass_rej(bts, &rqd->ref);
+ llist_del(lh_rqd);
+ talloc_free(rqd);
return 0;
}
@@ -1433,17 +1590,19 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
lchan->rqd_ref = talloc_zero(bts, struct gsm48_req_ref);
OSMO_ASSERT(lchan->rqd_ref);
- *(lchan->rqd_ref) = *rqd_ref;
- lchan->rqd_ta = rqd_ta;
+ *(lchan->rqd_ref) = rqd->ref;
+ lchan->rqd_ta = rqd->ta;
LOG_LCHAN(lchan, LOGL_DEBUG, "MS: Channel Request: reason=%s ra=0x%02x ta=%d\n",
- gsm_chreq_name(chreq_reason), rqd_ref->ra, rqd_ta);
+ gsm_chreq_name(rqd->reason), rqd->ref.ra, rqd->ta);
info = (struct lchan_activate_info){
.activ_for = FOR_MS_CHANNEL_REQUEST,
.chan_mode = GSM48_CMODE_SIGN,
};
lchan_activate(lchan, &info);
+ llist_del(lh_rqd);
+ talloc_free(rqd);
return 0;
}
diff --git a/src/osmo-bsc/bts.c b/src/osmo-bsc/bts.c
index 4318b7ef9..ff8526777 100644
--- a/src/osmo-bsc/bts.c
+++ b/src/osmo-bsc/bts.c
@@ -23,6 +23,7 @@
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/bts.h>
#include <osmocom/bsc/debug.h>
+#include <osmocom/bsc/abis_rsl.h>
const struct value_string bts_attribute_names[] = {
OSMO_VALUE_STRING(BTS_TYPE_VARIANT),
@@ -31,6 +32,14 @@ const struct value_string bts_attribute_names[] = {
{ 0, NULL }
};
+/* timer call-back to poll CHAN RQD queue */
+static void chan_rqd_poll_cb(void *data)
+{
+ struct gsm_bts *bts = (struct gsm_bts *)data;
+ abis_rsl_chan_rqd_queue_poll(bts);
+ osmo_timer_schedule(&bts->chan_rqd_queue_timer, 0, 100000);
+}
+
enum bts_attribute str2btsattr(const char *s)
{
return get_string_value(bts_attribute_names, s);
@@ -319,6 +328,11 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, uint8_t bts_num)
INIT_LLIST_HEAD(&bts->loc_list);
INIT_LLIST_HEAD(&bts->local_neighbors);
INIT_LLIST_HEAD(&bts->oml_fail_rep);
+ INIT_LLIST_HEAD(&bts->chan_rqd_queue);
+
+ /* Start CHAN RQD queue */
+ osmo_timer_setup(&bts->chan_rqd_queue_timer, chan_rqd_poll_cb, bts);
+ osmo_timer_schedule(&bts->chan_rqd_queue_timer, 0, 0);
/* Enable all codecs by default. These get reset to a more fine grained selection IF a
* 'codec-support' config appears in the config file (see bsc_vty.c). */
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index f6b3f2b5f..2e1f9a7b0 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -1477,6 +1477,13 @@ static void lchan_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event,
}
}
+void lchan_fsm_skip_error(struct gsm_lchan *lchan)
+{
+ struct osmo_fsm_inst *fi = lchan->fi;
+ if (fi->state == LCHAN_ST_WAIT_AFTER_ERROR)
+ lchan_fsm_state_chg(LCHAN_ST_UNUSED);
+}
+
static int lchan_fsm_timer_cb(struct osmo_fsm_inst *fi)
{
struct gsm_lchan *lchan = lchan_fi_lchan(fi);
diff --git a/src/osmo-bsc/lchan_select.c b/src/osmo-bsc/lchan_select.c
index d2dba1bb2..6f73fbcda 100644
--- a/src/osmo-bsc/lchan_select.c
+++ b/src/osmo-bsc/lchan_select.c
@@ -162,16 +162,11 @@ struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,
return lchan_select_by_type(bts, type);
}
-/* Return a matching lchan from a specific BTS that is currently available. The next logical step is
- * lchan_activate() on it, which would possibly cause dynamic timeslot pchan switching, taken care of by
- * the lchan and timeslot FSMs. */
-struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type)
+static struct gsm_lchan *_get_lchan_by_type(struct gsm_bts *bts, enum gsm_chan_t type)
{
struct gsm_lchan *lchan = NULL;
enum gsm_phys_chan_config first, first_cbch, second, second_cbch;
- LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_select_by_type(%s)\n", gsm_lchant_name(type));
-
switch (type) {
case GSM_LCHAN_SDCCH:
if (bts->chan_alloc_reverse) {
@@ -231,6 +226,20 @@ struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type
LOG_BTS(bts, DRLL, LOGL_ERROR, "Unknown gsm_chan_t %u\n", type);
}
+ return lchan;
+}
+
+/* Return a matching lchan from a specific BTS that is currently available. The next logical step is
+ * lchan_activate() on it, which would possibly cause dynamic timeslot pchan switching, taken care of by
+ * the lchan and timeslot FSMs. */
+struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type)
+{
+ struct gsm_lchan *lchan = NULL;
+
+ LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_select_by_type(%s)\n", gsm_lchant_name(type));
+
+ lchan = _get_lchan_by_type(bts, type);
+
if (lchan) {
lchan->type = type;
LOG_LCHAN(lchan, LOGL_INFO, "Selected\n");
@@ -240,3 +249,18 @@ struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type
return lchan;
}
+
+/* Look through the available BTS resources and tell if a desired channel type would be available */
+bool lchan_select_avail(struct gsm_bts *bts, enum gsm_chan_t type)
+{
+ struct gsm_lchan *lchan = NULL;
+
+ LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_select_avail(%s)\n", gsm_lchant_name(type));
+
+ lchan = _get_lchan_by_type(bts, type);
+
+ if (lchan)
+ return true;
+
+ return false;
+}
diff --git a/src/utils/bs11_config.c b/src/utils/bs11_config.c
index c279179d5..db804d51a 100644
--- a/src/utils/bs11_config.c
+++ b/src/utils/bs11_config.c
@@ -995,3 +995,4 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type, const uint8_t *data
int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len)
{ return 0; }
int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type si_type) { return 0; }
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) { return 0; }
diff --git a/src/utils/meas_json.c b/src/utils/meas_json.c
index b44a3008c..6c9d43890 100644
--- a/src/utils/meas_json.c
+++ b/src/utils/meas_json.c
@@ -210,3 +210,4 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type, const uint8_t *data
int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len)
{ return 0; }
int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type si_type) { return 0; }
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) { return 0; }
diff --git a/tests/abis/abis_test.c b/tests/abis/abis_test.c
index 9d26eddcd..e87564e22 100644
--- a/tests/abis/abis_test.c
+++ b/tests/abis/abis_test.c
@@ -196,3 +196,4 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type, const uint8_t *data
int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len)
{ return 0; }
int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type si_type) { return 0; }
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) { return 0; }
diff --git a/tests/acc/acc_test.c b/tests/acc/acc_test.c
index 72d3212f1..e92972d1e 100644
--- a/tests/acc/acc_test.c
+++ b/tests/acc/acc_test.c
@@ -65,6 +65,8 @@ static inline void _bts_del(struct gsm_bts *bts, const char *msg)
osmo_timer_del(&bts->acc_mgr.rotate_timer);
if (osmo_timer_pending(&bts->acc_ramp.step_timer))
osmo_timer_del(&bts->acc_ramp.step_timer);
+ if (osmo_timer_pending(&bts->chan_rqd_queue_timer))
+ osmo_timer_del(&bts->chan_rqd_queue_timer);
/* no need to llist_del(&bts->list), we never registered the bts there. */
talloc_free(bts);
fprintf(stderr, "BTS deallocated OK in %s()\n", msg);
@@ -531,3 +533,4 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type, const uint8_t *data
int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len)
{ return 0; }
int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type si_type) { return 0; }
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) { return 0; }
diff --git a/tests/bsc/bsc_test.c b/tests/bsc/bsc_test.c
index dd2b1bbb5..e387c37ea 100644
--- a/tests/bsc/bsc_test.c
+++ b/tests/bsc/bsc_test.c
@@ -245,3 +245,4 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type, const uint8_t *data
int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len)
{ return 0; }
int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type si_type) { return 0; }
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) { return 0; }
diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c
index 35531f81a..18ee788e3 100644
--- a/tests/gsm0408/gsm0408_test.c
+++ b/tests/gsm0408/gsm0408_test.c
@@ -142,6 +142,8 @@ static inline void _bts_del(struct gsm_bts *bts, const char *msg)
rate_ctr_group_free(bts->bts_ctrs);
if (osmo_timer_pending(&bts->acc_mgr.rotate_timer))
osmo_timer_del(&bts->acc_mgr.rotate_timer);
+ if (osmo_timer_pending(&bts->chan_rqd_queue_timer))
+ osmo_timer_del(&bts->chan_rqd_queue_timer);
/* no need to llist_del(&bts->list), we never registered the bts there. */
talloc_free(bts);
printf("BTS deallocated OK in %s()\n", msg);
@@ -976,3 +978,4 @@ void pcu_info_update(struct gsm_bts *bts) {};
int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type, const uint8_t *data, int len) { return 0; }
int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len)
{ return 0; }
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) { return 0; }
diff --git a/tests/nanobts_omlattr/nanobts_omlattr_test.c b/tests/nanobts_omlattr/nanobts_omlattr_test.c
index ea9840942..975c2803b 100644
--- a/tests/nanobts_omlattr/nanobts_omlattr_test.c
+++ b/tests/nanobts_omlattr/nanobts_omlattr_test.c
@@ -325,3 +325,4 @@ int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type, const uint8_t *data
int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len)
{ return 0; }
int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type si_type) { return 0; }
+int abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) { return 0; }