aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc/gsm_08_08.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bsc/gsm_08_08.c')
-rw-r--r--src/osmo-bsc/gsm_08_08.c104
1 files changed, 56 insertions, 48 deletions
diff --git a/src/osmo-bsc/gsm_08_08.c b/src/osmo-bsc/gsm_08_08.c
index ce7606f28..a2bab4bed 100644
--- a/src/osmo-bsc/gsm_08_08.c
+++ b/src/osmo-bsc/gsm_08_08.c
@@ -26,6 +26,7 @@
#include <osmocom/bsc/gsm_08_08.h>
#include <osmocom/bsc/codec_pref.h>
#include <osmocom/bsc/lchan_fsm.h>
+#include <osmocom/bsc/bsc_stats.h>
#include <osmocom/bsc/gsm_04_08_rr.h>
#include <osmocom/bsc/a_reset.h>
@@ -34,6 +35,7 @@
#include <osmocom/bsc/lcs_loc_req.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/mncc.h>
#include <osmocom/gsm/gsm48.h>
@@ -69,21 +71,23 @@ void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn,
{
int rc;
struct msgb *resp;
+ struct gsm_bts *bts;
if (!msc_connected(conn))
return;
- LOGP(DMSC, LOGL_NOTICE, "Tx MSC SAPI N REJECT (dlci=0x%02x, cause='%s')\n",
- dlci, gsm0808_cause_name(cause));
+ bts = conn_get_bts(conn);
+ LOG_BTS(bts, DMSC, LOGL_NOTICE, "Tx MSC SAPI N REJECT (dlci=0x%02x, cause='%s')\n",
+ dlci, gsm0808_cause_name(cause));
resp = gsm0808_create_sapi_reject_cause(dlci, cause);
- rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_SAPI_N_REJECT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_SAPI_N_REJECT));
rc = osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
if (rc != 0)
msgb_free(resp);
}
/*! MS->MSC: Tell MSC that ciphering has been enabled. */
-void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, struct msgb *msg, uint8_t chosen_encr)
+void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, struct msgb *msg, uint8_t chosen_a5_n)
{
int rc;
struct msgb *resp;
@@ -92,30 +96,13 @@ void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, struct msgb *
return;
LOGP(DMSC, LOGL_DEBUG, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n");
- resp = gsm0808_create_cipher_complete(msg, chosen_encr);
- rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_CIPHER_COMPLETE]);
+ resp = gsm0808_create_cipher_complete(msg, ALG_A5_NR_TO_BSSAP(chosen_a5_n));
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_CIPHER_COMPLETE));
rc = osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
if (rc != 0)
msgb_free(resp);
}
-/* 9.2.5 CM service accept */
-int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACK");
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
-
- msg->lchan = conn->lchan;
-
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_CM_SERV_ACC;
-
- DEBUGP(DMM, "-> CM SERVICE ACK\n");
-
- gscon_submit_rsl_dtap(conn, msg, 0, 0);
- return 0;
-}
-
static bool is_cm_service_for_emerg(struct msgb *msg)
{
struct gsm48_service_request *cm;
@@ -232,7 +219,7 @@ static struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
if (nri_matches_msc) {
LOG_NRI(LOGL_DEBUG, "matches msc %d, but this MSC is currently not connected\n",
msc->nr);
- rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_ATTACH_LOST]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_MSCPOOL_SUBSCR_ATTACH_LOST));
}
continue;
}
@@ -244,10 +231,10 @@ static struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
msc->nr);
} else {
LOG_NRI(LOGL_DEBUG, "matches msc %d\n", msc->nr);
- rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_KNOWN]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_MSCPOOL_SUBSCR_KNOWN));
if (is_emerg) {
- rate_ctr_inc(&msc->msc_ctrs->ctr[MSC_CTR_MSCPOOL_EMERG_FORWARDED]);
- rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_MSCPOOL_EMERG_FORWARDED]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(msc->msc_ctrs, MSC_CTR_MSCPOOL_EMERG_FORWARDED));
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_MSCPOOL_EMERG_FORWARDED));
}
return msc;
}
@@ -282,9 +269,9 @@ static struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
* them are usable -- wrap to the start. */
msc_target = msc_round_robin_next ? : msc_round_robin_first;
if (!msc_target) {
- rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_MSCPOOL_SUBSCR_NO_MSC]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_MSCPOOL_SUBSCR_NO_MSC));
if (is_emerg)
- rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_MSCPOOL_EMERG_LOST]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_MSCPOOL_EMERG_LOST));
return NULL;
}
@@ -292,13 +279,13 @@ static struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
osmo_mobile_identity_to_str_c(OTC_SELECT, mi), msc_target->nr);
if (is_null_nri)
- rate_ctr_inc(&msc_target->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_REATTACH]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(msc_target->msc_ctrs, MSC_CTR_MSCPOOL_SUBSCR_REATTACH));
else
- rate_ctr_inc(&msc_target->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_NEW]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(msc_target->msc_ctrs, MSC_CTR_MSCPOOL_SUBSCR_NEW));
if (is_emerg) {
- rate_ctr_inc(&msc_target->msc_ctrs->ctr[MSC_CTR_MSCPOOL_EMERG_FORWARDED]);
- rate_ctr_inc(&bsc_gsmnet->bsc_ctrs->ctr[BSC_CTR_MSCPOOL_EMERG_FORWARDED]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(msc_target->msc_ctrs, MSC_CTR_MSCPOOL_EMERG_FORWARDED));
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_MSCPOOL_EMERG_FORWARDED));
}
/* An MSC was picked by round-robin, so update the next round-robin nr to pick */
@@ -346,6 +333,7 @@ static void parse_powercap(struct gsm_subscriber_connection *conn, struct msgb *
/* No power cap in other messages */
return;
}
+ break;
/* FIXME: pwr_lev in Paging Response? */
default:
/* No power cap in other messages */
@@ -401,11 +389,10 @@ int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_chan
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));
- /* Likely this is an invalid Complete Layer 3 message that deserves to be rejected. However, the current
- * state of our ttcn3 tests does send invalid Layer 3 Info in some tests and expects osmo-bsc to not
- * care about that. So, changing the behavior to rejecting on missing MI causes test failure and, if at
- * all, should happen in a separate patch.
- * See e.g. BSC_Tests.TC_chan_rel_rll_rel_ind: "dt := * f_est_dchan('23'O, 23, '00010203040506'O);"
+ /* Likely this is an invalid Complete Layer 3 message that deserves to be rejected. However, the BSC is
+ * not expected to look at this layer so it's duty of the MSC to reject it.
+ * Hence, keep on going with the conn without an assigned bsc_subscr, forwarding the L3 to the MSC and
+ * letting it take decision on the matter.
*/
} else {
bsub = bsc_subscr_find_or_create_by_mi(bsc_gsmnet->bsc_subscribers, &mi, __func__);
@@ -413,8 +400,13 @@ int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_chan
/* If this Mobile Identity already has an active bsc_subscr, look whether there also is an active A-interface
* conn for this subscriber. This may be the case during a Perform Location Request (LCS) from the MSC that
- * started on an IDLE MS, and now the MS is becoming active. Associate with the existing conn. */
- if (bsub)
+ * started on an IDLE MS, and now the MS is becoming active. Associate with the existing conn.
+ *
+ * However, for a CM Re-Establishment Request, we must *not* re-use the existing conn, but allocate a second
+ * conn for the same bsub. The previous conn will be Clear'ed by the MSC as soon as it receives the L3 Complete
+ * message == the CM Re-Establishment Request.
+ */
+ if (bsub && !(pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_REEST_REQ))
conn = bsc_conn_by_bsub(bsub);
if (!conn) {
@@ -447,7 +439,10 @@ int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_chan
paged_from_msc = NULL;
paging_reasons = BSC_PAGING_NONE;
if (pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP) {
- paging_request_stop(&paged_from_msc, &paging_reasons, bts, conn->bsub);
+ /* It only makes sense to attempt to find a pending paging request if the subscriber from the
+ * Paging Response can be identified (bsub != NULL). */
+ if (conn->bsub)
+ paging_request_stop(&paged_from_msc, &paging_reasons, 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. */
@@ -455,12 +450,12 @@ int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_chan
"%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]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(bts->bts_ctrs, BTS_CTR_PAGING_NO_ACTIVE_PAGING));
+ rate_ctr_inc(rate_ctr_group_get_ctr(bsc_gsmnet->bsc_ctrs, BSC_CTR_PAGING_NO_ACTIVE_PAGING));
} else if (is_msc_usable(paged_from_msc, 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), paged_from_msc->nr);
- rate_ctr_inc(&paged_from_msc->msc_ctrs->ctr[MSC_CTR_MSCPOOL_SUBSCR_PAGED]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(paged_from_msc->msc_ctrs, 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",
@@ -539,11 +534,13 @@ int bsc_compl_l3(struct gsm_lchan *lchan, struct msgb *msg, uint16_t chosen_chan
early_exit:
if (release_lchan)
- lchan_release(lchan, false, true, RSL_ERR_EQUIPMENT_FAIL);
+ lchan_release(lchan, true, true, RSL_ERR_EQUIPMENT_FAIL,
+ gscon_last_eutran_plmn(conn));
log_set_context(LOG_CTX_BSC_SUBSCR, NULL);
return rc;
}
+
/*! MS->BSC/MSC: Um L3 message. */
void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg)
{
@@ -556,8 +553,9 @@ void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct ms
parse_powercap(conn, msg);
- /* Store link_id in msg->cb */
- OBSC_LINKID_CB(msg) = link_id;
+ /* convert RSL link ID to DLCI, store in msg->cb */
+ OBSC_LINKID_CB(msg) = RSL_LINK_ID2DLCI(link_id);
+
osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_MO_DTAP, msg);
done:
log_set_context(LOG_CTX_BSC_SUBSCR, NULL);
@@ -590,10 +588,20 @@ void bsc_cm_update(struct gsm_subscriber_connection *conn,
}
conn_update_ms_power_class(conn, rc8);
+ if (cm3 != NULL && cm3_len > 0) {
+ rc = gsm48_decode_classmark3(&conn->cm3, cm3, cm3_len);
+ if (rc < 0) {
+ LOGP(DMSC, LOGL_NOTICE, "Unable to decode classmark3 during CM Update.\n");
+ memset(&conn->cm3, 0, sizeof(conn->cm3));
+ conn->cm3_valid = false;
+ } else
+ conn->cm3_valid = true;
+ }
+
if (!msc_connected(conn))
return;
- rate_ctr_inc(&conn->sccp.msc->msc_ctrs->ctr[MSC_CTR_BSSMAP_TX_DT1_CLASSMARK_UPDATE]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(conn->sccp.msc->msc_ctrs, MSC_CTR_BSSMAP_TX_DT1_CLASSMARK_UPDATE));
resp = gsm0808_create_classmark_update(cm2, cm2_len, cm3, cm3_len);
rc = osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_TX_SCCP, resp);
if (rc != 0)