aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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; }