ipa: Further progress on the bsc-nat test suite
diff --git a/library/BSSMAP_Emulation.ttcn b/library/BSSMAP_Emulation.ttcn
index 5cf5342..7a84133 100644
--- a/library/BSSMAP_Emulation.ttcn
+++ b/library/BSSMAP_Emulation.ttcn
@@ -4,7 +4,9 @@
import from SCCPasp_Types all;
import from BSSAP_Types all;
import from BSSMAP_Templates all;
-//import from MSC_ConnectionHandler all;
+import from MGCP_Types all;
+import from MGCP_Templates all;
+import from IPA_Emulation all;
/* General "base class" component definition, of which specific implementations
* derive themselves by means of the "extends" feature */
@@ -29,7 +31,7 @@
/* port between individual per-connection components and this dispatcher */
type port BSSAP_Conn_PT message {
- inout PDU_BSSAP, BSSAP_Conn_Prim, BSSAP_Conn_Req;
+ inout PDU_BSSAP, BSSAP_Conn_Prim, BSSAP_Conn_Req, MgcpCommand, MgcpResponse;
} with { extension "internal" };
@@ -37,7 +39,11 @@
type record ConnectionData {
/* reference to the instance of the per-connection component */
BSSAP_ConnHdlr comp_ref,
- integer sccp_conn_id
+ integer sccp_conn_id,
+ /* most recent MGCP transaction ID (Used on MSC side) */
+ MgcpTransId mgcp_trans_id optional,
+ /* CIC that has been used for voice of this channel (BSC side) */
+ integer cic optional
}
type component BSSMAP_Emulation_CT {
@@ -45,6 +51,8 @@
port SCCPasp_PT SCCP;
/* BSSAP port to the per-connection clients */
port BSSAP_Conn_PT CLIENT;
+ /* MGCP port */
+ port IPA_MGCP_PT MGCP;
/* use 16 as this is also the number of SCCP connections that SCCP_Emulation can handle */
var ConnectionData ConnectionTable[16];
@@ -85,6 +93,56 @@
self.stop;
}
+/* resolve component reference by CIC */
+private function f_comp_by_mgcp_tid(MgcpTransId tid)
+runs on BSSMAP_Emulation_CT return BSSAP_ConnHdlr {
+ var integer i;
+ for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].mgcp_trans_id == tid) {
+ return ConnectionTable[i].comp_ref;
+ }
+ }
+ log("BSSMAP Connection table not found by MGCP Transaction ID ", tid);
+ self.stop;
+}
+
+private function f_comp_store_mgcp_tid(BSSAP_ConnHdlr client, MgcpTransId tid)
+runs on BSSMAP_Emulation_CT {
+ var integer i;
+ for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].comp_ref == client) {
+ ConnectionTable[i].mgcp_trans_id := tid;
+ return;
+ }
+ }
+ log("BSSMAP Connection table not found by component ", client);
+ self.stop;
+}
+
+private function f_comp_by_cic(integer cic)
+runs on BSSMAP_Emulation_CT return BSSAP_ConnHdlr {
+ var integer i;
+ for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].cic == cic) {
+ return ConnectionTable[i].comp_ref;
+ }
+ }
+ log("BSSMAP Connection table not found by CIC ", cic);
+ self.stop;
+}
+
+private function f_comp_store_cic(BSSAP_ConnHdlr client, integer cic)
+runs on BSSMAP_Emulation_CT {
+ var integer i;
+ for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].comp_ref == client) {
+ ConnectionTable[i].cic := cic;
+ return;
+ }
+ }
+ log("BSSMAP Connection table not found by component ", client);
+}
+
/* resolve connection ID by component reference */
private function f_conn_id_by_comp(BSSAP_ConnHdlr client)
runs on BSSMAP_Emulation_CT return integer {
@@ -113,6 +171,8 @@
for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
ConnectionTable[i].comp_ref := null;
ConnectionTable[i].sccp_conn_id := -1;
+ ConnectionTable[i].mgcp_trans_id := omit;
+ ConnectionTable[i].cic := omit;
}
}
@@ -178,6 +238,8 @@
var BSSAP_Conn_Req creq;
var BSSAP_ConnHdlr vc_conn;
var PDU_BSSAP bssap;
+ var MgcpCommand mgcp_req;
+ var MgcpResponse mgcp_resp;
alt {
/* SCCP -> Client: UNIT-DATA (connectionless SCCP) from a BSC */
@@ -266,14 +328,62 @@
[] CLIENT.receive(PDU_BSSAP:?) -> value bssap sender vc_conn {
var integer conn_id := f_conn_id_by_comp(vc_conn);
+ /* MSC Side: If this is an assignment command, store CIC */
+ if (ischosen(bssap.pdu.bssmap.assignmentRequest) and
+ ispresent(bssap.pdu.bssmap.assignmentRequest.circuitIdentityCode)) {
+ var BSSMAP_IE_CircuitIdentityCode cic_ie :=
+ bssap.pdu.bssmap.assignmentRequest.circuitIdentityCode;
+ var integer cic := (oct2int(cic_ie.cicHigh) * 256) + oct2int(cic_ie.cicLow);
+ f_comp_store_cic(vc_conn, cic);
+ }
/* encode + send it to dispatcher */
var octetstring userdata := enc_PDU_BSSAP(bssap);
SCCP.send(t_ASP_N_DATA_req(userdata, conn_id, omit));
}
+ /* Handling of MGCP in IPA SCCPLite case. This predates 3GPP AoIP
+ * and uses a MGCP session in parallel to BSSAP. BSSAP uses CIC
+ * as usual, and MGCP uses "CIC@mgw" endpoint naming, where CIC
+ * is printed as hex string, e.g. a@mgw for CIC 10 */
+
+ /* CLIENT -> MGCP */
+ [] CLIENT.receive(MgcpCommand:?) -> value mgcp_req sender vc_conn {
+ /* MGCP request from Handler (we're MSC) */
+ /* store the transaction ID we've seen */
+ f_comp_store_mgcp_tid(vc_conn, mgcp_req.line.trans_id);
+ /* simply forward any MGCP from the client to the port */
+ MGCP.send(mgcp_req);
+ }
+ [] CLIENT.receive(MgcpResponse:?) -> value mgcp_resp sender vc_conn {
+ /* MGCP response from Handler (we're BSC/MGW) */
+ /* simply forward any MGCP from the client to the port */
+ MGCP.send(mgcp_resp);
+ }
+
+ /* MGCP -> CLIENT */
+ [] MGCP.receive(MgcpCommand:?) -> value mgcp_req {
+ /* MGCP request from network side (we're BSC/MGW) */
+ /* Extract CIC from local part of endpoint name */
+ var integer cic := f_mgcp_ep_extract_cic(mgcp_req.line.ep);
+ /* Resolve the vc_conn by the CIC */
+ vc_conn := f_comp_by_cic(cic);
+ CLIENT.send(mgcp_req) to vc_conn;
+ }
+ [] MGCP.receive(MgcpResponse:?) -> value mgcp_resp {
+ /* MGCP response from network side (we're MSC) */
+ /* Resolve the vc_conn by the transaction ID */
+ vc_conn := f_comp_by_mgcp_tid(mgcp_resp.line.trans_id);
+ CLIENT.send(mgcp_resp) to vc_conn;
+ }
+
}
}
}
+private function f_mgcp_ep_extract_cic(charstring inp) return integer {
+ var charstring local_part := regexp(inp, "(.*)@(.*)", 0);
+ return hex2int(str2hex(local_part));
+
+}
}
diff --git a/library/IPA_CodecPort.ttcn b/library/IPA_CodecPort.ttcn
index de47a16..3c68e22 100644
--- a/library/IPA_CodecPort.ttcn
+++ b/library/IPA_CodecPort.ttcn
@@ -18,6 +18,13 @@
octetstring msg
}
+ template IPA_Send t_IPA_Send(ConnectionId conn_id, IpaStreamId stream_id,
+ octetstring msg, template IpaExtStreamId stream_id_ext := omit) := {
+ connId := conn_id,
+ streamId := stream_id,
+ streamIdExt := stream_id_ext,
+ msg := msg
+ }
/* 'stream' contains the octets received so far, we must return the total length */
function f_IPA_getMsgLen(in octetstring stream, inout ro_integer args) return integer {
diff --git a/library/IPA_Emulation.ttcn b/library/IPA_Emulation.ttcn
index 57edb00..3b8d931 100644
--- a/library/IPA_Emulation.ttcn
+++ b/library/IPA_Emulation.ttcn
@@ -7,6 +7,8 @@
import from MTP3asp_Types all;
import from MTP3asp_PortType all;
+import from MGCP_Types all;
+
/*
modulepar {
}
@@ -19,7 +21,7 @@
type record ASP_IPA_Unitdata {
IpaStreamId streamId,
- IpaStreamIdExt streamIdExt optional,
+ IpaExtStreamId streamIdExt optional,
octetstring payload
}
@@ -27,16 +29,24 @@
inout ASP_IPA_Unitdata;
} with { extension "internal" }
+type port IPA_MGCP_PT message {
+ inout MgcpCommand, MgcpResponse;
+} with { extension "internal" }
+
type component IPA_Emulation_CT {
/* down-facing port to IPA codec port */
port IPA_CODEC_PT IPA_PORT;
/* up-facing port to SCCP */
port MTP3asp_SP_PT MTP3_SP_PORT;
+ /* up-facing port for MGCP */
+ port IPA_MGCP_PT IPA_MGCP_PORT;
/* up-facing port for other streams */
port IPA_SP_PT IPA_SP_PORT;
var boolean g_initialized := false;
var ConnectionId g_ipa_conn_id := -1;
+ /* Are we a BSC/MGW (truel) or MSC (false) */
+ var boolean g_is_bsc_mgw;
var IpaMode g_mode;
}
@@ -47,6 +57,7 @@
res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
local_host, local_port, 0, { tcp:={} });
g_ipa_conn_id := res.connId;
+ g_is_bsc_mgw := true;
}
function f_bind(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
@@ -54,6 +65,7 @@
res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
local_host, local_port, { tcp:={} });
g_ipa_conn_id := res.connId;
+ g_is_bsc_mgw := false;
}
template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
@@ -103,12 +115,7 @@
/* transmit IPA CCM message */
private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
- var IPA_Send ipa_tx := {
- connId := g_ipa_conn_id,
- streamId := IPAC_PROTO_CCM,
- streamIdExt := omit,
- msg := enc_PDU_IPA_CCM(ccm)
- }
+ var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_CCM, enc_PDU_IPA_CCM(ccm)));
log("CCM Tx:", ccm);
IPA_PORT.send(ipa_tx);
}
@@ -160,12 +167,8 @@
}
private function f_from_asp(ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
- var IPA_Send ret := {
- connId := connId,
- streamId := ipa_tx.streamId,
- streamIdExt := ipa_tx.streamIdExt,
- msg := ipa_tx.payload
- }
+ var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
+ ipa_tx.streamIdExt));
return ret;
}
@@ -182,11 +185,24 @@
ScanEvents();
}
+private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
+ var charstring msg_ch := oct2char(msg);
+ if (g_is_bsc_mgw) {
+ log("============");
+ log(msg_ch);
+ IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
+ } else {
+ IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
+ }
+}
+
private function ScanEvents() runs on IPA_Emulation_CT {
var IPA_RecvFrom ipa_rx;
var ASP_IPA_Unitdata ipa_ud;
var ASP_MTP3_TRANSFERreq mtp_req;
var ASP_Event asp_evt;
+ var MgcpCommand mgcp_cmd;
+ var MgcpResponse mgcp_rsp;
while (true) {
alt {
@@ -197,13 +213,21 @@
var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
log("CCM Rx:", ccm);
f_ccm_rx(ccm);
- }
- case (IPAC_PROTO_SCCP) {
+ } case (IPAC_PROTO_SCCP) {
var ASP_MTP3_TRANSFERind mtp;
mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
MTP3_SP_PORT.send(mtp);
+ } case (IPAC_PROTO_MGCP_OLD) {
+ f_mgcp_to_user(ipa_rx.msg);
+ } case (IPAC_PROTO_OSMO) {
+ select (ipa_rx.streamIdExt) {
+ case (IPAC_PROTO_EXT_MGCP) {
+ f_mgcp_to_user(ipa_rx.msg);
+ } case else {
+ IPA_SP_PORT.send(f_to_asp(ipa_rx));
+ }
}
- case else {
+ } case else {
IPA_SP_PORT.send(f_to_asp(ipa_rx));
}
}
@@ -226,15 +250,31 @@
/* Received SCCP -> down into IPA */
[] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
- var IPA_Send ipa_tx := {
- connId := g_ipa_conn_id,
- streamId := IPAC_PROTO_SCCP,
- msg := mtp_req.data
- }
+ var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
+ mtp_req.data));
IPA_PORT.send(ipa_tx);
}
- /* Received MISC (RSL/OML/CTRL/MGCP) -> down into IPA */
+ /* Received MGCP -> down into IPA */
+ [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
+ ipa_ud := {
+ streamId := IPAC_PROTO_OSMO,
+ streamIdExt := IPAC_PROTO_EXT_MGCP,
+ payload := char2oct(enc_MgcpCommand(mgcp_cmd))
+ }
+ IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
+ }
+ [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
+ ipa_ud := {
+ streamId := IPAC_PROTO_OSMO,
+ streamIdExt := IPAC_PROTO_EXT_MGCP,
+ payload := char2oct(enc_MgcpResponse(mgcp_rsp))
+ }
+ IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
+ }
+
+
+ /* Received MISC (RSL/OML/CTRL) -> down into IPA */
[] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
}
diff --git a/library/MGCP_Templates.ttcn b/library/MGCP_Templates.ttcn
index f78bfc7..30a5c8e 100644
--- a/library/MGCP_Templates.ttcn
+++ b/library/MGCP_Templates.ttcn
@@ -102,6 +102,16 @@
return cmd;
}
+ template MgcpResponse tr_DLCX_ACK := {
+ line := {
+ code := "200",
+ trans_id := ?,
+ string := "OK"
+ },
+ params:= *,
+ sdp := *
+ }
+
/* SDP Templates */
template SDP_Origin ts_SDP_origin(charstring addr, charstring session_id,
charstring session_version := "1",