From 65a13b4d9812292e7ca3efe30df5f5afcc00ed55 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Sat, 12 Sep 2020 01:01:58 +0000 Subject: 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 --- src/osmo-bsc/gsm_08_08.c | 97 +++++++++++++++++------------------------------- src/osmo-bsc/paging.c | 74 ++++++++++++++---------------------- 2 files changed, 61 insertions(+), 110 deletions(-) (limited to 'src/osmo-bsc') 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) { -- cgit v1.2.3