aboutsummaryrefslogtreecommitdiffstats
path: root/library/RAN_Emulation.ttcnpp
diff options
context:
space:
mode:
Diffstat (limited to 'library/RAN_Emulation.ttcnpp')
-rw-r--r--library/RAN_Emulation.ttcnpp227
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);