blob: 659d5f1c47dee0e43c84484ef054b4a745939916 [file] [log] [blame]
Harald Welte00a067f2017-09-13 23:27:17 +02001module MGCP_Test {
Harald Weltef07c2862017-11-18 17:16:24 +01002 import from Osmocom_Types all;
Harald Welte00a067f2017-09-13 23:27:17 +02003 import from MGCP_Types all;
Harald Welte4029e8c2017-11-23 22:00:42 +01004 import from MGCP_Templates all;
Harald Welte3c6ebb92017-09-16 00:56:57 +08005 import from SDP_Types all;
6 import from MGCP_CodecPort all;
7 import from MGCP_CodecPort_CtrlFunct all;
Harald Weltef07c2862017-11-18 17:16:24 +01008 import from RTP_CodecPort all;
9 import from RTP_CodecPort_CtrlFunct all;
Harald Weltebb7523b2018-03-29 08:52:01 +020010 import from RTP_Emulation all;
Harald Welte3c6ebb92017-09-16 00:56:57 +080011 import from IPL4asp_Types all;
Harald Welte00a067f2017-09-13 23:27:17 +020012
Philipp Maierbb7a01c2018-02-01 12:32:57 +010013 const charstring c_mgw_domain := "mgw";
14 const charstring c_mgw_ep_rtpbridge := "rtpbridge/";
15
Harald Welte21ba5572017-09-19 17:55:05 +080016 /* any variables declared in the component will be available to
17 * all functions that 'run on' the named component, similar to
18 * class members in C++ */
Harald Welte00a067f2017-09-13 23:27:17 +020019 type component dummy_CT {
Harald Welte3c6ebb92017-09-16 00:56:57 +080020 port MGCP_CODEC_PT MGCP;
21 var boolean initialized := false;
Harald Welte55015362017-11-18 16:02:42 +010022 var ConnectionId g_mgcp_conn_id := -1;
Harald Weltee1e18c52017-09-17 16:23:07 +080023 var integer g_trans_id;
Harald Weltef07c2862017-11-18 17:16:24 +010024
Philipp Maier2321ef92018-06-27 17:52:04 +020025 var RTP_Emulation_CT vc_RTPEM[3];
26 port RTPEM_CTRL_PT RTPEM[3];
Harald Welte00a067f2017-09-13 23:27:17 +020027 };
28
Harald Weltee1e18c52017-09-17 16:23:07 +080029 function get_next_trans_id() runs on dummy_CT return MgcpTransId {
30 var MgcpTransId tid := int2str(g_trans_id);
31 g_trans_id := g_trans_id + 1;
32 return tid;
33 }
34
Harald Welte21ba5572017-09-19 17:55:05 +080035 /* all parameters declared here can be modified / overridden by
36 * the config file in the [MODULE_PARAMETERS] section. If no
37 * config file is used or the file doesn't specify them, the
38 * default values assigned below are used */
Harald Welte3c6ebb92017-09-16 00:56:57 +080039 modulepar {
40 PortNumber mp_local_udp_port := 2727;
41 charstring mp_local_ip := "127.0.0.1";
42 PortNumber mp_remote_udp_port := 2427;
43 charstring mp_remote_ip := "127.0.0.1";
Harald Weltef07c2862017-11-18 17:16:24 +010044 PortNumber mp_local_rtp_port_base := 10000;
Harald Welte3c6ebb92017-09-16 00:56:57 +080045 }
46
Harald Weltebb7523b2018-03-29 08:52:01 +020047 private function f_rtpem_init(inout RTP_Emulation_CT comp_ref, integer i)
48 runs on dummy_CT {
49 comp_ref := RTP_Emulation_CT.create("RTPEM" & int2str(i));
50 map(comp_ref:RTP, system:RTP);
51 map(comp_ref:RTCP, system:RTCP);
52 comp_ref.start(RTP_Emulation.f_main());
53 }
54
Harald Welte21ba5572017-09-19 17:55:05 +080055 /* initialization function, called by each test case at the
56 * beginning, but 'initialized' variable ensures its body is
57 * only executed once */
Harald Welteedc45c12017-11-18 19:15:05 +010058 private function f_init(template MgcpEndpoint ep := omit) runs on dummy_CT {
Harald Welte3c6ebb92017-09-16 00:56:57 +080059 var Result res;
Harald Weltef07c2862017-11-18 17:16:24 +010060 var uint32_t ssrc;
Philipp Maier28bb8292018-07-20 17:09:17 +020061
Harald Welteedc45c12017-11-18 19:15:05 +010062 if (initialized == false) {
63 initialized := true;
64
65 /* some random number for the initial transaction id */
66 g_trans_id := float2int(rnd()*65535.0);
67 map(self:MGCP, system:MGCP_CODEC_PT);
68 /* connect the MGCP test port using the given
69 * source/destionation ip/port and store the connection id in g_mgcp_conn_id
70 * */
71 res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, mp_remote_ip, mp_remote_udp_port, mp_local_ip, mp_local_udp_port, 0, { udp := {} });
Harald Welte9220f632018-05-23 20:27:02 +020072 if (not ispresent(res.connId)) {
73 setverdict(fail, "Could not connect MGCP, check your configuration");
74 self.stop;
75 }
Harald Welteedc45c12017-11-18 19:15:05 +010076 g_mgcp_conn_id := res.connId;
77
Harald Weltebb7523b2018-03-29 08:52:01 +020078 for (var integer i := 0; i < sizeof(vc_RTPEM); i := i+1) {
79 f_rtpem_init(vc_RTPEM[i], i);
80 connect(vc_RTPEM[i]:CTRL, self:RTPEM[i]);
81 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080082 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080083
Harald Welteedc45c12017-11-18 19:15:05 +010084 if (isvalue(ep)) {
85 /* do a DLCX on all connections of the EP */
86 f_dlcx_ignore(valueof(ep));
87 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080088 }
89
Harald Welte00a067f2017-09-13 23:27:17 +020090 testcase TC_selftest() runs on dummy_CT {
91 const charstring c_auep := "AUEP 158663169 ds/e1-1/2@172.16.6.66 MGCP 1.0\r\n";
Philipp Maierbb7a01c2018-02-01 12:32:57 +010092 const charstring c_mdcx3 := "MDCX 18983215 " & c_mgw_ep_rtpbridge & "1@" & c_mgw_domain & " MGCP 1.0\r\n";
Harald Welte00a067f2017-09-13 23:27:17 +020093 const charstring c_mdcx3_ret := "200 18983215 OK\r\n" &
94 "I: 1\n" &
95 "\n" &
96 "v=0\r\n" &
97 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
98 "s=-\r\n" &
99 "c=IN IP4 0.0.0.0\r\n" &
100 "t=0 0\r\n" &
101 "m=audio 0 RTP/AVP 126\r\n" &
102 "a=rtpmap:126 AMR/8000\r\n" &
103 "a=ptime:20\r\n";
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100104 const charstring c_mdcx4 := "MDCX 18983216 " & c_mgw_ep_rtpbridge & "1@" & c_mgw_domain & " MGCP 1.0\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200105 "M: sendrecv\r" &
106 "C: 2\r\n" &
107 "I: 1\r\n" &
108 "L: p:20, a:AMR, nt:IN\r\n" &
109 "\n" &
110 "v=0\r\n" &
111 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
Harald Welte2871d0b2017-09-14 22:42:12 +0800112 "s=-\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200113 "c=IN IP4 0.0.0.0\r\n" &
114 "t=0 0\r\n" &
115 "m=audio 4441 RTP/AVP 99\r\n" &
116 "a=rtpmap:99 AMR/8000\r\n" &
117 "a=ptime:40\r\n";
Harald Welte3c6ebb92017-09-16 00:56:57 +0800118 const charstring c_crcx510_ret := "510 23 FAIL\r\n"
Harald Welte00a067f2017-09-13 23:27:17 +0200119
120 log(c_auep);
121 log(dec_MgcpCommand(c_auep));
122
123 log(c_mdcx3);
124 log(dec_MgcpCommand(c_mdcx3));
125
126 log(c_mdcx3_ret);
127 log(dec_MgcpResponse(c_mdcx3_ret));
128
129 log(c_mdcx4);
130 log(dec_MgcpCommand(c_mdcx4));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800131
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100132 log(ts_CRCX("23", c_mgw_ep_rtpbridge & "42@" & c_mgw_domain, "sendrecv", '1234'H));
133 log(enc_MgcpCommand(valueof(ts_CRCX("23", c_mgw_ep_rtpbridge & "42@" & c_mgw_domain, "sendrecv", '1234'H))));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800134
135 log(c_crcx510_ret);
136 log(dec_MgcpResponse(c_crcx510_ret));
137 log(dec_MgcpMessage(c_crcx510_ret));
138 }
139
Harald Weltee636afd2017-09-17 16:24:09 +0800140 /* CRCX test ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100141 * x without mandatory CallId
Harald Weltee636afd2017-09-17 16:24:09 +0800142 * - with forbidden parameters (e.g. Capabilities, PackageList, ...
143 * - CRCX with remote session description and without
144 *
145 * general ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100146 * x packetization != 20ms
147 * x invalid mode
Harald Weltee636afd2017-09-17 16:24:09 +0800148 * x unsupported mode (517)
149 * x bidirectional mode before RemoteConnDesc: 527
150 * - invalid codec
Harald Weltee0b331f2017-11-18 20:34:33 +0100151 * x retransmission of same transaction
Harald Weltee636afd2017-09-17 16:24:09 +0800152 * - unsupported LocalConnectionOptions ("b", "a", "e", "gc", "s", "r", "k", ..)
153 */
154
Harald Welte21ba5572017-09-19 17:55:05 +0800155 /* build a receive template for receiving a MGCP message. You
156 * pass the MGCP response template in, and it will generate an
157 * MGCP_RecvFrom template that can match the primitives arriving on the
158 * MGCP_CodecPort */
Harald Weltee636afd2017-09-17 16:24:09 +0800159 function tr_MGCP_RecvFrom_R(template MgcpResponse resp) runs on dummy_CT return template MGCP_RecvFrom {
160 var template MGCP_RecvFrom mrf := {
Harald Welte55015362017-11-18 16:02:42 +0100161 connId := g_mgcp_conn_id,
Harald Weltee636afd2017-09-17 16:24:09 +0800162 remName := mp_remote_ip,
163 remPort := mp_remote_udp_port,
164 locName := mp_local_ip,
165 locPort := mp_local_udp_port,
166 msg := { response := resp }
167 }
168 return mrf;
169 }
170
171 /* Send a MGCP request + receive a (matching!) response */
172 function mgcp_transceive_mgw(template MgcpCommand cmd, template MgcpResponse resp := ?) runs on dummy_CT return MgcpResponse {
173 var MgcpMessage msg := { command := valueof(cmd) };
174 resp.line.trans_id := cmd.line.trans_id;
175 var template MGCP_RecvFrom mrt := tr_MGCP_RecvFrom_R(resp);
Harald Welte3c6ebb92017-09-16 00:56:57 +0800176 var MGCP_RecvFrom mrf;
177 timer T := 5.0;
178
Harald Welte55015362017-11-18 16:02:42 +0100179 MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800180 T.start;
181 alt {
Harald Weltee636afd2017-09-17 16:24:09 +0800182 [] MGCP.receive(mrt) -> value mrf { }
183 [] MGCP.receive(tr_MGCP_RecvFrom_R(?)) { setverdict(fail); }
Harald Welte3c6ebb92017-09-16 00:56:57 +0800184 [] MGCP.receive { repeat; }
185 [] T.timeout { setverdict(fail); }
186 }
187 T.stop;
Harald Weltee636afd2017-09-17 16:24:09 +0800188
189 if (isbound(mrf) and isbound(mrf.msg) and ischosen(mrf.msg.response)) {
190 return mrf.msg.response;
191 } else {
192 var MgcpResponse r := { line := { code := "999", trans_id := valueof(cmd.line.trans_id) } };
193 return r;
194 }
Harald Welte00a067f2017-09-13 23:27:17 +0200195 }
196
Harald Welteba62c8c2017-11-18 18:26:49 +0100197 function extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
198 var integer i;
199 for (i := 0; i < lengthof(resp.params); i := i + 1) {
200 var MgcpParameter par := resp.params[i];
201 if (par.code == "I") {
202 return str2hex(par.val);
203 }
204 }
205 setverdict(fail);
206 return '00000000'H;
207 }
208
Harald Welte10889c12017-11-18 19:40:31 +0100209 function f_dlcx(MgcpEndpoint ep, template MgcpResponseCode ret_code, template charstring ret_val,
210 template MgcpCallId call_id := omit,
211 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welteba62c8c2017-11-18 18:26:49 +0100212 var template MgcpCommand cmd;
213 var MgcpResponse resp;
214 var template MgcpResponse rtmpl := {
215 line := {
Harald Welte10889c12017-11-18 19:40:31 +0100216 code := ret_code,
217 string := ret_val
Harald Welteba62c8c2017-11-18 18:26:49 +0100218 },
219 params := *,
220 sdp := *
221 };
Harald Weltec40e0c32017-11-18 19:08:22 +0100222 cmd := ts_DLCX(get_next_trans_id(), ep, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100223 resp := mgcp_transceive_mgw(cmd, rtmpl);
224 }
225
Harald Welte10889c12017-11-18 19:40:31 +0100226 /* Send DLCX and expect OK response */
227 function f_dlcx_ok(MgcpEndpoint ep, template MgcpCallId call_id := omit,
228 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Weltef91edf32017-12-28 14:16:21 +0100229 f_dlcx(ep, ("200","250"), "OK", call_id, conn_id);
Harald Welte10889c12017-11-18 19:40:31 +0100230 }
231
Harald Welteba62c8c2017-11-18 18:26:49 +0100232 /* Send DLCX and accept any response */
Harald Weltec40e0c32017-11-18 19:08:22 +0100233 function f_dlcx_ignore(MgcpEndpoint ep, template MgcpCallId call_id := omit,
Harald Welteba62c8c2017-11-18 18:26:49 +0100234 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welte10889c12017-11-18 19:40:31 +0100235 f_dlcx(ep, ?, *, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100236 }
237
Harald Weltebb7523b2018-03-29 08:52:01 +0200238 type record HostPort {
239 charstring hostname,
240 integer portnr optional
241 }
242 type record RtpFlowData {
243 HostPort em, /* emulation side */
244 HostPort mgw, /* mgw side */
245 uint7_t pt,
246 charstring codec,
Philipp Maier28bb8292018-07-20 17:09:17 +0200247 MgcpConnectionId mgcp_conn_id optional,
248 RtpemConfig rtp_cfg optional
Harald Weltebb7523b2018-03-29 08:52:01 +0200249 }
250
Philipp Maier2321ef92018-06-27 17:52:04 +0200251 /* Create an RTP flow (bidirectional, or receive-only) */
252 function f_flow_create(RTPEM_CTRL_PT pt, MgcpEndpoint ep, MgcpCallId call_id, charstring mode, inout RtpFlowData flow,
Harald Weltebb7523b2018-03-29 08:52:01 +0200253 boolean one_phase := true)
254 runs on dummy_CT {
Harald Weltebb7523b2018-03-29 08:52:01 +0200255 var template MgcpCommand cmd;
256 var MgcpResponse resp;
257
258 /* bind local RTP emulation socket */
259 f_rtpem_bind(pt, flow.em.hostname, flow.em.portnr);
260
Philipp Maier28bb8292018-07-20 17:09:17 +0200261 /* configure rtp-emulation */
262 if (ispresent(flow.rtp_cfg)) {
263 f_rtpem_configure(pt, flow.rtp_cfg);
264 } else {
265 var RtpemConfig rtp_cfg := c_RtpemDefaultCfg;
266 rtp_cfg.tx_payload_type := flow.pt
267 f_rtpem_configure(pt, rtp_cfg);
268 }
269
Harald Weltebb7523b2018-03-29 08:52:01 +0200270 if (one_phase) {
Philipp Maier2321ef92018-06-27 17:52:04 +0200271 /* Connect flow to MGW using a CRCX that also contains an SDP
272 * part that tells the MGW where we are listening for RTP streams
273 * that come from the MGW. We get a fully working connection in
274 * one go. */
275
276 cmd := ts_CRCX(get_next_trans_id(), ep, mode, call_id);
Harald Welteedc88742018-03-29 18:01:16 +0200277 cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",
Harald Weltebb7523b2018-03-29 08:52:01 +0200278 flow.em.portnr, { int2str(flow.pt) },
279 { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),
280 valueof(ts_SDP_ptime(20)) });
281 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
282 flow.mgcp_conn_id := extract_conn_id(resp);
283 /* extract port number from response */
284 flow.mgw.portnr :=
285 resp.sdp.media_list[0].media_field.ports.port_number;
286 } else {
Philipp Maier2321ef92018-06-27 17:52:04 +0200287 /* Create a half-open connection only. We do not tell the MGW
288 * where it can send RTP streams to us. This means this
289 * connection will only be able to receive but can not send
290 * data back to us. In order to turn the connection in a fully
291 * bi-directional one, a separate MDCX is needed. */
292
293 cmd := ts_CRCX(get_next_trans_id(), ep, mode, call_id);
Harald Weltebb7523b2018-03-29 08:52:01 +0200294 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
295 flow.mgcp_conn_id := extract_conn_id(resp);
296 /* extract MGW-side port number from response */
297 flow.mgw.portnr :=
298 resp.sdp.media_list[0].media_field.ports.port_number;
Harald Weltebb7523b2018-03-29 08:52:01 +0200299 }
300 /* finally, connect the emulation-side RTP socket to the MGW */
301 f_rtpem_connect(pt, flow.mgw.hostname, flow.mgw.portnr);
302 }
303
Philipp Maier2321ef92018-06-27 17:52:04 +0200304 /* Modify an existing RTP flow */
305 function f_flow_modify(RTPEM_CTRL_PT pt, MgcpEndpoint ep, MgcpCallId call_id, charstring mode, inout RtpFlowData flow)
306 runs on dummy_CT {
307 var template MgcpCommand cmd;
308 var MgcpResponse resp;
309
310 /* rebind local RTP emulation socket to the new address */
311 f_rtpem_bind(pt, flow.em.hostname, flow.em.portnr);
312
Philipp Maier28bb8292018-07-20 17:09:17 +0200313 /* reconfigure rtp-emulation */
314 if (ispresent(flow.rtp_cfg)) {
315 f_rtpem_configure(pt, flow.rtp_cfg);
316 } else {
317 var RtpemConfig rtp_cfg := c_RtpemDefaultCfg;
318 rtp_cfg.tx_payload_type := flow.pt
319 f_rtpem_configure(pt, rtp_cfg);
320 }
321
Philipp Maier2321ef92018-06-27 17:52:04 +0200322 /* connect MGW side RTP socket to the emulation-side RTP socket using SDP */
323 cmd := ts_MDCX(get_next_trans_id(), ep, mode, call_id, flow.mgcp_conn_id);
324 cmd.sdp := ts_SDP(flow.em.hostname, flow.em.hostname, "23", "42",
325 flow.em.portnr, { int2str(flow.pt) },
326 { valueof(ts_SDP_rtpmap(flow.pt, flow.codec)),
327 valueof(ts_SDP_ptime(20)) });
328 resp := mgcp_transceive_mgw(cmd, tr_MDCX_ACK);
329
330 /* extract MGW-side port number from response. (usually this
331 * will not change, but thats is up to the MGW) */
332 flow.mgw.portnr :=
333 resp.sdp.media_list[0].media_field.ports.port_number;
334
335 /* reconnect the emulation-side RTP socket to the MGW */
336 f_rtpem_connect(pt, flow.mgw.hostname, flow.mgw.portnr);
337 }
338
339 /* Delete an existing RTP flow */
340 function f_flow_delete(RTPEM_CTRL_PT pt, template MgcpEndpoint ep := omit, template MgcpCallId call_id := omit)
341 runs on dummy_CT {
342 var template MgcpCommand cmd;
343 var MgcpResponse resp;
344
345 /* Switch off RTP flow */
346 f_rtpem_mode(pt, RTPEM_MODE_NONE);
347
348 /* Delete connection on MGW (if needed) */
349 if (isvalue(call_id) and isvalue(ep)) {
350 f_sleep(0.1);
351 f_dlcx_ok(valueof(ep), call_id);
352 }
353 }
354
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100355 function f_crcx(charstring ep_prefix) runs on dummy_CT {
356 var MgcpEndpoint ep := ep_prefix & "2@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800357 var template MgcpCommand cmd;
358 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100359 var MgcpCallId call_id := '1234'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800360
Harald Welteedc45c12017-11-18 19:15:05 +0100361 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800362
Harald Welteba62c8c2017-11-18 18:26:49 +0100363 /* create the connection on the MGW */
364 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100365 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welteba62c8c2017-11-18 18:26:49 +0100366 extract_conn_id(resp);
367
368 /* clean-up */
369 f_dlcx_ok(ep, call_id);
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100370 }
Harald Welteba62c8c2017-11-18 18:26:49 +0100371
Philipp Maier45635f42018-06-05 17:28:02 +0200372 function f_crcx_no_lco(charstring ep_prefix) runs on dummy_CT {
373 var MgcpEndpoint ep := ep_prefix & "2@" & c_mgw_domain;
374 var template MgcpCommand cmd;
375 var MgcpResponse resp;
376 var MgcpCallId call_id := '1234'H;
377
378 f_init(ep);
379
380 /* create the connection on the MGW */
381 cmd := ts_CRCX_no_lco(get_next_trans_id(), ep, "recvonly", call_id);
382 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
383 extract_conn_id(resp);
384
385 /* clean-up */
386 f_dlcx_ok(ep, call_id);
387
388 /* See also OS#2658: Even when we omit the LCO information, we
389 expect the MGW to pick a sane payload type for us. This
390 payload type should be visible in the SDP of the response. */
Philipp Maier76a8d012018-06-21 10:03:13 +0200391 if (resp.sdp.media_list[0].media_field.fmts[0] != "0") {
Philipp Maier45635f42018-06-05 17:28:02 +0200392 setverdict(fail, "SDP contains unexpected codec");
393 }
394
395 /* See also OS#2658: We also expect the MGW to assign a port
396 number to us. */
397 if (isbound(resp.sdp.media_list[0].media_field.ports.port_number) == false) {
398 setverdict(fail, "SDP does not contain a port number");
399 }
400 }
401
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100402 /* test valid CRCX without SDP */
403 testcase TC_crcx() runs on dummy_CT {
404 f_crcx(c_mgw_ep_rtpbridge);
405 setverdict(pass);
406 }
407
Philipp Maier45635f42018-06-05 17:28:02 +0200408 /* test valid CRCX without SDP and LCO */
409 testcase TC_crcx_no_lco() runs on dummy_CT {
410 f_crcx_no_lco(c_mgw_ep_rtpbridge);
411 setverdict(pass);
412 }
413
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100414 /* test valid CRCX without SDP (older method without endpoint prefix) */
415 testcase TC_crcx_noprefix() runs on dummy_CT {
416 f_crcx("");
Harald Weltee636afd2017-09-17 16:24:09 +0800417 setverdict(pass);
418 }
419
420 /* test CRCX with unsupported mode, expect 517 */
421 testcase TC_crcx_unsupp_mode() runs on dummy_CT {
422 var template MgcpCommand cmd;
423 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100424 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100425 var MgcpCallId call_id := '1233'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800426 var template MgcpResponse rtmpl := tr_MgcpResp_Err("517");
427
Harald Welteedc45c12017-11-18 19:15:05 +0100428 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800429
Harald Welteba62c8c2017-11-18 18:26:49 +0100430 cmd := ts_CRCX(get_next_trans_id(), ep, "netwtest", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800431 resp := mgcp_transceive_mgw(cmd, rtmpl);
432 setverdict(pass);
433 }
434
Harald Welte21ba5572017-09-19 17:55:05 +0800435 /* test CRCX with early bi-directional mode, expect 527 as
436 * bi-diretional media can only be established once both local and
437 * remote side are specified, see MGCP RFC */
Harald Weltee636afd2017-09-17 16:24:09 +0800438 testcase TC_crcx_early_bidir_mode() runs on dummy_CT {
439 var template MgcpCommand cmd;
440 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100441 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100442 var MgcpCallId call_id := '1232'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800443 var template MgcpResponse rtmpl := tr_MgcpResp_Err("527");
444
Harald Welteedc45c12017-11-18 19:15:05 +0100445 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800446
Harald Welteba62c8c2017-11-18 18:26:49 +0100447 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800448 resp := mgcp_transceive_mgw(cmd, rtmpl);
449 setverdict(pass);
450 }
451
452 /* test CRCX with unsupported Parameters */
453 testcase TC_crcx_unsupp_param() runs on dummy_CT {
454 var template MgcpCommand cmd;
455 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100456 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100457 var MgcpCallId call_id := '1231'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800458 var template MgcpResponse rtmpl := tr_MgcpResp_Err("539");
459
Harald Welteedc45c12017-11-18 19:15:05 +0100460 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800461
Harald Welteba62c8c2017-11-18 18:26:49 +0100462 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100463 /* osmo-bsc_mgcp/mgw doesn't implement notifications */
464 f_mgcp_par_append(cmd.params, MgcpParameter:{ "N", "foobar" });
465
Harald Weltee636afd2017-09-17 16:24:09 +0800466 resp := mgcp_transceive_mgw(cmd, rtmpl);
467 setverdict(pass);
468 }
469
470 /* test CRCX with missing CallId */
471 testcase TC_crcx_missing_callid() runs on dummy_CT {
472 var template MgcpCommand cmd;
473 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100474 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Weltef91edf32017-12-28 14:16:21 +0100475 var template MgcpResponse rtmpl := tr_MgcpResp_Err(("400","516"));
Harald Weltee636afd2017-09-17 16:24:09 +0800476
Harald Welteedc45c12017-11-18 19:15:05 +0100477 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800478
Harald Welteba62c8c2017-11-18 18:26:49 +0100479 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", '1230'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800480 cmd.params := {
481 t_MgcpParConnMode("recvonly"),
482 t_MgcpParLocConnOpt("p:20")
483 }
484 resp := mgcp_transceive_mgw(cmd, rtmpl);
485 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100486
Harald Weltee636afd2017-09-17 16:24:09 +0800487 }
488
489 /* test CRCX with missing Mode */
490 testcase TC_crcx_missing_mode() runs on dummy_CT {
491 var template MgcpCommand cmd;
492 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100493 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100494 var MgcpCallId call_id := '1229'H;
Harald Weltef91edf32017-12-28 14:16:21 +0100495 var template MgcpResponse rtmpl := tr_MgcpResp_Err(("400","517"));
Harald Weltee636afd2017-09-17 16:24:09 +0800496
Harald Welteedc45c12017-11-18 19:15:05 +0100497 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800498
Harald Welteba62c8c2017-11-18 18:26:49 +0100499 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800500 cmd.params := {
Harald Welteba62c8c2017-11-18 18:26:49 +0100501 ts_MgcpParCallId(call_id),
Harald Weltee636afd2017-09-17 16:24:09 +0800502 t_MgcpParLocConnOpt("p:20")
503 }
504 resp := mgcp_transceive_mgw(cmd, rtmpl);
505 setverdict(pass);
506 }
507
508 /* test CRCX with unsupported packetization interval */
509 testcase TC_crcx_unsupp_packet_intv() runs on dummy_CT {
510 var template MgcpCommand cmd;
511 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100512 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100513 var MgcpCallId call_id := '1228'H;
Harald Welte0d198612017-11-18 19:58:31 +0100514 var template MgcpResponse rtmpl := tr_MgcpResp_Err("535");
Harald Weltee636afd2017-09-17 16:24:09 +0800515
Harald Welteedc45c12017-11-18 19:15:05 +0100516 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800517
Harald Welteba62c8c2017-11-18 18:26:49 +0100518 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100519 cmd.params[2] := t_MgcpParLocConnOpt("p:111");
Harald Weltee636afd2017-09-17 16:24:09 +0800520 resp := mgcp_transceive_mgw(cmd, rtmpl);
521 setverdict(pass);
522 }
523
524 /* test CRCX with illegal double presence of local connection option */
525 testcase TC_crcx_illegal_double_lco() runs on dummy_CT {
526 var template MgcpCommand cmd;
527 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100528 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100529 var MgcpCallId call_id := '1227'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800530 var template MgcpResponse rtmpl := tr_MgcpResp_Err("524");
531
Harald Welteedc45c12017-11-18 19:15:05 +0100532 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800533
Harald Welteba62c8c2017-11-18 18:26:49 +0100534 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100535 /* p:20 is permitted only once and not twice! */
536 cmd.params[2] := t_MgcpParLocConnOpt("p:20, a:AMR, p:20");
Harald Weltee636afd2017-09-17 16:24:09 +0800537 resp := mgcp_transceive_mgw(cmd, rtmpl);
538 setverdict(pass);
539 }
540
541 /* test valid CRCX with valid SDP */
542 testcase TC_crcx_sdp() runs on dummy_CT {
543 var template MgcpCommand cmd;
544 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100545 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100546 var MgcpCallId call_id := '1226'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800547
Harald Welteedc45c12017-11-18 19:15:05 +0100548 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800549
Harald Welteba62c8c2017-11-18 18:26:49 +0100550 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800551 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
552 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
553 valueof(ts_SDP_ptime(20)) });
Harald Welte9988d282017-11-18 19:22:00 +0100554 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Philipp Maierdffa6a42018-02-02 11:55:44 +0100555
556 /* clean-up */
557 f_dlcx_ok(ep, call_id);
558
Harald Weltee636afd2017-09-17 16:24:09 +0800559 setverdict(pass);
560 }
561
Philipp Maier5e06cee2018-02-01 18:28:08 +0100562 /* test valid wildcarded CRCX */
563 testcase TC_crcx_wildcarded() runs on dummy_CT {
564 var template MgcpCommand cmd;
565 var MgcpResponse resp;
566 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
567 var MgcpCallId call_id := '1234'H;
568 var MgcpEndpoint ep_assigned;
569 f_init();
570
571 /* create the connection on the MGW */
572 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
573 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
574 extract_conn_id(resp);
575
576 /* extract endpoint name we got assigned by the MGW */
577 var MgcpMessage resp_msg := {
578 response := resp
579 }
580 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned) == false) {
581 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
582 }
583
584 /* clean-up */
585 f_dlcx_ok(ep_assigned, call_id);
586
587 setverdict(pass);
588 }
589
590 /* test valid wildcarded CRCX */
591 testcase TC_crcx_wildcarded_exhaust() runs on dummy_CT {
592 const integer n_endpoints := 32;
593 var integer i;
594 var template MgcpCommand cmd;
595 var MgcpResponse resp;
596 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
597 var MgcpCallId call_id := '1234'H;
598 var MgcpEndpoint ep_assigned[n_endpoints];
599 f_init();
600
601 /* Exhaust all endpoint resources on the virtual trunk */
602 for (i := 0; i < n_endpoints; i := i+1) {
603 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
604 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
605
606 /* Make sure we got a connection id */
607 extract_conn_id(resp);
608
609 var MgcpMessage resp_msg := {
610 response := resp
611 }
612 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned[i]) == false) {
613 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
614 }
615 }
616
617 /* Try to allocate one more endpoint, which should fail */
618 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
619 var template MgcpResponse rtmpl := tr_MgcpResp_Err("403");
620 resp := mgcp_transceive_mgw(cmd, rtmpl);
621 setverdict(pass);
622
623 /* clean-up */
624 for (i := 0; i < n_endpoints; i := i+1) {
625 f_dlcx_ok(ep_assigned[i], call_id);
626 }
627 setverdict(pass);
628 }
629
Harald Weltee636afd2017-09-17 16:24:09 +0800630 /* TODO: various SDP related bits */
631
632
633 /* TODO: CRCX with X-Osmux */
634 /* TODO: double CRCX without force_realloc */
635
636 /* TODO: MDCX (various) */
637
638 /* TODO: MDCX without CRCX first */
639 testcase TC_mdcx_without_crcx() runs on dummy_CT {
640 var template MgcpCommand cmd;
641 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100642 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "3@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100643 var MgcpCallId call_id := '1225'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800644 var template MgcpResponse rtmpl := {
645 line := {
646 /* TODO: accept/enforce better error? */
647 code := "400",
648 string := ?
649 },
650 params:= { },
651 sdp := omit
652 };
653
Harald Welteedc45c12017-11-18 19:15:05 +0100654 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800655
Harald Welte2bcfd3a2017-11-18 22:14:35 +0100656 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800657 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
658 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
659 valueof(ts_SDP_ptime(20)) });
660 resp := mgcp_transceive_mgw(cmd, rtmpl);
661 setverdict(pass);
662 }
663
664 /* DLCX without CRCX first */
665 testcase TC_dlcx_without_crcx() runs on dummy_CT {
666 var template MgcpCommand cmd;
667 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100668 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "4@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800669 var template MgcpResponse rtmpl := {
670 line := {
Harald Weltef91edf32017-12-28 14:16:21 +0100671 code := ("400", "515"),
Harald Weltee636afd2017-09-17 16:24:09 +0800672 string := ?
673 },
674 params:= { },
675 sdp := omit
676 };
677
Harald Welteedc45c12017-11-18 19:15:05 +0100678 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800679
Harald Welteedc45c12017-11-18 19:15:05 +0100680 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800681 resp := mgcp_transceive_mgw(cmd, rtmpl);
682 setverdict(pass);
683 }
684
Philipp Maier8a3dc922018-02-02 14:55:12 +0100685 /* test valid wildcarded MDCX */
686 testcase TC_mdcx_wildcarded() runs on dummy_CT {
687 /* Note: A wildcarded MDCX is not allowed, so we expect the
688 * MGW to reject this request */
689 var template MgcpCommand cmd;
690 var MgcpResponse resp;
691 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
692 var MgcpCallId call_id := '1225'H;
693 var template MgcpResponse rtmpl := {
694 line := {
695 /* TODO: accept/enforce better error? */
696 code := "507",
697 string := ?
698 },
699 params:= { },
700 sdp := omit
701 };
702
703 f_init(ep);
704
705 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, call_id);
706 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
707 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
708 valueof(ts_SDP_ptime(20)) });
709 resp := mgcp_transceive_mgw(cmd, rtmpl);
710 setverdict(pass);
711 }
712
713 /* test valid wildcarded DLCX */
714 testcase TC_dlcx_wildcarded() runs on dummy_CT {
715 /* Note: A wildcarded DLCX is specified, but our MGW does not
716 * support this feature so we expect the MGW to reject the
717 * request */
718 var template MgcpCommand cmd;
719 var MgcpResponse resp;
720 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
721 var template MgcpResponse rtmpl := {
722 line := {
723 code := "507",
724 string := ?
725 },
726 params:= { },
727 sdp := omit
728 };
729
730 f_init(ep);
731
732 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
733 resp := mgcp_transceive_mgw(cmd, rtmpl);
734 setverdict(pass);
735 }
736
Harald Welte79181ff2017-11-18 19:26:11 +0100737 /* Test (valid) CRCX followed by (valid) DLCX containig EP+CallId+ConnId */
738 testcase TC_crcx_and_dlcx_ep_callid_connid() runs on dummy_CT {
739 var template MgcpCommand cmd;
740 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100741 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte79181ff2017-11-18 19:26:11 +0100742 var MgcpCallId call_id := '51234'H;
743
744 f_init(ep);
745
746 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
747 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
748
749 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
750
751 setverdict(pass);
752 }
753
Harald Welte646ecdb2017-12-28 03:21:57 +0100754 function f_crcx_and_dlcx_ep_callid_connid(MgcpEndpoint ep, MgcpCallId call_id) runs on dummy_CT {
755 var template MgcpCommand cmd;
756 var MgcpResponse resp;
757
758 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
759 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
760
761 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
762
763 setverdict(pass);
764 }
765
766 testcase TC_crcx_dlcx_30ep() runs on dummy_CT {
767 var MgcpEndpoint ep;
768 var MgcpCallId call_id;
769 var integer ep_nr;
770
771 f_init();
772
773 for (ep_nr := 1; ep_nr < 30; ep_nr := ep_nr+1) {
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100774 ep := c_mgw_ep_rtpbridge & hex2str(int2hex(ep_nr, 2)) & "@" & c_mgw_domain;
Harald Welte646ecdb2017-12-28 03:21:57 +0100775 call_id := int2hex(ep_nr, 2) & '1234'H;
776 f_crcx_and_dlcx_ep_callid_connid(ep, call_id);
777 }
778 }
779
Harald Welte79181ff2017-11-18 19:26:11 +0100780 /* Test (valid) CRCX followed by (valid) DLCX containing EP+CallId */
781 testcase TC_crcx_and_dlcx_ep_callid() runs on dummy_CT {
Harald Welte5b4c44e2017-09-17 16:35:27 +0800782 var template MgcpCommand cmd;
783 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100784 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100785 var MgcpCallId call_id := '51233'H;
Harald Welte5b4c44e2017-09-17 16:35:27 +0800786
Harald Welteedc45c12017-11-18 19:15:05 +0100787 f_init(ep);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800788
Harald Welteba62c8c2017-11-18 18:26:49 +0100789 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100790 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800791
Harald Welteba62c8c2017-11-18 18:26:49 +0100792 f_dlcx_ok(ep, call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800793
794 setverdict(pass);
795 }
796
Harald Welte79181ff2017-11-18 19:26:11 +0100797 /* Test (valid) CRCX followed by (valid) DLCX containing EP */
798 testcase TC_crcx_and_dlcx_ep() runs on dummy_CT {
799 var template MgcpCommand cmd;
800 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100801 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100802 var MgcpCallId call_id := '51232'H;
Harald Welte79181ff2017-11-18 19:26:11 +0100803
804 f_init(ep);
805
806 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
807 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
808
809 f_dlcx_ok(ep);
810
811 setverdict(pass);
812 }
813
814
Harald Welte6d167f82017-11-18 19:41:35 +0100815 /* CRCX + DLCX of valid endpoint but invalid call-id */
816 testcase TC_crcx_and_dlcx_ep_callid_inval() runs on dummy_CT {
817 var template MgcpCommand cmd;
818 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100819 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100820 var MgcpCallId call_id := '51231'H;
821
822 f_init(ep);
823
824 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
825 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
826
827 f_dlcx(ep, "516", *, 'ffff'H);
828
829 setverdict(pass);
830 }
831
832
833 /* CRCX + DLCX of valid endpoint and call-id but invalid conn-id */
834 testcase TC_crcx_and_dlcx_ep_callid_connid_inval() runs on dummy_CT {
835 var template MgcpCommand cmd;
836 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100837 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100838 var MgcpCallId call_id := '51230'H;
839
840 f_init(ep);
841
842 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
843 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
844
845 f_dlcx(ep, "515", *, call_id, 'ffff'H);
846
847 setverdict(pass);
848 }
849
850
Harald Weltee636afd2017-09-17 16:24:09 +0800851 /* TODO: Double-DLCX (retransmission) */
Harald Weltef53f1642017-11-18 19:57:11 +0100852 testcase TC_crcx_and_dlcx_retrans() runs on dummy_CT {
853 var template MgcpCommand cmd;
854 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100855 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Weltef53f1642017-11-18 19:57:11 +0100856 var MgcpCallId call_id := '51229'H;
857 var template MgcpResponse rtmpl := {
858 line := {
859 code := "200",
860 string := "OK"
861 },
862 params:= { },
863 sdp := omit
864 };
865
866 f_init(ep);
867
868 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
869 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
870
871 cmd := ts_DLCX(get_next_trans_id(), ep, call_id);
872 resp := mgcp_transceive_mgw(cmd, rtmpl);
873 resp := mgcp_transceive_mgw(cmd, rtmpl);
874
875 setverdict(pass);
876 }
877
Harald Weltebb7523b2018-03-29 08:52:01 +0200878 template (value) RtpFlowData t_RtpFlow(charstring host_a, charstring host_b, uint7_t pt,
879 charstring codec) := {
880 em := {
881 hostname := host_a,
882 portnr := omit
883 },
884 mgw := {
885 hostname := host_b,
886 portnr := omit
887 },
888 pt := pt,
889 codec := codec
890 }
Harald Weltef53f1642017-11-18 19:57:11 +0100891
Harald Weltebb7523b2018-03-29 08:52:01 +0200892 /* transmit RTP streams between two RTP Emulations back-to-back; expect no loss */
893 testcase TC_rtpem_selftest() runs on dummy_CT {
894 var RtpemStats stats[2];
895 var integer local_port := 10000;
896 var integer local_port2 := 20000;
897
898 f_init();
899
900 f_rtpem_bind(RTPEM[0], "127.0.0.1", local_port);
901 f_rtpem_bind(RTPEM[1], "127.0.0.2", local_port2);
902
903 f_rtpem_connect(RTPEM[0], "127.0.0.2", local_port2);
904 f_rtpem_connect(RTPEM[1], "127.0.0.1", local_port);
905
906 log("=== starting");
907 f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
908 f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
909
910 f_sleep(5.0);
911
912 log("=== stopping");
913 f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
914 f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
915 f_sleep(0.5);
916 f_rtpem_mode(RTPEM[1], RTPEM_MODE_NONE);
917 f_rtpem_mode(RTPEM[0], RTPEM_MODE_NONE);
918
919 stats[0] := f_rtpem_stats_get(RTPEM[0]);
920 stats[1] := f_rtpem_stats_get(RTPEM[1]);
921 if (not f_rtpem_stats_compare(stats[0], stats[1])) {
922 setverdict(fail, "RTP endpoint statistics don't match");
923 }
924 setverdict(pass);
925 }
926
Philipp Maier2321ef92018-06-27 17:52:04 +0200927 /* Create one half open connection in receive-only mode. The MGW must accept
928 * the packets but must not send any. */
929 testcase TC_one_crcx_receive_only_rtp() runs on dummy_CT {
930 var RtpFlowData flow;
931 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "1@" & c_mgw_domain;
932 var MgcpCallId call_id := '1225'H;
933 var RtpemStats stats;
934
935 f_init(ep);
936 flow := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 112, "AMR/8000/1"));
937 flow.em.portnr := 10000;
938 f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow, false);
939
940 f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
941 f_sleep(1.0);
942 f_flow_delete(RTPEM[0], ep, call_id);
943
944 stats := f_rtpem_stats_get(RTPEM[0]);
945
946 if (stats.num_pkts_tx < 40) {
947 setverdict(fail);
948 }
949 if (stats.bytes_payload_tx < 190) {
950 setverdict(fail);
951 }
952 if (stats.num_pkts_rx != 0) {
953 setverdict(fail);
954 }
955 if (stats.num_pkts_rx_err_seq != 0) {
956 setverdict(fail);
957 }
958 if (stats.num_pkts_rx_err_ts != 0) {
959 setverdict(fail);
960 }
961 if (stats.num_pkts_rx_err_disabled != 0) {
962 setverdict(fail);
963 }
964
965 setverdict(pass);
966 }
967
968 /* Create one connection in loopback mode, test if the RTP packets are
969 * actually reflected */
970 testcase TC_one_crcx_loopback_rtp() runs on dummy_CT {
971 var RtpFlowData flow;
972 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "1@" & c_mgw_domain;
973 var MgcpCallId call_id := '1225'H;
974 var RtpemStats stats;
975
976 f_init(ep);
977 flow := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 111, "GSM-HR-08/8000/1"));
978 flow.em.portnr := 10000;
979 f_flow_create(RTPEM[0], ep, call_id, "loopback", flow);
980
981 f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
982 f_sleep(1.0);
983 f_flow_delete(RTPEM[0], ep, call_id);
984
985 stats := f_rtpem_stats_get(RTPEM[0]);
986
987 if (stats.num_pkts_tx != stats.num_pkts_rx) {
988 setverdict(fail);
989 }
990 if (stats.bytes_payload_tx != stats.bytes_payload_rx) {
991 setverdict(fail);
992 }
993 if (stats.num_pkts_rx_err_seq != 0) {
994 setverdict(fail);
995 }
996 if (stats.num_pkts_rx_err_ts != 0) {
997 setverdict(fail);
998 }
999 if (stats.num_pkts_rx_err_disabled != 0) {
1000 setverdict(fail);
1001 }
1002
1003 setverdict(pass);
1004 }
1005
1006 function f_TC_two_crcx_and_rtp(boolean bidir) runs on dummy_CT {
Harald Weltebb7523b2018-03-29 08:52:01 +02001007 var RtpFlowData flow[2];
1008 var RtpemStats stats[2];
Harald Weltebb7523b2018-03-29 08:52:01 +02001009 var MgcpResponse resp;
1010 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
1011 var MgcpCallId call_id := '1226'H;
Philipp Maier2321ef92018-06-27 17:52:04 +02001012 var integer tolerance := 0;
Harald Weltebb7523b2018-03-29 08:52:01 +02001013
1014 f_init(ep);
1015
1016 /* from us to MGW */
1017 flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
1018 /* bind local RTP emulation sockets */
1019 flow[0].em.portnr := 10000;
Philipp Maier2321ef92018-06-27 17:52:04 +02001020 f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
Harald Weltebb7523b2018-03-29 08:52:01 +02001021
1022 /* from MGW back to us */
1023 flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
1024 flow[1].em.portnr := 20000;
Philipp Maier2321ef92018-06-27 17:52:04 +02001025 f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
1026
1027 if (bidir) {
1028 f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
1029 f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
1030
1031 /* Note: When we test bidirectional we may
1032 * loose packets during switch off because
1033 * both ends are transmitting and we only
1034 * can switch them off one by one. */
1035 tolerance := 3;
1036 } else {
1037 f_rtpem_mode(RTPEM[0], RTPEM_MODE_RXONLY);
1038 f_rtpem_mode(RTPEM[1], RTPEM_MODE_TXONLY);
1039 }
1040
1041 f_sleep(1.0);
1042
1043 f_flow_delete(RTPEM[1]);
1044 f_flow_delete(RTPEM[0], ep, call_id);
1045
1046 stats[0] := f_rtpem_stats_get(RTPEM[0]);
1047 stats[1] := f_rtpem_stats_get(RTPEM[1]);
1048 if (not f_rtpem_stats_compare(stats[0], stats[1], tolerance)) {
1049 setverdict(fail, "RTP endpoint statistics don't match");
1050 }
1051
1052 setverdict(pass);
1053 }
1054
1055 /* create two local RTP emulations; create two connections on MGW EP, exchange some data */
1056 testcase TC_two_crcx_and_rtp() runs on dummy_CT {
1057 f_TC_two_crcx_and_rtp(false);
1058 }
1059
1060 /* create two local RTP emulations; create two connections on MGW EP,
1061 * exchange some data in both directions */
1062 testcase TC_two_crcx_and_rtp_bidir() runs on dummy_CT {
1063 f_TC_two_crcx_and_rtp(true);
1064 }
1065
1066 /* create two local RTP emulations and pass data in both directions */
1067 testcase TC_two_crcx_mdcx_and_rtp() runs on dummy_CT {
1068 var RtpFlowData flow[2];
1069 var RtpemStats stats[2];
1070 var MgcpResponse resp;
1071 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
1072 var MgcpCallId call_id := '1227'H;
1073 var integer num_pkts_tx[2];
1074 var integer temp;
1075
1076 f_init(ep);
1077
1078 /* Create the first connection in receive only mode */
1079 flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 3, "GSM/8000/1"));
1080 flow[0].em.portnr := 10000;
1081 f_flow_create(RTPEM[0], ep, call_id, "recvonly", flow[0], false);
1082
1083 /* Create the second connection. This connection will be also
1084 * in receive only mode */
1085 flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 3, "GSM/8000/1"));
1086 flow[1].em.portnr := 20000;
1087 f_flow_create(RTPEM[1], ep, call_id, "recvonly", flow[1], false);
1088
1089 /* The first leg starts transmitting */
1090 f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
1091 f_sleep(0.5);
1092 stats[0] := f_rtpem_stats_get(RTPEM[0]);
1093 if (stats[0].num_pkts_rx_err_disabled != 0) {
1094 setverdict(fail, "received packets from MGW on recvonly connection");
1095 }
1096 stats[1] := f_rtpem_stats_get(RTPEM[1]);
1097 if (stats[1].num_pkts_rx_err_disabled != 0) {
1098 setverdict(fail, "received packets from MGW on recvonly connection");
1099 }
1100
1101 /* The second leg starts transmitting a little later */
1102 f_rtpem_mode(RTPEM[1], RTPEM_MODE_TXONLY);
1103 f_sleep(1.0);
1104 stats[0] := f_rtpem_stats_get(RTPEM[0]);
1105 if (stats[0].num_pkts_rx_err_disabled != 0) {
1106 setverdict(fail, "received packets from MGW on recvonly connection");
1107 }
1108 stats[1] := f_rtpem_stats_get(RTPEM[1]);
1109 if (stats[1].num_pkts_rx_err_disabled != 0) {
1110 setverdict(fail, "received packets from MGW on recvonly connection");
1111 }
1112
1113 /* The first leg will now be switched into bidirectional
1114 * mode, but we do not expect any data comming back yet. */
1115 f_flow_modify(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
1116 f_sleep(0.5);
1117 stats[0] := f_rtpem_stats_get(RTPEM[0]);
1118 if (stats[1].num_pkts_rx_err_disabled != 0) {
1119 setverdict(fail, "received packets from MGW on recvonly connection");
1120 }
1121 stats[1] := f_rtpem_stats_get(RTPEM[1]);
1122 if (stats[1].num_pkts_rx_err_disabled != 0) {
1123 setverdict(fail, "received packets from MGW on recvonly connection");
1124 }
1125
1126 /* When the second leg is switched into bidirectional mode
1127 * as well, then the MGW will connect the two together and
1128 * we should see RTP streams passing through from both ends. */
1129 f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
1130 f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
1131 stats[0] := f_rtpem_stats_get(RTPEM[0]);
1132 num_pkts_tx[0] := stats[0].num_pkts_tx
1133 stats[1] := f_rtpem_stats_get(RTPEM[1]);
1134 num_pkts_tx[1] := stats[1].num_pkts_tx
1135
1136 f_flow_modify(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
1137 f_sleep(2.0);
1138
1139 stats[0] := f_rtpem_stats_get(RTPEM[0]);
1140 stats[1] := f_rtpem_stats_get(RTPEM[1]);
1141
1142 temp := stats[0].num_pkts_tx - num_pkts_tx[0] - stats[1].num_pkts_rx;
1143 if (temp > 3 or temp < -3) {
1144 setverdict(fail, "number of packets not within normal parameters");
1145 }
1146
1147 temp := stats[1].num_pkts_tx - num_pkts_tx[1] - stats[0].num_pkts_rx;
1148 if (temp > 3 or temp < -3) {
1149 setverdict(fail, "number of packets not within normal parameters");
1150 }
1151
1152 /* Tear down */
1153 f_flow_delete(RTPEM[0]);
1154 f_flow_delete(RTPEM[1], ep, call_id);
1155 setverdict(pass);
1156 }
1157
1158 /* Test what happens when two RTP streams from different sources target
1159 * a single connection. Is the unsolicited stream properly ignored? */
1160 testcase TC_two_crcx_and_unsolicited_rtp() runs on dummy_CT {
1161 var RtpFlowData flow[2];
1162 var RtpemStats stats[2];
1163 var MgcpResponse resp;
1164 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
1165 var MgcpCallId call_id := '1234321326'H;
1166 var integer unsolicited_port := 10002;
1167
1168 f_init(ep);
1169
1170 /* from us to MGW */
1171 flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
1172 /* bind local RTP emulation sockets */
1173 flow[0].em.portnr := 10000;
1174 f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
1175
1176 /* from MGW back to us */
1177 flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 98, "AMR/8000"));
1178 flow[1].em.portnr := 20000;
1179 f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
Harald Weltebb7523b2018-03-29 08:52:01 +02001180
1181 f_rtpem_mode(RTPEM[1], RTPEM_MODE_RXONLY);
1182 f_rtpem_mode(RTPEM[0], RTPEM_MODE_TXONLY);
1183
Philipp Maier2321ef92018-06-27 17:52:04 +02001184 f_sleep(0.5);
Harald Weltebb7523b2018-03-29 08:52:01 +02001185
Philipp Maier2321ef92018-06-27 17:52:04 +02001186 /* Start inserting unsolicited RTP packets */
Philipp Maier4de3e372018-06-29 17:15:22 +02001187 f_rtpem_bind(RTPEM[2], mp_local_ip, unsolicited_port);
1188 f_rtpem_connect(RTPEM[2], mp_remote_ip, flow[0].mgw.portnr);
Philipp Maier2321ef92018-06-27 17:52:04 +02001189 f_rtpem_mode(RTPEM[2], RTPEM_MODE_TXONLY);
1190
1191 f_sleep(0.5);
1192
1193 f_flow_delete(RTPEM[0]);
1194 f_flow_delete(RTPEM[1], ep, call_id);
Harald Weltebb7523b2018-03-29 08:52:01 +02001195
1196 stats[0] := f_rtpem_stats_get(RTPEM[0]);
1197 stats[1] := f_rtpem_stats_get(RTPEM[1]);
1198 if (not f_rtpem_stats_compare(stats[0], stats[1])) {
1199 setverdict(fail, "RTP endpoint statistics don't match");
1200 }
1201
Harald Weltebb7523b2018-03-29 08:52:01 +02001202 setverdict(pass);
Philipp Maier2321ef92018-06-27 17:52:04 +02001203 }
Harald Weltebb7523b2018-03-29 08:52:01 +02001204
Philipp Maier2321ef92018-06-27 17:52:04 +02001205 /* Test a handover situation. We first create two connections transmit
1206 * some data bidirectionally. Then we will simulate a handover situation. */
1207 testcase TC_two_crcx_and_one_mdcx_rtp_ho() runs on dummy_CT {
1208 var RtpFlowData flow[2];
1209 var RtpemStats stats[3];
1210 var MgcpResponse resp;
1211 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "4@" & c_mgw_domain;
1212 var MgcpCallId call_id := '76338'H;
1213 var integer port_old;
1214
1215 f_init(ep);
1216
1217 /* First connection (BTS) */
1218 flow[0] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 110, "GSM-EFR/8000"));
1219 /* bind local RTP emulation sockets */
1220 flow[0].em.portnr := 10000;
1221 f_flow_create(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
1222
1223 /* Second connection (PBX) */
1224 flow[1] := valueof(t_RtpFlow(mp_local_ip, mp_remote_ip, 110, "GSM-EFR/8000"));
1225 flow[1].em.portnr := 20000;
1226 f_flow_create(RTPEM[1], ep, call_id, "sendrecv", flow[1]);
1227
1228 /* Normal rtp flow for one second */
1229 f_rtpem_mode(RTPEM[0], RTPEM_MODE_BIDIR);
1230 f_rtpem_mode(RTPEM[1], RTPEM_MODE_BIDIR);
1231 f_sleep(1.0);
1232
1233 /* Now switch the flow over to a new port (BTS) */
1234 port_old := flow[0].em.portnr;
1235 flow[0].em.portnr := 10002;
1236 f_flow_modify(RTPEM[0], ep, call_id, "sendrecv", flow[0]);
1237
1238 /* When handing over a call, the old source may still keep
1239 * transmitting for a while. We simulate this by injecting
1240 * some unsolicited packets on the behalf of the old source,
1241 * (old remote port) */
Philipp Maier4de3e372018-06-29 17:15:22 +02001242 f_rtpem_bind(RTPEM[2], mp_local_ip, port_old);
1243 f_rtpem_connect(RTPEM[2], mp_remote_ip, flow[0].mgw.portnr);
Philipp Maier2321ef92018-06-27 17:52:04 +02001244 f_rtpem_mode(RTPEM[2], RTPEM_MODE_TXONLY);
1245 f_sleep(1.0);
1246 f_rtpem_mode(RTPEM[2], RTPEM_MODE_NONE);
1247 f_sleep(1.0);
1248
1249 /* Terminate call */
1250 f_flow_delete(RTPEM[0]);
1251 f_flow_delete(RTPEM[1], ep, call_id);
1252
1253 stats[0] := f_rtpem_stats_get(RTPEM[0]);
1254 stats[1] := f_rtpem_stats_get(RTPEM[1]);
1255 if (not f_rtpem_stats_compare(stats[0], stats[1], 5)) {
1256 setverdict(fail, "RTP endpoint statistics don't match");
1257 }
1258 stats[2] := f_rtpem_stats_get(RTPEM[2]);
1259 if (stats[2].num_pkts_rx_err_disabled != 0) {
1260 setverdict(fail, "received packets on old leg after handover");
1261 }
1262
1263 setverdict(pass);
Harald Weltebb7523b2018-03-29 08:52:01 +02001264 }
Harald Weltef53f1642017-11-18 19:57:11 +01001265
Harald Weltee636afd2017-09-17 16:24:09 +08001266 /* TODO: Double-DLCX (no retransmission) */
1267
1268
1269
1270 /* TODO: AUEP (various) */
1271 /* TODO: RSIP (various) */
1272 /* TODO: RQNT (various) */
1273 /* TODO: EPCF (various) */
1274 /* TODO: AUCX (various) */
1275 /* TODO: invalid verb (various) */
1276
Harald Welte00a067f2017-09-13 23:27:17 +02001277 control {
1278 execute(TC_selftest());
Harald Welte3c6ebb92017-09-16 00:56:57 +08001279 execute(TC_crcx());
Philipp Maier45635f42018-06-05 17:28:02 +02001280 execute(TC_crcx_no_lco());
Philipp Maierbb7a01c2018-02-01 12:32:57 +01001281 execute(TC_crcx_noprefix());
Harald Weltee636afd2017-09-17 16:24:09 +08001282 execute(TC_crcx_unsupp_mode());
1283 execute(TC_crcx_early_bidir_mode());
1284 execute(TC_crcx_unsupp_param());
1285 execute(TC_crcx_missing_callid());
1286 execute(TC_crcx_missing_mode());
1287 execute(TC_crcx_unsupp_packet_intv());
1288 execute(TC_crcx_illegal_double_lco());
1289 execute(TC_crcx_sdp());
Philipp Maier5e06cee2018-02-01 18:28:08 +01001290 execute(TC_crcx_wildcarded());
1291 execute(TC_crcx_wildcarded_exhaust());
Harald Weltee636afd2017-09-17 16:24:09 +08001292 execute(TC_mdcx_without_crcx());
1293 execute(TC_dlcx_without_crcx());
Philipp Maier8a3dc922018-02-02 14:55:12 +01001294 execute(TC_mdcx_wildcarded());
1295 execute(TC_dlcx_wildcarded());
Harald Welte79181ff2017-11-18 19:26:11 +01001296 execute(TC_crcx_and_dlcx_ep_callid_connid());
1297 execute(TC_crcx_and_dlcx_ep_callid());
1298 execute(TC_crcx_and_dlcx_ep());
Harald Welte6d167f82017-11-18 19:41:35 +01001299 execute(TC_crcx_and_dlcx_ep_callid_inval());
1300 execute(TC_crcx_and_dlcx_ep_callid_connid_inval());
Harald Weltef53f1642017-11-18 19:57:11 +01001301 execute(TC_crcx_and_dlcx_retrans());
Harald Welte33d82162017-12-28 03:21:57 +01001302
1303 execute(TC_crcx_dlcx_30ep());
Harald Weltebb7523b2018-03-29 08:52:01 +02001304
1305 execute(TC_rtpem_selftest());
Philipp Maier2321ef92018-06-27 17:52:04 +02001306
1307 execute(TC_one_crcx_receive_only_rtp());
1308 execute(TC_one_crcx_loopback_rtp());
Harald Weltebb7523b2018-03-29 08:52:01 +02001309 execute(TC_two_crcx_and_rtp());
Philipp Maier2321ef92018-06-27 17:52:04 +02001310 execute(TC_two_crcx_and_rtp_bidir());
1311 execute(TC_two_crcx_mdcx_and_rtp());
1312 execute(TC_two_crcx_and_unsolicited_rtp());
1313 execute(TC_two_crcx_and_one_mdcx_rtp_ho());
Harald Welte00a067f2017-09-13 23:27:17 +02001314 }
1315}