Change in osmo-bsc[master]: abis_rsl: prioritize emergency calls over regular calls

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

laforge gerrit-no-reply at lists.osmocom.org
Mon Sep 7 12:51:57 UTC 2020


laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/19793 )

Change subject: abis_rsl: prioritize emergency calls over regular calls
......................................................................

abis_rsl: prioritize emergency calls over regular calls

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. If
an emergency call is established while all channels are busy, an
arbitrary lchan is picked and freed. When freeing the lchan is done,
the queue is checked again and the emergency call is put on the free
lchan (TCH/H or TCH/F).

Change-Id: If8651265928797dbda9f528b544931dcfa4a0b36
Related: OS#4549
---
M include/osmocom/bsc/abis_rsl.h
M include/osmocom/bsc/bts.h
M include/osmocom/bsc/lchan_fsm.h
M include/osmocom/bsc/lchan_select.h
M src/osmo-bsc/abis_rsl.c
M src/osmo-bsc/bts.c
M src/osmo-bsc/lchan_fsm.c
M src/osmo-bsc/lchan_select.c
8 files changed, 284 insertions(+), 50 deletions(-)

Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved



diff --git a/include/osmocom/bsc/abis_rsl.h b/include/osmocom/bsc/abis_rsl.h
index 2611a3d..9879497 100644
--- a/include/osmocom/bsc/abis_rsl.h
+++ b/include/osmocom/bsc/abis_rsl.h
@@ -118,5 +118,7 @@
 
 int rsl_tx_rf_chan_release(struct gsm_lchan *lchan);
 
+void 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 a50c70e..7f36904 100644
--- a/include/osmocom/bsc/bts.h
+++ b/include/osmocom/bsc/bts.h
@@ -634,6 +634,7 @@
 	struct osmo_timer_list etws_timer;	/* when to stop ETWS PN */
 
 	struct llist_head oml_fail_rep;
+	struct llist_head chan_rqd_queue;
 };
 
 #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 df3ed22..9fe7db1 100644
--- a/include/osmocom/bsc/lchan_fsm.h
+++ b/include/osmocom/bsc/lchan_fsm.h
@@ -74,3 +74,5 @@
 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 865181b..41e7015 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);
+struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type);
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index 03d53c5..74cc760 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -1330,77 +1330,258 @@
 	return rsl_send_imm_ass_rej(bts, rqd_ref, wait_ind);
 }
 
