diff options
Diffstat (limited to 'library/RAN_Emulation.ttcnpp')
-rw-r--r-- | library/RAN_Emulation.ttcnpp | 227 |
1 files changed, 169 insertions, 58 deletions
diff --git a/library/RAN_Emulation.ttcnpp b/library/RAN_Emulation.ttcnpp index 3158dc40..fbe921d6 100644 --- a/library/RAN_Emulation.ttcnpp +++ b/library/RAN_Emulation.ttcnpp @@ -168,6 +168,7 @@ type port RAN_Conn_PT message { #endif #ifdef RAN_EMULATION_RANAP RANAP_PDU, + RANAP_N_UNITDATA_req, /* Client requests us to create SCCP Connection */ RANAP_Conn_Req, #endif @@ -406,7 +407,8 @@ runs on RAN_Emulation_CT { return; } } - testcase.stop("RAN Connection table full!"); + setverdict(fail, "RAN Connection table full!"); + mtc.stop; } private function f_conn_table_del(integer sccp_conn_id) @@ -439,9 +441,9 @@ runs on RAN_Emulation_CT return RAN_ConnHdlr { type record BSSAP_Conn_Req { SCCP_PAR_Address addr_peer, SCCP_PAR_Address addr_own, - PDU_BSSAP bssap + PDU_BSSAP bssap optional } -template BSSAP_Conn_Req ts_BSSAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, PDU_BSSAP bssap) := { +template BSSAP_Conn_Req ts_BSSAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, template (omit) PDU_BSSAP bssap) := { addr_peer := peer, addr_own := own, bssap := bssap @@ -502,8 +504,11 @@ private function CommonBssmapUnitdataCallback(PDU_BSSAP bssap) runs on RAN_Emulation_CT return template PDU_BSSAP { if (match(bssap, tr_BSSMAP_Paging)) { var RAN_ConnHdlr client := null; - client := f_imsi_table_find(bssap.pdu.bssmap.paging.iMSI.digits, - bssap.pdu.bssmap.paging.tMSI.tmsiOctets); + var template OCT4 tmsi := omit; + if (ispresent(bssap.pdu.bssmap.paging.tMSI)) { + tmsi := bssap.pdu.bssmap.paging.tMSI.tmsiOctets; + } + client := f_imsi_table_find(bssap.pdu.bssmap.paging.iMSI.digits, tmsi); if (client != null) { log("CommonBssmapUnitdataCallback: IMSI/TMSI found in table, dispatching to ", client); @@ -515,26 +520,37 @@ runs on RAN_Emulation_CT return template PDU_BSSAP { log("CommonBssmapUnitdataCallback: Not a paging message"); } /* ELSE: handle in user callback */ + if (not ispresent(g_ran_ops.unitdata_cb)) { + return omit; + } return g_ran_ops.unitdata_cb.apply(bssap); } function f_bssap_reset(SCCP_PAR_Address peer, SCCP_PAR_Address own) runs on RAN_Emulation_CT { timer T := 5.0; var boolean append_osmux_support := append_osmux_ie(); + var integer attempts := g_ran_ops.bssap_reset_retries; - BSSAP.send(ts_BSSAP_UNITDATA_req(peer, own, ts_BSSMAP_Reset(0, append_osmux_support))); - T.start; - alt { - [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(own, peer, tr_BSSMAP_ResetAck(append_osmux_support))) { - log("BSSMAP: Received RESET-ACK in response to RESET, we're ready to go!"); - } - [] as_reset_ack(append_osmux_support); - [] BSSAP.receive { repeat }; - [] T.timeout { - setverdict(fail, "BSSMAP: Timeout waiting for RESET-ACK after sending RESET"); - mtc.stop; + while (attempts > 0) { + attempts := attempts - 1; + + BSSAP.send(ts_BSSAP_UNITDATA_req(peer, own, ts_BSSMAP_Reset(0, append_osmux_support))); + T.start; + alt { + [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(own, peer, tr_BSSMAP_ResetAck(append_osmux_support))) { + log("BSSMAP: Received RESET-ACK in response to RESET, we're ready to go!"); + return; + } + [] as_reset_ack(append_osmux_support); + [] BSSAP.receive { repeat }; + [] T.timeout { + continue; + } } } + + setverdict(fail, "BSSMAP: Timeout waiting for RESET-ACK after sending RESET"); + mtc.stop; } private function f_bssap_l3_is_rr(PDU_BSSAP bssap) return boolean { @@ -547,9 +563,18 @@ private function f_bssap_l3_is_rr(PDU_BSSAP bssap) return boolean { type record RANAP_Conn_Req { SCCP_PAR_Address addr_peer, SCCP_PAR_Address addr_own, - RANAP_PDU ranap + RANAP_PDU ranap optional } -template (value) RANAP_Conn_Req ts_RANAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, RANAP_PDU ranap) := { +template (value) RANAP_Conn_Req ts_RANAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, + template (omit) RANAP_PDU ranap) := { + addr_peer := peer, + addr_own := own, + ranap := ranap +}; + +template RANAP_Conn_Req tr_RANAP_Conn_Req(template SCCP_PAR_Address peer := ?, + template SCCP_PAR_Address own := ?, + template (omit) RANAP_PDU ranap := omit) := { addr_peer := peer, addr_own := own, ranap := ranap @@ -569,7 +594,7 @@ private function f_handle_userData_RANAP(RAN_ConnHdlr client, RANAP_PDU ranap) runs on RAN_Emulation_CT { /* decode + send decoded RANAP to client */ var template (omit) octetstring l3 := f_ranap_extract_l3(ranap); - if (istemplatekind(l3, "omit")) { + if (istemplatekind(l3, "omit") or not g_ran_ops.decode_dtap) { CLIENT.send(ranap) to client; } else { var template (omit) SAPI sapi := f_ranap_extract_sapi(ranap); @@ -658,6 +683,9 @@ runs on RAN_Emulation_CT return template RANAP_PDU { } /* ELSE: handle in user callback */ + if (not ispresent(g_ran_ops.ranap_unitdata_cb)) { + return omit; + } return g_ran_ops.ranap_unitdata_cb.apply(ranap); } @@ -713,6 +741,7 @@ type record RanOps { RanProtocol protocol, RAN_Transport transport, boolean use_osmux, + integer bssap_reset_retries, /* needed for performing BSSMAP RESET */ SCCP_PAR_Address sccp_addr_local optional, SCCP_PAR_Address sccp_addr_peer optional @@ -944,6 +973,7 @@ private altstep as_main_ranap() runs on RAN_Emulation_CT { var RANAP_N_DISCONNECT_ind rdisc_ind; var RANAP_Conn_Req creq; var RANAP_PDU ranap; + var RANAP_N_UNITDATA_req ranap_ud; var RAN_ConnHdlr vc_conn; var PDU_DTAP_PS_MO ps_mo; var PDU_DTAP_PS_MT ps_mt; @@ -964,7 +994,12 @@ private altstep as_main_ranap() runs on RAN_Emulation_CT { /* store mapping between client components and SCCP connectionId */ f_conn_table_add(vc_conn, rconn_ind.connectionId); /* handle user payload */ - f_handle_userData_RANAP(vc_conn, rconn_ind.userData); + if (ispresent(rconn_ind.userData)) { + f_handle_userData_RANAP(vc_conn, rconn_ind.userData); + } else { + /* Notify client that we received an SCCP CR without user data */ + CLIENT.send(ts_RANAP_Conn_Req(rconn_ind.callingAddress, rconn_ind.calledAddress, omit)); + } /* confirm connection establishment */ RANAP.send(ts_RANAP_CONNECT_res(rconn_ind.connectionId, omit)); } @@ -1004,6 +1039,11 @@ private altstep as_main_ranap() runs on RAN_Emulation_CT { RANAP.send(ts_RANAP_DATA_req(conn_id, ranap)); } + /* e.g. for Paging from virtual MSC/SGSN to SUT osmo-hnbgw */ + [] CLIENT.receive(RANAP_N_UNITDATA_req:?) -> value ranap_ud sender vc_conn { + RANAP.send(ranap_ud); + } + /* Disconnect request client -> SCCP */ [] CLIENT.receive(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ) -> sender vc_conn { var integer conn_id := f_conn_id_by_comp(vc_conn); @@ -1236,16 +1276,24 @@ function main(RanOps ops, charstring id) runs on RAN_Emulation_CT { PROC.reply(RAN_register:{l3_info, vc_hdlr}) to vc_hdlr; } - [] PROC.getcall(RAN_register_handoverRequest:{?,?}) -> param(targetPointCode, vc_hdlr) { + [] PROC.getcall(RAN_register_n_connect:{?,?}) -> param(targetPointCode, vc_hdlr) { f_create_expect(omit, vc_hdlr, targetPointCode); - PROC.reply(RAN_register_handoverRequest:{targetPointCode, vc_hdlr}) to vc_hdlr; + PROC.reply(RAN_register_n_connect:{targetPointCode, vc_hdlr}) to vc_hdlr; + } + + [] PROC.getcall(RAN_register_sccp_cr_without_payload:{?}) -> param(vc_hdlr) { + f_create_expect(omit, vc_hdlr); + PROC.reply(RAN_register_sccp_cr_without_payload:{vc_hdlr}) to vc_hdlr; } [] PROC.getcall(RAN_register_imsi:{?,?,?}) -> param(imsi, tmsi, vc_hdlr) { f_create_imsi(imsi, tmsi, vc_hdlr); PROC.reply(RAN_register_imsi:{imsi, tmsi, vc_hdlr}) to vc_hdlr; } - + [] PROC.getcall(RAN_unregister_imsi:{?,?}) -> param(imsi, vc_hdlr) { + f_destroy_imsi(imsi, vc_hdlr); + PROC.reply(RAN_unregister_imsi:{imsi, vc_hdlr}) to vc_hdlr; + } } } @@ -1267,17 +1315,20 @@ private function f_mgcp_ep_extract_cic(charstring inp) return integer { type record ExpectData { /* L3 payload based on which we can match it */ octetstring l3_payload optional, - integer handoverRequestPointCode optional, + integer n_connectPointCode optional, + boolean sccp_cr_without_payload, /* component reference for this connection */ RAN_ConnHdlr vc_conn } /* procedure based port to register for incoming connections */ signature RAN_register(in octetstring l3, in RAN_ConnHdlr hdlr); -signature RAN_register_handoverRequest(in integer targetPointCode, in RAN_ConnHdlr hdlr); +signature RAN_register_n_connect(in integer targetPointCode, in RAN_ConnHdlr hdlr); +signature RAN_register_sccp_cr_without_payload(in RAN_ConnHdlr hdlr); /* procedure based port to register for incoming IMSI/TMSI */ signature RAN_register_imsi(in hexstring imsi, in OCT4 tmsi, in RAN_ConnHdlr hdlr); +signature RAN_unregister_imsi(in hexstring imsi, in RAN_ConnHdlr hdlr); /* If DTAP happens across other channels (e.g. GSUP), provide manual advancing of the n_sd sequence number */ signature RAN_last_n_sd(in RAN_ConnHdlr hdlr, out N_Sd_Array last_n_sd); @@ -1286,7 +1337,8 @@ signature RAN_last_n_sd(in RAN_ConnHdlr hdlr, out N_Sd_Array last_n_sd); signature RAN_continue_after_n_sd(N_Sd_Array last_n_sd, in RAN_ConnHdlr hdlr); type port RAN_PROC_PT procedure { - inout RAN_register, RAN_register_imsi, RAN_register_handoverRequest, RAN_last_n_sd, RAN_continue_after_n_sd; + inout RAN_register, RAN_register_imsi, RAN_unregister_imsi, RAN_register_n_connect, + RAN_register_sccp_cr_without_payload, RAN_last_n_sd, RAN_continue_after_n_sd; } with { extension "internal" }; #ifdef RAN_EMULATION_BSSAP @@ -1295,29 +1347,40 @@ function ExpectedCreateCallback(BSSAP_N_CONNECT_ind conn_ind, charstring id) runs on RAN_Emulation_CT return RAN_ConnHdlr { var RAN_ConnHdlr ret := null; var octetstring l3_info; - var boolean handoverRequest := false; - var integer handoverRequestPointCode; + var boolean n_connect := false; + var integer n_connectPointCode; 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); + n_connect := true; + n_connectPointCode := bit2int(conn_ind.calledAddress.signPointCode); + log("ExpectedCreateCallback handoverRequest ", n_connectPointCode); + } else if (ischosen(conn_ind.userData.pdu.bssmap.vGCS_VBSSetup)) { + n_connect := true; + n_connectPointCode := bit2int(conn_ind.calledAddress.signPointCode); + log("ExpectedCreateCallback VGCS/VBS Setup ", n_connectPointCode); + } else if (ischosen(conn_ind.userData.pdu.bssmap.vGCS_VBSAssignmentRequest)) { + n_connect := true; + n_connectPointCode := bit2int(conn_ind.calledAddress.signPointCode); + log("ExpectedCreateCallback VGCS/VBS Assignment ", n_connectPointCode); } else { - setverdict(fail, "N-CONNECT.ind with L3 != COMPLETE L3 nor a Handover Request"); + setverdict(fail, "N-CONNECT.ind with L3 != COMPLETE L3 nor a new BSS connection"); mtc.stop; } for (i := 0; i < sizeof(ExpectTable); i:= i+1) { - if (handoverRequest) { - log("ExpectTable[", i, "].handoverRequestPointCode = ", ExpectTable[i].handoverRequestPointCode, - " ==? ", handoverRequestPointCode); - if (ExpectTable[i].handoverRequestPointCode == handoverRequestPointCode) { + if (n_connect) { + log("ExpectTable[", i, "].n_connectPointCode = ", ExpectTable[i].n_connectPointCode, + " ==? ", n_connectPointCode); + if (ExpectTable[i].n_connectPointCode == n_connectPointCode) { ret := ExpectTable[i].vc_conn; - log("Found Expect[", i, "] for handoverRequest handled at ", ret); + /* release this entry to be used again */ + ExpectTable[i].n_connectPointCode := omit; + ExpectTable[i].vc_conn := null; + log("Found Expect[", i, "] for N-CONNECT handled at ", ret); return ret; } else { continue; @@ -1347,25 +1410,31 @@ function RanapExpectedCreateCallback(RANAP_N_CONNECT_ind conn_ind, charstring id runs on RAN_Emulation_CT return RAN_ConnHdlr { var RAN_ConnHdlr ret := null; var template (omit) octetstring l3_info; + var boolean rx_sccp_cr_without_payload; var integer i; - l3_info := f_ranap_extract_l3(conn_ind.userData); - if (istemplatekind(l3_info, "omit")) { - setverdict(fail, "N-CONNECT.ind without NAS payload"); - mtc.stop; - return ret; + if (ispresent(conn_ind.userData)) { + l3_info := f_ranap_extract_l3(conn_ind.userData); + rx_sccp_cr_without_payload := false; + if (istemplatekind(l3_info, "omit") and not rx_sccp_cr_without_payload) { + setverdict(fail, "N-CONNECT.ind without NAS payload"); + mtc.stop; + return ret; + } + } else { + l3_info := omit; + rx_sccp_cr_without_payload := true; } for (i := 0; i < sizeof(ExpectTable); i:= i+1) { - if (not ispresent(ExpectTable[i].l3_payload)) { - continue; - } - if (valueof(l3_info) == ExpectTable[i].l3_payload) { + if ((rx_sccp_cr_without_payload and ExpectTable[i].sccp_cr_without_payload) + or (ispresent(ExpectTable[i].l3_payload) and valueof(l3_info) == ExpectTable[i].l3_payload)) { ret := ExpectTable[i].vc_conn; /* release this entry to be used again */ + ExpectTable[i].sccp_cr_without_payload := false; ExpectTable[i].l3_payload := omit; ExpectTable[i].vc_conn := null; - log("Found Expect[", i, "] for ", l3_info, " handled at ", ret); + log("Found Expect[", i, "] for l3=", l3_info, " handled at ", ret); /* return the component reference */ return ret; } @@ -1377,29 +1446,33 @@ runs on RAN_Emulation_CT return RAN_ConnHdlr { #endif private function f_create_expect(template octetstring l3, RAN_ConnHdlr hdlr, - template integer handoverRequestPointCode := omit) + template integer n_connectPointCode := omit) runs on RAN_Emulation_CT { var integer i; - log("f_create_expect(l3 := ", l3, ", handoverRequest := ", handoverRequestPointCode); + log("f_create_expect(l3 := ", l3, ", n_connectPointCode := ", n_connectPointCode); for (i := 0; i < sizeof(ExpectTable); i := i+1) { if (not ispresent(ExpectTable[i].l3_payload) - and not ispresent(ExpectTable[i].handoverRequestPointCode)) { + and not ExpectTable[i].sccp_cr_without_payload + and not ispresent(ExpectTable[i].n_connectPointCode)) { if (ispresent(l3)) { ExpectTable[i].l3_payload := valueof(l3); + } else { + ExpectTable[i].sccp_cr_without_payload := true; } - if (ispresent(handoverRequestPointCode)) { - ExpectTable[i].handoverRequestPointCode := valueof(handoverRequestPointCode); + if (ispresent(n_connectPointCode)) { + ExpectTable[i].n_connectPointCode := valueof(n_connectPointCode); } ExpectTable[i].vc_conn := hdlr; - if (ispresent(handoverRequestPointCode)) { - log("Created Expect[", i, "] for handoverRequest to be handled at ", hdlr); + if (ispresent(n_connectPointCode)) { + log("Created Expect[", i, "] for N-CONNECT to be handled at ", hdlr); } else { log("Created Expect[", i, "] for ", l3, " to be handled at ", hdlr); } return; } } - testcase.stop("No space left in ExpectTable"); + setverdict(fail, "No space left in ExpectTable"); + mtc.stop; } private function f_create_imsi(hexstring imsi, OCT4 tmsi, RAN_ConnHdlr hdlr) @@ -1413,15 +1486,31 @@ runs on RAN_Emulation_CT { return; } } - testcase.stop("No space left in ImsiTable"); + setverdict(fail, "No space left in ImsiTable"); + mtc.stop; } +private function f_destroy_imsi(hexstring imsi, RAN_ConnHdlr hdlr) +runs on RAN_Emulation_CT { + for (var integer i := 0; i < sizeof(ImsiTable); i := i+1) { + if (ImsiTable[i].imsi == imsi and ImsiTable[i].comp_ref == hdlr) { + ImsiTable[i].comp_ref := null; + ImsiTable[i].imsi := omit; + ImsiTable[i].tmsi := 'FFFFFFFF'O; + log("Removed IMSI[", i, "] for ", imsi, " to be handled at ", hdlr); + return; + } + } + setverdict(fail, "Unable to find to-be-destroyed IMSI in ImsiTable"); + mtc.stop; +} private function f_expect_table_init() runs on RAN_Emulation_CT { for (var integer i := 0; i < sizeof(ExpectTable); i := i+1) { ExpectTable[i].l3_payload := omit; - ExpectTable[i].handoverRequestPointCode := omit; + ExpectTable[i].n_connectPointCode := omit; + ExpectTable[i].sccp_cr_without_payload := false; } } @@ -1442,9 +1531,31 @@ runs on RAN_ConnHdlr { } } +/* helper function for clients to register their IMSI/TMSI */ +function f_ran_unregister_imsi(hexstring imsi) +runs on RAN_ConnHdlr { + + BSSAP_PROC.call(RAN_unregister_imsi:{imsi, self}) { + [] BSSAP_PROC.getreply(RAN_unregister_imsi:{?,?}) {}; + } +} + +/* register an expect with the BSSMAP core */ +function f_ran_register_exp(octetstring l3_enc) runs on RAN_ConnHdlr { + BSSAP_PROC.call(RAN_register:{l3_enc, self}) { + [] BSSAP_PROC.getreply(RAN_register:{?, ?}) {}; + } +} + +function f_ran_register_sccp_cr_without_payload() runs on RAN_ConnHdlr { + BSSAP_PROC.call(RAN_register_sccp_cr_without_payload:{self}) { + [] BSSAP_PROC.getreply(RAN_register_sccp_cr_without_payload:{?}) {}; + } +} + #ifdef RAN_EMULATION_RANAP /* expect a IuReleaseCommand; Confirm that; expect SCCP-level N-DISCONNET.ind */ -altstep as_iu_release_compl_disc(float t := 5.0) runs on RAN_ConnHdlr { +altstep as_iu_release_compl_disc() runs on RAN_ConnHdlr { var RANAP_PDU ranap; [] BSSAP.receive(tr_RANAP_IuReleaseCommand(?)) { BSSAP.send(ts_RANAP_IuReleaseComplete); |