osmo-ttcn3-hacks/bsc/MSC_ConnectionHandler.ttcn

197 lines
6.0 KiB
Plaintext
Raw Normal View History

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)
}
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('0001'B, 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 := 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) 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
setverdict(pass);
}
[] BSSAP.receive(tr_BSSMAP_CipherModeRej) -> value bssap {
setverdict(fail, "Ciphering Mode Reject");
}
}
}
/* 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;
}
}