+struct chan_rqd {
+	struct llist_head entry;
+	struct gsm_bts *bts;
+	struct gsm48_req_ref ref;
+	enum gsm_chreq_reason_t reason;
+	uint8_t ta;
+	/* set to true to mark that the release of the release_lchan is in progress */
+	struct gsm_lchan *release_lchan;
+	time_t timestamp;
+};
+
 /* 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);
 }
 
+/* Protect against RACH DoS attack: If an excessive amount of RACH requests queues up it is likely that the current BTS
+ * is under RACH DoS attack. To prevent excessive memory usage, remove all expired or at least one of the oldest channel
+ * requests from the queue to prevent the queue from growing indefinetly. */
+static void reduce_rach_dos(struct gsm_bts *bts)
+{
+	int rlt = gsm_bts_get_radio_link_timeout(bts);
+	time_t timestamp_current = time(NULL);
+	struct chan_rqd *rqd;
+	struct chan_rqd *rqd_tmp;
+	unsigned int rqd_count = 0;
+
+	/* Drop all expired channel requests in the list */
+	llist_for_each_entry_safe(rqd, rqd_tmp, &bts->chan_rqd_queue, entry) {
+		/* If the channel request is older than the radio link timeout we drop it. This also means that the
+		 * queue is under its overflow limit again. */
+		if (timestamp_current - rqd->timestamp > rlt)
+			llist_del(&rqd->entry);
+		else
+			rqd_count++;
+	}
+
+	/* If we find more than 255 (256) unexpired channel requests in the queue it is very likely that there is a
+	 * problem with RACH dos on this BTS. We drop the first entry in the list to clip the growth of the list. */
+	if (rqd_count > 255) {
+		LOG_BTS(bts, DRSL, LOGL_INFO, "CHAN RQD: more than 255 queued RACH requests -- RACH DoS attack?\n");
+		llist_del(&llist_first_entry(&bts->chan_rqd_queue, struct chan_rqd, entry)->entry);
+	}
+}
+
 /* 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;
+
+	reduce_rach_dos(bts);
+
+	rqd = talloc_zero(bts, struct chan_rqd);
+	OSMO_ASSERT(rqd);
+
+	rqd->bts = bts;
+	rqd->timestamp = time(NULL);
 
 	/* 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);
 
-	/* 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);
+	rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CHREQ_TOTAL]);
+
+	/* Enqueue request */
+	llist_add_tail(&rqd->entry, &bts->chan_rqd_queue);
+
+	/* Forward the request directly. Most request will be finished with one attempt so no queuing will be
+	 * necessary. */
+	abis_rsl_chan_rqd_queue_poll(bts);
+
+	return 0;
+}
+
+/* Find any busy TCH/H or TCH/F lchan */
+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.
+ * Return true if freeing of a busy lchan is in progress, but not done yet, return false when done (either successfully
+ * or unsuccessfully). */
+static bool force_free_lchan_for_emergency(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 false;
+
+	/* First check the situation on the BTS, if we have TCH/H or TCH/F resources available for another (EMERGENCY)
+	 * call. If yes, then no (further) action has to be carried out. */
+	if (lchan_avail_by_type(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 false;
+	}
+	if (lchan_avail_by_type(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 false;
+	}
+
+	/* No free TCH/F or TCH/H was found, we now select one of the busy lchans and initate a release on that lchan.
+	 * This will take a short amount of time. We need to come back and check regulary to see if we managed to
+	 * free up another lchan. */
+	if (!rqd->release_lchan) {
+		/* Pick any busy TCH/F or TCH/H lchan and inititate a channel
+		 * release to make room for the incoming emergency call */
+		rqd->release_lchan = get_any_lchan(rqd->bts);
+		if (!rqd->release_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 false;
+		}
+
+		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->release_lchan), osmo_fsm_inst_state_name(rqd->release_lchan->fi));
+
+		lchan_release(rqd->release_lchan, !!(rqd->release_lchan->conn), true, 0);
+	} else {
+		/* BTS is shutting down, give up... */
+		if (rqd->release_lchan->ts->fi->state == TS_ST_NOT_INITIALIZED)
+			return false;
+
+		OSMO_ASSERT(rqd->release_lchan->fi);
+
+		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->release_lchan), osmo_fsm_inst_state_name(rqd->release_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->release_lchan->fi->state == LCHAN_ST_WAIT_AFTER_ERROR)
+			lchan_fsm_skip_error(rqd->release_lchan);
+	}
+
+	/* We are still in the process of releasing a busy lchan in favvor of the incoming emergency call. */
+	return true;
+}
+
+void abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts)
+{
+	struct lchan_activate_info info;
+	enum gsm_chan_t lctype;
+	struct gsm_lchan *lchan = NULL;
+	struct chan_rqd *rqd;
+
+	rqd = llist_first_entry_or_null(&bts->chan_rqd_queue, struct chan_rqd, entry);
+	if (!rqd)
+		return;
+
+	/* Handle PDCH related rach requests (in case of BSC-co-located-PCU) */
+	if (rqd->reason == GSM_CHREQ_REASON_PDCH) {
+		rsl_rx_pchan_rqd(rqd);
+		return;
+	}
+
+	/* Ensure that emergency calls will get priority over regular calls, however releasing
+	 * lchan in favor of an emergency call may take some time, so we exit here. The lchan_fsm
+	 * will poll again when an lchan becomes available. */
+	if (force_free_lchan_for_emergency(rqd))
+		return;
 
 	/* 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
 	 *
@@ -1410,49 +1591,60 @@
 	 * - 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);
-			return -EINVAL;
+			rsl_tx_imm_ass_rej(bts, &rqd->ref);
+			llist_del(&rqd->entry);
+			talloc_free(rqd);
+			return;
 		}
 	}
-	lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH);
+
+	/* Emergency calls will be put on a free TCH/H or TCH/F directly in the code below, all other channel requests
+	 * will get an SDCCH first (if possible). */
+	if (rqd->reason != GSM_CHREQ_REASON_EMERG)
+		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);
-		return 0;
+		rsl_tx_imm_ass_rej(bts, &rqd->ref);
+		llist_del(&rqd->entry);
+		talloc_free(rqd);
+		return;
 	}
 
 	/* save the RACH data as we need it after the CHAN ACT ACK */
 	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);
