aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2020-09-12 01:01:58 +0000
committerlaforge <laforge@osmocom.org>2020-10-07 10:19:58 +0000
commit65a13b4d9812292e7ca3efe30df5f5afcc00ed55 (patch)
treeb6650c3b5479801bcb6eca7104a2fc0f2695d0dd /src/osmo-bsc
parent90391fcfcd463a51e3d214cec1b85d55e6554765 (diff)
compl l3: move Paging Response handling out of bsc_find_msc()
Instead of iterating the llist of gsm_paging_requests first to find an MSC, and then again right away to mark the paging as served, do both in the same step. Change-Id: I447e61afc9934f3a5a82f6076e41c155d3328041
Diffstat (limited to 'src/osmo-bsc')
-rw-r--r--src/osmo-bsc/gsm_08_08.c97
-rw-r--r--src/osmo-bsc/paging.c74
2 files changed, 61 insertions, 110 deletions
diff --git a/src/osmo-bsc/gsm_08_08.c b/src/osmo-bsc/gsm_08_08.c
index 4c5391860..984e83044 100644
--- a/src/osmo-bsc/gsm_08_08.c
+++ b/src/osmo-bsc/gsm_08_08.c
@@ -196,11 +196,9 @@ static struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
struct bsc_msc_data *msc_round_robin_next = NULL;
struct bsc_msc_data *msc_round_robin_first = NULL;
uint8_t round_robin_next_nr;
- struct bsc_subscr *subscr;
bool is_emerg = false;
int16_t nri_v = -1;
bool is_null_nri = false;
- struct gsm_bts *bts;
if (msgb_l3len(msg) < sizeof(*gh)) {
LOGP(DRSL, LOGL_ERROR, "There is no GSM48 header here.\n");
@@ -213,27 +211,6 @@ static struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
is_emerg = (pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_SERV_REQ) && is_cm_service_for_emerg(msg);
- /* Has the subscriber been paged from a connected MSC? */
- bts = conn_get_bts(conn);
- if (bts && pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP) {
- subscr = bsc_subscr_find_by_mi(conn->network->bsc_subscribers, mi);
- if (subscr) {
- msc_target = paging_get_msc(bts, subscr);
- bsc_subscr_put(subscr);
- if (is_msc_usable(msc_target, is_emerg)) {
- LOG_COMPL_L3(pdisc, mtype, LOGL_DEBUG, "%s matches earlier Paging from msc %d\n",
- osmo_mobile_identity_to_str_c(OTC_SELECT, mi), msc_target->nr);
- rate_ctr_inc(&msc_target->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_PAGED]);
- return msc_target;
- } else {
- LOG_COMPL_L3(pdisc, mtype, LOGL_DEBUG,
- "%s matches earlier Paging from msc %d, but this MSC is not connected\n",
- osmo_mobile_identity_to_str_c(OTC_SELECT, mi), msc_target->nr);
- }
- msc_target = NULL;
- }
- }
-
#define LOG_NRI(LOGLEVEL, FORMAT, ARGS...) \
LOGP(DMSC, LOGLEVEL, "%s NRI(%d)=0x%x=%d: " FORMAT, osmo_mobile_identity_to_str_c(OTC_SELECT, mi), \
net->nri_bitlen, nri_v, nri_v, ##ARGS)
@@ -347,34 +324,6 @@ static struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
#undef LOG_NRI
}
-static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg,
- const struct osmo_mobile_identity *mi)
-{
- struct bsc_subscr *subscr = NULL;
- struct gsm_bts *bts = conn_get_bts(conn);
-
- if (!bts) {
- /* should never happen */
- LOGP(DRSL, LOGL_ERROR, "Paging Response without lchan\n");
- return -1;
- }
-
- if (mi->type == GSM_MI_TYPE_NONE)
- return -1;
-
- subscr = bsc_subscr_find_by_mi(conn->network->bsc_subscribers, mi);
- if (!subscr) {
- LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n");
- rate_ctr_inc(&conn->lchan->ts->trx->bts->bts_ctrs->ctr[BTS_CTR_PAGING_NO_ACTIVE_PAGING]);
- rate_ctr_inc(&conn->network->bsc_ctrs->ctr[BSC_CTR_PAGING_NO_ACTIVE_PAGING]);
- return -1;
- }
-
- paging_request_stop(&conn->network->bts_list, bts, subscr, conn, msg);
- bsc_subscr_put(subscr);
- return 0;
-}
-
static void parse_powercap(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
@@ -433,6 +382,7 @@ int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_chan
{
struct gsm_subscriber_connection *conn;
struct bsc_subscr *bsub = NULL;
+ struct bsc_msc_data *paged_from_msc;
struct bsc_msc_data *msc;
struct msgb *create_l3;
struct gsm0808_speech_codec_list scl;
@@ -454,6 +404,9 @@ int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_chan
pdisc = gsm48_hdr_pdisc(gh);
mtype = gsm48_hdr_msg_type(gh);
+ bts = lchan->ts->trx->bts;
+ OSMO_ASSERT(bts);
+
if (osmo_mobile_identity_decode_from_l3(&mi, msg, false)) {
LOG_COMPL_L3(pdisc, mtype, LOGL_ERROR, "Cannot extract Mobile Identity: %s\n",
msgb_hexdump_c(OTC_SELECT, msg));
@@ -482,8 +435,37 @@ int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_chan
log_set_context(LOG_CTX_BSC_SUBSCR, conn->bsub);
+ /* When receiving a Paging Response, stop Paging for this subscriber on all cells, and figure out which MSC
+ * sent the Paging Request, if any. */
+ paged_from_msc = NULL;
+ if (pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP) {
+ paged_from_msc = paging_request_stop(bts, conn->bsub);
+ if (!paged_from_msc) {
+ /* This looks like an unsolicited Paging Response. It is required to pick any MSC, because any
+ * MT-CSFB calls were Paged by the MSC via SGs, and hence are not listed in the BSC. */
+ LOG_COMPL_L3(pdisc, mtype, LOGL_DEBUG,
+ "%s Unsolicited Paging Response, possibly an MT-CSFB call.\n",
+ osmo_mobile_identity_to_str_c(OTC_SELECT, &mi));
+
+ rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_PAGING_NO_ACTIVE_PAGING]);
+ rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_PAGING_NO_ACTIVE_PAGING]);
+ } else if (is_msc_usable(paged_from_msc, false)) {
+ LOG_COMPL_L3(pdisc, mtype, LOGL_DEBUG, "%s matches earlier Paging from msc %d\n",
+ osmo_mobile_identity_to_str_c(OTC_SELECT, &mi), paged_from_msc->nr);
+ rate_ctr_inc(&paged_from_msc->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_PAGED]);
+ } else {
+ LOG_COMPL_L3(pdisc, mtype, LOGL_DEBUG,
+ "%s matches earlier Paging from msc %d, but this MSC is not connected\n",
+ osmo_mobile_identity_to_str_c(OTC_SELECT, &mi), paged_from_msc->nr);
+ paged_from_msc = NULL;
+ }
+ }
+
/* find the MSC link we want to use */
- msc = bsc_find_msc(conn, msg, &mi);
+ if (paged_from_msc)
+ msc = paged_from_msc;
+ else
+ msc = bsc_find_msc(conn, msg, &mi);
if (!msc) {
LOGP(DMSC, LOGL_ERROR, "Failed to find a MSC for a connection.\n");
rc = -1;
@@ -494,18 +476,7 @@ int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_chan
if (osmo_bsc_sigtran_new_conn(conn, msc) != BSC_CON_SUCCESS)
goto early_fail;
- bts = conn_get_bts(conn);
- if (!bts) {
- /* should never happen */
- LOG_COMPL_L3(pdisc, mtype, LOGL_ERROR, "%s: internal error: Compl L3 without BTS\n",
- osmo_mobile_identity_to_str_c(OTC_SELECT, &mi));
- rc = -1;
- goto early_fail;
- }
-
parse_powercap(conn, msg);
- if (pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP)
- handle_page_resp(conn, msg, &mi);
/* Send the Create Layer 3. */
use_scl = NULL;
diff --git a/src/osmo-bsc/paging.c b/src/osmo-bsc/paging.c
index 37ec61cef..0e5bf9fd0 100644
--- a/src/osmo-bsc/paging.c
+++ b/src/osmo-bsc/paging.c
@@ -387,13 +387,9 @@ int paging_request_bts(struct gsm_bts *bts, struct bsc_subscr *bsub, int type,
* to notify the paging originator that paging has completed.
* \param[in] bts BTS on which we shall stop paging
* \param[in] bsub subscriber which we shall stop paging
- * \param[in] conn connection to the subscriber (if any)
- * \param[in] msg message received from subscrbier (if any)
- * \returns 0 if an active paging request was stopped, an error code otherwise. */
-/* we consciously ignore the type of the request here */
-static int _paging_request_stop(struct gsm_bts *bts, struct bsc_subscr *bsub,
- struct gsm_subscriber_connection *conn,
- struct msgb *msg)
+ * \returns the MSC that paged the subscriber, if there was a pending request.
+ */
+static struct bsc_msc_data *paging_request_stop_bts(struct gsm_bts *bts, struct bsc_subscr *bsub)
{
struct gsm_bts_paging_state *bts_entry = &bts->paging;
struct gsm_paging_request *req, *req2;
@@ -403,51 +399,47 @@ static int _paging_request_stop(struct gsm_bts *bts, struct bsc_subscr *bsub,
llist_for_each_entry_safe(req, req2, &bts_entry->pending_requests,
entry) {
if (req->bsub == bsub) {
+ struct bsc_msc_data *from_msc = req->msc;
/* now give up the data structure */
paging_remove_request(&bts->paging, req);
LOG_BTS(bts, DPAG, LOGL_DEBUG, "Stop paging %s\n", bsc_subscr_name(bsub));
- return 0;
+ return from_msc;
}
}
- return -ENOENT;
+ return NULL;
}
/*! Stop paging on all other bts'
- * \param[in] bts_list list of BTSs to iterate
- * \param[in] _bts BTS which has received a paging response
+ * \param[in] bts BTS which has received a paging response
* \param[in] bsub subscriber
- * \param[in] msgb L3 message that we have received from \a bsub on \a _bts */
-void paging_request_stop(struct llist_head *bts_list,
- struct gsm_bts *_bts, struct bsc_subscr *bsub,
- struct gsm_subscriber_connection *conn,
- struct msgb *msg)
+ * \returns the MSC that paged the subscriber, if there was a pending request.
+ */
+struct bsc_msc_data *paging_request_stop(struct gsm_bts *bts, struct bsc_subscr *bsub)
{
- struct gsm_bts *bts;
-
- log_set_context(LOG_CTX_BSC_SUBSCR, bsub);
- conn->bsub = bsc_subscr_get(bsub);
- gscon_update_id(conn);
+ struct gsm_bts *bts_i;
+ struct bsc_msc_data *paged_from_msc;
+ OSMO_ASSERT(bts);
+
+ paged_from_msc = paging_request_stop_bts(bts, bsub);
+ if (paged_from_msc) {
+ rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_PAGING_RESPONDED]);
+ rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_RESPONDED]);
+ }
- /* Stop this first and dispatch the request */
- if (_bts) {
- if (_paging_request_stop(_bts, bsub, conn, msg) == 0) {
- rate_ctr_inc(&_bts->bts_ctrs->ctr[BTS_CTR_PAGING_RESPONDED]);
- rate_ctr_inc(&_bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_RESPONDED]);
+ llist_for_each_entry(bts_i, &bsc_gsmnet->bts_list, list) {
+ struct bsc_msc_data *paged_from_msc2 = paging_request_stop_bts(bts_i, bsub);
+ if (!paged_from_msc && paged_from_msc2) {
+ /* If this happened, it would be a bit weird: it means there was no Paging Request
+ * pending on the BTS that sent the Paging Reponse, but there *is* a Paging Request
+ * pending on a different BTS. But why not return an MSC when we found one. */
+ paged_from_msc = paged_from_msc2;
}
}
- /* Make sure to cancel this everywhere else */
- llist_for_each_entry(bts, bts_list, list) {
- /* Sort of an optimization. */
- if (bts == _bts)
- continue;
- _paging_request_stop(bts, bsub, NULL, NULL);
- }
- log_set_context(LOG_CTX_BSC_SUBSCR, NULL);
+ return paged_from_msc;
}
-
/*! Update the BTS paging buffer slots on given BTS */
void paging_update_buffer_space(struct gsm_bts *bts, uint16_t free_slots)
{
@@ -472,18 +464,6 @@ unsigned int paging_pending_requests_nr(struct gsm_bts *bts)
return requests;
}
-/*! Find any paging data for the given subscriber at the given BTS. */
-struct bsc_msc_data *paging_get_msc(struct gsm_bts *bts, struct bsc_subscr *bsub)
-{
- struct gsm_paging_request *req;
-
- llist_for_each_entry(req, &bts->paging.pending_requests, entry)
- if (req->bsub == bsub)
- return req->msc;
-
- return NULL;
-}
-
/*! Flush all paging requests at a given BTS for a given MSC (or NULL if all MSC should be flushed). */
void paging_flush_bts(struct gsm_bts *bts, struct bsc_msc_data *msc)
{