aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKeith Whyte <keith@rhizomatica.org>2021-05-16 02:59:52 +0200
committerlaforge <laforge@osmocom.org>2021-10-25 10:07:48 +0000
commita1a70be593a341f48fd7eeca96e6663109868370 (patch)
tree2be8a387f08d5c413d9a084a1e6ceb86ce1a149e /src
parent890ece12776f11da20bb6f7c36392fc60d1393cc (diff)
Add support for LCLS to the MSC
This commit is largely based on work by Max <msuraev@sysmocom.de> Adds LCLS parameters for A-interface transactions This commit also adds a vty option to facilitate globally disabling LCLS for all calls on this MSC. Add a global call reference (GCR) to MNCC and therefore bump the MNCC version to version 8. (This commit has to be merged at the same time as the corresponing commit in the osmo-sip-connector for mncc-external use.) Depends: osmo-sip-connector Id40d7e0fed9356f801b3627c118150055e7232b1 Change-Id: I705c860e51637b4537cad65a330ecbaaca96dd5b
Diffstat (limited to 'src')
-rw-r--r--src/libmsc/gsm_04_08_cc.c18
-rw-r--r--src/libmsc/msc_a.c8
-rw-r--r--src/libmsc/msc_vty.c22
-rw-r--r--src/libmsc/ran_msg_a.c3
-rw-r--r--src/libmsc/transaction.c60
-rw-r--r--src/osmo-msc/msc_main.c1
6 files changed, 111 insertions, 1 deletions
diff --git a/src/libmsc/gsm_04_08_cc.c b/src/libmsc/gsm_04_08_cc.c
index a8b4665e6..d6a2864e7 100644
--- a/src/libmsc/gsm_04_08_cc.c
+++ b/src/libmsc/gsm_04_08_cc.c
@@ -318,6 +318,16 @@ static void cc_paging_cb(struct msc_a *msc_a, struct gsm_trans *trans)
msc_a_get(msc_a, MSC_A_USE_CC);
trans->msc_a = msc_a;
trans->paging_request = NULL;
+
+ /* Get the GCR from the MO call leg (if any). */
+ if (!trans->cc.lcls) {
+ trans->cc.lcls = trans_lcls_compose(trans, true);
+ if (trans->cc.lcls) {
+ trans->cc.lcls->gcr = trans->cc.msg.gcr;
+ trans->cc.lcls->gcr_available = true;
+ }
+ }
+
osmo_fsm_inst_dispatch(msc_a->c.fi, MSC_A_EV_TRANSACTION_ACCEPTED, trans);
/* send SETUP request to called party */
gsm48_cc_tx_setup(trans, &trans->cc.msg);
@@ -502,6 +512,14 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
memset(&setup, 0, sizeof(struct gsm_mncc));
setup.callref = trans->callref;
+ /* New Global Call Reference */
+ if (!trans->cc.lcls)
+ trans->cc.lcls = trans_lcls_compose(trans, true);
+
+ /* Pass the LCLS GCR on to the MT call leg via MNCC */
+ if (trans->cc.lcls)
+ setup.gcr = trans->cc.lcls->gcr;
+
tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
/* emergency setup is identified by msg_type */
if (msg_type == GSM48_MT_CC_EMERG_SETUP) {
diff --git a/src/libmsc/msc_a.c b/src/libmsc/msc_a.c
index fa8e8428b..9b6b60223 100644
--- a/src/libmsc/msc_a.c
+++ b/src/libmsc/msc_a.c
@@ -569,6 +569,7 @@ static void msc_a_call_leg_ran_local_addr_available(struct msc_a *msc_a)
.osmux_cid = msc_a->cc.call_leg->rtp[RTP_TO_RAN]->local_osmux_cid,
.call_id_present = true,
.call_id = cc_trans->callref,
+ .lcls = cc_trans->cc.lcls,
},
};
if (msc_a_ran_down(msc_a, MSC_ROLE_I, &msg)) {
@@ -1506,6 +1507,13 @@ int msc_a_ran_dec_from_msc_i(struct msc_a *msc_a, struct msc_a_ran_dec_data *d)
rc = msc_a_up_ho(msc_a, d, MSC_HO_EV_RX_FAILURE);
break;
+ case RAN_MSG_LCLS_STATUS:
+ /* The BSS sends us LCLS_STATUS. We do nothing for now, but it is not an error. */
+ LOG_MSC_A(msc_a, LOGL_DEBUG, "LCLS_STATUS (%s) received from MSC-I\n",
+ gsm0808_lcls_status_name(msg->lcls_status.status));
+ rc = 0;
+ break;
+
default:
LOG_MSC_A(msc_a, LOGL_ERROR, "Message from MSC-I not implemented: %s\n", ran_msg_type_name(msg->msg_type));
rc = -ENOTSUP;
diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c
index 2a4dbbb82..e4e093741 100644
--- a/src/libmsc/msc_vty.c
+++ b/src/libmsc/msc_vty.c
@@ -499,6 +499,24 @@ DEFUN(cfg_msc_no_assign_tmsi, cfg_msc_no_assign_tmsi_cmd,
return CMD_SUCCESS;
}
+DEFUN_ATTR(cfg_msc_lcls_disable, cfg_msc_lcls_disable_cmd,
+ "lcls-permitted",
+ "Globally allow LCLS (Local Call Local Switch) for all calls on this MSC.\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ gsmnet->lcls_permitted = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(cfg_msc_no_lcls_disable, cfg_msc_no_lcls_disable_cmd,
+ "no lcls-permitted",
+ NO_STR "Globally disable LCLS (Local Call Local Switch) for all calls on this MSC.\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ gsmnet->lcls_permitted = false;
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_msc_cs7_instance_a,
cfg_msc_cs7_instance_a_cmd,
"cs7-instance-a <0-15>",
@@ -764,6 +782,8 @@ static int config_write_msc(struct vty *vty)
gsmnet->ncss_guard_timeout, VTY_NEWLINE);
vty_out(vty, " %sassign-tmsi%s",
gsmnet->vlr->cfg.assign_tmsi? "" : "no ", VTY_NEWLINE);
+ if (gsmnet->lcls_permitted)
+ vty_out(vty, " lcls-permitted%s", VTY_NEWLINE);
vty_out(vty, " cs7-instance-a %u%s", gsmnet->a.cs7_instance,
VTY_NEWLINE);
@@ -2083,6 +2103,8 @@ void msc_vty_init(struct gsm_network *msc_network)
install_node(&msc_node, config_write_msc);
install_element(MSC_NODE, &cfg_sms_database_cmd);
install_element(MSC_NODE, &cfg_msc_assign_tmsi_cmd);
+ install_element(MSC_NODE, &cfg_msc_lcls_disable_cmd);
+ install_element(MSC_NODE, &cfg_msc_no_lcls_disable_cmd);
install_element(MSC_NODE, &cfg_msc_mncc_internal_cmd);
install_element(MSC_NODE, &cfg_msc_mncc_external_cmd);
install_element(MSC_NODE, &cfg_msc_mncc_guard_timeout_cmd);
diff --git a/src/libmsc/ran_msg_a.c b/src/libmsc/ran_msg_a.c
index 273f8dddd..b50259d04 100644
--- a/src/libmsc/ran_msg_a.c
+++ b/src/libmsc/ran_msg_a.c
@@ -1004,7 +1004,8 @@ static struct msgb *ran_a_make_assignment_command(struct osmo_fsm_inst *log_fi,
if(ac->call_id_present == true)
call_id = &ac->call_id;
- msg = gsm0808_create_ass(ac->channel_type, NULL, use_rtp_addr, use_scl, call_id);
+ msg = gsm0808_create_ass2(ac->channel_type, NULL, use_rtp_addr, use_scl, call_id,
+ NULL, ac->lcls);
if (ac->osmux_present)
_gsm0808_assignment_extend_osmux(msg, ac->osmux_cid);
return msg;
diff --git a/src/libmsc/transaction.c b/src/libmsc/transaction.c
index 94712cc89..2108ab492 100644
--- a/src/libmsc/transaction.c
+++ b/src/libmsc/transaction.c
@@ -110,6 +110,66 @@ struct gsm_trans *trans_find_by_sm_rp_mr(const struct gsm_network *net,
return NULL;
}
+struct osmo_lcls *trans_lcls_compose(const struct gsm_trans *trans, bool use_lac)
+{
+ if (!trans->net->a.sri->sccp)
+ return NULL;
+
+ struct osmo_ss7_instance *ss7 = osmo_sccp_get_ss7(trans->net->a.sri->sccp);
+ struct osmo_lcls *lcls;
+ uint8_t w = osmo_ss7_pc_width(&ss7->cfg.pc_fmt);
+
+ if (!trans) {
+ LOGP(DCC, LOGL_ERROR, "LCLS: unable to fill parameters for unallocated transaction\n");
+ return NULL;
+ }
+
+ if (!trans->net->lcls_permitted) {
+ LOGP(DCC, LOGL_NOTICE, "LCLS disabled globally\n");
+ return NULL;
+ }
+
+ if (!trans->msc_a) {
+ LOGP(DCC, LOGL_ERROR, "LCLS: unable to fill parameters for transaction without connection\n");
+ return NULL;
+ }
+
+ if (trans->msc_a->c.ran->type != OSMO_RAT_GERAN_A) {
+ LOGP(DCC, LOGL_ERROR, "LCLS: only A interface is supported at the moment\n");
+ return NULL;
+ }
+
+ lcls = talloc_zero(trans, struct osmo_lcls);
+ if (!lcls) {
+ LOGP(DCC, LOGL_ERROR, "LCLS: failed to allocate osmo_lcls\n");
+ return NULL;
+ }
+
+ LOGP(DCC, LOGL_INFO, "LCLS: using %u bits (%u bytes) for node ID\n", w, w / 8);
+
+ lcls->gcr.net_len = 3;
+ lcls->gcr.node = ss7->cfg.primary_pc;
+
+ /* net id from Q.1902.3 3-5 bytes, this function gives 3 bytes exactly */
+ osmo_plmn_to_bcd(lcls->gcr.net, &trans->net->plmn);
+
+ osmo_store32be(trans->callref, lcls->gcr.cr);
+ osmo_store16be(use_lac ? trans->msc_a->via_cell.lai.lac : trans->msc_a->via_cell.cell_identity, lcls->gcr.cr + 3);
+
+ LOGP(DCC, LOGL_INFO, "LCLS: allocated %s-based CR-ID %s\n", use_lac ? "LAC" : "CI",
+ osmo_hexdump(lcls->gcr.cr, 5));
+
+ lcls->config = GSM0808_LCLS_CFG_BOTH_WAY;
+ lcls->control = GSM0808_LCLS_CSC_CONNECT;
+ lcls->corr_needed = true;
+ lcls->gcr_available = true;
+
+ LOGP(DCC, LOGL_DEBUG, "Filled %s\n", osmo_lcls_dump(lcls));
+ LOGP(DCC, LOGL_DEBUG, "Filled %s\n", osmo_gcr_dump(lcls));
+
+ return lcls;
+}
+
static const char *trans_vsub_use(enum trans_type type)
{
return get_value_string_or_null(trans_type_names, type) ? : "trans-type-unknown";
diff --git a/src/osmo-msc/msc_main.c b/src/osmo-msc/msc_main.c
index a0f584db8..cd91d54f7 100644
--- a/src/osmo-msc/msc_main.c
+++ b/src/osmo-msc/msc_main.c
@@ -258,6 +258,7 @@ struct gsm_network *msc_network_alloc(void *ctx,
mgcp_client_conf_init(&net->mgw.conf);
net->call_waiting = true;
+ net->lcls_permitted = false;
net->mgw.tdefs = g_mgw_tdefs;
osmo_tdefs_reset(net->mgw.tdefs);