-	return 0;
+	llist_del(&rqd->entry);
+	talloc_free(rqd);
+	return;
 }
 
 int rsl_tx_imm_assignment(struct gsm_lchan *lchan)
diff --git a/src/osmo-bsc/bts.c b/src/osmo-bsc/bts.c
index a17143d..ce1b200 100644
--- a/src/osmo-bsc/bts.c
+++ b/src/osmo-bsc/bts.c
@@ -263,6 +263,7 @@
 	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);
 
 	/* 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 115c3da..65d77c4 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -413,8 +413,24 @@
 static void lchan_fsm_unused_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
 {
 	struct gsm_lchan *lchan = lchan_fi_lchan(fi);
+	struct gsm_bts *bts = lchan->ts->trx->bts;
 	lchan_reset(lchan);
 	osmo_fsm_inst_dispatch(lchan->ts->fi, TS_EV_LCHAN_UNUSED, lchan);
+
+	/* Poll the channel request queue, so that waiting calls can make use of the lchan that just
+	 * has become unused now. */
+	abis_rsl_chan_rqd_queue_poll(bts);
+}
+
+static void lchan_fsm_wait_after_error_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+	struct gsm_lchan *lchan = lchan_fi_lchan(fi);
+	struct gsm_bts *bts = lchan->ts->trx->bts;
+
+	/* We also need to poll the channel request queue when the FSM enters the WAIT_AFTER_ERROR
+	 * state. In case of an emergency call the channel request queue will skip the waiting
+	 * period. */
+	abis_rsl_chan_rqd_queue_poll(bts);
 }
 
 /* Configure the multirate setting on this channel. */
@@ -1429,6 +1445,7 @@
 	},
 	[LCHAN_ST_WAIT_AFTER_ERROR] = {
 		.name = "WAIT_AFTER_ERROR",
+		.onenter = lchan_fsm_wait_after_error_onenter,
 		.in_event_mask = 0
 			| S(LCHAN_EV_RTP_RELEASED) /* ignore late lchan_rtp_fsm release events */
 			,
@@ -1496,6 +1513,13 @@
 	}
 }
 
+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 d2dba1b..6d3caac 100644
--- a/src/osmo-bsc/lchan_select.c
+++ b/src/osmo-bsc/lchan_select.c
@@ -162,15 +162,12 @@
 	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)
+struct gsm_lchan *lchan_avail_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));
+	LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_avail_by_type(%s)\n", gsm_lchant_name(type));
 
 	switch (type) {
 	case GSM_LCHAN_SDCCH:
@@ -231,6 +228,20 @@
 		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;
+
+	lchan = lchan_avail_by_type(bts, type);
+
+	LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_select_by_type(%s)\n", gsm_lchant_name(type));
+
 	if (lchan) {
 		lchan->type = type;
 		LOG_LCHAN(lchan, LOGL_INFO, "Selected\n");

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/19793
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: If8651265928797dbda9f528b544931dcfa4a0b36
Gerrit-Change-Number: 19793
Gerrit-PatchSet: 5
Gerrit-Owner: dexter <pmaier at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200907/7f6f5c93/attachment.htm>


More information about the gerrit-log mailing list