summaryrefslogtreecommitdiffstats
path: root/bsc-nat
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-11-25 02:32:50 +0100
committerHarald Welte <laforge@gnumonks.org>2017-11-25 02:32:50 +0100
commit79feba5ed43f98b3be2a2e0b8f77ad69ec8c3c50 (patch)
treec2a0aadce2ed56fb794974c1aca7703a613cdfde /bsc-nat
parent92632e1dce118ded7488398757a7bf3d4ea2c58a (diff)
rename 'ipa' directory to 'bsc-nat'
Diffstat (limited to 'bsc-nat')
-rw-r--r--bsc-nat/BSC_MS_ConnectionHandler.ttcn162
-rw-r--r--bsc-nat/BSC_MS_Simulation.ttcn94
-rw-r--r--bsc-nat/IPA_Test.cfg29
-rw-r--r--bsc-nat/IPA_Test.ttcn149
-rw-r--r--bsc-nat/MGCP_Adapter.ttcn72
-rw-r--r--bsc-nat/MSC_ConnectionHandler.ttcn154
-rwxr-xr-xbsc-nat/MSC_Simulation.ttcn78
-rwxr-xr-xbsc-nat/gen_links.sh59
-rwxr-xr-xbsc-nat/regen_makefile.sh11
9 files changed, 808 insertions, 0 deletions
diff --git a/bsc-nat/BSC_MS_ConnectionHandler.ttcn b/bsc-nat/BSC_MS_ConnectionHandler.ttcn
new file mode 100644
index 0000000..ee56401
--- /dev/null
+++ b/bsc-nat/BSC_MS_ConnectionHandler.ttcn
@@ -0,0 +1,162 @@
+module BSC_MS_ConnectionHandler {
+
+import from General_Types all;
+import from Osmocom_Types all;
+import from SCCPasp_Types all;
+import from BSSAP_Types all;
+import from BSSMAP_Emulation all;
+import from BSSMAP_Templates all;
+
+import from MobileL3_Types all;
+import from MobileL3_CommonIE_Types all;
+import from L3_Templates all;
+
+import from MGCP_Types all;
+import from MGCP_Templates all;
+import from SDP_Types all;
+
+/* this component represents a single subscriber connection at the MSC.
+ * There is a 1:1 mapping between SCCP connections and BSSAP_ConnHdlr components.
+ * We inherit all component variables, ports, functions, ... from BSSAP_ConnHdlr */
+type component BSC_MS_ConnHdlr extends BSSAP_ConnHdlr {
+ /* SCCP Connecction Identifier for the underlying SCCP connection */
+ var integer g_sccp_conn_id;
+ var MgcpConnectionId g_mgcp_conn_id;
+ var SDP_Message g_sdp;
+ var BSC_State g_state;
+}
+
+/* Callback function from general BSSMAP_Emulation whenever a new incoming
+ * SCCP connection arrivces. Must create + start a new component */
+private function CreateCallback(ASP_SCCP_N_CONNECT_ind conn_ind, charstring id)
+runs on BSSMAP_Emulation_CT return BSSAP_ConnHdlr {
+ log("Incoming SCCP Connection on BSC ?!?");
+ self.stop;
+}
+
+/* Callback function from general BSSMAP_Emulation whenever a connectionless
+ * BSSMAP message arrives. Can retunr a PDU_BSSAP that should be sent in return */
+private function UnitdataCallback(PDU_BSSAP bssap)
+runs on BSSMAP_Emulation_CT return template PDU_BSSAP {
+ var template PDU_BSSAP resp := omit;
+
+ if (match(bssap, tr_BSSMAP_Reset)) {
+ resp := ts_BSSMAP_ResetAck;
+ }
+
+ return resp;
+}
+
+const BssmapOps BSC_MS_BssmapOps := {
+ create_cb := refers(CreateCallback),
+ unitdata_cb := refers(UnitdataCallback)
+}
+
+
+function f_gen_cl3(hexstring imsi) return PDU_BSSAP {
+ var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(imsi));
+ var PDU_ML3_MS_NW l3 := valueof(ts_CM_SERV_REQ('0001'B, mi));
+ var BSSMAP_IE_CellIdentifier cell_id := valueof(ts_CellID_LAC_CI(23, 42));
+ var PDU_BSSAP bssap := valueof(ts_BSSMAP_ComplL3(cell_id, enc_PDU_ML3_MS_NW(l3)));
+ return bssap;
+}
+
+type enumerated BSC_State {
+ BSC_STATE_NONE,
+ BSC_STATE_WAIT_ASS_REQ,
+ BSC_STATE_WAIT_CRCX,
+ BSC_STATE_WAIT_MDCX,
+ BSC_STATE_WAIT_CLEAR_CMD,
+ BSC_STATE_WAIT_DLCX,
+ BSC_STATE_WAIT_DISC_IND
+}
+
+/* main function processing various incoming events */
+function main(SCCP_PAR_Address sccp_addr_own, SCCP_PAR_Address sccp_addr_remote)
+runs on BSC_MS_ConnHdlr {
+ var PDU_BSSAP bssap;
+ var MgcpCommand mgcp_cmd;
+ var MgcpResponse mgcp_resp;
+
+ log("Starting main of BSC_MS_ConnHdlr");
+
+ g_mgcp_conn_id := f_mgcp_alloc_conn_id();
+
+ /* generate and send the Complete Layer3 Info */
+ bssap := f_gen_cl3('901770123456789'H);
+ var BSSAP_Conn_Req creq := {
+ addr_peer := sccp_addr_remote,
+ addr_own := sccp_addr_own,
+ bssap := bssap
+ }
+ g_state := BSC_STATE_WAIT_ASS_REQ;
+ BSSAP.send(creq);
+
+ while (true) {
+ alt {
+ /* new SCCP-level connection indication from BSC */
+ [g_state == BSC_STATE_WAIT_ASS_REQ] BSSAP.receive(tr_BSSMAP_AssignmentReq) -> value bssap {
+ /* FIXME: Read CIC */
+ /* respond with ASSIGNMENT COMPL */
+ g_state := BSC_STATE_WAIT_CRCX;
+ BSSAP.send(ts_BSSMAP_AssignmentComplete(bssap.pdu.bssmap.assignmentRequest.circuitIdentityCode));
+ }
+
+ /* CRCX -> OK */
+ [g_state == BSC_STATE_WAIT_CRCX] BSSAP.receive(tr_CRCX) -> value mgcp_cmd {
+ /* FIXME: proper SDP parameters */
+ g_sdp := valueof(ts_SDP("127.0.0.1", "127.0.0.1", "foo", "21", 1000, { "98" },
+ { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
+ valueof(ts_SDP_ptime(20)) }));
+ /* respond with CRCX_ACK */
+ g_state := BSC_STATE_WAIT_MDCX;
+ BSSAP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, g_mgcp_conn_id, g_sdp));
+ }
+
+ /* MDCX -> OK */
+ [g_state == BSC_STATE_WAIT_MDCX] BSSAP.receive(tr_MDCX) -> value mgcp_cmd {
+ /* FIXME: verify if local part of endpoint name matches CIC */
+ /* respond with CRCX_ACK */
+ g_state := BSC_STATE_WAIT_CLEAR_CMD;
+ BSSAP.send(ts_MDCX_ACK(mgcp_cmd.line.trans_id, g_mgcp_conn_id, g_sdp));
+ }
+
+ /* CLEAR COMMAND from MSC; respond with CLEAR COMPLETE) */
+ [g_state == BSC_STATE_WAIT_CLEAR_CMD] BSSAP.receive(tr_BSSMAP_ClearCommand) -> value bssap {
+ g_state := BSC_STATE_WAIT_DLCX;
+ BSSAP.send(ts_BSSMAP_ClearComplete);
+ }
+
+ /* DLCX -> OK */
+ [g_state == BSC_STATE_WAIT_DLCX] BSSAP.receive(tr_DLCX) -> value mgcp_cmd {
+ /* FIXME: verify if local part of endpoint name matches CIC */
+ g_state := BSC_STATE_WAIT_DISC_IND;
+ BSSAP.send(ts_DLCX_ACK(mgcp_cmd.line.trans_id, g_mgcp_conn_id));
+ }
+
+ [] BSSAP.receive(tr_BSSAP_DTAP) -> value bssap {
+ /* FIXME: verify if local part of endpoint name matches CIC */
+ var PDU_ML3_MS_NW l3 := dec_PDU_ML3_MS_NW(bssap.pdu.dtap);
+ log("Unhandled DTAP ", l3);
+ }
+
+ [g_state == BSC_STATE_WAIT_DISC_IND] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
+ setverdict(pass);
+ self.stop;
+ }
+
+ /* disconnect in invalid state */
+ [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
+ setverdict(fail);
+ self.stop;
+ }
+
+
+ [] BSSAP.receive(PDU_BSSAP:?) -> value bssap {
+ log("Received unhandled SCCP-CO: ", bssap);
+ }
+ }
+ }
+}
+
+}
diff --git a/bsc-nat/BSC_MS_Simulation.ttcn b/bsc-nat/BSC_MS_Simulation.ttcn
new file mode 100644
index 0000000..eab7fe9
--- /dev/null
+++ b/bsc-nat/BSC_MS_Simulation.ttcn
@@ -0,0 +1,94 @@
+module BSC_MS_Simulation {
+
+import from IPL4asp_Types all;
+
+import from IPA_Emulation all;
+
+import from SCCP_Types all;
+import from SCCPasp_Types all;
+import from SCCP_Emulation all;
+
+import from BSSMAP_Emulation all;
+
+import from BSC_MS_ConnectionHandler all;
+
+type component BSC_CT {
+ /* component references */
+ var IPA_Emulation_CT vc_IPA;
+ var SCCP_CT vc_SCCP;
+ var BSSMAP_Emulation_CT vc_BSSMAP;
+ /* test port to SCCP emulation */
+ port SCCPasp_PT SCCP;
+
+ var SCCP_PAR_Address g_sccp_addr_own;
+ var SCCP_PAR_Address g_sccp_addr_remote;
+
+ var charstring g_bsc_num_str;
+}
+
+modulepar {
+ integer mp_num_iterations := 10;
+}
+
+function main(charstring remote_ip, PortNumber remote_port,
+ charstring local_ip, PortNumber local_port,
+ MSC_SCCP_MTP3_parameters sccp_pars,
+ SCCP_PAR_Address sccp_addr_own,
+ SCCP_PAR_Address sccp_addr_remote, charstring id) runs on BSC_CT
+{
+ var integer i := 0;
+ timer T := 1.0;
+
+ g_sccp_addr_own := sccp_addr_own;
+ g_sccp_addr_remote := sccp_addr_remote;
+
+ /* create components for IPA/SCCP/BSS[M]AP stack */
+ vc_IPA := IPA_Emulation_CT.create(id & "-IPA");
+ vc_SCCP := SCCP_CT.create(id & "-SCCP");
+ vc_BSSMAP := BSSMAP_Emulation_CT.create(id & "-BSSMAP");
+
+ map(vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
+
+ /* connect MTP3 service provider (IPA) to lower side of SCCP */
+ connect(vc_IPA:MTP3_SP_PORT, vc_SCCP:MTP3_SCCP_PORT);
+
+ /* connect BSSMAP dispatcher to upper side of SCCP */
+ connect(vc_BSSMAP:SCCP, vc_SCCP:SCCP_SP_PORT);
+
+ /* connect BSSMAP dispatcher to IPA_Emulation MGCP */
+ connect(vc_BSSMAP:MGCP, vc_IPA:IPA_MGCP_PORT);
+
+ /* start components */
+ vc_IPA.start(IPA_Emulation.main_client(remote_ip, remote_port, local_ip, local_port));
+ vc_SCCP.start(SCCPStart(sccp_pars));
+ vc_BSSMAP.start(BSSMAP_Emulation.main(BSC_MS_BssmapOps, id));
+
+ /* Initial delay to wait for IPA connection establishment */
+ T.start(2.0);
+ T.timeout;
+
+ for (i := 0; i < mp_num_iterations; i := i+1) {
+ f_start_BSC_MS(id & "-MS-" & int2str(i));
+ }
+
+ /* explicitly stop all components that we started above */
+ vc_IPA.stop;
+ vc_BSSMAP.stop;
+ vc_SCCP.stop;
+}
+
+function f_start_BSC_MS(charstring id) runs on BSC_CT {
+ var BSC_MS_ConnHdlr vc_conn;
+
+ /* start new component */
+ vc_conn := BSC_MS_ConnHdlr.create(id);
+ /* connect client BSSAP port to BSSAP dispatcher */
+ connect(vc_conn:BSSAP, vc_BSSMAP:CLIENT);
+ /* start component */
+ vc_conn.start(BSC_MS_ConnectionHandler.main(g_sccp_addr_own, g_sccp_addr_remote));
+ /* blocking wait until component terminates. If you want to start MSs in parallel,
+ * you have to remove this statement here */
+ vc_conn.done;
+}
+
+}
diff --git a/bsc-nat/IPA_Test.cfg b/bsc-nat/IPA_Test.cfg
new file mode 100644
index 0000000..3a34102
--- /dev/null
+++ b/bsc-nat/IPA_Test.cfg
@@ -0,0 +1,29 @@
+[LOGGING]
+#FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC;
+#ConsoleMask := ERROR | WARNING | TESTCASE | TTCN_MATCHING | DEBUG_ENCDEC
+FileMask := LOG_ALL | TTCN_MATCHING;
+
+[TESTPORT_PARAMETERS]
+#*.*.udpReuseAddress := "yes";
+
+[MODULE_PARAMETERS]
+#mp_bsc_port := 49999;
+#mp_bsc_ip := "127.0.0.1";
+#mp_msc_port := 5100;
+#mp_msc_ip := "127.0.0.1";
+#mp_nat_port := 5000;
+#mp_nat_ip := "127.0.0.1";
+
+#mp_ipa_mgcp_uses_osmo_ext := true;
+
+#mp_mgcp_uses_udp := true;
+#mp_callagent_ip := "127.0.0.1";
+#mp_callagent_udp_port := 2727;
+#mp_mgw_ip := "127.0.0.1";
+#mp_mgw_udp_port := 2427;
+
+[MAIN_CONTROLLER]
+
+[EXECUTE]
+#MGCP_Test.TC_selftest
+IPA_Test.TC_recv_dump
diff --git a/bsc-nat/IPA_Test.ttcn b/bsc-nat/IPA_Test.ttcn
new file mode 100644
index 0000000..fbff84a
--- /dev/null
+++ b/bsc-nat/IPA_Test.ttcn
@@ -0,0 +1,149 @@
+module IPA_Test {
+
+import from Osmocom_Types all;
+
+import from IPL4asp_Types all;
+
+import from IPA_Emulation all;
+
+import from MTP3asp_Types all;
+
+import from SCCP_Types all;
+import from SCCPasp_Types all;
+import from SCCP_Emulation all;
+
+import from MSC_Simulation all;
+import from BSC_MS_Simulation all;
+
+const integer NUM_MSC := 1;
+const integer NUM_BSC := 1;
+
+type record BscState {
+ BSC_CT BSC,
+ MSC_SCCP_MTP3_parameters sccp_pars,
+ SCCP_PAR_Address sccp_addr_own,
+ SCCP_PAR_Address sccp_addr_peer
+}
+
+type record MscState {
+ MSC_CT MSC,
+ MSC_SCCP_MTP3_parameters sccp_pars,
+ SCCP_PAR_Address sccp_addr_own
+}
+
+type component test_CT {
+ var MscState msc[NUM_MSC];
+ var BscState bsc[NUM_BSC];
+
+ var boolean g_initialized := false;
+ var octetstring g_sio := '83'O;
+}
+
+modulepar {
+ PortNumber mp_bsc_port := 49999;
+ charstring mp_bsc_ip := "127.0.0.1";
+
+ PortNumber mp_msc_port := 5000;
+ charstring mp_msc_ip := "127.0.0.1";
+
+ PortNumber mp_nat_port := 5000;
+ charstring mp_nat_ip := "127.0.0.1";
+
+ charstring mp_sccp_service_type := "mtp3_itu";
+
+ integer mp_bsc_pc := 196;
+ integer mp_bsc_ssn := 254;
+
+ integer mp_msc_pc := 185; /* 0.23.1 */
+ integer mp_msc_ssn := 254;
+}
+
+/* construct a SCCP_PAR_Address with just PC + SSN and no GT */
+template (value) SCCP_PAR_Address ts_SccpAddr_PC_SSN(integer pc, integer ssn) := {
+ addressIndicator := {
+ pointCodeIndic := '1'B,
+ ssnIndicator := '1'B,
+ globalTitleIndic := '0000'B,
+ routingIndicator := '1'B
+ },
+ signPointCode := SCCP_SPC_int2bit(pc, mp_sccp_service_type, '83'O),
+ //signPointCode := SCCP_SPC_int2bit(pc, mp_sccp_service_type, g_sio),
+ subsystemNumber := ssn,
+ globalTitle := omit
+}
+
+template MTP3_Field_sio ts_sio(octetstring sio_in) := {
+ ni := substr(oct2bit(sio_in),0,2),
+ prio := substr(oct2bit(sio_in),2,2),
+ si := substr(oct2bit(sio_in),4,4)
+}
+
+template MSC_SCCP_MTP3_parameters ts_SCCP_Pars(octetstring sio, integer opc, integer dpc,
+ integer local_ssn) := {
+ sio := ts_sio(sio),
+ opc := opc,
+ dpc := dpc,
+ sls := 0,
+ sccp_serviceType := mp_sccp_service_type,
+ ssn := local_ssn
+};
+
+function f_init_BscState(inout BscState bsc_st, integer opc, integer dpc, integer local_ssn, integer remote_ssn)
+runs on test_CT {
+ bsc_st.sccp_pars := valueof(ts_SCCP_Pars(g_sio, opc, dpc, local_ssn));
+ bsc_st.sccp_addr_own := valueof(ts_SccpAddr_PC_SSN(opc, local_ssn));
+ bsc_st.sccp_addr_peer := valueof(ts_SccpAddr_PC_SSN(dpc, remote_ssn));
+}
+
+function f_init_MscState(inout MscState msc_st, integer opc, integer dpc, integer local_ssn, integer remote_ssn)
+runs on test_CT {
+ msc_st.sccp_pars := valueof(ts_SCCP_Pars(g_sio, opc, dpc, local_ssn));
+ msc_st.sccp_addr_own := valueof(ts_SccpAddr_PC_SSN(opc, local_ssn));
+}
+
+function f_init() runs on test_CT {
+ var integer i;
+ var charstring id;
+
+ for (i := 0; i < NUM_MSC; i := i+1) {
+ f_init_MscState(msc[i], mp_msc_pc +i, mp_bsc_pc, mp_msc_ssn, mp_bsc_ssn);
+ msc[i].MSC := MSC_CT.create;
+ id := "MSC" & int2str(i);
+ msc[i].MSC.start(MSC_Simulation.main(mp_msc_ip, mp_msc_port + i, msc[i].sccp_pars, msc[i].sccp_addr_own, id));
+ }
+
+ for (i := 0; i < NUM_BSC; i := i+1) {
+ f_init_BscState(bsc[i], mp_bsc_pc +i, mp_msc_pc, mp_bsc_ssn, mp_msc_ssn);
+ bsc[i].BSC := BSC_CT.create;
+ id := "BSC" & int2str(i);
+ bsc[i].BSC.start(BSC_MS_Simulation.main(mp_nat_ip, mp_nat_port, mp_bsc_ip, mp_bsc_port+i,
+ bsc[i].sccp_pars, bsc[i].sccp_addr_own,
+ bsc[i].sccp_addr_peer, id));
+ }
+
+}
+
+testcase TC_recv_dump() runs on test_CT {
+ var integer i;
+ timer T := 30.0;
+
+ f_init();
+
+ alt {
+ /* wait for BSC to stop. The idea is that the BSC components terminate first */
+ [] bsc[0].BSC.done { }
+ [] T.timeout { setverdict(fail); }
+ }
+
+ all component.stop;
+ /* terminate the MSCs */
+ for (i := 0; i < NUM_MSC; i := i+1) {
+ msc[i].MSC.stop;
+ }
+}
+
+control {
+ execute( TC_recv_dump() );
+}
+
+}
diff --git a/bsc-nat/MGCP_Adapter.ttcn b/bsc-nat/MGCP_Adapter.ttcn
new file mode 100644
index 0000000..1351997
--- /dev/null
+++ b/bsc-nat/MGCP_Adapter.ttcn
@@ -0,0 +1,72 @@
+module MGCP_Adapter {
+
+import from IPL4asp_Types all;
+
+import from MGCP_Types all;
+import from MGCP_CodecPort all;
+import from MGCP_CodecPort_CtrlFunct all;
+
+import from IPA_Emulation all;
+
+
+type component MGCP_Adapter_CT {
+ /* MGCP Codec Port for MGCP-over-UDP */
+ port MGCP_CODEC_PT MGCP_UDP;
+ port IPA_MGCP_PT MGCP;
+ var integer g_mgcp_conn_id := -1;
+}
+
+modulepar {
+ charstring mp_callagent_ip := "127.0.0.1";
+ PortNumber mp_callagent_udp_port := 2727;
+ charstring mp_mgw_ip := "127.0.0.1";
+ PortNumber mp_mgw_udp_port := 2427;
+}
+
+/* build a receive template for receiving a MGCP message. You
+ * pass the MGCP response template in, and it will generate an
+ * MGCP_RecvFrom template that can match the primitives arriving on the
+ * MGCP_CodecPort */
+function tr_MGCP_RecvFrom_R(template MgcpResponse resp)
+runs on MGCP_Adapter_CT return template MGCP_RecvFrom {
+ var template MGCP_RecvFrom mrf := {
+ connId := g_mgcp_conn_id,
+ remName := mp_mgw_ip,
+ remPort := mp_mgw_udp_port,
+ locName := mp_callagent_ip,
+ locPort := mp_callagent_udp_port,
+ msg := { response := resp }
+ }
+ return mrf;
+}
+
+
+function main() runs on MGCP_Adapter_CT {
+ var Result res;
+ map(self:MGCP_UDP, system:MGCP_CODEC_PT);
+ res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP_UDP, mp_mgw_ip, mp_mgw_udp_port,
+ mp_callagent_ip, mp_callagent_udp_port,
+ 0, { udp:={} });
+ g_mgcp_conn_id := res.connId;
+
+ while (true) {
+ var MgcpCommand mgcp_cmd;
+ var MGCP_RecvFrom mrf;
+
+ alt {
+ /* From BSC/MGW via UDP up to MSC / Call Agent */
+ [] MGCP_UDP.receive(tr_MGCP_RecvFrom_R(?)) -> value mrf {
+ MGCP.send(mrf.msg.response);
+ }
+
+ /* From MSC / Call Agent down to BSC/MGW */
+ [] MGCP.receive(MgcpCommand:?) -> value mgcp_cmd {
+ var MgcpMessage msg := { command := mgcp_cmd };
+ MGCP_UDP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
+ }
+
+ }
+ }
+}
+
+}
diff --git a/bsc-nat/MSC_ConnectionHandler.ttcn b/bsc-nat/MSC_ConnectionHandler.ttcn
new file mode 100644
index 0000000..6a9a57f
--- /dev/null
+++ b/bsc-nat/MSC_ConnectionHandler.ttcn
@@ -0,0 +1,154 @@
+module MSC_ConnectionHandler {
+
+import from General_Types all;
+import from Osmocom_Types all;
+import from SCCPasp_Types all;
+import from BSSAP_Types all;
+import from BSSMAP_Emulation all;
+import from BSSMAP_Templates all;
+
+import from MGCP_Types all;
+import from MGCP_Templates all;
+import from SDP_Types all;
+
+/* this component represents a single subscriber connection at the MSC.
+ * There is a 1:1 mapping between SCCP connections and BSSAP_ConnHdlr components.
+ * We inherit all component variables, ports, functions, ... from BSSAP_ConnHdlr */
+type component MSC_ConnHdlr extends BSSAP_ConnHdlr {
+ /* SCCP Connecction Identifier for the underlying SCCP connection */
+ var integer g_sccp_conn_id;
+
+ var MSC_State g_state := MSC_STATE_NONE;
+ var MgcpEndpoint g_ep_name;
+ var MgcpCallId g_call_id;
+ var MgcpConnectionId g_mgcp_conn_id;
+}
+
+/* Callback function from general BSSMAP_Emulation whenever a new incoming
+ * SCCP connection arrivces. Must create + start a new component */
+private function CreateCallback(ASP_SCCP_N_CONNECT_ind conn_ind, charstring id)
+runs on BSSMAP_Emulation_CT return BSSAP_ConnHdlr {
+ var MSC_ConnHdlr vc_conn;
+ /* Create a new BSSAP_ConnHdlr component */
+ vc_conn := MSC_ConnHdlr.create(g_bssmap_id & "-Conn-" & int2str(conn_ind.connectionId));
+ /* connect it to the port */
+ connect(vc_conn:BSSAP, self:CLIENT);
+ /* start it */
+ vc_conn.start(MSC_ConnectionHandler.main(conn_ind.connectionId, g_next_e1_ts));
+ /* increment next E1 timeslot */
+ g_next_e1_ts := g_next_e1_ts + 1;
+ return vc_conn;
+}
+
+/* Callback function from general BSSMAP_Emulation whenever a connectionless
+ * BSSMAP message arrives. Can retunr a PDU_BSSAP that should be sent in return */
+private function UnitdataCallback(PDU_BSSAP bssap)
+runs on BSSMAP_Emulation_CT return template PDU_BSSAP {
+ var template PDU_BSSAP resp := omit;
+
+ if (match(bssap, tr_BSSMAP_Reset)) {
+ resp := ts_BSSMAP_ResetAck;
+ }
+
+ return resp;
+}
+
+const BssmapOps MSC_BssmapOps := {
+ create_cb := refers(CreateCallback),
+ unitdata_cb := refers(UnitdataCallback)
+}
+
+type enumerated MSC_State {
+ MSC_STATE_NONE,
+ MSC_STATE_WAIT_ASS_COMPL,
+ MSC_STATE_WAIT_CRCX_ACK,
+ MSC_STATE_WAIT_MDCX_ACK,
+ MSC_STATE_WAIT_CLEAR_COMPL,
+ MSC_STATE_WAIT_DLCX_ACK
+}
+
+/* main function processing various incoming events */
+function main(integer connection_id, integer e1_timeslot) runs on MSC_ConnHdlr {
+ var MgcpResponse mgcp_rsp;
+ timer T := 5.0;
+
+ g_sccp_conn_id := connection_id;
+ g_call_id := f_mgcp_alloc_call_id();
+ g_ep_name := hex2str(int2hex(e1_timeslot, 1)) & "@mgw";
+
+ /* we just accepted an incoming SCCP connection, start guard timer */
+ T.start;
+
+ while (true) {
+ var PDU_BSSAP bssap;
+ alt {
+ /* new SCCP-level connection indication from BSC */
+ [g_state == MSC_STATE_NONE] BSSAP.receive(tr_BSSMAP_ComplL3) -> value bssap {
+ /* respond with ASSIGNMENT CMD */
+ g_state := MSC_STATE_WAIT_ASS_COMPL;
+ BSSAP.send(ts_BSSMAP_AssignmentReq(0, e1_timeslot));
+ }
+ [g_state == MSC_STATE_WAIT_ASS_COMPL] BSSAP.receive(tr_BSSMAP_AssignmentComplete) {
+ /* FIXME: Send MGCP CRCX */
+ g_state := MSC_STATE_WAIT_CRCX_ACK;
+ var MgcpTransId trans_id := f_mgcp_alloc_tid();
+ //template SDP_Message sdp := omit;
+ BSSAP.send(ts_CRCX(trans_id, g_ep_name, "recvonly", g_call_id)); //, sdp));
+ }
+ /*
+ [] BSSAP.receive(tr_BSSMAP_AssignmentFail) {
+ }
+ */
+
+ /* receive CRCX ACK: transmit MDCX */
+ [g_state == MSC_STATE_WAIT_CRCX_ACK] BSSAP.receive(tr_CRCX_ACK) -> value mgcp_rsp {
+ /* extract connection ID */
+ g_mgcp_conn_id := f_MgcpResp_extract_conn_id(mgcp_rsp);
+ g_state := MSC_STATE_WAIT_MDCX_ACK;
+ var MgcpTransId trans_id := f_mgcp_alloc_tid();
+ BSSAP.send(ts_MDCX(trans_id, g_ep_name, "sendrecv", g_call_id, g_mgcp_conn_id));
+ }
+
+ /* receive MDCX ACK: wait + transmit CLEAR COMMAND */
+ [g_state == MSC_STATE_WAIT_MDCX_ACK] BSSAP.receive(tr_CRCX_ACK) -> value mgcp_rsp {
+ g_state := MSC_STATE_WAIT_CLEAR_COMPL
+ BSSAP.send(ts_BSSMAP_ClearCommand(9)); /* Cause: call control */
+ }
+
+ /* CLEAR COMPLETE from BSS (response to CLEAR COMMAND) */
+ [g_state == MSC_STATE_WAIT_CLEAR_COMPL] BSSAP.receive(tr_BSSMAP_ClearComplete) {
+ /* send DLCX */
+ g_state := MSC_STATE_WAIT_DLCX_ACK;
+ var MgcpTransId trans_id := f_mgcp_alloc_tid();
+ BSSAP.send(ts_DLCX(trans_id, g_ep_name, g_call_id));
+ }
+
+ [g_state == MSC_STATE_WAIT_DLCX_ACK] BSSAP.receive(tr_DLCX_ACK) {
+ BSSAP.send(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
+ setverdict(pass);
+ self.stop;
+ }
+
+ /* TODO: CLEAR REQUEST from BSS */
+
+ [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
+ setverdict(fail);
+ self.stop;
+ }
+
+ [] BSSAP.receive(PDU_BSSAP:?) -> value bssap {
+ log("Received unhandled SCCP-CO: ", bssap);
+ }
+
+ /* Guard timer has expired, close connection */
+ [] T.timeout {
+ BSSAP.send(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
+ setverdict(inconc);
+ self.stop;
+ }
+
+ }
+ }
+}
+
+}
diff --git a/bsc-nat/MSC_Simulation.ttcn b/bsc-nat/MSC_Simulation.ttcn
new file mode 100755
index 0000000..f9fb0d4
--- /dev/null
+++ b/bsc-nat/MSC_Simulation.ttcn
@@ -0,0 +1,78 @@
+module MSC_Simulation {
+
+import from IPL4asp_Types all;
+
+import from IPA_Emulation all;
+
+import from SCCP_Types all;
+import from SCCPasp_Types all;
+import from SCCP_Emulation all;
+
+/*
+import from MobileL3_Types all;
+import from MobileL3_CommonIE_Types all;
+import from L3_Templates all;
+
+import from BSSAP_Types all;
+import from BSSMAP_Templates all;
+*/
+import from BSSMAP_Emulation all;
+
+import from MGCP_Adapter all;
+
+import from MSC_ConnectionHandler all;
+
+type component MSC_CT {
+ /* component references */
+ var IPA_Emulation_CT vc_IPA;
+ var SCCP_CT vc_SCCP;
+ var BSSMAP_Emulation_CT vc_BSSMAP;
+ var MGCP_Adapter_CT vc_MGCP_UDP;
+ /* test port to SCCP emulation */
+ port SCCPasp_PT SCCP;
+}
+
+modulepar {
+ boolean mp_mgcp_uses_udp := false;
+}
+
+function main(charstring local_ip, PortNumber local_port,
+ MSC_SCCP_MTP3_parameters sccp_pars,
+ SCCP_PAR_Address sccp_addr_own, charstring id) runs on MSC_CT
+{
+ /* create components */
+ vc_IPA := IPA_Emulation_CT.create(id & "-IPA");
+ vc_SCCP := SCCP_CT.create(id & "-SCCP");
+ vc_BSSMAP := BSSMAP_Emulation_CT.create(id & "-BSSMAP");
+
+ map(vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
+
+ /* connect MTP3 service provider (IPA) to lower side of SCCP */
+ connect(vc_IPA:MTP3_SP_PORT, vc_SCCP:MTP3_SCCP_PORT);
+
+ /* connect BSSNAP dispatcher to upper side of SCCP */
+ connect(vc_BSSMAP:SCCP, vc_SCCP:SCCP_SP_PORT);
+
+ if (mp_mgcp_uses_udp == false) {
+ /* connect BSSMAP dispatcher to IPA_Emulation MGCP */
+ connect(vc_BSSMAP:MGCP, vc_IPA:IPA_MGCP_PORT);
+ } else {
+ vc_MGCP_UDP := MGCP_Adapter_CT.create(id & "-MGCP_UDP");
+ connect(vc_BSSMAP:MGCP, vc_MGCP_UDP:MGCP);
+ vc_MGCP_UDP.start(MGCP_Adapter.main());
+ }
+
+ vc_IPA.start(IPA_Emulation.main_server(local_ip, local_port));
+ vc_SCCP.start(SCCPStart(sccp_pars));
+ vc_BSSMAP.start(BSSMAP_Emulation.main(MSC_BssmapOps, id & "-BSSMAP"));
+
+ /* wait until termination of respective components */
+ vc_IPA.done;
+ vc_BSSMAP.done;
+ vc_SCCP.done;
+ if (mp_mgcp_uses_udp) {
+ vc_MGCP_UDP.done;
+ }
+}
+
+}
diff --git a/bsc-nat/gen_links.sh b/bsc-nat/gen_links.sh
new file mode 100755
index 0000000..7be9a2d
--- /dev/null
+++ b/bsc-nat/gen_links.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+BASEDIR=~/projects/git
+
+gen_links() {
+ DIR=$1
+ FILES=$*
+ for f in $FILES; do
+ echo "Linking $f"
+ ln -sf $DIR/$f $f
+ done
+}
+
+#DIR=$BASEDIR/titan.TestPorts.UNIX_DOMAIN_SOCKETasp/src
+#FILES="UD_PT.cc UD_PT.hh UD_PortType.ttcn UD_Types.ttcn"
+#gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src
+FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCConversion.hh TCCInterface.cc TCCInterface_ip.h SDP_EncDec.cc"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src
+FILES="Socket_API_Definitions.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.IPL4asp/src
+FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn IPL4asp_discovery.cc IPL4asp_protocol_L234.hh"
+gen_links $DIR $FILES
+
+# required by SCCP Emulation
+DIR=../MTP3asp_CNL113337/src
+FILES="MTP3asp_PortType.ttcn MTP3asp_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=../SCCP_CNL113341/src
+FILES="SCCP_Emulation.ttcn SCCP_EncDec.cc SCCP_Mapping.ttcnpp SCCP_Types.ttcn SCCPasp_Types.ttcn"
+gen_links $DIR $FILES
+ln -sf SCCP_Mapping.ttcnpp SCCP_Mapping.ttcn
+
+DIR=$BASEDIR/titan.ProtocolModules.BSSMAP_v11.2.0/src
+FILES="BSSAP_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolModules.MobileL3_v13.4.0/src
+FILES="MobileL3_CC_Types.ttcn MobileL3_CommonIE_Types.ttcn MobileL3_GMM_SM_Types.ttcn MobileL3_MM_Types.ttcn MobileL3_RRM_Types.ttcn MobileL3_SMS_Types.ttcn MobileL3_SS_Types.ttcn MobileL3_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolModules.SDP/src
+FILES="SDP_EncDec.cc SDP_Types.ttcn SDP_parse_.tab.c SDP_parse_.tab.h SDP_parse_parser.h SDP_parser.l
+SDP_parser.y lex.SDP_parse_.c"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolModules.RTP/src
+FILES="RTP_EncDec.cc RTP_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=../library
+FILES="General_Types.ttcn Osmocom_Types.ttcn IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcn L3_Templates.ttcn BSSMAP_Templates.ttcn BSSMAP_Emulation.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc"
+gen_links $DIR $FILES
diff --git a/bsc-nat/regen_makefile.sh b/bsc-nat/regen_makefile.sh
new file mode 100755
index 0000000..b6f6bb5
--- /dev/null
+++ b/bsc-nat/regen_makefile.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+MAIN=IPA_Test.ttcn
+
+FILES="*.ttcn SCCP_EncDec.cc IPA_CodecPort_CtrlFunctDef.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc RTP_EncDec.cc SDP_EncDec.cc *.c MGCP_CodecPort_CtrlFunctDef.cc"
+
+ttcn3_makefilegen -l -f $MAIN $FILES
+sed -i -e 's/# TTCN3_DIR = /TTCN3_DIR = \/usr/' Makefile
+sed -i -e 's/LDFLAGS = /LDFLAGS = -L \/usr\/lib\/titan /' Makefile
+#sed -i -e 's/TTCN3_LIB = ttcn3-parallel/TTCN3_LIB = ttcn3/' Makefile
+sed -i -e 's/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include -I\/usr\/include\/titan/' Makefile