module MSC_ConnectionHandler { import from General_Types all; import from Osmocom_Types all; import from GSM_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; import from RSL_Emulation all; import from RSL_Types all; import from MobileL3_Types all; import from MobileL3_CommonIE_Types all; //import from MobileL3_RRM_Types all; import from L3_Templates 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, RSL_DchanHdlr { /* SCCP Connecction Identifier for the underlying SCCP connection */ var integer g_sccp_conn_id; /* procedure port back to our parent (BSSMAP_Emulation_CT) for control */ port BSSMAPEM_PROC_PT BSSMAPEM; var MSC_State g_state := MSC_STATE_NONE; } /* 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; /* answer all RESET with a RESET ACK */ if (match(bssap, tr_BSSMAP_Reset)) { resp := ts_BSSMAP_ResetAck; } return resp; } const BssmapOps MSC_BssmapOps := { create_cb := refers(BSSMAP_Emulation.ExpectedCreateCallback), unitdata_cb := refers(UnitdataCallback), decode_dtap := false, role_ms := false } 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 } /* register an expect with the BSSMAP core */ private function f_create_exp(octetstring l3_enc) runs on MSC_ConnHdlr { BSSMAPEM.call(BSSMAPEM_register:{l3_enc, self}) { [] BSSMAPEM.getreply(BSSMAPEM_register:{?, ?}) {}; } } type record TestHdlrParams { OCT1 ra, GsmFrameNumber fn, hexstring imsi, RslLinkId link_id }; template (value) TestHdlrParams t_def_TestHdlrPars := { ra := '23'O, fn := 23, imsi := '001019876543210'H, link_id := valueof(ts_RslLinkID_DCCH(0)) } function f_create_chan_and_exp(TestHdlrParams pars) runs on MSC_ConnHdlr { var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(pars.imsi)); var PDU_ML3_MS_NW l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, mi)); var octetstring l3_enc := enc_PDU_ML3_MS_NW(l3_info); /* call helper function for CHAN_RQD -> IMM ASS ->EST_IND */ RSL_Emulation.f_chan_est(pars.ra, l3_enc, pars.link_id, pars.fn); f_create_exp(l3_enc); } function f_rsl_reply(template PDU_ML3_MS_NW l3, RSL_Message orig) runs on MSC_ConnHdlr { var RslChannelNr chan_nr := orig.ies[0].body.chan_nr; var RslLinkId link_id; if (orig.msg_type == RSL_MT_ENCR_CMD) { link_id := orig.ies[2].body.link_id; } else { link_id := orig.ies[1].body.link_id; } RSL.send(ts_RSL_DATA_IND(chan_nr, link_id, enc_PDU_ML3_MS_NW(valueof(l3)))); } function f_cipher_mode(OCT1 alg, OCT8 key, template OCT16 kc128 := omit, boolean exp_fail := false) runs on MSC_ConnHdlr { var PDU_BSSAP bssap; var RSL_Message rsl; if (isvalue(kc128)) { BSSAP.send(ts_BSSMAP_CipherModeCmdKc128(alg, key, valueof(kc128))); } else { BSSAP.send(ts_BSSMAP_CipherModeCmd(alg, key)); } alt { /* RSL/UE Side */ [] RSL.receive(tr_RSL_ENCR_CMD(g_chan_nr, ?, alg, key)) -> value rsl { var PDU_ML3_NW_MS l3 := dec_PDU_ML3_NW_MS(rsl.ies[3].body.l3_info.payload); log("Rx L3 from net: ", l3); if (ischosen(l3.msgs.rrm.cipheringModeCommand)) { f_rsl_reply(ts_RRM_CiphModeCompl, rsl); } repeat; } [] BSSAP.receive(tr_BSSMAP_CipherModeCompl) -> value bssap { // bssap.bssmap.cipherModeComplete.chosenEncryptionAlgorithm.algoritmhIdentifier if (exp_fail == true) { setverdict(fail, "Unexpected Cipher Mode Complete"); } else { setverdict(pass); } } [] BSSAP.receive(tr_BSSMAP_CipherModeRej) -> value bssap { if (exp_fail == false) { setverdict(fail, "Ciphering Mode Reject"); } else { setverdict(pass); } } } } /* establish a channel fully, expecting an assignment matching 'exp' */ function f_establish_fully(TestHdlrParams pars, PDU_BSSAP ass_cmd, template PDU_BSSAP exp_ass_cpl) runs on MSC_ConnHdlr return PDU_BSSAP { var PDU_BSSAP bssap; var RSL_Message rsl; timer T := 10.0; var boolean exp_compl := ischosen(exp_ass_cpl.pdu.bssmap.assignmentComplete); var boolean crcx_seen := false; var boolean rr_modify_seen := false; f_create_chan_and_exp(pars); /* we should now have a COMPL_L3 at the MSC */ BSSAP.receive(tr_BSSMAP_ComplL3); BSSAP.send(ass_cmd); alt { /* if we receive exactly what we expected, always return + pass */ [] BSSAP.receive(exp_ass_cpl) -> value bssap { setverdict(pass); return bssap; } [rr_modify_seen == false] RSL.receive(tr_RSL_DATA_REQ(g_chan_nr)) -> value rsl { var PDU_ML3_NW_MS l3 := dec_PDU_ML3_NW_MS(rsl.ies[2].body.l3_info.payload); log("Rx L3 from net: ", l3); if (ischosen(l3.msgs.rrm.channelModeModify)) { f_rsl_reply(ts_RRM_ModeModifyAck(l3.msgs.rrm.channelModeModify.channelDescription, l3.msgs.rrm.channelModeModify.channelMode), rsl); rr_modify_seen := true; } repeat; } [rr_modify_seen] RSL.receive(tr_RSL_MsgTypeD(RSL_MT_MODE_MODIFY_REQ)) -> value rsl { RSL.send(ts_RSL_MODE_MODIFY_ACK(g_chan_nr)); repeat; } [crcx_seen == false] RSL.receive(tr_RSL_IPA_CRCX(g_chan_nr)) -> value rsl { RSL.send(ts_RSL_IPA_CRCX_ACK(g_chan_nr, 1, 1, 1, 1)); crcx_seen := true; repeat; } [crcx_seen] RSL.receive(tr_RSL_IPA_MDCX(g_chan_nr, ?)) -> value rsl{ RSL.send(ts_RSL_IPA_MDCX_ACK(g_chan_nr, 1, 1, 1, 1)); repeat; } [exp_compl] BSSAP.receive(tr_BSSMAP_AssignmentComplete) { setverdict(fail, "Received non-matching ASSIGNMENT COMPLETE"); } [exp_compl] BSSAP.receive(tr_BSSMAP_AssignmentFail) { setverdict(fail, "Received unexpected ASSIGNMENT FAIL"); } [not exp_compl] BSSAP.receive(tr_BSSMAP_AssignmentComplete) { setverdict(fail, "Received unexpected ASSIGNMENT COMPLETE"); } [not exp_compl] BSSAP.receive(tr_BSSMAP_AssignmentFail) { setverdict(fail, "Received non-matching ASSIGNMENT FAIL"); } [] T.timeout { setverdict(inconc, "Timeout waiting for ASSIGNMENT COMPLETE"); } } self.stop; } }