aboutsummaryrefslogtreecommitdiffstats
path: root/mgw
diff options
context:
space:
mode:
Diffstat (limited to 'mgw')
-rw-r--r--mgw/MGCP_Test.default9
-rw-r--r--mgw/MGCP_Test.ttcn1264
-rw-r--r--mgw/expected-results.xml63
-rwxr-xr-xmgw/gen_links.sh7
-rw-r--r--mgw/osmo-mgw.cfg36
-rwxr-xr-xmgw/regen_makefile.sh29
6 files changed, 1211 insertions, 197 deletions
diff --git a/mgw/MGCP_Test.default b/mgw/MGCP_Test.default
index 35f7ed0d..54bf9afe 100644
--- a/mgw/MGCP_Test.default
+++ b/mgw/MGCP_Test.default
@@ -11,6 +11,15 @@ 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;
diff --git a/mgw/MGCP_Test.ttcn b/mgw/MGCP_Test.ttcn
index f6dfe57e..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 {
@@ -71,6 +84,10 @@ module MGCP_Test {
charstring mp_remote_ipv6 := "::1";
PortNumber mp_local_rtp_port_base := 10000;
PortNumber mp_local_osmux_port := 1985;
+ 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 {
@@ -141,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));
@@ -313,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) */
@@ -333,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);
@@ -347,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) {
@@ -359,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);
@@ -391,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) {
@@ -419,16 +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. */
- if (flow.osmux_cid != -1) {
+ 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_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;
}
- 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);
+ 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 */
@@ -441,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);
@@ -461,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 */
@@ -478,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);
@@ -492,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
@@ -517,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
@@ -573,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;
}
@@ -614,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;
@@ -699,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);
@@ -918,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 := 31;
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);
@@ -939,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 */
@@ -952,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);
}
@@ -1013,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
@@ -1043,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);
}
@@ -1101,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 {
@@ -1113,7 +1302,7 @@ module MGCP_Test {
f_init(ep, true);
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 */
@@ -1126,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);
}
@@ -1150,7 +1339,7 @@ module MGCP_Test {
f_init(ep, true);
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);
@@ -1217,7 +1406,7 @@ module MGCP_Test {
return true;
}
- function f_TC_two_crcx_and_rtp_osmux(boolean bidir,
+ 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];
@@ -1228,15 +1417,35 @@ 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(local_ip_rtp, remote_ip_rtp, 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]);
@@ -1244,8 +1453,8 @@ module MGCP_Test {
/* from MGW back to us */
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) {
@@ -1274,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;
}
@@ -1287,30 +1496,39 @@ 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, mp_local_ipv4, mp_remote_ipv4,
+ 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, mp_local_ipv4, mp_remote_ipv4,
+ 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);
}
+
/* 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, mp_local_ipv6, mp_remote_ipv6,
+ 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, mp_local_ipv4, mp_remote_ipv4,
+ 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, mp_local_ipv6, mp_remote_ipv6,
+ f_TC_two_crcx_and_rtp_osmux(true, true, mp_local_ipv6, mp_remote_ipv6,
mp_local_ipv4, mp_remote_ipv4);
}
@@ -1324,7 +1542,7 @@ module MGCP_Test {
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);
@@ -1332,10 +1550,11 @@ module MGCP_Test {
/* Create the first connection in receive only mode */
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], true);
@@ -1346,11 +1565,11 @@ module MGCP_Test {
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;
+ flow[1].osmux.cfg := c_OsmuxemDefaultCfg;
f_flow_create_osmux(OsmuxEM, ep, call_id, "recvonly", flow[1], true);
@@ -1385,51 +1604,68 @@ 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);
- stats_osmux := f_osmuxem_stats_get(OsmuxEM);
- num_pkts_tx[1] := stats_osmux.num_pkts_tx;
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_osmuxem_mode(OsmuxEM, OSMUXEM_MODE_BIDIR);
- stats_rtp := f_rtpem_stats_get(RTPEM[0]);
- num_pkts_tx[0] := stats_rtp.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;
}
@@ -1602,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];
@@ -1693,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_ipv4, mp_remote_ipv4, 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);
@@ -1710,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);
@@ -1722,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];
@@ -1799,7 +2049,9 @@ module MGCP_Test {
/* create two local RTP emulations and pass data in both directions */
function f_tc_two_crcx_mdcx_and_rtp(charstring local_ip_a, charstring remote_ip_a,
- charstring local_ip_b, charstring remote_ip_b) runs on dummy_CT {
+ 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;
@@ -1811,13 +2063,13 @@ module MGCP_Test {
f_init(ep);
/* Create the first connection in receive only mode */
- flow[0] := valueof(t_RtpFlow(local_ip_a, remote_ip_a, 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], true);
/* Create the second connection. This connection will be also
* in receive only mode */
- flow[1] := valueof(t_RtpFlow(local_ip_b, remote_ip_b, 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], true);
@@ -1915,6 +2167,13 @@ module MGCP_Test {
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 {
@@ -2037,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;
@@ -2055,22 +2366,24 @@ module MGCP_Test {
f_vty_transceive(MGWVTY, "rtp-patch rfc5993hr");
/* Connection #0 (Bidirectional) */
- flow[0] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 111, "GSM-HR-08/8000"));
+ 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]);
/* Connection #1 (Bidirectional) */
- flow[1] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 111, "GSM-HR-08/8000"));
+ 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]);
/* Send RTP packets to connection #0, receive on connection #1 */
@@ -2107,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;
@@ -2120,24 +2446,36 @@ module MGCP_Test {
f_init(ep);
/* Connection #0 (Bidirectional) */
- flow[0] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 112, "AMR/8000"));
+ 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]);
/* Connection #1 (Bidirectional) */
- flow[1] := valueof(t_RtpFlow(mp_local_ipv4, mp_remote_ipv4, 112, "AMR/8000"));
+ 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]);
/* Send RTP packets to connection #0, receive on connection #1 */
@@ -2175,16 +2513,46 @@ module MGCP_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('2014e959f35fdfe5e9667ffbc088818088'O, '217a567cd7f7f97a599ffef022206022'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) */
@@ -2207,7 +2575,7 @@ 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_ipv4, mp_remote_ipv4, 111, "GSM-HR-08/8000/1"));
@@ -2232,6 +2600,9 @@ 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);
}
@@ -2317,6 +2688,69 @@ module MGCP_Test {
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;
@@ -2383,8 +2817,473 @@ module MGCP_Test {
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());
@@ -2401,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());
@@ -2413,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());
@@ -2426,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());
@@ -2433,16 +3336,23 @@ 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());
+ 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());
@@ -2454,5 +3364,21 @@ module MGCP_Test {
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/expected-results.xml b/mgw/expected-results.xml
index d44e43e5..d9b9a155 100644
--- a/mgw/expected-results.xml
+++ b/mgw/expected-results.xml
@@ -1,10 +1,12 @@
<?xml version="1.0"?>
-<testsuite name='Titan' tests='62' failures='5' errors='0' skipped='0' inconc='0' time='MASKED'>
+<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'/>
@@ -16,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'/>
@@ -27,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'/>
@@ -44,10 +50,16 @@
<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
@@ -55,36 +67,41 @@
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'/>
- <testcase classname='MGCP_Test' name='TC_e1_crcx_loopback' time='MASKED'/>
- <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'>
- <failure type='fail-verdict'>Received unexpected type from Osmux
- MGCP_Test.ttcn:MASKED MGCP_Test control part
- MGCP_Test.ttcn:MASKED TC_two_crcx_and_rtp_osmux_bidir_ipv6 testcase
- </failure>
- </testcase>
- <testcase classname='MGCP_Test' name='TC_two_crcx_and_rtp_osmux_bidir_ipv4_ipv6' time='MASKED'>
- <failure type='fail-verdict'>Received unexpected type from Osmux
+ <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_two_crcx_and_rtp_osmux_bidir_ipv4_ipv6 testcase
+ MGCP_Test.ttcn:MASKED TC_e1_crcx_with_overlap testcase
</failure>
</testcase>
- <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'>
- <failure type='fail-verdict'>Received unexpected type from Osmux
+ <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_two_crcx_mdcx_and_rtp_osmux_ipv6 testcase
+ MGCP_Test.ttcn:MASKED TC_e1_crcx_loopback testcase
</failure>
</testcase>
- <testcase classname='MGCP_Test' name='TC_two_crcx_mdcx_and_rtp_osmux_ipv4_ipv6' time='MASKED'>
- <failure type='fail-verdict'>Received unexpected type from Osmux
+ <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_two_crcx_mdcx_and_rtp_osmux_ipv4_ipv6 testcase
+ 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 8893954c..2fd2b0da 100755
--- a/mgw/gen_links.sh
+++ b/mgw/gen_links.sh
@@ -38,13 +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 beb6fdf0..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,6 +22,21 @@ 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
@@ -24,7 +45,7 @@ mgcp
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
@@ -34,6 +55,17 @@ mgcp
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