aboutsummaryrefslogtreecommitdiffstats
path: root/mgw
diff options
context:
space:
mode:
Diffstat (limited to 'mgw')
-rw-r--r--mgw/MGCP_Test.default13
-rw-r--r--mgw/MGCP_Test.ttcn1685
-rw-r--r--mgw/README.md9
-rw-r--r--mgw/RTP_CodecPort_CtrlFunct.ttcn44
-rw-r--r--mgw/RTP_CodecPort_CtrlFunctDef.cc56
-rw-r--r--mgw/expected-results.xml62
-rwxr-xr-xmgw/gen_links.sh8
-rw-r--r--mgw/osmo-mgw.cfg38
-rwxr-xr-xmgw/regen_makefile.sh29
9 files changed, 1594 insertions, 350 deletions
diff --git a/mgw/MGCP_Test.default b/mgw/MGCP_Test.default
index 4336033d..54bf9afe 100644
--- a/mgw/MGCP_Test.default
+++ b/mgw/MGCP_Test.default
@@ -11,12 +11,21 @@ FileMask := LOG_ALL | TTCN_MATCHING;
*.MGWVTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes"
*.MGWVTY.CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT := "yes"
*.MGWVTY.PROMPT1 := "OsmoMGW> "
+*.STATSVTY.CTRL_MODE := "client"
+*.STATSVTY.CTRL_HOSTNAME := "127.0.0.1"
+*.STATSVTY.CTRL_PORTNUM := "4243"
+*.STATSVTY.CTRL_LOGIN_SKIPPED := "yes"
+*.STATSVTY.CTRL_DETECT_SERVER_DISCONNECTED := "yes"
+*.STATSVTY.CTRL_READMODE := "buffered"
+*.STATSVTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes"
+*.STATSVTY.CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT := "yes"
+*.STATSVTY.PROMPT1 := "OsmoMGW> "
[MODULE_PARAMETERS]
mp_local_udp_port := 2727;
-mp_local_ip:= "127.0.0.1";
+mp_local_ipv4:= "127.0.0.1";
mp_remote_udp_port := 2427;
-mp_remote_ip:= "127.0.0.1";
+mp_remote_ipv4:= "127.0.0.1";
Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoMGW";
[MAIN_CONTROLLER]
diff --git a/mgw/MGCP_Test.ttcn b/mgw/MGCP_Test.ttcn
index 7ddb6ea6..7090b340 100644
--- a/mgw/MGCP_Test.ttcn
+++ b/mgw/MGCP_Test.ttcn
@@ -10,19 +10,23 @@
*/
module MGCP_Test {
+ import from Misc_Helpers all;
import from Osmocom_Types all;
import from MGCP_Types all;
import from MGCP_Templates all;
import from SDP_Types all;
+ import from SDP_Templates all;
import from MGCP_CodecPort all;
import from MGCP_CodecPort_CtrlFunct all;
import from RTP_CodecPort all;
import from RTP_CodecPort_CtrlFunct all;
import from RTP_Emulation all;
+ import from IuUP_Emulation all;
import from OSMUX_Types all;
import from OSMUX_CodecPort all;
import from OSMUX_CodecPort_CtrlFunct all;
import from OSMUX_Emulation all;
+ import from AMR_Types all;
import from IPL4asp_Types all;
import from General_Types all;
import from Native_Functions all;
@@ -30,6 +34,13 @@ module MGCP_Test {
import from IP_Types all;
import from Osmocom_VTY_Functions all;
import from TELNETasp_PortType all;
+ import from StatsD_Types all;
+ import from StatsD_CodecPort all;
+ import from StatsD_CodecPort_CtrlFunct all;
+ import from StatsD_Checker all;
+ import from Osmocom_CTRL_Functions all;
+ import from Osmocom_CTRL_Types all;
+ import from Osmocom_CTRL_Adapter all;
const charstring c_mgw_domain := "mgw";
const charstring c_mgw_ep_rtpbridge := "rtpbridge/";
@@ -37,7 +48,7 @@ module MGCP_Test {
/* any variables declared in the component will be available to
* all functions that 'run on' the named component, similar to
* class members in C++ */
- type component dummy_CT {
+ type component dummy_CT extends StatsD_ConnHdlr, CTRL_Adapter_CT {
port MGCP_CODEC_PT MGCP;
var boolean initialized := false;
var ConnectionId g_mgcp_conn_id := -1;
@@ -50,6 +61,8 @@ module MGCP_Test {
port OsmuxEM_CTRL_PT OsmuxEM;
port TELNETasp_PT MGWVTY;
+
+ var StatsD_Checker_CT vc_STATSD;
};
function get_next_trans_id() runs on dummy_CT return MgcpTransId {
@@ -64,15 +77,17 @@ module MGCP_Test {
* default values assigned below are used */
modulepar {
PortNumber mp_local_udp_port := 2727;
- charstring mp_local_ip := "127.0.0.1";
+ charstring mp_local_ipv4 := "127.0.0.1";
+ charstring mp_local_ipv6 := "::1";
PortNumber mp_remote_udp_port := 2427;
- charstring mp_remote_ip := "127.0.0.1";
+ charstring mp_remote_ipv4 := "127.0.0.1";
+ charstring mp_remote_ipv6 := "::1";
PortNumber mp_local_rtp_port_base := 10000;
PortNumber mp_local_osmux_port := 1985;
-
- /* Whether to enable conn-timeout tests. Can be dropped completely and enabled unconditionally once new
- * version of osmo-mgw is released (current version: 1.5.0) */
- boolean mp_enable_conn_timeout_test := true;
+ PortNumber mp_mgw_statsd_port := 8125;
+ PortNumber mp_mgw_ctrl_port := 4267;
+ /* Maximum number of available endpoints in osmo-mgw.cfg ("number endpoints"): */
+ integer mp_num_endpoints := 300;
}
private function f_vty_enable_osmux(boolean osmux_on) runs on dummy_CT {
@@ -95,9 +110,6 @@ module MGCP_Test {
f_vty_transceive(MGWVTY, "enable");
f_vty_enable_osmux(osmux_on);
- if (mp_enable_conn_timeout_test) {
- f_vty_config(MGWVTY, "mgcp", "conn-timeout 0");
- }
}
private function f_rtpem_init(inout RTP_Emulation_CT comp_ref, integer i)
@@ -131,7 +143,7 @@ module MGCP_Test {
/* connect the MGCP test port using the given
* source/destionation ip/port and store the connection id in g_mgcp_conn_id
* */
- res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, mp_remote_ip, mp_remote_udp_port, mp_local_ip, mp_local_udp_port, 0, { udp := {} });
+ res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, mp_remote_ipv4, mp_remote_udp_port, mp_local_ipv4, mp_local_udp_port, 0, { udp := {} });
if (not ispresent(res.connId)) {
setverdict(fail, "Could not connect MGCP, check your configuration");
mtc.stop;
@@ -146,8 +158,15 @@ module MGCP_Test {
f_osmuxem_init(vc_OsmuxEM);
connect(vc_OsmuxEM:CTRL, self:OsmuxEM);
}
+
+ f_init_statsd("VirtCallAgent", vc_STATSD, mp_local_ipv4, mp_mgw_statsd_port);
+ connect(self:STATSD_PROC, vc_STATSD:STATSD_PROC);
+
+ f_statsd_reset();
}
+ f_ipa_ctrl_start_client(mp_remote_ipv4, mp_mgw_ctrl_port);
+
if (isvalue(ep)) {
/* do a DLCX on all connections of the EP */
f_dlcx_ignore(valueof(ep));
@@ -231,9 +250,9 @@ module MGCP_Test {
function tr_MGCP_RecvFrom_R(template MgcpResponse resp) runs on dummy_CT return template MGCP_RecvFrom {
var template MGCP_RecvFrom mrf := {
connId := g_mgcp_conn_id,
- remName := mp_remote_ip,
+ remName := mp_remote_ipv4,
remPort := mp_remote_udp_port,
- locName := mp_local_ip,
+ locName := mp_local_ipv4,
locPort := mp_local_udp_port,
msg := { response := resp }
}
@@ -318,18 +337,100 @@ module MGCP_Test {
charstring hostname,
integer portnr optional
}
+ type record RtpOsmuxFlowData {
+ boolean local_cid_sent, /* whther non wildcarded CID was already sent to MGW */
+ MgcpOsmuxCID local_cid optional,
+ MgcpOsmuxCID remote_cid optional,
+ OsmuxemConfig cfg optional
+ }
+ type record RtpCodecDescr {
+ uint7_t pt,
+ charstring codec,
+ charstring fmtp optional
+ }
type record RtpFlowData {
HostPort em, /* emulation side */
HostPort mgw, /* mgw side */
- uint7_t pt,
- charstring codec,
MgcpConnectionId mgcp_conn_id optional,
+ record of RtpCodecDescr codec_descr,
RtpemConfig rtp_cfg optional,
- boolean osmux_cid_sent, /* whther non wildcarded CID was already sent to MGW */
- MgcpOsmuxCID osmux_cid optional,
- MgcpOsmuxCID osmux_cid_response optional,
- OsmuxemConfig osmux_cfg optional,
- charstring fmtp optional
+ RtpOsmuxFlowData osmux
+ }
+
+ template RtpFlowData t_RtpFlow(charstring host_a, charstring host_b, uint7_t pt,
+ charstring codec, template charstring fmtp := omit) := {
+ em := {
+ hostname := host_a,
+ portnr := omit
+ },
+ mgw := {
+ hostname := host_b,
+ portnr := omit
+ },
+ codec_descr := {{
+ pt := pt,
+ codec := codec,
+ fmtp := fmtp
+ }},
+ osmux:= {
+ local_cid_sent := false,
+ local_cid := omit,
+ remote_cid := omit,
+ cfg := omit
+ }
+ }
+
+ /* To be used with f_flow_create/modify... functions */
+ function f_gen_sdp(RtpFlowData flow) runs on dummy_CT return SDP_Message {
+ var template SDP_Message sdp;
+ var SDP_fmt_list fmt_list := {};
+ var SDP_attribute_list attributes := {};
+
+ /* Add SDP RTMAP attributes (codec type, referenced by PT) */
+ for (var integer i := 0; i < lengthof(flow.codec_descr); i := i + 1) {
+ attributes := attributes & { valueof(ts_SDP_rtpmap(flow.codec_descr[i].pt,
+ flow.codec_descr[i].codec)) };
+ }
+
+ /* Add SDP PTIME attribute, regardless of which codec, the packet intervall remains the same */
+ attributes := attributes & { valueof(ts_SDP_ptime(20)) };
+
+ /* Add SDP FMTP attributes (codec parameters for each codec, referenced by PT) */
+ for (var integer i := 0; i < lengthof(flow.codec_descr); i := i + 1) {
+ if (isvalue(flow.codec_descr[i].fmtp) and flow.codec_descr[i].fmtp != "") {
+ attributes := attributes & { valueof(ts_SDP_fmtp(flow.codec_descr[i].pt,
+ flow.codec_descr[i].fmtp)) };
+ }
+ }
+
+ /* Final step: Generate SDP */
+ for (var integer i := 0; i < lengthof(flow.codec_descr); i := i + 1) {
+ fmt_list := fmt_list & {int2str(flow.codec_descr[i].pt)};
+ }
+ sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42", flow.em.portnr, fmt_list, attributes);
+
+ return valueof(sdp);
+ }
+
+ /* Generate a valid RTP emulation config from the payload type numbers configured in the flow description and
+ * the the default configuration of the RTP emulation module. */
+ function f_gen_rtpem_config_from_flow(RtpFlowData flow) return RtpemConfig {
+ var RtpemConfig rtp_cfg := c_RtpemDefaultCfg;
+
+ for (var integer i := 0; i < lengthof(flow.codec_descr); i := i + 1) {
+ var RtpemConfigPayload tx_cfg_payload;
+ var RtpemConfigPayload rx_cfg_payload;
+
+ tx_cfg_payload.payload_type := flow.codec_descr[i].pt;
+ tx_cfg_payload.fixed_payload := c_RtpemDefaultCfg.tx_payloads[0].fixed_payload;
+ rx_cfg_payload.payload_type := flow.codec_descr[i].pt;
+ rx_cfg_payload.fixed_payload := c_RtpemDefaultCfg.rx_payloads[0].fixed_payload;
+
+ rtp_cfg.tx_payloads := rtp_cfg.tx_payloads & {tx_cfg_payload};
+ rtp_cfg.rx_payloads := rtp_cfg.rx_payloads & {rx_cfg_payload};
+ }
+
+ return rtp_cfg;
}
/* Create an RTP flow (bidirectional, or receive-only) */
@@ -338,12 +439,6 @@ module MGCP_Test {
runs on dummy_CT {
var template MgcpCommand cmd;
var MgcpResponse resp;
- var SDP_attribute_list attributes;
-
- attributes := { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)), valueof(ts_SDP_ptime(20)) };
- if (isvalue(flow.fmtp)) {
- attributes := attributes & { valueof(ts_SDP_fmtp(flow.pt, flow.fmtp)) };
- }
/* bind local RTP emulation socket */
f_rtpem_bind(pt, flow.em.hostname, flow.em.portnr);
@@ -352,9 +447,7 @@ module MGCP_Test {
if (ispresent(flow.rtp_cfg)) {
f_rtpem_configure(pt, flow.rtp_cfg);
} else {
- var RtpemConfig rtp_cfg := c_RtpemDefaultCfg;
- rtp_cfg.tx_payload_type := flow.pt
- f_rtpem_configure(pt, rtp_cfg);
+ f_rtpem_configure(pt, f_gen_rtpem_config_from_flow(flow));
}
if (one_phase) {
@@ -364,8 +457,7 @@ module MGCP_Test {
* one go. */
cmd := ts_CRCX(get_next_trans_id(), ep, mode, call_id);
- cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",
- flow.em.portnr, { int2str(flow.pt) }, attributes);
+ cmd.sdp := f_gen_sdp(flow);
resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
flow.mgcp_conn_id := extract_conn_id(resp);
@@ -396,27 +488,21 @@ module MGCP_Test {
runs on dummy_CT {
var template MgcpCommand cmd;
var MgcpResponse resp;
- var SDP_attribute_list attributes;
var OsmuxTxHandle tx_hdl;
var OsmuxRxHandle rx_hdl;
var charstring cid_response;
var OsmuxCID cid_resp_parsed
- attributes := { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)), valueof(ts_SDP_ptime(20)) };
- if (isvalue(flow.fmtp)) {
- attributes := attributes & { valueof(ts_SDP_fmtp(flow.pt, flow.fmtp)) };
- }
-
/* bind local Osmux emulation socket */
f_osmuxem_bind(pt, flow.em.hostname, flow.em.portnr);
/* configure osmux-emulation */
- if (ispresent(flow.osmux_cfg)) {
- f_osmuxem_configure(pt, flow.osmux_cfg);
+ if (ispresent(flow.osmux.cfg)) {
+ f_osmuxem_configure(pt, flow.osmux.cfg);
} else {
var OsmuxemConfig osmux_cfg := c_OsmuxemDefaultCfg;
f_osmuxem_configure(pt, osmux_cfg);
- flow.osmux_cfg := osmux_cfg
+ flow.osmux.cfg := osmux_cfg
}
if (one_phase) {
@@ -424,13 +510,15 @@ module MGCP_Test {
* part that tells the MGW where we are listening for Osmux streams
* that come from the MGW. We get a fully working connection in
* one go. */
- rx_hdl := c_OsmuxemDefaultRxHandle;
- rx_hdl.cid := flow.osmux_cid;
- f_osmuxem_register_rxhandle(pt, rx_hdl);
- flow.osmux_cid_sent := true;
- cmd := ts_CRCX_osmux(get_next_trans_id(), ep, mode, call_id, flow.osmux_cid);
- cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",
- flow.em.portnr, { int2str(flow.pt) }, attributes);
+ if (flow.osmux.local_cid != -1) {
+ /* We may still want to negotiate osmux CID later at MDCX */
+ rx_hdl := c_OsmuxemDefaultRxHandle;
+ rx_hdl.cid := flow.osmux.local_cid;
+ f_osmuxem_register_rxhandle(pt, rx_hdl);
+ flow.osmux.local_cid_sent := true;
+ }
+ cmd := ts_CRCX_osmux(get_next_trans_id(), ep, mode, call_id, flow.osmux.local_cid);
+ cmd.sdp := f_gen_sdp(flow);
resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK_osmux);
flow.mgcp_conn_id := extract_conn_id(resp);
/* extract port number from response */
@@ -443,7 +531,7 @@ module MGCP_Test {
* data back to us. In order to turn the connection in a fully
* bi-directional one, a separate MDCX is needed. */
- cmd := ts_CRCX_osmux(get_next_trans_id(), ep, mode, call_id, flow.osmux_cid);
+ cmd := ts_CRCX_osmux(get_next_trans_id(), ep, mode, call_id, flow.osmux.local_cid);
resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK_osmux);
flow.mgcp_conn_id := extract_conn_id(resp);
@@ -463,12 +551,12 @@ module MGCP_Test {
}
/* Make sure response is no wildcard */
- flow.osmux_cid_response := f_mgcp_osmux_cid_decode(cid_response);
- if (flow.osmux_cid_response == -1) {
+ flow.osmux.remote_cid := f_mgcp_osmux_cid_decode(cid_response);
+ if (flow.osmux.remote_cid == -1) {
setverdict(fail, "Osmux CID in MGCP response contains unexpected wildcard");
mtc.stop;
}
- tx_hdl := valueof(t_TxHandleAMR590(flow.osmux_cid_response));
+ tx_hdl := valueof(t_TxHandleAMR590(flow.osmux.remote_cid));
f_osmuxem_register_txhandle(pt, tx_hdl);
/* finally, connect the emulation-side RTP socket to the MGW */
@@ -480,12 +568,6 @@ module MGCP_Test {
runs on dummy_CT {
var template MgcpCommand cmd;
var MgcpResponse resp;
- var SDP_attribute_list attributes;
-
- attributes := { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)), valueof(ts_SDP_ptime(20)) };
- if (isvalue(flow.fmtp)) {
- attributes := attributes & { valueof(ts_SDP_fmtp(flow.pt, flow.fmtp)) };
- }
/* rebind local RTP emulation socket to the new address */
f_rtpem_bind(pt, flow.em.hostname, flow.em.portnr);
@@ -494,15 +576,12 @@ module MGCP_Test {
if (ispresent(flow.rtp_cfg)) {
f_rtpem_configure(pt, flow.rtp_cfg);
} else {
- var RtpemConfig rtp_cfg := c_RtpemDefaultCfg;
- rtp_cfg.tx_payload_type := flow.pt
- f_rtpem_configure(pt, rtp_cfg);
+ f_rtpem_configure(pt, f_gen_rtpem_config_from_flow(flow));
}
/* connect MGW side RTP socket to the emulation-side RTP socket using SDP */
cmd := ts_MDCX(get_next_trans_id(), ep, mode, call_id, flow.mgcp_conn_id);
- cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",
- flow.em.portnr, { int2str(flow.pt) }, attributes);
+ cmd.sdp := f_gen_sdp(flow);
resp := mgcp_transceive_mgw(cmd, tr_MDCX_ACK);
/* extract MGW-side port number from response. (usually this
@@ -519,39 +598,32 @@ module MGCP_Test {
runs on dummy_CT {
var template MgcpCommand cmd;
var MgcpResponse resp;
- var SDP_attribute_list attributes;
var OsmuxRxHandle rx_hdl;
var charstring cid_response;
var OsmuxCID cid_resp_parsed
- attributes := { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)), valueof(ts_SDP_ptime(20)) };
- if (isvalue(flow.fmtp)) {
- attributes := attributes & { valueof(ts_SDP_fmtp(flow.pt, flow.fmtp)) };
- }
-
/* rebind local Osmux emulation socket to the new address */
f_osmuxem_bind(pt, flow.em.hostname, flow.em.portnr);
/* configure osmux-emulation */
- if (ispresent(flow.osmux_cfg)) {
- f_osmuxem_configure(pt, flow.osmux_cfg);
+ if (ispresent(flow.osmux.cfg)) {
+ f_osmuxem_configure(pt, flow.osmux.cfg);
} else {
var OsmuxemConfig osmux_cfg := c_OsmuxemDefaultCfg;
f_osmuxem_configure(pt, osmux_cfg);
}
/* We didn't send a non-wildcarded Osmux CID yet. If caller wants to submit it, register handler */
- if (flow.osmux_cid_sent == false and flow.osmux_cid != -1) {
+ if (flow.osmux.local_cid_sent == false and flow.osmux.local_cid != -1) {
rx_hdl := c_OsmuxemDefaultRxHandle;
- rx_hdl.cid := flow.osmux_cid;
+ rx_hdl.cid := flow.osmux.local_cid;
f_osmuxem_register_rxhandle(pt, rx_hdl);
- flow.osmux_cid_sent := true;
+ flow.osmux.local_cid_sent := true;
}
/* connect MGW side Osmux socket to the emulation-side Osmux socket using SDP */
- cmd := ts_MDCX_osmux(get_next_trans_id(), ep, mode, call_id, flow.mgcp_conn_id, flow.osmux_cid);
- cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",
- flow.em.portnr, { int2str(flow.pt) }, attributes);
+ cmd := ts_MDCX_osmux(get_next_trans_id(), ep, mode, call_id, flow.mgcp_conn_id, flow.osmux.local_cid);
+ cmd.sdp := f_gen_sdp(flow);
resp := mgcp_transceive_mgw(cmd, tr_MDCX_ACK);
/* extract MGW-side port number from response. (usually this
@@ -575,7 +647,7 @@ module MGCP_Test {
setverdict(fail, "Osmux CID in MGCP response contains unexpected wildcard");
mtc.stop;
}
- if (cid_resp_parsed != flow.osmux_cid_response) {
+ if (cid_resp_parsed != flow.osmux.remote_cid) {
setverdict(fail, "Osmux CID in MGCP MDCX response changed from prev value");
mtc.stop;
}
@@ -616,6 +688,18 @@ module MGCP_Test {
}
}
+ /* Send an AuditEndpoint message to the MGW */
+ function f_auep(charstring ep_prefix) runs on dummy_CT {
+ var MgcpEndpoint ep := ep_prefix & "@" & c_mgw_domain;
+ var template MgcpCommand cmd;
+ var MgcpResponse resp;
+
+ f_init(ep);
+
+ cmd := ts_AUEP(get_next_trans_id(), ep);
+ resp := mgcp_transceive_mgw(cmd, tr_AUEP_ACK);
+ }
+
function f_crcx(charstring ep_prefix) runs on dummy_CT {
var MgcpEndpoint ep := ep_prefix & "2@" & c_mgw_domain;
var template MgcpCommand cmd;
@@ -701,6 +785,12 @@ module MGCP_Test {
f_dlcx_ok(ep, call_id);
}
+ /* test valid AUEP towards "null" endpoint */
+ testcase TC_auep_null() runs on dummy_CT {
+ f_auep("null");
+ setverdict(pass);
+ }
+
/* test valid CRCX without SDP */
testcase TC_crcx() runs on dummy_CT {
f_crcx(c_mgw_ep_rtpbridge);
@@ -734,6 +824,35 @@ module MGCP_Test {
setverdict(pass);
}
+ /* Test CRCX with X-Osmo-IGN, using same message as SYS#5063 to make sure it doesn't cause a crash. */
+ testcase TC_crcx_osmo_ign() runs on dummy_CT {
+ var template MgcpCommand cmd;
+ var MgcpResponse resp;
+ var MgcpEndpoint ep := "7@" & c_mgw_domain;
+ var MgcpCallId call_id := '3'H;
+
+ f_init(ep);
+
+ /* CRCX 1 7@mgw MGCP 1.0
+ C: 3
+ L: p:20, a:GSM-EFR, nt:IN
+ M: recvonly
+ X-Osmo-IGN: C
+ */
+
+ cmd := ts_CRCX(get_next_trans_id(), ep, "netwtest", call_id);
+ cmd.params := {ts_MgcpParCallId(call_id),
+ t_MgcpParLocConnOpt("p:20, a:GSM-EFR, nt:IN"),
+ t_MgcpParConnMode("recvonly"),
+ t_MgcpParOsmoIGN("C")};
+ resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ extract_conn_id(resp);
+
+ /* clean-up */
+ f_dlcx_ok(ep, call_id);
+ setverdict(pass);
+ }
+
/* test CRCX with early bi-directional mode, expect 527 as
* bi-diretional media can only be established once both local and
* remote side are specified, see MGCP RFC */
@@ -891,18 +1010,19 @@ module MGCP_Test {
}
/* test valid wildcarded CRCX */
+ type record of MgcpEndpoint MgcpEndpointList;
testcase TC_crcx_wildcarded_exhaust() runs on dummy_CT {
- const integer n_endpoints := 32;
var integer i;
var template MgcpCommand cmd;
var MgcpResponse resp;
var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
var MgcpCallId call_id := '1234'H;
- var MgcpEndpoint ep_assigned[n_endpoints];
+ var MgcpEndpoint ep_assigned;
+ var MgcpEndpointList ep_assigned_li := {};
f_init();
/* Exhaust all endpoint resources on the virtual trunk */
- for (i := 0; i < n_endpoints; i := i+1) {
+ for (i := 0; i < mp_num_endpoints; i := i+1) {
cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
@@ -912,10 +1032,11 @@ module MGCP_Test {
var MgcpMessage resp_msg := {
response := resp
}
- if (f_mgcp_find_param(resp_msg, "Z", ep_assigned[i]) == false) {
+ if (f_mgcp_find_param(resp_msg, "Z", ep_assigned) == false) {
setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
mtc.stop;
}
+ ep_assigned_li := ep_assigned_li & {ep_assigned}
}
/* Try to allocate one more endpoint, which should fail */
@@ -925,8 +1046,8 @@ module MGCP_Test {
setverdict(pass);
/* clean-up */
- for (i := 0; i < n_endpoints; i := i+1) {
- f_dlcx_ok(ep_assigned[i], call_id);
+ for (i := 0; i < mp_num_endpoints; i := i+1) {
+ f_dlcx_ok(ep_assigned_li[i], call_id);
}
setverdict(pass);
}
@@ -986,6 +1107,28 @@ module MGCP_Test {
setverdict(pass);
}
+ /* DLCX to non existing endpoint */
+ testcase TC_dlcx_non_existant_ep() runs on dummy_CT {
+ var template MgcpCommand cmd;
+ var MgcpResponse resp;
+ var charstring non_existant_ep := hex2str(int2hex(mp_num_endpoints + 1, 4))
+ var MgcpEndpoint ep := c_mgw_ep_rtpbridge & non_existant_ep & "@" & c_mgw_domain;
+ var template MgcpResponse rtmpl := {
+ line := {
+ code := ("500"),
+ string := ?
+ },
+ params:= { },
+ sdp := omit
+ };
+
+ f_init(ep);
+
+ cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
+ resp := mgcp_transceive_mgw(cmd, rtmpl);
+ setverdict(pass);
+ }
+
/* test valid wildcarded MDCX */
testcase TC_mdcx_wildcarded() runs on dummy_CT {
/* Note: A wildcarded MDCX is not allowed, so we expect the
@@ -1016,25 +1159,53 @@ module MGCP_Test {
/* test valid wildcarded DLCX */
testcase TC_dlcx_wildcarded() runs on dummy_CT {
- /* Note: A wildcarded DLCX is specified, but our MGW does not
- * support this feature so we expect the MGW to reject the
- * request */
var template MgcpCommand cmd;
var MgcpResponse resp;
var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
+ var integer i;
+ var MgcpCallId call_id := '1234'H;
+ var StatsDExpects expect;
+ f_init(ep);
+
+ /* Allocate a few endpoints */
+ for (i := 0; i < mp_num_endpoints; i := i+1) {
+ cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
+ resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ }
+
+ /* Wait until the stats items have seteled and then check if we get the expected number (all) of
+ * occupied endpoints */
+ f_sleep(1.0)
+ expect := {
+ { name := "TTCN3.trunk.virtual-0.common.endpoints.used", mtype := "g", min := mp_num_endpoints, max := mp_num_endpoints}
+ };
+ f_statsd_expect(expect);
+
+ /* Send wildcarded DLCX */
var template MgcpResponse rtmpl := {
line := {
- code := "507",
+ code := "200",
string := ?
},
params:= { },
sdp := omit
};
+ cmd := ts_DLCX(get_next_trans_id(), ep);
+ mgcp_transceive_mgw(cmd, rtmpl);
- f_init(ep);
+ /* Query a the statsd once to ensure that intermediate results are pulled from the
+ * pipeline. The second query (below) will return the actual result. */
+ expect := {
+ { name := "TTCN3.trunk.virtual-0.common.endpoints.used", mtype := "g", min := 0, max := mp_num_endpoints}
+ };
+ f_statsd_expect(expect);
+
+ /* The second query must resturn a result with 0 endpoints in use. */
+ expect := {
+ { name := "TTCN3.trunk.virtual-0.common.endpoints.used", mtype := "g", min := 0, max := 0}
+ };
+ f_statsd_expect(expect);
- cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
- resp := mgcp_transceive_mgw(cmd, rtmpl);
setverdict(pass);
}
@@ -1074,6 +1245,51 @@ module MGCP_Test {
setverdict(pass);
}
+ /* test Creating 257 concurrent osmux conns. It should fail since maximum is 256. */
+ testcase TC_crcx_osmux_257() runs on dummy_CT {
+ var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
+ var template MgcpCommand cmd;
+ var MgcpResponse resp;
+ var charstring cid_response;
+ var integer i;
+
+ f_init(ep, true);
+
+ for (i := 0; i < 256; i := i + 1) {
+
+ cmd := ts_CRCX_osmux(get_next_trans_id(), ep, "recvonly", int2hex(i, 4), -1);
+ resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK_osmux);
+ extract_conn_id(resp);
+
+ /* extract Osmux CID we got assigned by the MGW */
+ var MgcpMessage resp_msg := {
+ response := resp
+ }
+
+ if (f_mgcp_find_param(resp_msg, "X-OSMUX", cid_response) == false) {
+ setverdict(fail, "No Osmux CID in MGCP response", resp);
+ mtc.stop;
+ }
+
+ /* Make sure response is no wildcard */
+ if (f_mgcp_osmux_cid_decode(cid_response) == -1) {
+ setverdict(fail, "Osmux CID in MGCP response contains unexpected wildcard");
+ mtc.stop;
+ }
+ }
+
+ /* Now conn num 257, it should fail due to all Osmux conns already allocated: */
+ cmd := ts_CRCX_osmux(get_next_trans_id(), ep, "recvonly", int2hex(i, 4), -1);
+ resp := mgcp_transceive_mgw(cmd, tr_MgcpResp_Err("400"));
+
+ setverdict(pass);
+
+ /* Clean up */
+ for (i := 0; i < 256; i := i + 1) {
+ f_dlcx_ok(ep, int2hex(i, 4));
+ }
+ }
+
/* Create one half open connection in receive-only mode. The MGW must accept
* the packets but must not send any. */
testcase TC_one_crcx_receive_only_osmux() runs on dummy_CT {
@@ -1084,9 +1300,9 @@ module MGCP_Test {
var OsmuxTxHandle tx_hdl;
f_init(ep, true);
- flow := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 112, "AMR/8000/1"));
+ flow := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 112, "AMR/8000/1"));
flow.em.portnr := mp_local_osmux_port;
- flow.osmux_cid := -1;
+ flow.osmux.local_cid := -1;
f_flow_create_osmux(OsmuxEM, ep, call_id, "recvonly", flow, false);
/* create a transmitter not yet known by MGW */
@@ -1099,10 +1315,10 @@ module MGCP_Test {
stats := f_osmuxem_stats_get(OsmuxEM);
- if (stats.num_pkts_tx < 40 / flow.osmux_cfg.batch_size) {
+ if (stats.num_pkts_tx < 40 / flow.osmux.cfg.batch_size) {
setverdict(fail);
}
- if (stats.bytes_payload_tx < stats.num_pkts_tx * f_amrft_payload_len(tx_hdl.amr_ft) * flow.osmux_cfg.batch_size) {
+ if (stats.bytes_payload_tx < stats.num_pkts_tx * f_amrft_payload_len(tx_hdl.amr_ft) * flow.osmux.cfg.batch_size) {
setverdict(fail);
}
@@ -1121,9 +1337,9 @@ module MGCP_Test {
var OsmuxTxHandle tx_hdl;
f_init(ep, true);
- flow := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 111, "GSM-HR-08/8000/1"));
+ flow := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 111, "GSM-HR-08/8000/1"));
flow.em.portnr := mp_local_osmux_port;
- flow.osmux_cid := 2;
+ flow.osmux.local_cid := 2;
f_flow_create_osmux(OsmuxEM, ep, call_id, "loopback", flow);
f_osmuxem_mode(OsmuxEM, OSMUXEM_MODE_BIDIR);
@@ -1190,7 +1406,9 @@ module MGCP_Test {
return true;
}
- function f_TC_two_crcx_and_rtp_osmux(boolean bidir) runs on dummy_CT {
+ function f_TC_two_crcx_and_rtp_osmux(boolean bidir, boolean rtp_amr_oa,
+ charstring local_ip_rtp, charstring remote_ip_rtp,
+ charstring local_ip_osmux, charstring remote_ip_osmux) runs on dummy_CT {
var RtpFlowData flow[2];
var RtpemStats stats_rtp;
var OsmuxemStats stats_osmux;
@@ -1199,24 +1417,44 @@ module MGCP_Test {
var MgcpCallId call_id := '1226'H;
var integer tolerance := 0;
+ var octetstring amr_payload;
+ var charstring fmtp;
+
f_init(ep, true);
+ var AMRFT cmr := AMR_FT_0;
+ var AMRFT ft := AMR_FT_2;
+ if (rtp_amr_oa) {
+ fmtp := "octet-align=1";
+ var RTP_AMR_Hdr amr_oa_hdr := valueof(ts_RTP_AMR_Hdr(enum2int(cmr), enum2int(ft)));
+ amr_payload := enc_RTP_AMR_Hdr(amr_oa_hdr) &
+ f_osmux_gen_expected_rx_rtp_payload(enum2int(ft), c_OsmuxemDefaultCfg.tx_fixed_payload);
+ } else {
+ fmtp := "octet-align=0";
+ /* Convert OA to BWE: */
+ var RTP_AMR_BWE_Hdr amr_bwe_hdr := valueof(ts_RTP_AMR_BWE_Hdr(enum2int(cmr), enum2int(ft)));
+ var bitstring amr_bwe_hdr_bits := substr(oct2bit(enc_RTP_AMR_BWE_Hdr(amr_bwe_hdr)), 0 , 10);
+ var bitstring amr_data_bits := oct2bit(f_osmux_gen_expected_rx_rtp_payload(enum2int(ft), c_OsmuxemDefaultCfg.tx_fixed_payload));
+ var bitstring amr_payload_bits := amr_bwe_hdr_bits & substr(amr_data_bits, 0, f_amrft_payload_bits_len(enum2int(ft)));
+ amr_payload := bit2oct(f_pad_bit(amr_payload_bits, (lengthof(amr_payload_bits)+7)/8*8, '0'B));
+ };
+
/* from us to MGW */
- flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 112, "AMR/8000"));
+ flow[0] := valueof(t_RtpFlow(local_ip_rtp, remote_ip_rtp, 112, "AMR/8000", fmtp));
flow[0].rtp_cfg := c_RtpemDefaultCfg
- flow[0].rtp_cfg.tx_payload_type := flow[0].pt;
- /* 0014 is the ToC (CMR=AMR4.75) in front of AMR Payload in RTP Payload */
- flow[0].rtp_cfg.rx_fixed_payload := '0014'O & f_osmux_gen_expected_rx_rtp_payload(2 /* AMR_FT_2, 5.90 */, c_OsmuxemDefaultCfg.tx_fixed_payload);
- flow[0].rtp_cfg.tx_fixed_payload := flow[0].rtp_cfg.rx_fixed_payload;
+ flow[0].rtp_cfg.rx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.rx_payloads[0].fixed_payload := amr_payload;
+ flow[0].rtp_cfg.tx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.tx_payloads[0].fixed_payload := amr_payload;
/* bind local RTP emulation sockets */
flow[0].em.portnr := 10000;
f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
/* from MGW back to us */
- flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 110, "AMR/8000"));
+ flow[1] := valueof(t_RtpFlow(local_ip_osmux, remote_ip_osmux, 110, "AMR/8000"));
flow[1].em.portnr := mp_local_osmux_port;
- flow[1].osmux_cid := 2;
- flow[1].osmux_cfg := c_OsmuxemDefaultCfg;
+ flow[1].osmux.local_cid := 2;
+ flow[1].osmux.cfg := c_OsmuxemDefaultCfg;
f_flow_create_osmux(OsmuxEM, ep, call_id, "sendrecv", flow[1]);
if (bidir) {
@@ -1245,7 +1483,7 @@ module MGCP_Test {
stats_rtp := f_rtpem_stats_get(RTPEM[0]);
stats_osmux := f_osmuxem_stats_get(OsmuxEM);
- if (not f_rtp_osmux_stats_compare(stats_rtp, stats_osmux, flow[1].osmux_cfg.batch_size, tolerance)) {
+ if (not f_rtp_osmux_stats_compare(stats_rtp, stats_osmux, flow[1].osmux.cfg.batch_size, tolerance)) {
setverdict(fail, "RTP and Osmux endpoint statistics don't match");
mtc.stop;
}
@@ -1258,51 +1496,81 @@ module MGCP_Test {
/* create one RTP and one OSmux emulations; create two connections on MGW EP, exchange some data */
testcase TC_two_crcx_and_rtp_osmux() runs on dummy_CT {
- f_TC_two_crcx_and_rtp_osmux(false);
+ f_TC_two_crcx_and_rtp_osmux(false, true, mp_local_ipv4, mp_remote_ipv4,
+ mp_local_ipv4, mp_remote_ipv4);
}
/* create one RTP and one OSmux emulations; create two connections on MGW EP,
* exchange some data in both directions */
testcase TC_two_crcx_and_rtp_osmux_bidir() runs on dummy_CT {
- f_TC_two_crcx_and_rtp_osmux(true);
+ f_TC_two_crcx_and_rtp_osmux(true, true, mp_local_ipv4, mp_remote_ipv4,
+ mp_local_ipv4, mp_remote_ipv4);
+ }
+
+ /* create one RTP and one OSmux emulations; create two connections on MGW EP,
+ * exchange some data in both directions. RTP side is configured to
+ * rx/rx AMR in bandwidth-efficient mode. */
+ testcase TC_two_crcx_and_rtp_osmux_bidir_amr_bwe() runs on dummy_CT {
+ f_TC_two_crcx_and_rtp_osmux(true, false, mp_local_ipv4, mp_remote_ipv4,
+ mp_local_ipv4, mp_remote_ipv4);
}
- function f_two_crcx_mdcx_and_rtp_osmux(boolean crcx_osmux_wildcard) runs on dummy_CT {
+ /* Same as TC_two_crcx_and_rtp_osmux_bidir, but using IPv6 */
+ testcase TC_two_crcx_and_rtp_osmux_bidir_ipv6() runs on dummy_CT {
+ f_TC_two_crcx_and_rtp_osmux(true, true, mp_local_ipv6, mp_remote_ipv6,
+ mp_local_ipv6, mp_remote_ipv6);
+ }
+ /* Same as TC_two_crcx_and_rtp_osmux_bidir, but using IPv4 (RTP) and IPv6 (Osmux) */
+ testcase TC_two_crcx_and_rtp_osmux_bidir_ipv4_ipv6() runs on dummy_CT {
+ f_TC_two_crcx_and_rtp_osmux(true, true, mp_local_ipv4, mp_remote_ipv4,
+ mp_local_ipv6, mp_remote_ipv6);
+ }
+ /* Same as TC_two_crcx_and_rtp_osmux_bidir, but using IPv6 (RTP) and IPv4 (Osmux) */
+ testcase TC_two_crcx_and_rtp_osmux_bidir_ipv6_ipv4() runs on dummy_CT {
+ f_TC_two_crcx_and_rtp_osmux(true, true, mp_local_ipv6, mp_remote_ipv6,
+ mp_local_ipv4, mp_remote_ipv4);
+ }
+
+
+ function f_two_crcx_mdcx_and_rtp_osmux(boolean crcx_osmux_wildcard,
+ charstring local_ip_rtp, charstring remote_ip_rtp,
+ charstring local_ip_osmux, charstring remote_ip_osmux) runs on dummy_CT {
var RtpFlowData flow[2];
var RtpemStats stats_rtp;
var OsmuxemStats stats_osmux;
var MgcpResponse resp;
var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
var MgcpCallId call_id := '1227'H;
- var integer num_pkts_tx[2];
+ var integer num_pkts_tx[2], num_pkts_rx[2];
var integer temp;
f_init(ep, true);
/* Create the first connection in receive only mode */
- flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 112, "AMR/8000"));
+ flow[0] := valueof(t_RtpFlow(local_ip_rtp, remote_ip_rtp, 112, "AMR/8000"));
flow[0].rtp_cfg := c_RtpemDefaultCfg
- flow[0].rtp_cfg.tx_payload_type := flow[0].pt;
+ flow[0].rtp_cfg.rx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.tx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
/* 0014 is the ToC (CMR=AMR4.75) in front of AMR Payload in RTP Payload */
- flow[0].rtp_cfg.rx_fixed_payload := '0014'O & f_osmux_gen_expected_rx_rtp_payload(2 /* AMR_FT_2, 5.90 */, c_OsmuxemDefaultCfg.tx_fixed_payload);
- flow[0].rtp_cfg.tx_fixed_payload := flow[0].rtp_cfg.rx_fixed_payload;
+ flow[0].rtp_cfg.rx_payloads[0].fixed_payload := '0014'O & f_osmux_gen_expected_rx_rtp_payload(2 /* AMR_FT_2, 5.90 */, c_OsmuxemDefaultCfg.tx_fixed_payload);
+ flow[0].rtp_cfg.tx_payloads[0].fixed_payload := flow[0].rtp_cfg.rx_payloads[0].fixed_payload;
/* bind local RTP emulation sockets */
flow[0].em.portnr := 10000;
- f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow[0], false);
+ f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow[0], true);
/* Create the second connection. This connection will be also
* in receive only mode */
- flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 110, "AMR/8000"));
+ flow[1] := valueof(t_RtpFlow(local_ip_osmux, remote_ip_osmux, 110, "AMR/8000"));
flow[1].em.portnr := mp_local_osmux_port;
if (crcx_osmux_wildcard) {
- flow[1].osmux_cid := -1;
+ flow[1].osmux.local_cid := -1;
} else {
- flow[1].osmux_cid := 2;
+ flow[1].osmux.local_cid := 2;
}
- flow[1].osmux_cfg := c_OsmuxemDefaultCfg;
- f_flow_create_osmux(OsmuxEM, ep, call_id, "recvonly", flow[1], false);
+ flow[1].osmux.cfg := c_OsmuxemDefaultCfg;
+ f_flow_create_osmux(OsmuxEM, ep, call_id, "recvonly", flow[1], true);
/* The first leg starts transmitting */
@@ -1335,52 +1603,69 @@ module MGCP_Test {
/* The first leg will now be switched into bidirectional
* mode, but we do not expect any data comming back yet. */
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
f_flow_modify(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
+ /* At this point in time, flow[1](Osmux)->MGW->flow[0](RTP) is active,
+ * hence if local CID was provided during CRCX we should already be seeing packets
+ * flowing in one direction, aka stats_rtp.num_pkts_rx sould be >0 after a while: */
f_sleep(0.5);
stats_rtp := f_rtpem_stats_get(RTPEM[0]);
if (stats_rtp.num_pkts_rx_err_disabled != 0) {
setverdict(fail, "received packets from RTP MGW on recvonly connection");
mtc.stop;
}
+ if (not crcx_osmux_wildcard and stats_rtp.num_pkts_rx == 0) {
+ setverdict(fail, "received 0 packets Osmux->MGW->RTP");
+ mtc.stop;
+ }
+
stats_osmux := f_osmuxem_stats_get(OsmuxEM);
if (stats_osmux.num_pkts_rx_err_disabled != 0) {
setverdict(fail, "received packets from Osmux MGW on recvonly connection");
mtc.stop;
}
+ if (stats_osmux.num_pkts_rx > 0) {
+ setverdict(fail, "received unexpected ", stats_osmux.num_pkts_rx, " packets RTP->MGW->Osmux");
+ mtc.stop;
+ }
/* When the second leg is switched into bidirectional mode
* as well, then the MGW will connect the two together and
* we should see RTP streams passing through from both ends. */
- f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
f_osmuxem_mode(OsmuxEM, OSMUXEM_MODE_BIDIR);
- stats_rtp := f_rtpem_stats_get(RTPEM[0]);
- num_pkts_tx[0] := stats_rtp.num_pkts_tx
- stats_osmux := f_osmuxem_stats_get(OsmuxEM);
- num_pkts_tx[1] := stats_osmux.num_pkts_tx
-
if (crcx_osmux_wildcard) {
- /* For now we must set same CID as the MGW recvCID,
- * having sendCID!=recvCID is not yet supported. */
- flow[1].osmux_cid := flow[1].osmux_cid_response;
+ /* We set now the local CID in MDCX: */
+ flow[1].osmux.local_cid := 2;
}
f_flow_modify_osmux(OsmuxEM, ep, call_id, "sendrecv", flow[1]);
+ stats_rtp := f_rtpem_stats_get(RTPEM[0]);
+ stats_osmux := f_osmuxem_stats_get(OsmuxEM);
+ num_pkts_tx[0] := stats_rtp.num_pkts_tx;
+ num_pkts_tx[1] := stats_osmux.num_pkts_tx;
+ num_pkts_rx[0] := stats_rtp.num_pkts_rx;
+ num_pkts_rx[1] := stats_osmux.num_pkts_rx;
f_sleep(2.0);
stats_rtp := f_rtpem_stats_get(RTPEM[0]);
stats_osmux := f_osmuxem_stats_get(OsmuxEM);
- temp := stats_rtp.num_pkts_tx - num_pkts_tx[0] - stats_osmux.num_pkts_rx * flow[1].osmux_cfg.batch_size;
- if (temp > 3 * flow[1].osmux_cfg.batch_size or temp < -3 * flow[1].osmux_cfg.batch_size) {
+ temp := (stats_rtp.num_pkts_tx - num_pkts_tx[0]) -
+ (stats_osmux.num_pkts_rx - num_pkts_rx[1]) * flow[1].osmux.cfg.batch_size;
+ if (temp > 3 * flow[1].osmux.cfg.batch_size or temp < -3 * flow[1].osmux.cfg.batch_size) {
log("stats_rtp: ", stats_rtp);
log("stats_osmux: ", stats_osmux);
log("old_rtp_tx: ", num_pkts_tx[0]);
- setverdict(fail, "number of packets not within normal parameters (" & int2str(temp) & ")");
+ setverdict(fail, "RTP-Tx vs OSmux-Rx number of packets not within normal parameters (" & int2str(temp) & ")");
mtc.stop;
}
- temp := stats_osmux.num_pkts_tx - num_pkts_tx[1] - stats_rtp.num_pkts_rx / flow[1].osmux_cfg.batch_size;
+ temp := (stats_osmux.num_pkts_tx - num_pkts_tx[1]) -
+ ((stats_rtp.num_pkts_rx - num_pkts_rx[0])/ flow[1].osmux.cfg.batch_size);
if (temp > 3 or temp < -3) {
- setverdict(fail, "number of packets not within normal parameters (" & int2str(temp) & ")");
+ log("stats_rtp: ", stats_rtp);
+ log("stats_osmux: ", stats_osmux);
+ log("old_osmux_tx: ", num_pkts_tx[1]);
+ setverdict(fail, "Osmux-Tx vs RTP-Rx number of packets not within normal parameters (" & int2str(temp) & ")");
mtc.stop;
}
@@ -1397,14 +1682,32 @@ module MGCP_Test {
directions. Create CRCX with wildcard Osmux CID and set it later
during MDCX. This is similar to how MSC sets up the call in AoIP. */
testcase TC_two_crcx_mdcx_and_rtp_osmux_wildcard() runs on dummy_CT {
- f_two_crcx_mdcx_and_rtp_osmux(true);
+ f_two_crcx_mdcx_and_rtp_osmux(true, mp_local_ipv4, mp_remote_ipv4,
+ mp_local_ipv4, mp_remote_ipv4);
}
/* create one RTP and one OSmux emulations and pass data in both
directions. Create CRCX with fixed Osmux CID and keep it during
MDCX. This is similar to how BSC sets up the call in AoIP. */
testcase TC_two_crcx_mdcx_and_rtp_osmux_fixed() runs on dummy_CT {
- f_two_crcx_mdcx_and_rtp_osmux(false);
+ f_two_crcx_mdcx_and_rtp_osmux(false, mp_local_ipv4, mp_remote_ipv4,
+ mp_local_ipv4, mp_remote_ipv4);
+ }
+
+ /* Same as TC_two_crcx_mdcx_and_rtp_osmux_wildcard, but using IPv6. */
+ testcase TC_two_crcx_mdcx_and_rtp_osmux_ipv6() runs on dummy_CT {
+ f_two_crcx_mdcx_and_rtp_osmux(false, mp_local_ipv6, mp_remote_ipv6,
+ mp_local_ipv6, mp_remote_ipv6);
+ }
+ /* Same as TC_two_crcx_mdcx_and_rtp_osmux_wildcard, but using IPv4 (RTP) and IPv6 (Osmux). */
+ testcase TC_two_crcx_mdcx_and_rtp_osmux_ipv4_ipv6() runs on dummy_CT {
+ f_two_crcx_mdcx_and_rtp_osmux(false, mp_local_ipv4, mp_remote_ipv4,
+ mp_local_ipv6, mp_remote_ipv6);
+ }
+ /* Same as TC_two_crcx_mdcx_and_rtp_osmux_wildcard, but using IPv6 (RTP) and IPv4 (Osmux). */
+ testcase TC_two_crcx_mdcx_and_rtp_osmux_ipv6_ipv4() runs on dummy_CT {
+ f_two_crcx_mdcx_and_rtp_osmux(false, mp_local_ipv6, mp_remote_ipv6,
+ mp_local_ipv4, mp_remote_ipv4);
}
function f_crcx_and_dlcx_ep_callid_connid(MgcpEndpoint ep, MgcpCallId call_id) runs on dummy_CT {
@@ -1427,7 +1730,11 @@ module MGCP_Test {
f_init();
for (ep_nr := 1; ep_nr < 30; ep_nr := ep_nr+1) {
- ep := c_mgw_ep_rtpbridge & hex2str(int2hex(ep_nr, 2)) & "@" & c_mgw_domain;
+ if(ep_nr > 15) {
+ ep := c_mgw_ep_rtpbridge & hex2str(int2hex(ep_nr, 2)) & "@" & c_mgw_domain;
+ } else {
+ ep := c_mgw_ep_rtpbridge & hex2str(int2hex(ep_nr, 1)) & "@" & c_mgw_domain;
+ }
call_id := int2hex(ep_nr, 2) & '1234'H;
f_crcx_and_dlcx_ep_callid_connid(ep, call_id);
}
@@ -1531,21 +1838,6 @@ module MGCP_Test {
setverdict(pass);
}
- template (value) RtpFlowData t_RtpFlow(charstring host_a, charstring host_b, uint7_t pt,
- charstring codec) := {
- em := {
- hostname := host_a,
- portnr := omit
- },
- mgw := {
- hostname := host_b,
- portnr := omit
- },
- pt := pt,
- codec := codec,
- osmux_cid_sent := false
- }
-
/* transmit RTP streams between two RTP Emulations back-to-back; expect no loss */
testcase TC_rtpem_selftest() runs on dummy_CT {
var RtpemStats stats[2];
@@ -1591,9 +1883,9 @@ module MGCP_Test {
var RtpemStats stats;
f_init(ep);
- flow := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 112, "AMR/8000/1"));
+ flow := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 112, "AMR/8000/1"));
flow.em.portnr := 10000;
- f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow, false);
+ f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow, true);
f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
f_sleep(1.0);
@@ -1601,10 +1893,17 @@ module MGCP_Test {
stats := f_rtpem_stats_get(RTPEM[0]);
- if (stats.num_pkts_tx < 40) {
+ /* Make sure that at least some amount of RTP packets/bytes
+ * have has been transmitted. The compare values for
+ * stats.num_pkts_tx and stats.bytes_payload_tx are determined
+ * using a testrun and the results were devided by 2, so even
+ * in load situations we should reach the minimum amount of
+ * required packets/bytes */
+
+ if (stats.num_pkts_tx < 24) {
setverdict(fail);
}
- if (stats.bytes_payload_tx < 190) {
+ if (stats.bytes_payload_tx < 96) {
setverdict(fail);
}
@@ -1615,16 +1914,16 @@ module MGCP_Test {
/* Create one connection in loopback mode, test if the RTP packets are
* actually reflected */
- testcase TC_one_crcx_loopback_rtp() runs on dummy_CT {
+ function f_TC_one_crcx_loopback_rtp(charstring local_ip, charstring remote_ip, boolean one_phase := true) runs on dummy_CT {
var RtpFlowData flow;
var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "1@" & c_mgw_domain;
var MgcpCallId call_id := '1225'H;
var RtpemStats stats;
f_init(ep);
- flow := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 111, "GSM-HR-08/8000/1"));
+ flow := valueof(t_RtpFlow(local_ip, remote_ip, 112, "GSM-HR-08/8000/1"));
flow.em.portnr := 10000;
- f_flow_create(RTPEM[0], ep, call_id, "loopback", flow);
+ f_flow_create(RTPEM[0], ep, call_id, "loopback", flow, one_phase := one_phase);
f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
f_sleep(1.0);
@@ -1632,11 +1931,22 @@ module MGCP_Test {
stats := f_rtpem_stats_get(RTPEM[0]);
- if (stats.num_pkts_tx != stats.num_pkts_rx) {
- setverdict(fail);
- }
- if (stats.bytes_payload_tx != stats.bytes_payload_rx) {
- setverdict(fail);
+ if (one_phase) {
+ /* osmo-mgw knows both local and remote RTP address. Expect all packets to be reflected. */
+ if (stats.num_pkts_tx != stats.num_pkts_rx) {
+ setverdict(fail);
+ }
+ if (stats.bytes_payload_tx != stats.bytes_payload_rx) {
+ setverdict(fail);
+ }
+ } else {
+ /* osmo-mgw knows only the local RTP address. Expect no packets to be reflected. */
+ if (stats.num_pkts_rx > 0) {
+ setverdict(fail, "stats.num_pkts_rx=", stats.num_pkts_rx, ": osmo-mgw should not send RTP packets to an arbitrary peer");
+ }
+ if (stats.bytes_payload_rx > 0) {
+ setverdict(fail);
+ }
}
f_rtpem_stats_err_check(stats);
@@ -1644,6 +1954,24 @@ module MGCP_Test {
setverdict(pass);
}
+ /* Create one connection in loopback mode, test if the RTP packets are
+ * actually reflected */
+ testcase TC_one_crcx_loopback_rtp() runs on dummy_CT {
+ f_TC_one_crcx_loopback_rtp(mp_local_ipv4, mp_remote_ipv4, one_phase := true)
+ }
+ testcase TC_one_crcx_loopback_rtp_ipv6() runs on dummy_CT {
+ f_TC_one_crcx_loopback_rtp(mp_local_ipv6, mp_remote_ipv6, one_phase := true)
+ }
+
+ /* Same as above, but we will intenionally not tell the MGW where to
+ * send the outgoing traffic. The connection is still created in
+ * loopback mode, so the MGW should take the originating address from
+ * the incoming RTP packet and send it back to the source */
+ testcase TC_one_crcx_loopback_rtp_implicit() runs on dummy_CT {
+ f_TC_one_crcx_loopback_rtp(mp_local_ipv6, mp_remote_ipv6, one_phase := false)
+ }
+
+
function f_TC_two_crcx_and_rtp(boolean bidir, charstring codec_name_a, integer pt_a,
charstring codec_name_b, integer pt_b) runs on dummy_CT {
var RtpFlowData flow[2];
@@ -1656,13 +1984,13 @@ module MGCP_Test {
f_init(ep);
/* from us to MGW */
- flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, pt_a, codec_name_a));
+ flow[0] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, pt_a, codec_name_a));
/* bind local RTP emulation sockets */
flow[0].em.portnr := 10000;
f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
/* from MGW back to us */
- flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, pt_b, codec_name_b));
+ flow[1] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, pt_b, codec_name_b));
flow[1].em.portnr := 20000;
f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
@@ -1720,7 +2048,10 @@ module MGCP_Test {
}
/* create two local RTP emulations and pass data in both directions */
- testcase TC_two_crcx_mdcx_and_rtp() runs on dummy_CT {
+ function f_tc_two_crcx_mdcx_and_rtp(charstring local_ip_a, charstring remote_ip_a,
+ charstring local_ip_b, charstring remote_ip_b,
+ uint7_t payload_type := 3,
+ charstring codec_name := "GSM/8000/1") runs on dummy_CT {
var RtpFlowData flow[2];
var RtpemStats stats[2];
var MgcpResponse resp;
@@ -1732,27 +2063,27 @@ module MGCP_Test {
f_init(ep);
/* Create the first connection in receive only mode */
- flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 3, "GSM/8000/1"));
+ flow[0] := valueof(t_RtpFlow(local_ip_a, remote_ip_a, payload_type, codec_name));
flow[0].em.portnr := 10000;
- f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow[0], false);
+ f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow[0], true);
/* Create the second connection. This connection will be also
* in receive only mode */
- flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 3, "GSM/8000/1"));
+ flow[1] := valueof(t_RtpFlow(local_ip_b, remote_ip_b, payload_type, codec_name));
flow[1].em.portnr := 20000;
- f_flow_create(RTPEM[1], ep, call_id, "recvonly", flow[1], false);
+ f_flow_create(RTPEM[1], ep, call_id, "recvonly", flow[1], true);
/* The first leg starts transmitting */
f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
f_sleep(0.5);
stats[0] := f_rtpem_stats_get(RTPEM[0]);
if (stats[0].num_pkts_rx_err_disabled != 0) {
- setverdict(fail, "received packets from MGW on recvonly connection");
+ setverdict(fail, "received packets from MGW on recvonly connection 0");
mtc.stop;
}
stats[1] := f_rtpem_stats_get(RTPEM[1]);
if (stats[1].num_pkts_rx_err_disabled != 0) {
- setverdict(fail, "received packets from MGW on recvonly connection");
+ setverdict(fail, "received packets from MGW on recvonly connection 1");
mtc.stop;
}
@@ -1761,40 +2092,39 @@ module MGCP_Test {
f_sleep(1.0);
stats[0] := f_rtpem_stats_get(RTPEM[0]);
if (stats[0].num_pkts_rx_err_disabled != 0) {
- setverdict(fail, "received packets from MGW on recvonly connection");
+ setverdict(fail, "received packets from MGW on recvonly connection 0");
mtc.stop;
}
stats[1] := f_rtpem_stats_get(RTPEM[1]);
if (stats[1].num_pkts_rx_err_disabled != 0) {
- setverdict(fail, "received packets from MGW on recvonly connection");
+ setverdict(fail, "received packets from MGW on recvonly connection 1");
mtc.stop;
}
/* The first leg will now be switched into bidirectional
* mode, but we do not expect any data comming back yet. */
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
+ stats[1] := f_rtpem_stats_get(RTPEM[1]);
+ num_pkts_tx[1] := stats[1].num_pkts_tx;
f_flow_modify(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
f_sleep(0.5);
stats[0] := f_rtpem_stats_get(RTPEM[0]);
- if (stats[1].num_pkts_rx_err_disabled != 0) {
- setverdict(fail, "received packets from MGW on recvonly connection");
+ if (stats[0].num_pkts_rx_err_disabled != 0) {
+ setverdict(fail, "received packets from MGW on recvonly connection 0");
mtc.stop;
}
stats[1] := f_rtpem_stats_get(RTPEM[1]);
if (stats[1].num_pkts_rx_err_disabled != 0) {
- setverdict(fail, "received packets from MGW on recvonly connection");
+ setverdict(fail, "received packets from MGW on recvonly connection 1");
mtc.stop;
}
/* When the second leg is switched into bidirectional mode
* as well, then the MGW will connect the two together and
* we should see RTP streams passing through from both ends. */
- f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
stats[0] := f_rtpem_stats_get(RTPEM[0]);
- num_pkts_tx[0] := stats[0].num_pkts_tx
- stats[1] := f_rtpem_stats_get(RTPEM[1]);
- num_pkts_tx[1] := stats[1].num_pkts_tx
-
+ num_pkts_tx[0] := stats[0].num_pkts_tx;
f_flow_modify(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
f_sleep(2.0);
@@ -1803,13 +2133,13 @@ module MGCP_Test {
temp := stats[0].num_pkts_tx - num_pkts_tx[0] - stats[1].num_pkts_rx;
if (temp > 3 or temp < -3) {
- setverdict(fail, "number of packets not within normal parameters");
+ setverdict(fail, "number of packets not within normal parameters:", temp);
mtc.stop;
}
temp := stats[1].num_pkts_tx - num_pkts_tx[1] - stats[0].num_pkts_rx;
if (temp > 3 or temp < -3) {
- setverdict(fail, "number of packets not within normal parameters");
+ setverdict(fail, "number of packets not within normal parameters:", temp);
mtc.stop;
}
@@ -1822,6 +2152,28 @@ module MGCP_Test {
setverdict(pass);
}
+ testcase TC_two_crcx_mdcx_and_rtp() runs on dummy_CT {
+ f_tc_two_crcx_mdcx_and_rtp(mp_local_ipv4, mp_remote_ipv4,
+ mp_local_ipv4, mp_remote_ipv4);
+ }
+
+ testcase TC_two_crcx_mdcx_and_rtp_ipv6() runs on dummy_CT {
+ f_tc_two_crcx_mdcx_and_rtp(mp_local_ipv6, mp_remote_ipv6,
+ mp_local_ipv6, mp_remote_ipv6);
+ }
+
+ testcase TC_two_crcx_mdcx_and_rtp_ipv4_ipv6() runs on dummy_CT {
+ f_tc_two_crcx_mdcx_and_rtp(mp_local_ipv4, mp_remote_ipv4,
+ mp_local_ipv6, mp_remote_ipv6);
+ }
+
+ testcase TC_two_crcx_mdcx_and_rtp_clearmode() runs on dummy_CT {
+ f_tc_two_crcx_mdcx_and_rtp(mp_local_ipv4, mp_remote_ipv4,
+ mp_local_ipv4, mp_remote_ipv4,
+ 120, /* 3GPP TS 48.103 table 5.4.2.2.1 */
+ "CLEARMODE/8000");
+ }
+
/* Test what happens when two RTP streams from different sources target
* a single connection. Is the unsolicited stream properly ignored? */
testcase TC_two_crcx_and_unsolicited_rtp() runs on dummy_CT {
@@ -1835,13 +2187,13 @@ module MGCP_Test {
f_init(ep);
/* from us to MGW */
- flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
+ flow[0] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 98, "AMR/8000"));
/* bind local RTP emulation sockets */
flow[0].em.portnr := 10000;
f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
/* from MGW back to us */
- flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
+ flow[1] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 98, "AMR/8000"));
flow[1].em.portnr := 20000;
f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
@@ -1851,8 +2203,8 @@ module MGCP_Test {
f_sleep(0.5);
/* Start inserting unsolicited RTP packets */
- f_rtpem_bind(RTPEM[2], mp_local_ip, unsolicited_port);
- f_rtpem_connect(RTPEM[2], mp_remote_ip, flow[0].mgw.portnr);
+ f_rtpem_bind(RTPEM[2], mp_local_ipv4, unsolicited_port);
+ f_rtpem_connect(RTPEM[2], mp_remote_ipv4, flow[0].mgw.portnr);
f_rtpem_mode(RTPEM[2], RTPEM_MODE_TXONLY);
f_sleep(0.5);
@@ -1888,13 +2240,13 @@ module MGCP_Test {
f_init(ep);
/* First connection (BTS) */
- flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 110, "GSM-EFR/8000"));
+ flow[0] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 110, "GSM-EFR/8000"));
/* bind local RTP emulation sockets */
flow[0].em.portnr := 10000;
f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
/* Second connection (PBX) */
- flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 110, "GSM-EFR/8000"));
+ flow[1] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 110, "GSM-EFR/8000"));
flow[1].em.portnr := 20000;
f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
@@ -1914,8 +2266,8 @@ module MGCP_Test {
* transmitting for a while. We simulate this by injecting
* some unsolicited packets on the behalf of the old source,
* (old remote port) */
- f_rtpem_bind(RTPEM[2], mp_local_ip, port_old);
- f_rtpem_connect(RTPEM[2], mp_remote_ip, flow[0].mgw.portnr);
+ f_rtpem_bind(RTPEM[2], mp_local_ipv4, port_old);
+ f_rtpem_connect(RTPEM[2], mp_remote_ipv4, flow[0].mgw.portnr);
f_rtpem_mode(RTPEM[2], RTPEM_MODE_TXONLY);
f_sleep(1.0);
f_rtpem_mode(RTPEM[2], RTPEM_MODE_NONE);
@@ -1944,10 +2296,62 @@ module MGCP_Test {
setverdict(pass);
}
+ testcase TC_two_crcx_confecho_sendonly_rtp() runs on dummy_CT {
+ var RtpFlowData flow[2];
+ var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
+ var MgcpCallId call_id := '1225'H;
+ var RtpemStats stats[2];
+
+ f_init(ep);
+
+ /* "Talker" is sending to MGW and receives echo. */
+ flow[0] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 112, "GSM-HR-08/8000/1"));
+ flow[0].em.portnr := 10000;
+ f_flow_create(RTPEM[0], ep, call_id, "confecho", flow[0]);
+
+ /* "Listener" receives from MGW. */
+ flow[1] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 112, "GSM-HR-08/8000/1"));
+ flow[1].em.portnr := 20000;
+ f_flow_create(RTPEM[1], ep, call_id, "sendonly", flow[1]);
+
+
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
+ f_sleep(1.0);
+ f_flow_delete(RTPEM[0]);
+ f_flow_delete(RTPEM[1], ep, call_id);
+
+ stats[0] := f_rtpem_stats_get(RTPEM[0]);
+ stats[1] := f_rtpem_stats_get(RTPEM[1]);
+
+ /* The "Talker" will receive his RTP, so TX must match RX.
+ * As RTP from "Listener" is ignored, no extra packets shall be received. */
+ if (stats[0].num_pkts_tx != stats[0].num_pkts_rx) {
+ setverdict(fail, "Talker does not receive as many packets as it transmits!");
+ }
+ if (stats[0].bytes_payload_tx != stats[0].bytes_payload_rx) {
+ setverdict(fail, "Talker does not receive as many payload as it transmits!");
+ }
+
+ /* The "Listener" will also receive RTP of the "Talker",
+ * so TX of "Talker" must match RX of "Listener". */
+ if (stats[0].num_pkts_tx != stats[1].num_pkts_rx) {
+ setverdict(fail, "Listener does not receive as many packets as talker transmits!");
+ }
+ if (stats[0].bytes_payload_tx != stats[1].bytes_payload_rx) {
+ setverdict(fail, "Listener does not receive as many payload as talker transmits!");
+ }
+
+ f_rtpem_stats_err_check(stats[0]);
+ f_rtpem_stats_err_check(stats[1]);
+
+ setverdict(pass);
+ }
+
/* create two local RTP emulations; create two connections on MGW EP, see if
- * exchanged data is converted bwtween ts101318 and rfc5993 */
- testcase TC_ts101318_rfc5993_rtp_conversion() runs on dummy_CT {
+ * exchanged data is converted between ts101318 and rfc5993 */
+ function f_ts101318_rfc5993_rtp_conversion(octetstring pl0, octetstring pl1, charstring fmtp0, charstring fmtp1) runs on dummy_CT {
var RtpFlowData flow[2];
var RtpemStats stats[2];
var MgcpResponse resp;
@@ -1961,36 +2365,52 @@ module MGCP_Test {
f_vty_transceive(MGWVTY, "mgcp");
f_vty_transceive(MGWVTY, "rtp-patch rfc5993hr");
- /* from us to MGW */
- flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 111, "GSM-HR-08/8000"));
+ /* Connection #0 (Bidirectional) */
+ flow[0] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 111, "GSM-HR-08/8000", fmtp0));
/* bind local RTP emulation sockets */
flow[0].em.portnr := 10000;
flow[0].rtp_cfg := c_RtpemDefaultCfg;
- flow[0].rtp_cfg.tx_payload_type := flow[0].pt;
- flow[0].rtp_cfg.rx_fixed_payload := '0b11b3eede60be4e3ec68838c7b5'O;
- flow[0].rtp_cfg.tx_fixed_payload := '0b11b3eede60be4e3ec68838c7b5'O;
+ flow[0].rtp_cfg.rx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.tx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.rx_payloads[0].fixed_payload := pl0;
+ flow[0].rtp_cfg.tx_payloads[0].fixed_payload := pl0;
f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
- /* from MGW back to us */
- flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 111, "GSM-HR-08/8000"));
+ /* Connection #1 (Bidirectional) */
+ flow[1] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 111, "GSM-HR-08/8000", fmtp1));
flow[1].em.portnr := 20000;
flow[1].rtp_cfg := c_RtpemDefaultCfg;
- flow[1].rtp_cfg.tx_payload_type := flow[1].pt;
- flow[1].rtp_cfg.rx_fixed_payload := '000b11b3eede60be4e3ec68838c7b5'O;
- flow[1].rtp_cfg.tx_fixed_payload := '000b11b3eede60be4e3ec68838c7b5'O;
+ flow[1].rtp_cfg.rx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.tx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.rx_payloads[0].fixed_payload := pl1;
+ flow[1].rtp_cfg.tx_payloads[0].fixed_payload := pl1;
f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
- f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
- f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
+ /* Send RTP packets to connection #0, receive on connection #1 */
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
+ f_sleep(0.5);
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
+ f_sleep(1.0);
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
+ f_sleep(0.5);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_NONE);
+ /* Send RTP packets to connection #1, receive on connection #0 */
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
+ f_sleep(0.5);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_TXONLY);
f_sleep(1.0);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_NONE);
+ f_sleep(0.5);
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
+ /* Remove RTP flows and check statistics */
f_flow_delete(RTPEM[0]);
f_flow_delete(RTPEM[1], ep, call_id);
+ /* Check for errors */
stats[0] := f_rtpem_stats_get(RTPEM[0]);
stats[1] := f_rtpem_stats_get(RTPEM[1]);
-
f_rtpem_stats_err_check(stats[0]);
f_rtpem_stats_err_check(stats[1]);
@@ -2000,10 +2420,23 @@ module MGCP_Test {
setverdict(pass);
}
+ const octetstring rtp_hr_gsm_ts101318 := '0b11b3eede60be4e3ec68838c7b5'O;
+ const octetstring rtp_hr_gsm_rfc5993 := '000b11b3eede60be4e3ec68838c7b5'O;
+
+ testcase TC_ts101318_rfc5993_rtp_conversion() runs on dummy_CT {
+ f_ts101318_rfc5993_rtp_conversion(rtp_hr_gsm_ts101318, rtp_hr_gsm_rfc5993, "", "");
+ }
+
+ testcase TC_ts101318_rfc5993_rtp_conversion_fmtp() runs on dummy_CT {
+ f_ts101318_rfc5993_rtp_conversion(rtp_hr_gsm_ts101318, rtp_hr_gsm_rfc5993, "gsm-hr-format=ts101318", "gsm-hr-format=rfc5993");
+ }
+
/* create two local RTP emulations; create two connections on MGW EP, see if
- * exchanged data is converted between AMR octet-aligned and bandwith
+ * exchanged data is converted between AMR octet-aligned and bandwidth
* efficient-mode */
- function f_TC_amr_x_x_rtp_conversion(octetstring pl0, octetstring pl1, charstring fmtp0, charstring fmtp1) runs on dummy_CT {
+ function f_TC_amr_x_x_rtp_conversion(charstring fmtp0, octetstring pl0,
+ charstring fmtp1a, octetstring pl1a,
+ charstring fmtp1b, octetstring pl1b) runs on dummy_CT {
var RtpFlowData flow[2];
var RtpemStats stats[2];
var MgcpResponse resp;
@@ -2012,54 +2445,114 @@ module MGCP_Test {
f_init(ep);
- /* from us to MGW */
- flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 112, "AMR/8000"));
+ /* Connection #0 (Bidirectional) */
+ flow[0] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 96, "AMR/8000", fmtp0));
/* bind local RTP emulation sockets */
flow[0].em.portnr := 10000;
flow[0].rtp_cfg := c_RtpemDefaultCfg;
- flow[0].rtp_cfg.tx_payload_type := flow[0].pt;
- flow[0].rtp_cfg.rx_fixed_payload := pl0;
- flow[0].rtp_cfg.tx_fixed_payload := pl0;
- flow[0].fmtp := fmtp0;
+ flow[0].rtp_cfg.rx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.tx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.rx_payloads[0].fixed_payload := pl0;
+ flow[0].rtp_cfg.tx_payloads[0].fixed_payload := pl0;
f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
- /* from MGW back to us */
- flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 112, "AMR/8000"));
+ /* Connection #1 (Bidirectional) */
+ flow[1] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 112, "AMR/8000", fmtp1a));
flow[1].em.portnr := 20000;
flow[1].rtp_cfg := c_RtpemDefaultCfg;
- flow[1].rtp_cfg.tx_payload_type := flow[1].pt;
- flow[1].rtp_cfg.rx_fixed_payload := pl1;
- flow[1].rtp_cfg.tx_fixed_payload := pl1;
- flow[1].fmtp := fmtp1;
+ flow[1].rtp_cfg.rx_payloads := {};
+ flow[1].rtp_cfg.tx_payloads := {};
+ if (pl1a != ''O) {
+ flow[1].rtp_cfg.rx_payloads := flow[1].rtp_cfg.rx_payloads & {{112, pl1a}};
+ flow[1].rtp_cfg.tx_payloads := flow[1].rtp_cfg.tx_payloads & {{112, pl1a}};
+ }
+
+ /* The second fmtp parameter is to simulate a call agent that offers the transmission both modes. */
+ if (fmtp1b != "") {
+ flow[1].codec_descr := flow[1].codec_descr & {{113, "AMR/8000", fmtp1b}};
+ if (pl1b != ''O) {
+ flow[1].rtp_cfg.rx_payloads := flow[1].rtp_cfg.rx_payloads & {{113, pl1b}};
+ flow[1].rtp_cfg.tx_payloads := flow[1].rtp_cfg.tx_payloads & {{113, pl1b}};
+ }
+ }
+
f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
- f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
- f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
+ /* Send RTP packets to connection #0, receive on connection #1 */
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
+ f_sleep(0.5);
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
+ f_sleep(1.0);
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
+ f_sleep(0.5);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_NONE);
+ /* Send RTP packets to connection #1, receive on connection #0 */
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
+ f_sleep(0.5);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_TXONLY);
f_sleep(1.0);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_NONE);
+ f_sleep(0.5);
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
+ /* Remove RTP flows and check statistics */
f_flow_delete(RTPEM[0]);
f_flow_delete(RTPEM[1], ep, call_id);
+ /* Check for errors */
stats[0] := f_rtpem_stats_get(RTPEM[0]);
stats[1] := f_rtpem_stats_get(RTPEM[1]);
-
f_rtpem_stats_err_check(stats[0]);
f_rtpem_stats_err_check(stats[1]);
setverdict(pass);
}
+ /* Note: The hexstrings used with the f_TC_amr_x_x_rtp_conversion test
+ * functions are real world AMR RTP payloads including AMR header. The
+ * payloads were extracted from a trace with known good payloads. */
+
+ const octetstring rtp_amr_5_90k_oa := '2014e959f35fdfe5e9667ffbc088818088'O;
+ const octetstring rtp_amr_5_90k_bwe := '217a567cd7f7f97a599ffef022206022'O;
+ const octetstring rtp_amr_5_15k_oa := '100c4e9ba850e30d5d53d04de41e7c'O;
+ const octetstring rtp_amr_5_15k_bwe := '10d3a6ea1438c35754f41379079f'O;
+
+ /* Only one codec on each side */
testcase TC_amr_oa_bwe_rtp_conversion() runs on dummy_CT {
- f_TC_amr_x_x_rtp_conversion('100c4e9ba850e30d5d53d04de41e7c'O, '10d3a6ea1438c35754f41379079f'O, "octet-align=1", "octet-align=0");
+ f_TC_amr_x_x_rtp_conversion("octet-align=1", rtp_amr_5_90k_oa, "octet-align=0", rtp_amr_5_90k_bwe, "", ''O);
}
-
testcase TC_amr_oa_oa_rtp_conversion() runs on dummy_CT {
- f_TC_amr_x_x_rtp_conversion('100c4e9ba850e30d5d53d04de41e7c'O, '100c4e9ba850e30d5d53d04de41e7c'O, "octet-align=1", "octet-align=1");
+ f_TC_amr_x_x_rtp_conversion("octet-align=1", rtp_amr_5_15k_oa, "octet-align=1", rtp_amr_5_15k_oa, "", ''O);
}
-
testcase TC_amr_bwe_bwe_rtp_conversion() runs on dummy_CT {
- f_TC_amr_x_x_rtp_conversion('10d3a6ea1438c35754f41379079f'O, '10d3a6ea1438c35754f41379079f'O, "octet-align=0", "octet-align=0");
+ f_TC_amr_x_x_rtp_conversion("octet-align=0", rtp_amr_5_15k_bwe, "octet-align=0", rtp_amr_5_15k_bwe, "", ''O);
+ }
+
+ /* Only one codec on one side, two codecs (compatibility) on other side. The payloads are the same on both
+ * sides, so the expectation is that conversion must not be performed. Each test is done with both formats in
+ * two different configurations.*/
+ testcase TC_amr_oa_oa_no_bwe_rtp_conversion() runs on dummy_CT {
+ f_TC_amr_x_x_rtp_conversion("octet-align=1", rtp_amr_5_15k_oa,
+ "octet-align=1", rtp_amr_5_15k_oa,
+ "octet-align=0", ''O); /* We expect to see NO bandwidth efficient packets! */
+ }
+ testcase TC_amr_oa_no_bwe_oa_rtp_conversion() runs on dummy_CT {
+ /* (Same as above but flipped on the opposite side) */
+ f_TC_amr_x_x_rtp_conversion("octet-align=1", rtp_amr_5_15k_oa,
+ "octet-align=0", ''O, /* We expect to see NO bandwidth efficient packets! */
+ "octet-align=1", rtp_amr_5_15k_oa);
+ }
+ testcase TC_amr_bwe_bwe_no_oa_rtp_conversion() runs on dummy_CT {
+ f_TC_amr_x_x_rtp_conversion("octet-align=0", rtp_amr_5_15k_bwe,
+ "octet-align=0", rtp_amr_5_15k_bwe,
+ "octet-align=1", ''O); /* We expect to see NO octet aligned packets! */
+ }
+ testcase TC_amr_bwe_no_oa_bwe_rtp_conversion() runs on dummy_CT {
+ /* (Same as above but flipped on the opposite side) */
+ f_TC_amr_x_x_rtp_conversion("octet-align=0", rtp_amr_5_15k_bwe,
+ "octet-align=1", ''O, /* We expect to see NO octet aligned packets! */
+ "octet-align=0", rtp_amr_5_15k_bwe);
}
/* TODO: Double-DLCX (no retransmission) */
@@ -2082,10 +2575,10 @@ module MGCP_Test {
f_init(ep);
log("Setting conn-timeout to 1s");
- f_vty_config(MGWVTY, "mgcp", "conn-timeout 1"); /* reset in f_init_vty() */
+ f_vty_config(MGWVTY, "mgcp", "conn-timeout 1");
log("Sending RTP data for 1.5s");
- flow := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 111, "GSM-HR-08/8000/1"));
+ flow := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 111, "GSM-HR-08/8000/1"));
flow.em.portnr := 10000;
f_flow_create(RTPEM[0], ep, call_id, "loopback", flow);
f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
@@ -2107,15 +2600,695 @@ module MGCP_Test {
f_sleep(0.2);
f_rtpem_conn_refuse_verify(RTPEM[0]);
+ log("Setting conn-timeout back to 0 (disabled)");
+ f_vty_config(MGWVTY, "mgcp", "conn-timeout 0");
+
+ setverdict(pass);
+ }
+
+ /* Test (valid) CRCX followed by (valid) DLCX containing EP (E1) */
+ testcase TC_e1_crcx_and_dlcx_ep() runs on dummy_CT {
+ var template MgcpCommand cmd;
+ var MgcpResponse resp;
+ var MgcpEndpoint ep := "ds/e1-1/s-1/su16-0@" & c_mgw_domain;
+ var MgcpCallId call_id := '8376F297'H;
+
+ f_init(ep);
+
+ cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
+ resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+
+ f_dlcx_ok(ep);
+
setverdict(pass);
}
+ /* Test what happens when overlapping endpoints are selected (E1) */
+ testcase TC_e1_crcx_with_overlap() runs on dummy_CT {
+ var template MgcpCommand cmd;
+ var MgcpResponse resp;
+ var MgcpEndpoint ep_1 := "ds/e1-1/s-1/su8-0@" & c_mgw_domain;
+ var MgcpEndpoint ep_2 := "ds/e1-1/s-1/su16-0@" & c_mgw_domain;
+ var MgcpCallId call_id_1 := '8376F297'H;
+ var MgcpCallId call_id_2 := '837AF2A7'H;
+
+ f_init();
+
+ /* ep_1 and ep_2 are overlapping, selecting both one after
+ * another should work fine: */
+ cmd := ts_CRCX(get_next_trans_id(), ep_1, "recvonly", call_id_1);
+ resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ f_dlcx_ok(ep_1);
+ cmd := ts_CRCX(get_next_trans_id(), ep_2, "recvonly", call_id_2);
+ resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ f_dlcx_ok(ep_2);
+
+ /* When ep_1 is serving a call we can not select ep_2 becaus
+ * it is overlapping with ep_1 */
+ cmd := ts_CRCX(get_next_trans_id(), ep_1, "recvonly", call_id_1);
+ resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ cmd := ts_CRCX(get_next_trans_id(), ep_2, "recvonly", call_id_2);
+ resp := mgcp_transceive_mgw(cmd, ?);
+ if (resp.line.code != "501") {
+ setverdict(fail, "unexpected CRCX returncode, CRCX should fail!");
+ }
+ f_dlcx_ok(ep_1);
+
+ setverdict(pass);
+ }
+
+ /* Create one connection in loopback mode, test if the RTP packets are
+ * actually reflected */
+ testcase TC_e1_crcx_loopback() runs on dummy_CT {
+ var RtpFlowData flow;
+ var MgcpEndpoint ep := "ds/e1-1/s-1/su16-0@" & c_mgw_domain;
+ var MgcpCallId call_id := '12250989'H;
+ var RtpemStats stats;
+
+ f_init(ep);
+ flow := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 111, "GSM-HR-08/8000/1"));
+ flow.em.portnr := 10000;
+ f_flow_create(RTPEM[0], ep, call_id, "loopback", flow);
+
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
+ f_sleep(1.0);
+ f_flow_delete(RTPEM[0], ep, call_id);
+
+ stats := f_rtpem_stats_get(RTPEM[0]);
+
+ if (stats.num_pkts_tx != stats.num_pkts_rx) {
+ setverdict(fail);
+ }
+ if (stats.bytes_payload_tx != stats.bytes_payload_rx) {
+ setverdict(fail);
+ }
+
+ f_rtpem_stats_err_check(stats);
+
+ setverdict(pass);
+ }
+
+ /* test valid wildcarded DLCX on an E1 trunk */
+ testcase TC_e1_dlcx_wildcarded() runs on dummy_CT {
+ var template MgcpCommand cmd;
+ var MgcpEndpoint ep;
+ var MgcpCallId call_id := '8376F297'H;
+ var integer n_e1_ts := 4;
+ var StatsDExpects expect;
+
+ f_init();
+
+ /* Open a few E1 timeslots */
+ for (var integer i := 0; i < n_e1_ts; i := i+1) {
+ ep := "ds/e1-1/s-" & int2str(i+1) & "/su16-0@" & c_mgw_domain;
+ cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
+ mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ ep := "ds/e1-1/s-" & int2str(i+1) & "/su16-2@" & c_mgw_domain;
+ cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
+ mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ ep := "ds/e1-1/s-" & int2str(i+1) & "/su16-4@" & c_mgw_domain;
+ cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
+ mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ ep := "ds/e1-1/s-" & int2str(i+1) & "/su16-6@" & c_mgw_domain;
+ cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
+ mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ }
+
+ /* Wait until the stats items have settled and then check if we get the expected number (all) of
+ * occupied endpoints */
+ f_sleep(1.0)
+ expect := {
+ { name := "TTCN3.trunk.e1-1.common.endpoints.used", mtype := "g", min := n_e1_ts * 4, max := n_e1_ts * 4}
+ };
+ f_statsd_expect(expect);
+
+ /* Send wildcarded DLCX */
+ var template MgcpResponse rtmpl := {
+ line := {
+ code := "200",
+ string := ?
+ },
+ params:= { },
+ sdp := omit
+ };
+ ep := "ds/e1-1/*@" & c_mgw_domain;
+ cmd := ts_DLCX(get_next_trans_id(), ep);
+ mgcp_transceive_mgw(cmd, rtmpl);
+
+ /* Query the statsd once to ensure that intermediate results are pulled from the
+ * pipeline. The second query (below) will return the actual result. */
+ expect := {
+ { name := "TTCN3.trunk.e1-1.common.endpoints.used", mtype := "g", min := 0, max := n_e1_ts * 4}
+ };
+ f_statsd_expect(expect);
+
+ /* The second query must return a result with 0 endpoints in use. */
+ expect := {
+ { name := "TTCN3.trunk.e1-1.common.endpoints.used", mtype := "g", min := 0, max := 0}
+ };
+ f_statsd_expect(expect);
+
+ setverdict(pass);
+ }
+
+ /* test valid CRCX then MDCX with IPv4 address, MGW provides a local IPv4 too */
+ testcase TC_crcx_mdcx_ip4() runs on dummy_CT {
+ var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
+ var template MgcpCommand cmd;
+ var MgcpResponse resp;
+ var MgcpCallId call_id := '1234'H;
+ var MgcpConnectionId conn_id;
+
+ f_init(ep);
+
+ /* create the connection on the MGW */
+ cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
+ resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ conn_id := extract_conn_id(resp);
+
+ cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, conn_id);
+ cmd.sdp := ts_SDP("127.0.0.2", "127.0.0.1", "23", "42", 2344, { "98" },
+ { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
+ valueof(ts_SDP_ptime(20)) });
+ resp := mgcp_transceive_mgw(cmd, tr_MDCX_ACK);
+
+ if (not ispresent(resp.sdp) or not ispresent(resp.sdp.connection)) {
+ setverdict(fail, "No RemoteConnection info found in MDCX ACK!");
+ }
+ if (not match(resp.sdp.connection, ts_SDP_connection_IP("127.0.0.1", "IP4"))) {
+ setverdict(fail, "Wrong RemoteConnection in MDCX ACK!", resp.sdp.connection);
+ }
+
+ /* clean-up */
+ f_dlcx_ok(ep, call_id);
+ setverdict(pass);
+ }
+
+ /* test valid CRCX then MDCX with IPv6 address, MGW provides a local IPv6 too */
+ testcase TC_crcx_mdcx_ip6() runs on dummy_CT {
+ var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
+ var template MgcpCommand cmd;
+ var MgcpResponse resp;
+ var MgcpCallId call_id := '1234'H;
+ var MgcpConnectionId conn_id;
+
+ f_init(ep);
+
+ /* create the connection on the MGW */
+ cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
+ resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
+ conn_id := extract_conn_id(resp);
+
+ cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, conn_id);
+ cmd.sdp := ts_SDP("::2", "::1", "23", "42", 2344, { "98" },
+ { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
+ valueof(ts_SDP_ptime(20)) });
+ resp := mgcp_transceive_mgw(cmd, tr_MDCX_ACK);
+
+ if (not ispresent(resp.sdp) or not ispresent(resp.sdp.connection)) {
+ setverdict(fail, "No RemoteConnection info found in MDCX ACK!");
+ }
+ if (not match(resp.sdp.connection, ts_SDP_connection_IP("::1", "IP6"))) {
+ setverdict(fail, "Wrong RemoteConnection in MDCX ACK!", resp.sdp.connection);
+ }
+
+ /* clean-up */
+ f_dlcx_ok(ep, call_id);
+ setverdict(pass);
+ }
+
+ /* create two local emulations and pass data in both directions */
+ function f_two_crcx_mdcx_data_transfer(MgcpEndpoint ep, MgcpCallId call_id, inout RtpFlowData flow_a,
+ inout RtpFlowData flow_b, boolean tear_down_rtp := true) runs on dummy_CT {
+ var RtpemStats stats[2];
+ var MgcpResponse resp;
+ var integer num_pkts_tx[2];
+ var integer temp;
+
+ /* Create the first connection in receive only mode (RNC side, IuUP-Init active) */
+ f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow_a, true);
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
+
+ /* Create the second connection. This connection will be also
+ * in receive only mode (CN side, regular RTP) */
+ f_flow_create(RTPEM[1], ep, call_id, "recvonly", flow_b, true);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
+
+ /* The first leg starts transmitting */
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
+ f_sleep(0.5);
+ stats[0] := f_rtpem_stats_get(RTPEM[0]);
+ if (stats[0].num_pkts_rx_err_disabled != 0) {
+ setverdict(fail, "received packets from MGW on recvonly connection 0");
+ mtc.stop;
+ }
+ stats[1] := f_rtpem_stats_get(RTPEM[1]);
+ if (stats[1].num_pkts_rx_err_disabled != 0) {
+ setverdict(fail, "received packets from MGW on recvonly connection 1");
+ mtc.stop;
+ }
+
+ /* The second leg starts transmitting a little later */
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_TXONLY);
+ f_sleep(1.0);
+ stats[0] := f_rtpem_stats_get(RTPEM[0]);
+ if (stats[0].num_pkts_rx_err_disabled != 0) {
+ setverdict(fail, "received packets from MGW on recvonly connection 0");
+ mtc.stop;
+ }
+ stats[1] := f_rtpem_stats_get(RTPEM[1]);
+ if (stats[1].num_pkts_rx_err_disabled != 0) {
+ setverdict(fail, "received packets from MGW on recvonly connection 1");
+ mtc.stop;
+ }
+
+ /* The first leg will now be switched into bidirectional
+ * mode, but we do not expect any data coming back yet. */
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
+ stats[1] := f_rtpem_stats_get(RTPEM[1]);
+ num_pkts_tx[1] := stats[1].num_pkts_tx;
+ f_flow_modify(RTPEM[0], ep, call_id, "sendrecv", flow_a);
+ f_sleep(0.5);
+ stats[0] := f_rtpem_stats_get(RTPEM[0]);
+ if (stats[0].num_pkts_rx_err_disabled != 0) {
+ setverdict(fail, "received packets from MGW on recvonly connection 0");
+ mtc.stop;
+ }
+ stats[1] := f_rtpem_stats_get(RTPEM[1]);
+ if (stats[1].num_pkts_rx_err_disabled != 0) {
+ setverdict(fail, "received packets from MGW on recvonly connection 1");
+ mtc.stop;
+ }
+
+ /* When the second leg is switched into bidirectional mode
+ * as well, then the MGW will connect the two together and
+ * we should see RTP streams passing through from both ends. */
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
+ stats[0] := f_rtpem_stats_get(RTPEM[0]);
+ num_pkts_tx[0] := stats[0].num_pkts_tx;
+ f_flow_modify(RTPEM[1], ep, call_id, "sendrecv", flow_b);
+ f_sleep(2.0);
+
+ stats[0] := f_rtpem_stats_get(RTPEM[0]);
+ stats[1] := f_rtpem_stats_get(RTPEM[1]);
+
+ temp := stats[0].num_pkts_tx - num_pkts_tx[0] - stats[1].num_pkts_rx;
+ if (temp > 3 or temp < -3) {
+ setverdict(fail, "number of packets not within normal parameters:", temp);
+ mtc.stop;
+ }
+
+ temp := stats[1].num_pkts_tx - num_pkts_tx[1] - stats[0].num_pkts_rx;
+ if (temp > 3 or temp < -3) {
+ setverdict(fail, "number of packets not within normal parameters:", temp);
+ mtc.stop;
+ }
+
+ f_rtpem_stats_err_check(stats[0]);
+ f_rtpem_stats_err_check(stats[1]);
+
+ /* Tear down */
+ if (tear_down_rtp) {
+ f_flow_delete(RTPEM[0]);
+ f_flow_delete(RTPEM[1], ep, call_id);
+ }
+ setverdict(pass);
+ }
+
+ /* create two local RTP+IuUP emulations and pass data in both directions */
+ function f_tc_two_crcx_mdcx_and_iuup(charstring local_ip_a, charstring remote_ip_a,
+ IuUP_RabFlowCombinationList rfcl_a,
+ charstring local_ip_b, charstring remote_ip_b) runs on dummy_CT {
+ var RtpFlowData flow[2];
+ var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
+ var MgcpCallId call_id := '1227'H;
+
+ f_init(ep);
+
+ /* Create the first connection in receive only mode (RNC side, IuUP-Init active) */
+ flow[0] := valueof(t_RtpFlow(local_ip_a, remote_ip_a, 96, "VND.3GPP.IUFP/16000"));
+ flow[0].em.portnr := 10000;
+ flow[0].rtp_cfg := c_RtpemDefaultCfg;
+ flow[0].rtp_cfg.rx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.tx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.iuup_mode := true;
+ flow[0].rtp_cfg.iuup_cfg.active_init := true;
+ flow[0].rtp_cfg.iuup_cfg.rab_flow_combs := rfcl_a;
+
+ /* Create the second connection. This connection will be also
+ * in receive only mode (CN side, IuUP-Init passive) */
+ flow[1] := valueof(t_RtpFlow(local_ip_b, remote_ip_b, 96, "VND.3GPP.IUFP/16000"));
+ flow[1].em.portnr := 20000;
+ flow[1].rtp_cfg := c_RtpemDefaultCfg;
+ flow[1].rtp_cfg.rx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.tx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.iuup_mode := true;
+ flow[1].rtp_cfg.iuup_cfg.active_init := false;
+
+ f_two_crcx_mdcx_data_transfer(ep, call_id, flow[0], flow[1], true);
+ setverdict(pass);
+ }
+ testcase TC_two_crcx_mdcx_and_iuup() runs on dummy_CT {
+ var template (value) IuUP_RabFlowCombinationList rfcl := {
+ t_IuUP_RFC_AMR_12_2(0),
+ t_IuUP_RFC_AMR_SID(1),
+ t_IuUP_RFC_AMR_NO_DATA(2)
+ };
+ f_tc_two_crcx_mdcx_and_iuup(mp_local_ipv4, mp_remote_ipv4, valueof(rfcl),
+ mp_local_ipv4, mp_remote_ipv4);
+ }
+ /* Same as TC_two_crcx_mdcx_and_iuup, but passing unordered RFCI list (ID != position) */
+ testcase TC_two_crcx_mdcx_and_iuup_rfci_unordered() runs on dummy_CT {
+ var template (value) IuUP_RabFlowCombinationList rfcl := {
+ t_IuUP_RFC_AMR_12_2(1),
+ t_IuUP_RFC_AMR_SID(2),
+ t_IuUP_RFC_AMR_NO_DATA(0)
+ };
+ f_tc_two_crcx_mdcx_and_iuup(mp_local_ipv4, mp_remote_ipv4, valueof(rfcl),
+ mp_local_ipv4, mp_remote_ipv4);
+ }
+
+ /* Test that once IuUP->RTP has been set up, if the RTP/IuUP conn is set
+ * as "recvonly", no more RTP/IuUP packets get out of the MGW. */
+ function f_tc_two_crcx_mdcx_and_iuup_mdcx_recvonly(charstring local_ip_a, charstring remote_ip_a,
+ IuUP_RabFlowCombinationList rfcl_a,
+ charstring local_ip_b, charstring remote_ip_b) runs on dummy_CT {
+ var RtpFlowData flow[2];
+ var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
+ var MgcpCallId call_id := '1227'H;
+ var RtpemStats stats[2];
+
+ f_init(ep);
+
+ /* Create the first connection in receive only mode (RNC side, IuUP-Init active) */
+ flow[0] := valueof(t_RtpFlow(local_ip_a, remote_ip_a, 96, "VND.3GPP.IUFP/16000"));
+ flow[0].em.portnr := 10000;
+ flow[0].rtp_cfg := c_RtpemDefaultCfg;
+ flow[0].rtp_cfg.rx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.tx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.iuup_mode := true;
+ flow[0].rtp_cfg.iuup_cfg.active_init := true;
+ flow[0].rtp_cfg.iuup_cfg.rab_flow_combs := rfcl_a;
+
+ /* Create the second connection. This connection will be also
+ * in receive only mode (CN side, IuUP-Init passive) */
+ flow[1] := valueof(t_RtpFlow(local_ip_b, remote_ip_b, 96, "VND.3GPP.IUFP/16000"));
+ flow[1].em.portnr := 20000;
+ flow[1].rtp_cfg := c_RtpemDefaultCfg;
+ flow[1].rtp_cfg.rx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.tx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.iuup_mode := true;
+ flow[1].rtp_cfg.iuup_cfg.active_init := false;
+
+ f_two_crcx_mdcx_data_transfer(ep, call_id, flow[0], flow[1], false);
+
+ /* Now validate we don't receive more RTP packets after setting it to recvonly: */
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
+ f_flow_modify(RTPEM[1], ep, call_id, "recvonly", flow[1]);
+ f_sleep(0.5);
+ stats[0] := f_rtpem_stats_get(RTPEM[1]);
+ f_sleep(0.5);
+ stats[1] := f_rtpem_stats_get(RTPEM[1]);
+ if (stats[1].num_pkts_rx > stats[0].num_pkts_rx) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("received ", stats[1].num_pkts_rx - stats[0].num_pkts_rx, " RTP packets from MGW on recvonly connection 1"));
+ }
+
+ /* Now do the same on the IuUP port: */
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_TXONLY);
+ f_flow_modify(RTPEM[0], ep, call_id, "recvonly", flow[0]);
+ f_sleep(0.5);
+ stats[0] := f_rtpem_stats_get(RTPEM[0]);
+ f_sleep(0.5);
+ stats[1] := f_rtpem_stats_get(RTPEM[0]);
+ if (stats[1].num_pkts_rx > stats[0].num_pkts_rx) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("received ", stats[1].num_pkts_rx - stats[0].num_pkts_rx, " IuUP packets from MGW on recvonly connection 1"));
+ }
+
+ /* Tear down */
+ f_flow_delete(RTPEM[0]);
+ f_flow_delete(RTPEM[1], ep, call_id);
+ setverdict(pass);
+ }
+ testcase TC_two_crcx_mdcx_and_iuup_mdcx_recvonly() runs on dummy_CT {
+ var template (value) IuUP_RabFlowCombinationList rfcl := {
+ t_IuUP_RFC_AMR_12_2(0),
+ t_IuUP_RFC_AMR_SID(1),
+ t_IuUP_RFC_AMR_NO_DATA(2)
+ };
+ f_tc_two_crcx_mdcx_and_iuup_mdcx_recvonly(mp_local_ipv4, mp_remote_ipv4, valueof(rfcl),
+ mp_local_ipv4, mp_remote_ipv4);
+ }
+
+ /* create two local emulations (1 RTP, 1 RTP+IuUP) and pass data in both directions */
+ function f_tc_two_crcx_mdcx_and_iuup_rtp(charstring local_ip_a, charstring remote_ip_a,
+ IuUP_RabFlowCombinationList rfcl_a,
+ charstring local_ip_b, charstring remote_ip_b) runs on dummy_CT {
+ var RtpFlowData flow[2];
+ var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
+ var MgcpCallId call_id := '1227'H;
+
+ f_init(ep);
+
+ /* Create the first connection in receive only mode (RNC side, IuUP-Init active) */
+ flow[0] := valueof(t_RtpFlow(local_ip_a, remote_ip_a, 96, "VND.3GPP.IUFP/16000"));
+ flow[0].em.portnr := 10000;
+ flow[0].rtp_cfg := c_RtpemDefaultCfg;
+ flow[0].rtp_cfg.tx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.rx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.tx_payloads[0].fixed_payload := '4f28959ffeb80181f5c4e83d176c897b4a4e333298333419a493ca63ded6e0'O;
+ /* flow[1].rtp_cfg.rx_payloads[0].fixed_payload converted AMR-BE-RTP->AMR-IUUP*/
+ flow[0].rtp_cfg.rx_payloads[0].fixed_payload := '08556d944c71a1a081e7ead204244480000ecd82b81118000097c4794e7740'O;
+ flow[0].rtp_cfg.iuup_mode := true;
+ flow[0].rtp_cfg.iuup_cfg.active_init := true;
+ flow[0].rtp_cfg.iuup_cfg.rab_flow_combs := rfcl_a;
+
+ /* Create the second connection. This connection will be also
+ * in receive only mode (CN side, regular RTP) */
+ flow[1] := valueof(t_RtpFlow(local_ip_b, remote_ip_b, 112, "AMR/8000"));
+ flow[1].em.portnr := 20000;
+ flow[1].rtp_cfg := c_RtpemDefaultCfg;
+ flow[1].rtp_cfg.tx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.rx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.tx_payloads[0].fixed_payload := '0382155b65131c68682079fab4810911200003b360ae0446000025f11e539dd0'O;
+ /* flow[0].rtp_cfg.rx_payloads[0].fixed_payload converted AMR-IuUP->AMR-BE-RTP*/
+ flow[1].rtp_cfg.rx_payloads[0].fixed_payload := 'f3d3ca2567ffae00607d713a0f45db225ed2938ccca60ccd066924f298f7b5b8'O;
+ flow[1].rtp_cfg.iuup_mode := false;
+
+ f_two_crcx_mdcx_data_transfer(ep, call_id, flow[0], flow[1], true);
+ setverdict(pass);
+ }
+ testcase TC_two_crcx_mdcx_and_iuup_rtp() runs on dummy_CT {
+ var template (value) IuUP_RabFlowCombinationList rfcl := {
+ t_IuUP_RFC_AMR_12_2(0),
+ t_IuUP_RFC_AMR_SID(1),
+ t_IuUP_RFC_AMR_NO_DATA(2)
+ };
+ f_tc_two_crcx_mdcx_and_iuup_rtp(mp_local_ipv4, mp_remote_ipv4, valueof(rfcl),
+ mp_local_ipv4, mp_remote_ipv4);
+ }
+ /* Same as TC_two_crcx_mdcTC_two_crcx_mdcx_and_iuup_rtpx_and_iuup, but passing unordered RFCI list (ID != position) */
+ testcase TC_two_crcx_mdcx_and_iuup_rtp_rfci_unordered() runs on dummy_CT {
+ var template (value) IuUP_RabFlowCombinationList rfcl := {
+ t_IuUP_RFC_AMR_12_2(1),
+ t_IuUP_RFC_AMR_SID(2),
+ t_IuUP_RFC_AMR_NO_DATA(0)
+ };
+ f_tc_two_crcx_mdcx_and_iuup_rtp(mp_local_ipv4, mp_remote_ipv4, valueof(rfcl),
+ mp_local_ipv4, mp_remote_ipv4);
+ }
+
+ /* Test that once IuUP->RTP has been set up, if the RTP/IuUP conn is set
+ * as "recvonly", no more RTP/IuUP packets get out of the MGW. */
+ function f_tc_two_crcx_mdcx_and_iuup_rtp_mdcx_recvonly(charstring local_ip_a, charstring remote_ip_a,
+ IuUP_RabFlowCombinationList rfcl_a,
+ charstring local_ip_b, charstring remote_ip_b) runs on dummy_CT {
+ var RtpFlowData flow[2];
+ var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
+ var MgcpCallId call_id := '1227'H;
+ var RtpemStats stats[2];
+
+ f_init(ep);
+
+ /* Create the first connection in receive only mode (RNC side, IuUP-Init active) */
+ flow[0] := valueof(t_RtpFlow(local_ip_a, remote_ip_a, 96, "VND.3GPP.IUFP/16000"));
+ flow[0].em.portnr := 10000;
+ flow[0].rtp_cfg := c_RtpemDefaultCfg;
+ flow[0].rtp_cfg.tx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.rx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.tx_payloads[0].fixed_payload := '4f28959ffeb80181f5c4e83d176c897b4a4e333298333419a493ca63ded6e0'O;
+ /* flow[1].rtp_cfg.rx_payloads[0].fixed_payload converted AMR-BE-RTP->AMR-IUUP*/
+ flow[0].rtp_cfg.rx_payloads[0].fixed_payload := '08556d944c71a1a081e7ead204244480000ecd82b81118000097c4794e7740'O;
+ flow[0].rtp_cfg.iuup_mode := true;
+ flow[0].rtp_cfg.iuup_cfg.active_init := true;
+ flow[0].rtp_cfg.iuup_cfg.rab_flow_combs := rfcl_a;
+
+ /* Create the second connection. This connection will be also
+ * in receive only mode (CN side, regular RTP) */
+ flow[1] := valueof(t_RtpFlow(local_ip_b, remote_ip_b, 112, "AMR/8000"));
+ flow[1].em.portnr := 20000;
+ flow[1].rtp_cfg := c_RtpemDefaultCfg;
+ flow[1].rtp_cfg.tx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.rx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.tx_payloads[0].fixed_payload := '0382155b65131c68682079fab4810911200003b360ae0446000025f11e539dd0'O;
+ /* flow[0].rtp_cfg.rx_payloads[0].fixed_payload converted AMR-IuUP->AMR-BE-RTP*/
+ flow[1].rtp_cfg.rx_payloads[0].fixed_payload := 'f3d3ca2567ffae00607d713a0f45db225ed2938ccca60ccd066924f298f7b5b8'O;
+ flow[1].rtp_cfg.iuup_mode := false;
+
+ f_two_crcx_mdcx_data_transfer(ep, call_id, flow[0], flow[1], false);
+
+ /* Now validate we don't receive more RTP packets after setting it to recvonly: */
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
+ f_flow_modify(RTPEM[1], ep, call_id, "recvonly", flow[1]);
+ f_sleep(0.5);
+ stats[0] := f_rtpem_stats_get(RTPEM[1]);
+ f_sleep(0.5);
+ stats[1] := f_rtpem_stats_get(RTPEM[1]);
+ if (stats[1].num_pkts_rx > stats[0].num_pkts_rx) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("received ", stats[1].num_pkts_rx - stats[0].num_pkts_rx, " RTP packets from MGW on recvonly connection 1"));
+ }
+
+ /* Now do the same on the IuUP port: */
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
+ f_flow_modify(RTPEM[0], ep, call_id, "recvonly", flow[0]);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_TXONLY);
+ f_flow_modify(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
+ f_sleep(0.5);
+ stats[0] := f_rtpem_stats_get(RTPEM[0]);
+ f_sleep(0.5);
+ stats[1] := f_rtpem_stats_get(RTPEM[0]);
+ if (stats[1].num_pkts_rx > stats[0].num_pkts_rx) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("received ", stats[1].num_pkts_rx - stats[0].num_pkts_rx, " IuUP packets from MGW on recvonly connection 1"));
+ }
+
+ /* Tear down */
+ f_flow_delete(RTPEM[0]);
+ f_flow_delete(RTPEM[1], ep, call_id);
+ setverdict(pass);
+ }
+ testcase TC_two_crcx_mdcx_and_iuup_rtp_mdcx_recvonly() runs on dummy_CT {
+ var template (value) IuUP_RabFlowCombinationList rfcl := {
+ t_IuUP_RFC_AMR_12_2(0),
+ t_IuUP_RFC_AMR_SID(1),
+ t_IuUP_RFC_AMR_NO_DATA(2)
+ };
+ f_tc_two_crcx_mdcx_and_iuup_rtp_mdcx_recvonly(mp_local_ipv4, mp_remote_ipv4, valueof(rfcl),
+ mp_local_ipv4, mp_remote_ipv4);
+ }
+
+ /* Set up Endpoint with 1 IuUP conn and 1 RTP-AMR conn, then MDCX the later to become IuUP. */
+ function f_tc_two_crcx_mdcx_and_iuup_rtp_mdcx_to_iuup(charstring local_ip_a, charstring remote_ip_a,
+ IuUP_RabFlowCombinationList rfcl_a,
+ charstring local_ip_b, charstring remote_ip_b) runs on dummy_CT {
+ var RtpFlowData flow[2];
+ var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
+ var MgcpCallId call_id := '1227'H;
+ var RtpemStats stats[2][2];
+
+ f_init(ep);
+
+ /* Create the first connection in receive only mode (RNC side, IuUP-Init active) */
+ flow[0] := valueof(t_RtpFlow(local_ip_a, remote_ip_a, 96, "VND.3GPP.IUFP/16000"));
+ flow[0].em.portnr := 10000;
+ flow[0].rtp_cfg := c_RtpemDefaultCfg;
+ flow[0].rtp_cfg.tx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.rx_payloads[0].payload_type := flow[0].codec_descr[0].pt;
+ flow[0].rtp_cfg.tx_payloads[0].fixed_payload := '4f28959ffeb80181f5c4e83d176c897b4a4e333298333419a493ca63ded6e0'O;
+ /* flow[1].rtp_cfg.rx_payloads[0].fixed_payload converted AMR-BE-RTP->AMR-IUUP*/
+ flow[0].rtp_cfg.rx_payloads[0].fixed_payload := '08556d944c71a1a081e7ead204244480000ecd82b81118000097c4794e7740'O;
+ flow[0].rtp_cfg.iuup_mode := true;
+ flow[0].rtp_cfg.iuup_cfg.active_init := true;
+ flow[0].rtp_cfg.iuup_cfg.rab_flow_combs := rfcl_a;
+
+ /* Create the second connection. This connection will be also
+ * in receive only mode (CN side, regular RTP) */
+ flow[1] := valueof(t_RtpFlow(local_ip_b, remote_ip_b, 112, "AMR/8000"));
+ flow[1].em.portnr := 20000;
+ flow[1].rtp_cfg := c_RtpemDefaultCfg;
+ flow[1].rtp_cfg.tx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.rx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ flow[1].rtp_cfg.tx_payloads[0].fixed_payload := '0382155b65131c68682079fab4810911200003b360ae0446000025f11e539dd0'O;
+ /* flow[0].rtp_cfg.rx_payloads[0].fixed_payload converted AMR-IuUP->AMR-BE-RTP*/
+ flow[1].rtp_cfg.rx_payloads[0].fixed_payload := 'f3d3ca2567ffae00607d713a0f45db225ed2938ccca60ccd066924f298f7b5b8'O;
+ flow[1].rtp_cfg.iuup_mode := false;
+
+ f_two_crcx_mdcx_data_transfer(ep, call_id, flow[0], flow[1], false);
+ setverdict(pass);
+
+ /* Stop sending further pkts to RTPEM[1], to avoid race conditions where RTP is sent while we
+ * reconfigure MGW (and our RTPEM) for IuUP:
+ */
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
+ f_sleep(0.5);
+
+ /* Modify the AMR side to also do IuUP */
+ flow[1].codec_descr := {{
+ pt := 96,
+ codec := "VND.3GPP.IUFP/16000",
+ fmtp := omit
+ }};
+ flow[1].rtp_cfg.iuup_mode := true;
+ flow[1].rtp_cfg.iuup_cfg.active_init := false;
+ flow[1].rtp_cfg.iuup_cfg.rab_flow_combs := rfcl_a;
+ flow[1].rtp_cfg.tx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ /* Send whatever payload is expected by the other RTPEM, now without AMR-BE_RTP<->AMR-IUUP conversion: */
+ flow[1].rtp_cfg.tx_payloads[0].fixed_payload := flow[0].rtp_cfg.rx_payloads[0].fixed_payload;
+ flow[1].rtp_cfg.rx_payloads[0].payload_type := flow[1].codec_descr[0].pt;
+ /* Expect whatever payload is sent by the other RTPEM, now without AMR-BE_RTP<->AMR-IUUP conversion: */
+ flow[1].rtp_cfg.rx_payloads[0].fixed_payload := flow[0].rtp_cfg.tx_payloads[0].fixed_payload;
+ f_flow_modify(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
+ f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
+ f_sleep(1.0);
+ f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
+
+ /* Now, if MGW would keep sending RTP instead of expected IuUP, then that would make the RTPEM[1]
+ * component to fail, since it would error trying to decode an RTP pkt as IuUP.
+ * We simply need to make sure some packets are being forwarded to it:
+ */
+ stats[0][0] := f_rtpem_stats_get(RTPEM[0]);
+ stats[1][0] := f_rtpem_stats_get(RTPEM[1]);
+ f_sleep(1.0);
+ stats[0][1] := f_rtpem_stats_get(RTPEM[0]);
+ stats[1][1] := f_rtpem_stats_get(RTPEM[1]);
+
+ f_rtpem_stats_err_check(stats[0][1]);
+ f_rtpem_stats_err_check(stats[1][1]);
+ if (stats[0][1].num_pkts_rx == stats[0][0].num_pkts_rx) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("No packets received in connection 0 after MDCX"));
+ }
+ if (stats[1][1].num_pkts_rx == stats[1][0].num_pkts_rx) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("No packets received in connection 1 after MDCX"));
+ }
+
+ /* Tear down */
+ f_flow_delete(RTPEM[0]);
+ f_flow_delete(RTPEM[1], ep, call_id);
+ setverdict(pass);
+ }
+ testcase TC_two_crcx_mdcx_and_iuup_rtp_mdcx_to_iuup() runs on dummy_CT {
+ var template (value) IuUP_RabFlowCombinationList rfcl := {
+ t_IuUP_RFC_AMR_12_2(0),
+ t_IuUP_RFC_AMR_SID(1),
+ t_IuUP_RFC_AMR_NO_DATA(2)
+ };
+ f_tc_two_crcx_mdcx_and_iuup_rtp_mdcx_to_iuup(mp_local_ipv4, mp_remote_ipv4, valueof(rfcl),
+ mp_local_ipv4, mp_remote_ipv4);
+ }
control {
execute(TC_selftest());
+ execute(TC_auep_null());
execute(TC_crcx());
execute(TC_crcx_no_lco());
execute(TC_crcx_noprefix());
execute(TC_crcx_unsupp_mode());
+ execute(TC_crcx_osmo_ign());
execute(TC_crcx_early_bidir_mode());
execute(TC_crcx_unsupp_param());
execute(TC_crcx_missing_callid());
@@ -2127,6 +3300,7 @@ module MGCP_Test {
execute(TC_crcx_wildcarded_exhaust());
execute(TC_mdcx_without_crcx());
execute(TC_dlcx_without_crcx());
+ execute(TC_dlcx_non_existant_ep());
execute(TC_mdcx_wildcarded());
execute(TC_dlcx_wildcarded());
execute(TC_crcx_and_dlcx_ep_callid_connid());
@@ -2139,10 +3313,12 @@ module MGCP_Test {
execute(TC_crcx_osmux_wildcard());
execute(TC_crcx_osmux_fixed());
execute(TC_crcx_osmux_fixed_twice());
+ execute(TC_crcx_osmux_257());
execute(TC_one_crcx_receive_only_osmux());
execute(TC_one_crcx_loopback_osmux());
execute(TC_two_crcx_and_rtp_osmux());
execute(TC_two_crcx_and_rtp_osmux_bidir());
+ execute(TC_two_crcx_and_rtp_osmux_bidir_amr_bwe());
execute(TC_two_crcx_mdcx_and_rtp_osmux_wildcard());
execute(TC_two_crcx_mdcx_and_rtp_osmux_fixed());
@@ -2152,6 +3328,7 @@ module MGCP_Test {
execute(TC_one_crcx_receive_only_rtp());
execute(TC_one_crcx_loopback_rtp());
+ execute(TC_one_crcx_loopback_rtp_ipv6());
execute(TC_two_crcx_and_rtp());
execute(TC_two_crcx_and_rtp_bidir());
execute(TC_two_crcx_diff_pt_and_rtp());
@@ -2159,13 +3336,49 @@ module MGCP_Test {
execute(TC_two_crcx_mdcx_and_rtp());
execute(TC_two_crcx_and_unsolicited_rtp());
execute(TC_two_crcx_and_one_mdcx_rtp_ho());
+ execute(TC_two_crcx_confecho_sendonly_rtp());
execute(TC_ts101318_rfc5993_rtp_conversion());
+ execute(TC_ts101318_rfc5993_rtp_conversion_fmtp());
execute(TC_amr_oa_bwe_rtp_conversion());
execute(TC_amr_oa_oa_rtp_conversion());
execute(TC_amr_bwe_bwe_rtp_conversion());
-
- if (mp_enable_conn_timeout_test) {
- execute(TC_conn_timeout());
- }
+ execute(TC_amr_oa_oa_no_bwe_rtp_conversion());
+ execute(TC_amr_oa_no_bwe_oa_rtp_conversion());
+ execute(TC_amr_bwe_bwe_no_oa_rtp_conversion());
+ execute(TC_amr_bwe_no_oa_bwe_rtp_conversion());
+
+ execute(TC_conn_timeout());
+
+ execute(TC_e1_crcx_and_dlcx_ep());
+ execute(TC_e1_crcx_with_overlap());
+ execute(TC_e1_crcx_loopback());
+ execute(TC_e1_dlcx_wildcarded());
+
+ execute(TC_crcx_mdcx_ip4());
+ execute(TC_crcx_mdcx_ip6());
+ execute(TC_two_crcx_mdcx_and_rtp_ipv4_ipv6());
+ execute(TC_two_crcx_mdcx_and_rtp_ipv6());
+ execute(TC_two_crcx_and_rtp_osmux_bidir_ipv6());
+ execute(TC_two_crcx_and_rtp_osmux_bidir_ipv4_ipv6());
+ execute(TC_two_crcx_and_rtp_osmux_bidir_ipv6_ipv4());
+ execute(TC_two_crcx_mdcx_and_rtp_osmux_ipv6());
+ execute(TC_two_crcx_mdcx_and_rtp_osmux_ipv4_ipv6());
+ execute(TC_two_crcx_mdcx_and_rtp_osmux_ipv6_ipv4());
+
+ execute(TC_two_crcx_mdcx_and_iuup());
+ execute(TC_two_crcx_mdcx_and_iuup_rfci_unordered());
+ execute(TC_two_crcx_mdcx_and_iuup_mdcx_recvonly());
+ execute(TC_two_crcx_mdcx_and_iuup_rtp());
+ execute(TC_two_crcx_mdcx_and_iuup_rtp_rfci_unordered());
+ execute(TC_two_crcx_mdcx_and_iuup_rtp_mdcx_recvonly());
+ execute(TC_two_crcx_mdcx_and_iuup_rtp_mdcx_to_iuup());
+
+ execute(TC_two_crcx_mdcx_and_rtp_clearmode());
+
+ /* Note: This testcase will trigger an OSMO_ASSERT() bug in
+ * older versions of osmo-mgw. This eventually leads into
+ * a failure of all subsequent testcases, so it is important
+ * not to add new testcaes after this one. */
+ execute(TC_one_crcx_loopback_rtp_implicit());
}
}
diff --git a/mgw/README.md b/mgw/README.md
index 8f082624..86f0eeea 100644
--- a/mgw/README.md
+++ b/mgw/README.md
@@ -1,8 +1,10 @@
-== MGW_Test.ttcn
+# MGW_Test.ttcn
* external interfaces
* MGCP (emulates call agent)
* RTP (stream source/sink)
+ * Osmux (stream source/sink)
+ * VTY
{% dot mgw_tests.svg
digraph G {
@@ -10,8 +12,9 @@ digraph G {
MGW [label="IUT\nosmo-mgw",shape="box"];
ATS [label="ATS\nMGCP_Test.ttcn"];
- ATS -> MGW [label="RTP"];
+ ATS -> MGW [label="RTP", dir="both"];
+ ATS -> MGW [label="Osmux", dir="both"];
ATS -> MGW [label="MGCP"];
- MGW -> ATS [label="RTP"];
+ ATS -> MGW [label="VTY"];
}
%}
diff --git a/mgw/RTP_CodecPort_CtrlFunct.ttcn b/mgw/RTP_CodecPort_CtrlFunct.ttcn
deleted file mode 100644
index 9f6cad2d..00000000
--- a/mgw/RTP_CodecPort_CtrlFunct.ttcn
+++ /dev/null
@@ -1,44 +0,0 @@
-module RTP_CodecPort_CtrlFunct {
-
- import from RTP_CodecPort all;
- import from IPL4asp_Types all;
-
- external function f_IPL4_listen(
- inout RTP_CODEC_PT portRef,
- in HostName locName,
- in PortNumber locPort,
- in ProtoTuple proto,
- in OptionList options := {}
- ) return Result;
-
- external function f_IPL4_connect(
- inout RTP_CODEC_PT portRef,
- in HostName remName,
- in PortNumber remPort,
- in HostName locName,
- in PortNumber locPort,
- in ConnectionId connId,
- in ProtoTuple proto,
- in OptionList options := {}
- ) return Result;
-
- external function f_IPL4_close(
- inout RTP_CODEC_PT portRef,
- in ConnectionId id,
- in ProtoTuple proto := { unspecified := {} }
- ) return Result;
-
- external function f_IPL4_setUserData(
- inout RTP_CODEC_PT portRef,
- in ConnectionId id,
- in UserData userData
- ) return Result;
-
- external function f_IPL4_getUserData(
- inout RTP_CODEC_PT portRef,
- in ConnectionId id,
- out UserData userData
- ) return Result;
-
-}
-
diff --git a/mgw/RTP_CodecPort_CtrlFunctDef.cc b/mgw/RTP_CodecPort_CtrlFunctDef.cc
deleted file mode 100644
index ce8e176b..00000000
--- a/mgw/RTP_CodecPort_CtrlFunctDef.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "IPL4asp_PortType.hh"
-#include "RTP_CodecPort.hh"
-#include "IPL4asp_PT.hh"
-
-namespace RTP__CodecPort__CtrlFunct {
-
- IPL4asp__Types::Result f__IPL4__listen(
- RTP__CodecPort::RTP__CODEC__PT& portRef,
- const IPL4asp__Types::HostName& locName,
- const IPL4asp__Types::PortNumber& locPort,
- const IPL4asp__Types::ProtoTuple& proto,
- const IPL4asp__Types::OptionList& options)
- {
- return f__IPL4__PROVIDER__listen(portRef, locName, locPort, proto, options);
- }
-
- IPL4asp__Types::Result f__IPL4__connect(
- RTP__CodecPort::RTP__CODEC__PT& portRef,
- const IPL4asp__Types::HostName& remName,
- const IPL4asp__Types::PortNumber& remPort,
- const IPL4asp__Types::HostName& locName,
- const IPL4asp__Types::PortNumber& locPort,
- const IPL4asp__Types::ConnectionId& connId,
- const IPL4asp__Types::ProtoTuple& proto,
- const IPL4asp__Types::OptionList& options)
- {
- return f__IPL4__PROVIDER__connect(portRef, remName, remPort,
- locName, locPort, connId, proto, options);
- }
-
- IPL4asp__Types::Result f__IPL4__close(
- RTP__CodecPort::RTP__CODEC__PT& portRef,
- const IPL4asp__Types::ConnectionId& connId,
- const IPL4asp__Types::ProtoTuple& proto)
- {
- return f__IPL4__PROVIDER__close(portRef, connId, proto);
- }
-
- IPL4asp__Types::Result f__IPL4__setUserData(
- RTP__CodecPort::RTP__CODEC__PT& portRef,
- const IPL4asp__Types::ConnectionId& connId,
- const IPL4asp__Types::UserData& userData)
- {
- return f__IPL4__PROVIDER__setUserData(portRef, connId, userData);
- }
-
- IPL4asp__Types::Result f__IPL4__getUserData(
- RTP__CodecPort::RTP__CODEC__PT& portRef,
- const IPL4asp__Types::ConnectionId& connId,
- IPL4asp__Types::UserData& userData)
- {
- return f__IPL4__PROVIDER__getUserData(portRef, connId, userData);
- }
-
-}
-
diff --git a/mgw/expected-results.xml b/mgw/expected-results.xml
index 8975f784..d9b9a155 100644
--- a/mgw/expected-results.xml
+++ b/mgw/expected-results.xml
@@ -1,12 +1,12 @@
<?xml version="1.0"?>
-<testsuite name='Titan' tests='44' failures='0' errors='0' skipped='1' inconc='0' time='MASKED'>
- <testcase classname='MGCP_Test' name='TC_selftest' time='MASKED'>
- <skipped>no verdict</skipped>
- </testcase>
+<testsuite name='Titan' tests='84' failures='5' errors='0' skipped='0' inconc='0' time='MASKED'>
+ <testcase classname='MGCP_Test' name='TC_selftest' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_auep_null' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx_no_lco' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx_noprefix' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx_unsupp_mode' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_crcx_osmo_ign' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx_early_bidir_mode' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx_unsupp_param' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx_missing_callid' time='MASKED'/>
@@ -18,6 +18,7 @@
<testcase classname='MGCP_Test' name='TC_crcx_wildcarded_exhaust' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_mdcx_without_crcx' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_dlcx_without_crcx' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_dlcx_non_existant_ep' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_mdcx_wildcarded' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_dlcx_wildcarded' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx_and_dlcx_ep_callid_connid' time='MASKED'/>
@@ -29,16 +30,19 @@
<testcase classname='MGCP_Test' name='TC_crcx_osmux_wildcard' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx_osmux_fixed' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx_osmux_fixed_twice' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_crcx_osmux_257' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_one_crcx_receive_only_osmux' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_one_crcx_loopback_osmux' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp_osmux' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp_osmux_bidir' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp_osmux_bidir_amr_bwe' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp_osmux_wildcard' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp_osmux_fixed' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_crcx_dlcx_30ep' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_rtpem_selftest' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_one_crcx_receive_only_rtp' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_one_crcx_loopback_rtp' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_one_crcx_loopback_rtp_ipv6' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp_bidir' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_two_crcx_diff_pt_and_rtp' time='MASKED'/>
@@ -46,8 +50,58 @@
<testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_two_crcx_and_unsolicited_rtp' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_two_crcx_and_one_mdcx_rtp_ho' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_confecho_sendonly_rtp' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_ts101318_rfc5993_rtp_conversion' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_ts101318_rfc5993_rtp_conversion_fmtp' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_amr_oa_bwe_rtp_conversion' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_amr_oa_oa_rtp_conversion' time='MASKED'/>
<testcase classname='MGCP_Test' name='TC_amr_bwe_bwe_rtp_conversion' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_amr_oa_oa_no_bwe_rtp_conversion' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_amr_oa_no_bwe_oa_rtp_conversion' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_amr_bwe_bwe_no_oa_rtp_conversion' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_amr_bwe_no_oa_bwe_rtp_conversion' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_conn_timeout' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_e1_crcx_and_dlcx_ep' time='MASKED'>
+ <failure type='fail-verdict'>Response didn't match template
+ MGCP_Test.ttcn:MASKED MGCP_Test control part
+ MGCP_Test.ttcn:MASKED TC_e1_crcx_and_dlcx_ep testcase
+ </failure>
+ </testcase>
+ <testcase classname='MGCP_Test' name='TC_e1_crcx_with_overlap' time='MASKED'>
+ <failure type='fail-verdict'>Response didn't match template
+ MGCP_Test.ttcn:MASKED MGCP_Test control part
+ MGCP_Test.ttcn:MASKED TC_e1_crcx_with_overlap testcase
+ </failure>
+ </testcase>
+ <testcase classname='MGCP_Test' name='TC_e1_crcx_loopback' time='MASKED'>
+ <failure type='fail-verdict'>Response didn't match template
+ MGCP_Test.ttcn:MASKED MGCP_Test control part
+ MGCP_Test.ttcn:MASKED TC_e1_crcx_loopback testcase
+ </failure>
+ </testcase>
+ <testcase classname='MGCP_Test' name='TC_e1_dlcx_wildcarded' time='MASKED'>
+ <failure type='fail-verdict'>Response didn't match template
+ MGCP_Test.ttcn:MASKED MGCP_Test control part
+ MGCP_Test.ttcn:MASKED TC_e1_dlcx_wildcarded testcase
+ </failure>
+ </testcase>
+ <testcase classname='MGCP_Test' name='TC_crcx_mdcx_ip4' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_crcx_mdcx_ip6' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp_ipv4_ipv6' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp_ipv6' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp_osmux_bidir_ipv6' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp_osmux_bidir_ipv4_ipv6' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp_osmux_bidir_ipv6_ipv4' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp_osmux_ipv6' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp_osmux_ipv4_ipv6' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp_osmux_ipv6_ipv4' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_iuup' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_iuup_rfci_unordered' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_iuup_mdcx_recvonly' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_iuup_rtp' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_iuup_rtp_rfci_unordered' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_iuup_rtp_mdcx_recvonly' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_iuup_rtp_mdcx_to_iuup' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp_clearmode' time='MASKED'/>
+ <testcase classname='MGCP_Test' name='TC_one_crcx_loopback_rtp_implicit' time='MASKED'/>
</testsuite>
diff --git a/mgw/gen_links.sh b/mgw/gen_links.sh
index f9196370..2fd2b0da 100755
--- a/mgw/gen_links.sh
+++ b/mgw/gen_links.sh
@@ -38,12 +38,18 @@ FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn"
gen_links $DIR $FILES
DIR=../library
-FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn
+FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn SDP_Templates.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn
MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc "
+FILES+="AMR_Types.ttcn "
FILES+="RTP_CodecPort.ttcn RTP_Emulation.ttcn IuUP_Types.ttcn IuUP_Emulation.ttcn IuUP_EncDec.cc "
FILES+="OSMUX_CodecPort.ttcn OSMUX_Emulation.ttcn OSMUX_Types.ttcn OSMUX_CodecPort_CtrlFunct.ttcn OSMUX_CodecPort_CtrlFunctDef.cc "
FILES+="Native_Functions.ttcn Native_FunctionDefs.cc IPCP_Types.ttcn "
FILES+="Osmocom_VTY_Functions.ttcn "
+FILES+="RTP_CodecPort_CtrlFunct.ttcn RTP_CodecPort_CtrlFunctDef.cc "
+FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn "
+FILES+="IPA_Types.ttcn IPA_Emulation.ttcnpp IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc "
+FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn "
+
gen_links $DIR $FILES
ignore_pp_results
diff --git a/mgw/osmo-mgw.cfg b/mgw/osmo-mgw.cfg
index b27a50c1..2af7dffc 100644
--- a/mgw/osmo-mgw.cfg
+++ b/mgw/osmo-mgw.cfg
@@ -2,11 +2,17 @@
! OsmoMGW (1.2.0.17-52e3) configuration saved from vty
!!
!
+log gsmtap 127.0.0.1
+ logging level set-all debug
+ logging filter all 1
+!
log stderr
logging filter all 1
logging color 1
+ logging print level 1
logging print category 1
logging timestamp 1
+ logging print file basename last
logging print extended-timestamp 1
logging level set-all notice
logging level lmgcp debug
@@ -16,14 +22,30 @@ stats interval 5
line vty
no login
bind 127.0.0.1
+ctrl
+ bind 127.0.0.1
+!
+stats interval 0
+stats reporter statsd
+ prefix TTCN3
+ level global
+ remote-ip 127.0.0.1
+ remote-port 8125
+ flush-period 1
+ mtu 1024
+ enable
+!
+e1_input
+ e1_line 0 driver ipa
!
mgcp
bind ip 127.0.0.1
bind port 2427
rtp port-range 4002 16000
rtp bind-ip 127.0.0.1
+ rtp bind-ip-v6 ::1
rtp ip-probing
- rtp ip-dscp 184
+ rtp ip-dscp 46
no rtp keep-alive
no rtcp-omit
no rtp-patch
@@ -31,7 +53,19 @@ mgcp
sdp audio-payload name GSM
sdp audio-payload send-ptime
sdp audio-payload send-name
+ conn-timeout 0
loop 0
- number endpoints 31
+ number endpoints 300
allow-transcoding
osmux off
+ osmux bind-ip 127.0.0.1
+ osmux bind-ip-v6 ::1
+ trunk 1
+ sdp audio-payload send-ptime
+ sdp audio-payload send-name
+ no rtp keep-alive
+ loop 0
+ no rtcp-omit
+ no rtp-patch
+ allow-transcoding
+ line 0
diff --git a/mgw/regen_makefile.sh b/mgw/regen_makefile.sh
index 4662933d..921956ca 100755
--- a/mgw/regen_makefile.sh
+++ b/mgw/regen_makefile.sh
@@ -1,5 +1,30 @@
#!/bin/sh
-FILES="*.ttcn SDP_EncDec.cc *.c MGCP_CodecPort_CtrlFunctDef.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc RTP_EncDec.cc RTP_CodecPort_CtrlFunctDef.cc OSMUX_CodecPort_CtrlFunctDef.cc IuUP_EncDec.cc Native_FunctionDefs.cc TELNETasp_PT.cc IP_EncDec.cc "
+NAME=MGCP_Test
-../regen-makefile.sh MGCP_Test.ttcn $FILES
+FILES="
+ *.c
+ *.ttcn
+ *.ttcnpp
+ IPA_CodecPort_CtrlFunctDef.cc
+ IPL4asp_PT.cc
+ IPL4asp_discovery.cc
+ IP_EncDec.cc
+ IuUP_EncDec.cc
+ MGCP_CodecPort_CtrlFunctDef.cc
+ Native_FunctionDefs.cc
+ OSMUX_CodecPort_CtrlFunctDef.cc
+ RTP_CodecPort_CtrlFunctDef.cc
+ RTP_EncDec.cc
+ SDP_EncDec.cc
+ StatsD_CodecPort_CtrlFunctdef.cc
+ TCCConversion.cc
+ TCCInterface.cc
+ TELNETasp_PT.cc
+"
+
+export CPPFLAGS_TTCN3="
+ -DIPA_EMULATION_CTRL
+"
+
+../regen-makefile.sh -e $NAME $FILES