From 9f1c0944821cbbe3fae3f9405077338111c6fd35 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 21 Aug 2020 12:39:11 +0200 Subject: bsc: Add Lb interface support This introduces the Lb interface stack, which allows BSC_Tests.ttcn to emulate a SMLC towards the BSC. In accordance with https://osmocom.org/projects/cellular-infrastructure/wiki/Point_Codes we use 0.23.6 as point code for emulating the SMLC. Change-Id: I854618cc08de1a716784f52542a4df3c7f7ad900 --- bsc/BSC_Tests.ttcn | 25 ++++++++ bsc/MSC_ConnectionHandler.ttcn | 28 ++++++++- bsc/gen_links.sh | 4 +- library/BSSAP_LE_Adapter.ttcn | 130 ++++++++++++++++++++++++++++++++++++++++ library/BSSAP_LE_Emulation.ttcn | 46 +++++--------- library/RAN_Emulation.ttcnpp | 4 +- 6 files changed, 203 insertions(+), 34 deletions(-) create mode 100644 library/BSSAP_LE_Adapter.ttcn diff --git a/bsc/BSC_Tests.ttcn b/bsc/BSC_Tests.ttcn index 0e764762..e8e06f74 100644 --- a/bsc/BSC_Tests.ttcn +++ b/bsc/BSC_Tests.ttcn @@ -28,6 +28,8 @@ import from IPL4asp_Types all; import from BSSAP_Types all; import from RAN_Adapter all; +import from BSSAP_LE_Adapter all; +import from BSSAP_LE_CodecPort all; import from BSSAP_CodecPort all; import from BSSMAP_Templates all; import from IPA_Emulation all; @@ -480,8 +482,10 @@ type component test_CT extends CTRL_Adapter_CT { var StatsD_Checker_CT vc_STATSD; var RAN_Adapter g_bssap[NUM_MSC]; + var BSSAP_LE_Adapter g_bssap_le; /* for old legacy-tests only */ port BSSAP_CODEC_PT BSSAP; + port BSSAP_LE_CODEC_PT BSSAP_LE; /* are we initialized yet */ var boolean g_initialized := false; @@ -553,6 +557,17 @@ modulepar { } }; + BSSAP_LE_Configuration mp_bssap_le_cfg := { + sccp_service_type := "mtp3_itu", + sctp_addr := { 23908, "127.0.0.1", 2905, "127.0.0.1" }, + own_pc := 6, /* 0.0.6 SMLC emulation */ + own_ssn := 252, /* SMLC side SSN */ + peer_pc := 187, /* 0.23.3 osmo-bsc */ + peer_ssn := 250, /* BSC side SSN */ + sio := '83'O, + rctx := 6 + }; + /* Whether to enable osmux tests. Can be dropped completely and enable unconditionally once new version of osmo-bsc is released (current version: 1.4.1) */ @@ -928,6 +943,14 @@ function f_init(integer nr_bts := NUM_BTS, boolean handler_mode := false, boolea } } + if (handler_mode) { + f_bssap_le_adapter_init(g_bssap_le, mp_bssap_le_cfg, "VirtSMLC", SMLC_BssapLeOps); + } else { + f_bssap_le_adapter_init(g_bssap_le, mp_bssap_le_cfg, "VirtSMLC", omit); + connect(self:BSSAP_LE, g_bssap_le.vc_SCCP:SCCP_SP_PORT); + } + f_bssap_le_adapter_start(g_bssap_le); + /* start the test with exactly all enabled MSCs allowed to attach */ f_vty_msc_allow_attach(BSCVTY, allow_attach); @@ -2767,6 +2790,7 @@ testcase TC_oml_unknown_unit_id() runs on test_CT { ***********************************************************************/ import from RAN_Emulation all; +import from BSSAP_LE_Emulation all; import from RSL_Emulation all; import from MSC_ConnectionHandler all; @@ -2787,6 +2811,7 @@ private function f_connect_handler(inout MSC_ConnHdlr vc_conn, integer bssap_idx connect(vc_conn:RSL2_PROC, bts[2].rsl.vc_RSL:RSL_PROC); } connect(vc_conn:BSSAP, g_bssap[bssap_idx].vc_RAN:CLIENT); + connect(vc_conn:BSSAP_LE, g_bssap_le.vc_BSSAP_LE:CLIENT); connect(vc_conn:MGCP, vc_MGCP:MGCP_CLIENT); connect(vc_conn:MGCP_MULTI, vc_MGCP:MGCP_CLIENT_MULTI); connect(vc_conn:STATSD_PROC, vc_STATSD:STATSD_PROC); diff --git a/bsc/MSC_ConnectionHandler.ttcn b/bsc/MSC_ConnectionHandler.ttcn index bf96eff8..f02cfb47 100644 --- a/bsc/MSC_ConnectionHandler.ttcn +++ b/bsc/MSC_ConnectionHandler.ttcn @@ -19,6 +19,9 @@ import from IPA_Emulation all; import from SCCPasp_Types all; import from BSSAP_Types all; import from RAN_Emulation all; +import from BSSAP_LE_Emulation all; +import from BSSAP_LE_Types all; +import from BSSMAP_LE_Templates all; import from BSSMAP_Templates all; import from IPL4asp_Types all; @@ -411,7 +414,7 @@ altstep as_Media() runs on MSC_ConnHdlr { /* this component represents a single subscriber connection at the MSC. * There is a 1:1 mapping between SCCP connections and RAN_ConnHdlr components. * We inherit all component variables, ports, functions, ... from RAN_ConnHdlr */ -type component MSC_ConnHdlr extends RAN_ConnHdlr, RSL_DchanHdlr, MGCP_ConnHdlr, StatsD_ConnHdlr { +type component MSC_ConnHdlr extends RAN_ConnHdlr, RSL_DchanHdlr, MGCP_ConnHdlr, BSSAP_LE_ConnHdlr, StatsD_ConnHdlr { /* SCCP Connecction Identifier for the underlying SCCP connection */ var integer g_sccp_conn_id; @@ -470,6 +473,20 @@ runs on RAN_Emulation_CT return template PDU_BSSAP { return resp; } +/* Callback function from general BSSAP_LE_Emulation whenever a connectionless + * BSSAP_LE message arrives. Can return a PDU_BSSAP_LE that should be sent in return */ +private function BSSAP_LE_UnitdataCallback(PDU_BSSAP_LE bssap) +runs on BSSAP_LE_Emulation_CT return template PDU_BSSAP_LE { + var template PDU_BSSAP_LE resp := omit; + + /* answer all RESET with a RESET ACK */ + if (match(bssap, tr_BSSMAP_LE_Reset)) { + resp := ts_BSSMAP_LE_ResetAck; + } + + return resp; +} + const RanOps MSC_RanOps := { create_cb := refers(RAN_Emulation.ExpectedCreateCallback), unitdata_cb := refers(UnitdataCallback), @@ -482,6 +499,15 @@ const RanOps MSC_RanOps := { sccp_addr_peer := omit } +const BssapLeOps SMLC_BssapLeOps := { + create_cb := refers(BSSAP_LE_Emulation.ExpectedCreateCallback), + unitdata_cb := refers(BSSAP_LE_UnitdataCallback), + decode_dtap := false, + role_ms := false, + sccp_addr_local := omit, + sccp_addr_peer := omit +} + const MGCPOps MSC_MGCPOps := { create_cb := refers(MGCP_Emulation.ExpectedCreateCallback), unitdata_cb := refers(MGCP_Emulation.DummyUnitdataCallback) diff --git a/bsc/gen_links.sh b/bsc/gen_links.sh index 02e093d1..f316509c 100755 --- a/bsc/gen_links.sh +++ b/bsc/gen_links.sh @@ -70,7 +70,9 @@ DIR=../library FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcnpp L3_Templates.ttcn BSSMAP_Templates.ttcn RAN_Emulation.ttcnpp RLCMAC_CSN1_Templates.ttcn RLCMAC_CSN1_Types.ttcn GSM_RR_Types.ttcn RSL_Types.ttcn RSL_Emulation.ttcn MGCP_Emulation.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc BSSAP_CodecPort.ttcn RAN_Adapter.ttcnpp Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunct.ttcn RTP_CodecPort_CtrlFunctDef.cc RTP_Emulation.ttcn IuUP_Types.ttcn IuUP_EncDec.cc IuUP_Emulation.ttcn SCCP_Templates.ttcn IPA_Testing.ttcn GSM_SystemInformation.ttcn GSM_RestOctets.ttcn " FILES+="CBSP_Types.ttcn CBSP_Templates.ttcn " FILES+="CBSP_CodecPort.ttcn CBSP_CodecPort_CtrlFunct.ttcn CBSP_CodecPort_CtrlFunctdef.cc CBSP_Adapter.ttcn " -FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn" +FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn " +FILES+="BSSAP_LE_CodecPort.ttcn BSSAP_LE_Emulation.ttcn BSSAP_LE_Types.ttcn BSSAP_LE_Adapter.ttcn BSSLAP_Types.ttcn BSSMAP_LE_Templates.ttcn " + gen_links $DIR $FILES ignore_pp_results diff --git a/library/BSSAP_LE_Adapter.ttcn b/library/BSSAP_LE_Adapter.ttcn new file mode 100644 index 00000000..dba8841b --- /dev/null +++ b/library/BSSAP_LE_Adapter.ttcn @@ -0,0 +1,130 @@ +module BSSAP_LE_Adapter { + +/* This module implements a 'dumb' BSSAP_LE adapter. It creates the M3UA and SCCP components and stacks a + * BSSAP_LE codec port on top. As a result, it provides the ability to transceive SCCP-User-SAP primitives + * with deoded BSSAP_LE payload. Use this if you want to have full control about what you transmit or + * receive, without any automatisms in place. Allows you to refuse connections or other abnormal behavior. */ + +/* (C) 2017-2020 Harald Welte + * contributions by sysmocom - s.f.m.c. GmbH + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +import from General_Types all; +import from Osmocom_Types all; + +import from M3UA_Emulation all; +import from MTP3asp_Types all; +import from MTP3asp_PortType all; + +import from IPA_Emulation all; + +import from SCCP_Types all; +import from SCCPasp_Types all; +import from SCCP_Emulation all; +import from SCCP_Templates all; + +import from SCTPasp_Types all; +import from SCTPasp_PortType all; + +import from BSSMAP_LE_Templates all; +import from BSSAP_LE_Emulation all; + +type record BSSAP_LE_Adapter { + /* component references */ + M3UA_CT vc_M3UA, /* only in 3GPP AoIP */ + SCCP_CT vc_SCCP, + + MSC_SCCP_MTP3_parameters sccp_pars, + SCCP_PAR_Address sccp_addr_own, + SCCP_PAR_Address sccp_addr_peer, + + /* handler mode */ + BSSAP_LE_Emulation_CT vc_BSSAP_LE +} + +type record BSSAP_LE_Configuration { + charstring sccp_service_type, + SCTP_Association_Address sctp_addr, + integer own_pc, + integer own_ssn, + integer peer_pc, + integer peer_ssn, + octetstring sio, + integer rctx +}; +type record of BSSAP_LE_Configuration BSSAP_LE_Configurations; + +private function init_pars(inout BSSAP_LE_Adapter ba, in BSSAP_LE_Configuration cfg) { + ba.sccp_pars := { + sio := { + ni := substr(oct2bit(cfg.sio),0,2), + prio := substr(oct2bit(cfg.sio),2,2), + si := substr(oct2bit(cfg.sio),4,4) + }, + opc := cfg.own_pc, + dpc := cfg.peer_pc, + sls := 0, + sccp_serviceType := cfg.sccp_service_type, + ssn := cfg.own_ssn + }; + ba.sccp_addr_own := valueof(ts_SccpAddr_PC_SSN(cfg.own_pc, cfg.own_ssn, cfg.sio, cfg.sccp_service_type)); + ba.sccp_addr_peer := valueof(ts_SccpAddr_PC_SSN(cfg.peer_pc, cfg.peer_ssn, cfg.sio, cfg.sccp_service_type)); +} + + +function f_bssap_le_adapter_init(inout BSSAP_LE_Adapter ba, in BSSAP_LE_Configuration cfg, charstring id, + template BssapLeOps ops) { + init_pars(ba, cfg); + ops.sccp_addr_local := ba.sccp_addr_own; + ops.sccp_addr_peer := ba.sccp_addr_peer; + + /* create components */ + ba.vc_SCCP := SCCP_CT.create(id & "-SCCP"); + if (isvalue(ops)) { + ba.vc_BSSAP_LE := BSSAP_LE_Emulation_CT.create(id & "-BSSAP_LE"); + } else { + ba.vc_BSSAP_LE := null; + } + ba.vc_M3UA := M3UA_CT.create(id & "-M3UA"); + map(ba.vc_M3UA:SCTP_PORT, system:sctp); + /* connect MTP3 service provider (M3UA) to lower side of SCCP */ + connect(ba.vc_M3UA:MTP3_SP_PORT, ba.vc_SCCP:MTP3_SCCP_PORT); + ba.vc_M3UA.start(f_M3UA_Emulation(cfg.sctp_addr, cfg.rctx)); + + if (isvalue(ops)) { + timer T := 5.0; + T.start; + //T.timeout; + /* connect BSSNAP component to upper side of SCCP */ + log("Connecting BSSAP_LE_Emulation to SCCP_SP_PORT"); + connect(ba.vc_BSSAP_LE:BSSAP_LE, ba.vc_SCCP:SCCP_SP_PORT); + log("Starting BSSAP_LE_Emulation"); + ba.vc_BSSAP_LE.start(BSSAP_LE_Emulation.main(valueof(ops), "")); + } + + +} + +function f_bssap_le_adapter_start(inout BSSAP_LE_Adapter ba) { + ba.vc_SCCP.start(SCCPStart(ba.sccp_pars)); +} + +function f_bssap_le_adapter_cleanup(inout BSSAP_LE_Adapter ba) { + if (ba.vc_BSSAP_LE != null) { + disconnect(ba.vc_BSSAP_LE:BSSAP_LE, ba.vc_SCCP:SCCP_SP_PORT); + ba.vc_BSSAP_LE.stop; + } + unmap(ba.vc_M3UA:SCTP_PORT, system:sctp); + disconnect(ba.vc_M3UA:MTP3_SP_PORT, ba.vc_SCCP:MTP3_SCCP_PORT); + ba.vc_M3UA.stop; + ba.vc_SCCP.stop; +} + + +} diff --git a/library/BSSAP_LE_Emulation.ttcn b/library/BSSAP_LE_Emulation.ttcn index 519d10f3..8276e56d 100644 --- a/library/BSSAP_LE_Emulation.ttcn +++ b/library/BSSAP_LE_Emulation.ttcn @@ -289,7 +289,6 @@ runs on BSSAP_LE_Emulation_CT return template PDU_BSSAP_LE; /* handle common Unitdata such as Paging */ private function CommonBssmapUnitdataCallback(PDU_BSSAP_LE bssap) runs on BSSAP_LE_Emulation_CT return template PDU_BSSAP_LE { -/* if (match(bssap, tr_BSSMAP_LE_Paging)) { var BSSAP_LE_ConnHdlr client := null; client := f_imsi_table_find(bssap.pdu.bssmap.paging.iMSI.digits, @@ -304,15 +303,14 @@ runs on BSSAP_LE_Emulation_CT return template PDU_BSSAP_LE { } else { log("CommonBssmapUnitdataCallback: Not a paging message"); } -*/ /* ELSE: handle in user callback */ return g_ran_ops.unitdata_cb.apply(bssap); } -function f_bssap_reset(SCCP_PAR_Address peer, SCCP_PAR_Address own) runs on BSSAP_LE_Emulation_CT { +private function f_bssap_le_reset(SCCP_PAR_Address peer, SCCP_PAR_Address own) runs on BSSAP_LE_Emulation_CT { timer T := 5.0; - BSSAP_LE.send(ts_BSSAP_LE_UNITDATA_req(peer, own, ts_BSSMAP_LE_Reset(0))); + BSSAP_LE.send(ts_BSSAP_LE_UNITDATA_req(peer, own, ts_BSSMAP_LE_Reset(GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE))); T.start; alt { [] BSSAP_LE.receive(tr_BSSAP_LE_UNITDATA_ind(own, peer, tr_BSSMAP_LE_ResetAck)) { @@ -371,7 +369,7 @@ private altstep as_main_bssap_le() runs on BSSAP_LE_Emulation_CT { /* SCCP -> Client: UNIT-DATA (connectionless SCCP) from a BSC */ [] BSSAP_LE.receive(BSSAP_LE_N_UNITDATA_ind:?) -> value ud_ind { /* Connectionless Procedures like RESET */ - var template PDU_BSSAP resp; + var template PDU_BSSAP_LE resp; resp := CommonBssmapUnitdataCallback(ud_ind.userData); if (isvalue(resp)) { BSSAP_LE.send(ts_BSSAP_LE_UNITDATA_req(ud_ind.callingAddress, @@ -417,7 +415,7 @@ private altstep as_main_bssap_le() runs on BSSAP_LE_Emulation_CT { f_handle_userData(vc_conn, conn_cfm.userData); } } - [] CLIENT.receive(PDU_BSSAP:?) -> value bssap sender vc_conn { + [] CLIENT.receive(PDU_BSSAP_LE:?) -> value bssap sender vc_conn { var integer conn_id := f_conn_id_by_comp(vc_conn); /* send it to dispatcher */ BSSAP_LE.send(ts_BSSAP_LE_DATA_req(conn_id, bssap)); @@ -435,7 +433,7 @@ private altstep as_main_bssap_le() runs on BSSAP_LE_Emulation_CT { } /* BSSAP from client -> SCCP */ - [] CLIENT.receive(BSSAP_Conn_Req:?) -> value creq sender vc_conn { + [] CLIENT.receive(BSSAP_LE_Conn_Req:?) -> value creq sender vc_conn { var integer conn_id; /* send to dispatcher */ @@ -486,6 +484,16 @@ private function f_xmit_raw_l3(integer sccp_conn_id, OCT1 dlci, octetstring l3_e BSSAP_LE.send(ts_BSSAP_LE_DATA_req(sccp_conn_id, bssap)); } +/* patch N(SD) into enc_l3, according to 24.007 11.2.3.2 */ +private function f_ML3_patch_seq(inout ConnectionData cd, in PDU_ML3_MS_NW dtap, inout octetstring enc_l3) { + var integer n_sd_idx := f_ML3_n_sd_idx(dtap); + if (n_sd_idx < 0) { + return; + } + var uint2_t seq_nr := f_next_n_sd(cd.n_sd, n_sd_idx); + f_ML3_patch_seq_nr(seq_nr, enc_l3); +} + function main(BssapLeOps ops, charstring id) runs on BSSAP_LE_Emulation_CT { g_ran_id := id; @@ -529,9 +537,6 @@ function main(BssapLeOps ops, charstring id) runs on BSSAP_LE_Emulation_CT { f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, dtap_mt.dlci, l3_enc); } - [] as_main_mgcp(); - [] as_main_ctrl(); - [] PROC.getcall(BSSAP_LE_register:{?,?}) -> param(l3_info, vc_hdlr) { f_create_expect(l3_info, vc_hdlr); PROC.reply(BSSAP_LE_register:{l3_info, vc_hdlr}) to vc_hdlr; @@ -587,35 +592,17 @@ function ExpectedCreateCallback(BSSAP_LE_N_CONNECT_ind conn_ind, charstring id) runs on BSSAP_LE_Emulation_CT return BSSAP_LE_ConnHdlr { var BSSAP_LE_ConnHdlr ret := null; var octetstring l3_info; - var boolean handoverRequest := false; - var integer handoverRequestPointCode; var integer i; if (ischosen(conn_ind.userData.pdu.bssmap.completeLayer3Information)) { l3_info := conn_ind.userData.pdu.bssmap.completeLayer3Information.layer3Information.layer3info; log("ExpectedCreateCallback completeLayer3Information"); - } else if (ischosen(conn_ind.userData.pdu.bssmap.handoverRequest)) { - handoverRequest := true; - handoverRequestPointCode := bit2int(conn_ind.calledAddress.signPointCode); - log("ExpectedCreateCallback handoverRequest ", handoverRequestPointCode); } else { - setverdict(fail, "N-CONNECT.ind with L3 != COMPLETE L3 nor a Handover Request"); + setverdict(fail, "N-CONNECT.ind with L3 != COMPLETE L3"); mtc.stop; - return ret; } for (i := 0; i < sizeof(ExpectTable); i:= i+1) { - if (handoverRequest) { - log("ExpectTable[", i, "].handoverRequestPointCode = ", ExpectTable[i].handoverRequestPointCode, - " ==? ", handoverRequestPointCode); - if (ExpectTable[i].handoverRequestPointCode == handoverRequestPointCode) { - ret := ExpectTable[i].vc_conn; - log("Found Expect[", i, "] for handoverRequest handled at ", ret); - return ret; - } else { - continue; - } - } if (not ispresent(ExpectTable[i].l3_payload)) { continue; } @@ -631,7 +618,6 @@ runs on BSSAP_LE_Emulation_CT return BSSAP_LE_ConnHdlr { } setverdict(fail, "Couldn't find Expect for incoming connection ", conn_ind); mtc.stop; - return ret; } diff --git a/library/RAN_Emulation.ttcnpp b/library/RAN_Emulation.ttcnpp index c1dc0363..f410427b 100644 --- a/library/RAN_Emulation.ttcnpp +++ b/library/RAN_Emulation.ttcnpp @@ -720,7 +720,7 @@ type record RanOps { template BIT4 t_ML3_DISC_CC_MM_SS := ('0011'B, '0101'B, '1011'B); -private function f_L3_is_rr(template octetstring l3) return boolean { +function f_L3_is_rr(template octetstring l3) return boolean { if (not isvalue(l3)) { return false; } @@ -773,7 +773,7 @@ function f_ML3_n_sd_idx(in PDU_ML3_MS_NW dtap) return integer { } /* patch N(SD) into enc_l3, according to 24.007 11.2.3.2 */ -function f_ML3_patch_seq(inout ConnectionData cd, in PDU_ML3_MS_NW dtap, inout octetstring enc_l3) { +private function f_ML3_patch_seq(inout ConnectionData cd, in PDU_ML3_MS_NW dtap, inout octetstring enc_l3) { var integer n_sd_idx := f_ML3_n_sd_idx(dtap); if (n_sd_idx < 0) { return; -- cgit v1.2.3