blob: 6c47e27b118504305353aa0259aabd1262922297 [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;
10 import from RTP_Endpoint 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;
Harald Weltef07c2862017-11-18 17:16:24 +010021 port RTP_CODEC_PT RTP;
Harald Welte3c6ebb92017-09-16 00:56:57 +080022 var boolean initialized := false;
Harald Welte55015362017-11-18 16:02:42 +010023 var ConnectionId g_mgcp_conn_id := -1;
Harald Weltee1e18c52017-09-17 16:23:07 +080024 var integer g_trans_id;
Harald Weltef07c2862017-11-18 17:16:24 +010025
26 var RtpEndpoint g_rtp_ep[2];
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 Welte21ba5572017-09-19 17:55:05 +080047 /* initialization function, called by each test case at the
48 * beginning, but 'initialized' variable ensures its body is
49 * only executed once */
Harald Welteedc45c12017-11-18 19:15:05 +010050 private function f_init(template MgcpEndpoint ep := omit) runs on dummy_CT {
Harald Welte3c6ebb92017-09-16 00:56:57 +080051 var Result res;
Harald Weltef07c2862017-11-18 17:16:24 +010052 var uint32_t ssrc;
Harald Welteedc45c12017-11-18 19:15:05 +010053 if (initialized == false) {
54 initialized := true;
55
56 /* some random number for the initial transaction id */
57 g_trans_id := float2int(rnd()*65535.0);
58 map(self:MGCP, system:MGCP_CODEC_PT);
59 /* connect the MGCP test port using the given
60 * source/destionation ip/port and store the connection id in g_mgcp_conn_id
61 * */
62 res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, mp_remote_ip, mp_remote_udp_port, mp_local_ip, mp_local_udp_port, 0, { udp := {} });
63 g_mgcp_conn_id := res.connId;
64
65 map(self:RTP, system:RTP_CODEC_PT);
66 ssrc := float2int(rnd()*4294967296.0);
67 rtp_endpoint_init(g_rtp_ep[0], mp_local_ip, mp_local_rtp_port_base, ssrc);
68 rtp_endpoint_bind(RTP, g_rtp_ep[0]);
69 rtp_endpoint_init(g_rtp_ep[1], mp_local_ip, mp_local_rtp_port_base+2, ssrc);
70 rtp_endpoint_bind(RTP, g_rtp_ep[1]);
Harald Welte3c6ebb92017-09-16 00:56:57 +080071 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080072
Harald Welteedc45c12017-11-18 19:15:05 +010073 if (isvalue(ep)) {
74 /* do a DLCX on all connections of the EP */
75 f_dlcx_ignore(valueof(ep));
76 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080077 }
78
Harald Welte00a067f2017-09-13 23:27:17 +020079 testcase TC_selftest() runs on dummy_CT {
80 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 +010081 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 +020082 const charstring c_mdcx3_ret := "200 18983215 OK\r\n" &
83 "I: 1\n" &
84 "\n" &
85 "v=0\r\n" &
86 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
87 "s=-\r\n" &
88 "c=IN IP4 0.0.0.0\r\n" &
89 "t=0 0\r\n" &
90 "m=audio 0 RTP/AVP 126\r\n" &
91 "a=rtpmap:126 AMR/8000\r\n" &
92 "a=ptime:20\r\n";
Philipp Maierbb7a01c2018-02-01 12:32:57 +010093 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 +020094 "M: sendrecv\r" &
95 "C: 2\r\n" &
96 "I: 1\r\n" &
97 "L: p:20, a:AMR, nt:IN\r\n" &
98 "\n" &
99 "v=0\r\n" &
100 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
Harald Welte2871d0b2017-09-14 22:42:12 +0800101 "s=-\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200102 "c=IN IP4 0.0.0.0\r\n" &
103 "t=0 0\r\n" &
104 "m=audio 4441 RTP/AVP 99\r\n" &
105 "a=rtpmap:99 AMR/8000\r\n" &
106 "a=ptime:40\r\n";
Harald Welte3c6ebb92017-09-16 00:56:57 +0800107 const charstring c_crcx510_ret := "510 23 FAIL\r\n"
Harald Welte00a067f2017-09-13 23:27:17 +0200108
109 log(c_auep);
110 log(dec_MgcpCommand(c_auep));
111
112 log(c_mdcx3);
113 log(dec_MgcpCommand(c_mdcx3));
114
115 log(c_mdcx3_ret);
116 log(dec_MgcpResponse(c_mdcx3_ret));
117
118 log(c_mdcx4);
119 log(dec_MgcpCommand(c_mdcx4));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800120
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100121 log(ts_CRCX("23", c_mgw_ep_rtpbridge & "42@" & c_mgw_domain, "sendrecv", '1234'H));
122 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 +0800123
124 log(c_crcx510_ret);
125 log(dec_MgcpResponse(c_crcx510_ret));
126 log(dec_MgcpMessage(c_crcx510_ret));
127 }
128
Harald Weltee636afd2017-09-17 16:24:09 +0800129 /* CRCX test ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100130 * x without mandatory CallId
Harald Weltee636afd2017-09-17 16:24:09 +0800131 * - with forbidden parameters (e.g. Capabilities, PackageList, ...
132 * - CRCX with remote session description and without
133 *
134 * general ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100135 * x packetization != 20ms
136 * x invalid mode
Harald Weltee636afd2017-09-17 16:24:09 +0800137 * x unsupported mode (517)
138 * x bidirectional mode before RemoteConnDesc: 527
139 * - invalid codec
Harald Weltee0b331f2017-11-18 20:34:33 +0100140 * x retransmission of same transaction
Harald Weltee636afd2017-09-17 16:24:09 +0800141 * - unsupported LocalConnectionOptions ("b", "a", "e", "gc", "s", "r", "k", ..)
142 */
143
Harald Welte21ba5572017-09-19 17:55:05 +0800144 /* build a receive template for receiving a MGCP message. You
145 * pass the MGCP response template in, and it will generate an
146 * MGCP_RecvFrom template that can match the primitives arriving on the
147 * MGCP_CodecPort */
Harald Weltee636afd2017-09-17 16:24:09 +0800148 function tr_MGCP_RecvFrom_R(template MgcpResponse resp) runs on dummy_CT return template MGCP_RecvFrom {
149 var template MGCP_RecvFrom mrf := {
Harald Welte55015362017-11-18 16:02:42 +0100150 connId := g_mgcp_conn_id,
Harald Weltee636afd2017-09-17 16:24:09 +0800151 remName := mp_remote_ip,
152 remPort := mp_remote_udp_port,
153 locName := mp_local_ip,
154 locPort := mp_local_udp_port,
155 msg := { response := resp }
156 }
157 return mrf;
158 }
159
160 /* Send a MGCP request + receive a (matching!) response */
161 function mgcp_transceive_mgw(template MgcpCommand cmd, template MgcpResponse resp := ?) runs on dummy_CT return MgcpResponse {
162 var MgcpMessage msg := { command := valueof(cmd) };
163 resp.line.trans_id := cmd.line.trans_id;
164 var template MGCP_RecvFrom mrt := tr_MGCP_RecvFrom_R(resp);
Harald Welte3c6ebb92017-09-16 00:56:57 +0800165 var MGCP_RecvFrom mrf;
166 timer T := 5.0;
167
Harald Welte55015362017-11-18 16:02:42 +0100168 MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800169 T.start;
170 alt {
Harald Weltee636afd2017-09-17 16:24:09 +0800171 [] MGCP.receive(mrt) -> value mrf { }
172 [] MGCP.receive(tr_MGCP_RecvFrom_R(?)) { setverdict(fail); }
Harald Welte3c6ebb92017-09-16 00:56:57 +0800173 [] MGCP.receive { repeat; }
174 [] T.timeout { setverdict(fail); }
175 }
176 T.stop;
Harald Weltee636afd2017-09-17 16:24:09 +0800177
178 if (isbound(mrf) and isbound(mrf.msg) and ischosen(mrf.msg.response)) {
179 return mrf.msg.response;
180 } else {
181 var MgcpResponse r := { line := { code := "999", trans_id := valueof(cmd.line.trans_id) } };
182 return r;
183 }
Harald Welte00a067f2017-09-13 23:27:17 +0200184 }
185
Harald Welteba62c8c2017-11-18 18:26:49 +0100186 function extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
187 var integer i;
188 for (i := 0; i < lengthof(resp.params); i := i + 1) {
189 var MgcpParameter par := resp.params[i];
190 if (par.code == "I") {
191 return str2hex(par.val);
192 }
193 }
194 setverdict(fail);
195 return '00000000'H;
196 }
197
Harald Welte10889c12017-11-18 19:40:31 +0100198 function f_dlcx(MgcpEndpoint ep, template MgcpResponseCode ret_code, template charstring ret_val,
199 template MgcpCallId call_id := omit,
200 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welteba62c8c2017-11-18 18:26:49 +0100201 var template MgcpCommand cmd;
202 var MgcpResponse resp;
203 var template MgcpResponse rtmpl := {
204 line := {
Harald Welte10889c12017-11-18 19:40:31 +0100205 code := ret_code,
206 string := ret_val
Harald Welteba62c8c2017-11-18 18:26:49 +0100207 },
208 params := *,
209 sdp := *
210 };
Harald Weltec40e0c32017-11-18 19:08:22 +0100211 cmd := ts_DLCX(get_next_trans_id(), ep, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100212 resp := mgcp_transceive_mgw(cmd, rtmpl);
213 }
214
Harald Welte10889c12017-11-18 19:40:31 +0100215 /* Send DLCX and expect OK response */
216 function f_dlcx_ok(MgcpEndpoint ep, template MgcpCallId call_id := omit,
217 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Weltef91edf32017-12-28 14:16:21 +0100218 f_dlcx(ep, ("200","250"), "OK", call_id, conn_id);
Harald Welte10889c12017-11-18 19:40:31 +0100219 }
220
Harald Welteba62c8c2017-11-18 18:26:49 +0100221 /* Send DLCX and accept any response */
Harald Weltec40e0c32017-11-18 19:08:22 +0100222 function f_dlcx_ignore(MgcpEndpoint ep, template MgcpCallId call_id := omit,
Harald Welteba62c8c2017-11-18 18:26:49 +0100223 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welte10889c12017-11-18 19:40:31 +0100224 f_dlcx(ep, ?, *, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100225 }
226
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100227 function f_crcx(charstring ep_prefix) runs on dummy_CT {
228 var MgcpEndpoint ep := ep_prefix & "2@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800229 var template MgcpCommand cmd;
230 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100231 var MgcpCallId call_id := '1234'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800232
Harald Welteedc45c12017-11-18 19:15:05 +0100233 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800234
Harald Welteba62c8c2017-11-18 18:26:49 +0100235 /* create the connection on the MGW */
236 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100237 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welteba62c8c2017-11-18 18:26:49 +0100238 extract_conn_id(resp);
239
240 /* clean-up */
241 f_dlcx_ok(ep, call_id);
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100242 }
Harald Welteba62c8c2017-11-18 18:26:49 +0100243
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100244 /* test valid CRCX without SDP */
245 testcase TC_crcx() runs on dummy_CT {
246 f_crcx(c_mgw_ep_rtpbridge);
247 setverdict(pass);
248 }
249
250 /* test valid CRCX without SDP (older method without endpoint prefix) */
251 testcase TC_crcx_noprefix() runs on dummy_CT {
252 f_crcx("");
Harald Weltee636afd2017-09-17 16:24:09 +0800253 setverdict(pass);
254 }
255
256 /* test CRCX with unsupported mode, expect 517 */
257 testcase TC_crcx_unsupp_mode() runs on dummy_CT {
258 var template MgcpCommand cmd;
259 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100260 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100261 var MgcpCallId call_id := '1233'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800262 var template MgcpResponse rtmpl := tr_MgcpResp_Err("517");
263
Harald Welteedc45c12017-11-18 19:15:05 +0100264 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800265
Harald Welteba62c8c2017-11-18 18:26:49 +0100266 cmd := ts_CRCX(get_next_trans_id(), ep, "netwtest", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800267 resp := mgcp_transceive_mgw(cmd, rtmpl);
268 setverdict(pass);
269 }
270
Harald Welte21ba5572017-09-19 17:55:05 +0800271 /* test CRCX with early bi-directional mode, expect 527 as
272 * bi-diretional media can only be established once both local and
273 * remote side are specified, see MGCP RFC */
Harald Weltee636afd2017-09-17 16:24:09 +0800274 testcase TC_crcx_early_bidir_mode() runs on dummy_CT {
275 var template MgcpCommand cmd;
276 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100277 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100278 var MgcpCallId call_id := '1232'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800279 var template MgcpResponse rtmpl := tr_MgcpResp_Err("527");
280
Harald Welteedc45c12017-11-18 19:15:05 +0100281 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800282
Harald Welteba62c8c2017-11-18 18:26:49 +0100283 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800284 resp := mgcp_transceive_mgw(cmd, rtmpl);
285 setverdict(pass);
286 }
287
288 /* test CRCX with unsupported Parameters */
289 testcase TC_crcx_unsupp_param() runs on dummy_CT {
290 var template MgcpCommand cmd;
291 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100292 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100293 var MgcpCallId call_id := '1231'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800294 var template MgcpResponse rtmpl := tr_MgcpResp_Err("539");
295
Harald Welteedc45c12017-11-18 19:15:05 +0100296 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800297
Harald Welteba62c8c2017-11-18 18:26:49 +0100298 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100299 /* osmo-bsc_mgcp/mgw doesn't implement notifications */
300 f_mgcp_par_append(cmd.params, MgcpParameter:{ "N", "foobar" });
301
Harald Weltee636afd2017-09-17 16:24:09 +0800302 resp := mgcp_transceive_mgw(cmd, rtmpl);
303 setverdict(pass);
304 }
305
306 /* test CRCX with missing CallId */
307 testcase TC_crcx_missing_callid() runs on dummy_CT {
308 var template MgcpCommand cmd;
309 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100310 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Weltef91edf32017-12-28 14:16:21 +0100311 var template MgcpResponse rtmpl := tr_MgcpResp_Err(("400","516"));
Harald Weltee636afd2017-09-17 16:24:09 +0800312
Harald Welteedc45c12017-11-18 19:15:05 +0100313 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800314
Harald Welteba62c8c2017-11-18 18:26:49 +0100315 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", '1230'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800316 cmd.params := {
317 t_MgcpParConnMode("recvonly"),
318 t_MgcpParLocConnOpt("p:20")
319 }
320 resp := mgcp_transceive_mgw(cmd, rtmpl);
321 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100322
Harald Weltee636afd2017-09-17 16:24:09 +0800323 }
324
325 /* test CRCX with missing Mode */
326 testcase TC_crcx_missing_mode() runs on dummy_CT {
327 var template MgcpCommand cmd;
328 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100329 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100330 var MgcpCallId call_id := '1229'H;
Harald Weltef91edf32017-12-28 14:16:21 +0100331 var template MgcpResponse rtmpl := tr_MgcpResp_Err(("400","517"));
Harald Weltee636afd2017-09-17 16:24:09 +0800332
Harald Welteedc45c12017-11-18 19:15:05 +0100333 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800334
Harald Welteba62c8c2017-11-18 18:26:49 +0100335 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800336 cmd.params := {
Harald Welteba62c8c2017-11-18 18:26:49 +0100337 ts_MgcpParCallId(call_id),
Harald Weltee636afd2017-09-17 16:24:09 +0800338 t_MgcpParLocConnOpt("p:20")
339 }
340 resp := mgcp_transceive_mgw(cmd, rtmpl);
341 setverdict(pass);
342 }
343
344 /* test CRCX with unsupported packetization interval */
345 testcase TC_crcx_unsupp_packet_intv() runs on dummy_CT {
346 var template MgcpCommand cmd;
347 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100348 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100349 var MgcpCallId call_id := '1228'H;
Harald Welte0d198612017-11-18 19:58:31 +0100350 var template MgcpResponse rtmpl := tr_MgcpResp_Err("535");
Harald Weltee636afd2017-09-17 16:24:09 +0800351
Harald Welteedc45c12017-11-18 19:15:05 +0100352 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800353
Harald Welteba62c8c2017-11-18 18:26:49 +0100354 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100355 cmd.params[2] := t_MgcpParLocConnOpt("p:111");
Harald Weltee636afd2017-09-17 16:24:09 +0800356 resp := mgcp_transceive_mgw(cmd, rtmpl);
357 setverdict(pass);
358 }
359
360 /* test CRCX with illegal double presence of local connection option */
361 testcase TC_crcx_illegal_double_lco() runs on dummy_CT {
362 var template MgcpCommand cmd;
363 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100364 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100365 var MgcpCallId call_id := '1227'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800366 var template MgcpResponse rtmpl := tr_MgcpResp_Err("524");
367
Harald Welteedc45c12017-11-18 19:15:05 +0100368 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800369
Harald Welteba62c8c2017-11-18 18:26:49 +0100370 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100371 /* p:20 is permitted only once and not twice! */
372 cmd.params[2] := t_MgcpParLocConnOpt("p:20, a:AMR, p:20");
Harald Weltee636afd2017-09-17 16:24:09 +0800373 resp := mgcp_transceive_mgw(cmd, rtmpl);
374 setverdict(pass);
375 }
376
377 /* test valid CRCX with valid SDP */
378 testcase TC_crcx_sdp() runs on dummy_CT {
379 var template MgcpCommand cmd;
380 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100381 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "2@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100382 var MgcpCallId call_id := '1226'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800383
Harald Welteedc45c12017-11-18 19:15:05 +0100384 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800385
Harald Welteba62c8c2017-11-18 18:26:49 +0100386 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800387 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
388 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
389 valueof(ts_SDP_ptime(20)) });
Harald Welte9988d282017-11-18 19:22:00 +0100390 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Philipp Maierdffa6a42018-02-02 11:55:44 +0100391
392 /* clean-up */
393 f_dlcx_ok(ep, call_id);
394
Harald Weltee636afd2017-09-17 16:24:09 +0800395 setverdict(pass);
396 }
397
Philipp Maier5e06cee2018-02-01 18:28:08 +0100398 /* test valid wildcarded CRCX */
399 testcase TC_crcx_wildcarded() runs on dummy_CT {
400 var template MgcpCommand cmd;
401 var MgcpResponse resp;
402 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
403 var MgcpCallId call_id := '1234'H;
404 var MgcpEndpoint ep_assigned;
405 f_init();
406
407 /* create the connection on the MGW */
408 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
409 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
410 extract_conn_id(resp);
411
412 /* extract endpoint name we got assigned by the MGW */
413 var MgcpMessage resp_msg := {
414 response := resp
415 }
416 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned) == false) {
417 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
418 }
419
420 /* clean-up */
421 f_dlcx_ok(ep_assigned, call_id);
422
423 setverdict(pass);
424 }
425
426 /* test valid wildcarded CRCX */
427 testcase TC_crcx_wildcarded_exhaust() runs on dummy_CT {
428 const integer n_endpoints := 32;
429 var integer i;
430 var template MgcpCommand cmd;
431 var MgcpResponse resp;
432 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
433 var MgcpCallId call_id := '1234'H;
434 var MgcpEndpoint ep_assigned[n_endpoints];
435 f_init();
436
437 /* Exhaust all endpoint resources on the virtual trunk */
438 for (i := 0; i < n_endpoints; i := i+1) {
439 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
440 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
441
442 /* Make sure we got a connection id */
443 extract_conn_id(resp);
444
445 var MgcpMessage resp_msg := {
446 response := resp
447 }
448 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned[i]) == false) {
449 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
450 }
451 }
452
453 /* Try to allocate one more endpoint, which should fail */
454 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
455 var template MgcpResponse rtmpl := tr_MgcpResp_Err("403");
456 resp := mgcp_transceive_mgw(cmd, rtmpl);
457 setverdict(pass);
458
459 /* clean-up */
460 for (i := 0; i < n_endpoints; i := i+1) {
461 f_dlcx_ok(ep_assigned[i], call_id);
462 }
463 setverdict(pass);
464 }
465
Harald Weltee636afd2017-09-17 16:24:09 +0800466 /* TODO: various SDP related bits */
467
468
469 /* TODO: CRCX with X-Osmux */
470 /* TODO: double CRCX without force_realloc */
471
472 /* TODO: MDCX (various) */
473
474 /* TODO: MDCX without CRCX first */
475 testcase TC_mdcx_without_crcx() runs on dummy_CT {
476 var template MgcpCommand cmd;
477 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100478 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "3@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100479 var MgcpCallId call_id := '1225'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800480 var template MgcpResponse rtmpl := {
481 line := {
482 /* TODO: accept/enforce better error? */
483 code := "400",
484 string := ?
485 },
486 params:= { },
487 sdp := omit
488 };
489
Harald Welteedc45c12017-11-18 19:15:05 +0100490 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800491
Harald Welte2bcfd3a2017-11-18 22:14:35 +0100492 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800493 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
494 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
495 valueof(ts_SDP_ptime(20)) });
496 resp := mgcp_transceive_mgw(cmd, rtmpl);
497 setverdict(pass);
498 }
499
500 /* DLCX without CRCX first */
501 testcase TC_dlcx_without_crcx() runs on dummy_CT {
502 var template MgcpCommand cmd;
503 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100504 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "4@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800505 var template MgcpResponse rtmpl := {
506 line := {
Harald Weltef91edf32017-12-28 14:16:21 +0100507 code := ("400", "515"),
Harald Weltee636afd2017-09-17 16:24:09 +0800508 string := ?
509 },
510 params:= { },
511 sdp := omit
512 };
513
Harald Welteedc45c12017-11-18 19:15:05 +0100514 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800515
Harald Welteedc45c12017-11-18 19:15:05 +0100516 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800517 resp := mgcp_transceive_mgw(cmd, rtmpl);
518 setverdict(pass);
519 }
520
Harald Welte79181ff2017-11-18 19:26:11 +0100521 /* Test (valid) CRCX followed by (valid) DLCX containig EP+CallId+ConnId */
522 testcase TC_crcx_and_dlcx_ep_callid_connid() runs on dummy_CT {
523 var template MgcpCommand cmd;
524 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100525 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte79181ff2017-11-18 19:26:11 +0100526 var MgcpCallId call_id := '51234'H;
527
528 f_init(ep);
529
530 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
531 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
532
533 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
534
535 setverdict(pass);
536 }
537
Harald Welte646ecdb2017-12-28 03:21:57 +0100538 function f_crcx_and_dlcx_ep_callid_connid(MgcpEndpoint ep, MgcpCallId call_id) runs on dummy_CT {
539 var template MgcpCommand cmd;
540 var MgcpResponse resp;
541
542 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
543 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
544
545 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
546
547 setverdict(pass);
548 }
549
550 testcase TC_crcx_dlcx_30ep() runs on dummy_CT {
551 var MgcpEndpoint ep;
552 var MgcpCallId call_id;
553 var integer ep_nr;
554
555 f_init();
556
557 for (ep_nr := 1; ep_nr < 30; ep_nr := ep_nr+1) {
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100558 ep := c_mgw_ep_rtpbridge & hex2str(int2hex(ep_nr, 2)) & "@" & c_mgw_domain;
Harald Welte646ecdb2017-12-28 03:21:57 +0100559 call_id := int2hex(ep_nr, 2) & '1234'H;
560 f_crcx_and_dlcx_ep_callid_connid(ep, call_id);
561 }
562 }
563
Harald Welte79181ff2017-11-18 19:26:11 +0100564 /* Test (valid) CRCX followed by (valid) DLCX containing EP+CallId */
565 testcase TC_crcx_and_dlcx_ep_callid() runs on dummy_CT {
Harald Welte5b4c44e2017-09-17 16:35:27 +0800566 var template MgcpCommand cmd;
567 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100568 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100569 var MgcpCallId call_id := '51233'H;
Harald Welte5b4c44e2017-09-17 16:35:27 +0800570
Harald Welteedc45c12017-11-18 19:15:05 +0100571 f_init(ep);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800572
Harald Welteba62c8c2017-11-18 18:26:49 +0100573 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100574 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800575
Harald Welteba62c8c2017-11-18 18:26:49 +0100576 f_dlcx_ok(ep, call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800577
578 setverdict(pass);
579 }
580
Harald Welte79181ff2017-11-18 19:26:11 +0100581 /* Test (valid) CRCX followed by (valid) DLCX containing EP */
582 testcase TC_crcx_and_dlcx_ep() runs on dummy_CT {
583 var template MgcpCommand cmd;
584 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100585 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100586 var MgcpCallId call_id := '51232'H;
Harald Welte79181ff2017-11-18 19:26:11 +0100587
588 f_init(ep);
589
590 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
591 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
592
593 f_dlcx_ok(ep);
594
595 setverdict(pass);
596 }
597
598
Harald Welte6d167f82017-11-18 19:41:35 +0100599 /* CRCX + DLCX of valid endpoint but invalid call-id */
600 testcase TC_crcx_and_dlcx_ep_callid_inval() runs on dummy_CT {
601 var template MgcpCommand cmd;
602 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100603 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100604 var MgcpCallId call_id := '51231'H;
605
606 f_init(ep);
607
608 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
609 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
610
611 f_dlcx(ep, "516", *, 'ffff'H);
612
613 setverdict(pass);
614 }
615
616
617 /* CRCX + DLCX of valid endpoint and call-id but invalid conn-id */
618 testcase TC_crcx_and_dlcx_ep_callid_connid_inval() runs on dummy_CT {
619 var template MgcpCommand cmd;
620 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100621 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100622 var MgcpCallId call_id := '51230'H;
623
624 f_init(ep);
625
626 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
627 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
628
629 f_dlcx(ep, "515", *, call_id, 'ffff'H);
630
631 setverdict(pass);
632 }
633
634
Harald Weltee636afd2017-09-17 16:24:09 +0800635 /* TODO: Double-DLCX (retransmission) */
Harald Weltef53f1642017-11-18 19:57:11 +0100636 testcase TC_crcx_and_dlcx_retrans() runs on dummy_CT {
637 var template MgcpCommand cmd;
638 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100639 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Weltef53f1642017-11-18 19:57:11 +0100640 var MgcpCallId call_id := '51229'H;
641 var template MgcpResponse rtmpl := {
642 line := {
643 code := "200",
644 string := "OK"
645 },
646 params:= { },
647 sdp := omit
648 };
649
650 f_init(ep);
651
652 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
653 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
654
655 cmd := ts_DLCX(get_next_trans_id(), ep, call_id);
656 resp := mgcp_transceive_mgw(cmd, rtmpl);
657 resp := mgcp_transceive_mgw(cmd, rtmpl);
658
659 setverdict(pass);
660 }
661
662
663
Harald Weltee636afd2017-09-17 16:24:09 +0800664 /* TODO: Double-DLCX (no retransmission) */
665
666
667
668 /* TODO: AUEP (various) */
669 /* TODO: RSIP (various) */
670 /* TODO: RQNT (various) */
671 /* TODO: EPCF (various) */
672 /* TODO: AUCX (various) */
673 /* TODO: invalid verb (various) */
674
Harald Welte00a067f2017-09-13 23:27:17 +0200675 control {
676 execute(TC_selftest());
Harald Welte3c6ebb92017-09-16 00:56:57 +0800677 execute(TC_crcx());
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100678 execute(TC_crcx_noprefix());
Harald Weltee636afd2017-09-17 16:24:09 +0800679 execute(TC_crcx_unsupp_mode());
680 execute(TC_crcx_early_bidir_mode());
681 execute(TC_crcx_unsupp_param());
682 execute(TC_crcx_missing_callid());
683 execute(TC_crcx_missing_mode());
684 execute(TC_crcx_unsupp_packet_intv());
685 execute(TC_crcx_illegal_double_lco());
686 execute(TC_crcx_sdp());
Philipp Maier5e06cee2018-02-01 18:28:08 +0100687 execute(TC_crcx_wildcarded());
688 execute(TC_crcx_wildcarded_exhaust());
Harald Weltee636afd2017-09-17 16:24:09 +0800689 execute(TC_mdcx_without_crcx());
690 execute(TC_dlcx_without_crcx());
Harald Welte79181ff2017-11-18 19:26:11 +0100691 execute(TC_crcx_and_dlcx_ep_callid_connid());
692 execute(TC_crcx_and_dlcx_ep_callid());
693 execute(TC_crcx_and_dlcx_ep());
Harald Welte6d167f82017-11-18 19:41:35 +0100694 execute(TC_crcx_and_dlcx_ep_callid_inval());
695 execute(TC_crcx_and_dlcx_ep_callid_connid_inval());
Harald Weltef53f1642017-11-18 19:57:11 +0100696 execute(TC_crcx_and_dlcx_retrans());
Harald Welte33d82162017-12-28 03:21:57 +0100697
698 execute(TC_crcx_dlcx_30ep());
Harald Welte00a067f2017-09-13 23:27:17 +0200699 }
700}