blob: 55559cd2c92fa4a0f9f8369767d59f5637b06b80 [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);
Harald Weltee636afd2017-09-17 16:24:09 +0800391 setverdict(pass);
392 }
393
Philipp Maier5e06cee2018-02-01 18:28:08 +0100394 /* test valid wildcarded CRCX */
395 testcase TC_crcx_wildcarded() runs on dummy_CT {
396 var template MgcpCommand cmd;
397 var MgcpResponse resp;
398 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
399 var MgcpCallId call_id := '1234'H;
400 var MgcpEndpoint ep_assigned;
401 f_init();
402
403 /* create the connection on the MGW */
404 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
405 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
406 extract_conn_id(resp);
407
408 /* extract endpoint name we got assigned by the MGW */
409 var MgcpMessage resp_msg := {
410 response := resp
411 }
412 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned) == false) {
413 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
414 }
415
416 /* clean-up */
417 f_dlcx_ok(ep_assigned, call_id);
418
419 setverdict(pass);
420 }
421
422 /* test valid wildcarded CRCX */
423 testcase TC_crcx_wildcarded_exhaust() runs on dummy_CT {
424 const integer n_endpoints := 32;
425 var integer i;
426 var template MgcpCommand cmd;
427 var MgcpResponse resp;
428 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "*@" & c_mgw_domain;
429 var MgcpCallId call_id := '1234'H;
430 var MgcpEndpoint ep_assigned[n_endpoints];
431 f_init();
432
433 /* Exhaust all endpoint resources on the virtual trunk */
434 for (i := 0; i < n_endpoints; i := i+1) {
435 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
436 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
437
438 /* Make sure we got a connection id */
439 extract_conn_id(resp);
440
441 var MgcpMessage resp_msg := {
442 response := resp
443 }
444 if (f_mgcp_find_param(resp_msg, "Z", ep_assigned[i]) == false) {
445 setverdict(fail, "No SpecificEndpointName in MGCP response", resp);
446 }
447 }
448
449 /* Try to allocate one more endpoint, which should fail */
450 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
451 var template MgcpResponse rtmpl := tr_MgcpResp_Err("403");
452 resp := mgcp_transceive_mgw(cmd, rtmpl);
453 setverdict(pass);
454
455 /* clean-up */
456 for (i := 0; i < n_endpoints; i := i+1) {
457 f_dlcx_ok(ep_assigned[i], call_id);
458 }
459 setverdict(pass);
460 }
461
Harald Weltee636afd2017-09-17 16:24:09 +0800462 /* TODO: various SDP related bits */
463
464
465 /* TODO: CRCX with X-Osmux */
466 /* TODO: double CRCX without force_realloc */
467
468 /* TODO: MDCX (various) */
469
470 /* TODO: MDCX without CRCX first */
471 testcase TC_mdcx_without_crcx() 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 & "3@" & c_mgw_domain;
Harald Welteba62c8c2017-11-18 18:26:49 +0100475 var MgcpCallId call_id := '1225'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800476 var template MgcpResponse rtmpl := {
477 line := {
478 /* TODO: accept/enforce better error? */
479 code := "400",
480 string := ?
481 },
482 params:= { },
483 sdp := omit
484 };
485
Harald Welteedc45c12017-11-18 19:15:05 +0100486 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800487
Harald Welte2bcfd3a2017-11-18 22:14:35 +0100488 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800489 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
490 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
491 valueof(ts_SDP_ptime(20)) });
492 resp := mgcp_transceive_mgw(cmd, rtmpl);
493 setverdict(pass);
494 }
495
496 /* DLCX without CRCX first */
497 testcase TC_dlcx_without_crcx() runs on dummy_CT {
498 var template MgcpCommand cmd;
499 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100500 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "4@" & c_mgw_domain;
Harald Weltee636afd2017-09-17 16:24:09 +0800501 var template MgcpResponse rtmpl := {
502 line := {
Harald Weltef91edf32017-12-28 14:16:21 +0100503 code := ("400", "515"),
Harald Weltee636afd2017-09-17 16:24:09 +0800504 string := ?
505 },
506 params:= { },
507 sdp := omit
508 };
509
Harald Welteedc45c12017-11-18 19:15:05 +0100510 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800511
Harald Welteedc45c12017-11-18 19:15:05 +0100512 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800513 resp := mgcp_transceive_mgw(cmd, rtmpl);
514 setverdict(pass);
515 }
516
Harald Welte79181ff2017-11-18 19:26:11 +0100517 /* Test (valid) CRCX followed by (valid) DLCX containig EP+CallId+ConnId */
518 testcase TC_crcx_and_dlcx_ep_callid_connid() runs on dummy_CT {
519 var template MgcpCommand cmd;
520 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100521 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte79181ff2017-11-18 19:26:11 +0100522 var MgcpCallId call_id := '51234'H;
523
524 f_init(ep);
525
526 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
527 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
528
529 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
530
531 setverdict(pass);
532 }
533
Harald Welte646ecdb2017-12-28 03:21:57 +0100534 function f_crcx_and_dlcx_ep_callid_connid(MgcpEndpoint ep, MgcpCallId call_id) runs on dummy_CT {
535 var template MgcpCommand cmd;
536 var MgcpResponse resp;
537
538 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
539 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
540
541 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
542
543 setverdict(pass);
544 }
545
546 testcase TC_crcx_dlcx_30ep() runs on dummy_CT {
547 var MgcpEndpoint ep;
548 var MgcpCallId call_id;
549 var integer ep_nr;
550
551 f_init();
552
553 for (ep_nr := 1; ep_nr < 30; ep_nr := ep_nr+1) {
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100554 ep := c_mgw_ep_rtpbridge & hex2str(int2hex(ep_nr, 2)) & "@" & c_mgw_domain;
Harald Welte646ecdb2017-12-28 03:21:57 +0100555 call_id := int2hex(ep_nr, 2) & '1234'H;
556 f_crcx_and_dlcx_ep_callid_connid(ep, call_id);
557 }
558 }
559
Harald Welte79181ff2017-11-18 19:26:11 +0100560 /* Test (valid) CRCX followed by (valid) DLCX containing EP+CallId */
561 testcase TC_crcx_and_dlcx_ep_callid() runs on dummy_CT {
Harald Welte5b4c44e2017-09-17 16:35:27 +0800562 var template MgcpCommand cmd;
563 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100564 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100565 var MgcpCallId call_id := '51233'H;
Harald Welte5b4c44e2017-09-17 16:35:27 +0800566
Harald Welteedc45c12017-11-18 19:15:05 +0100567 f_init(ep);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800568
Harald Welteba62c8c2017-11-18 18:26:49 +0100569 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100570 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800571
Harald Welteba62c8c2017-11-18 18:26:49 +0100572 f_dlcx_ok(ep, call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800573
574 setverdict(pass);
575 }
576
Harald Welte79181ff2017-11-18 19:26:11 +0100577 /* Test (valid) CRCX followed by (valid) DLCX containing EP */
578 testcase TC_crcx_and_dlcx_ep() runs on dummy_CT {
579 var template MgcpCommand cmd;
580 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100581 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100582 var MgcpCallId call_id := '51232'H;
Harald Welte79181ff2017-11-18 19:26:11 +0100583
584 f_init(ep);
585
586 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
587 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
588
589 f_dlcx_ok(ep);
590
591 setverdict(pass);
592 }
593
594
Harald Welte6d167f82017-11-18 19:41:35 +0100595 /* CRCX + DLCX of valid endpoint but invalid call-id */
596 testcase TC_crcx_and_dlcx_ep_callid_inval() runs on dummy_CT {
597 var template MgcpCommand cmd;
598 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100599 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100600 var MgcpCallId call_id := '51231'H;
601
602 f_init(ep);
603
604 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
605 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
606
607 f_dlcx(ep, "516", *, 'ffff'H);
608
609 setverdict(pass);
610 }
611
612
613 /* CRCX + DLCX of valid endpoint and call-id but invalid conn-id */
614 testcase TC_crcx_and_dlcx_ep_callid_connid_inval() runs on dummy_CT {
615 var template MgcpCommand cmd;
616 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100617 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Welte6d167f82017-11-18 19:41:35 +0100618 var MgcpCallId call_id := '51230'H;
619
620 f_init(ep);
621
622 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
623 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
624
625 f_dlcx(ep, "515", *, call_id, 'ffff'H);
626
627 setverdict(pass);
628 }
629
630
Harald Weltee636afd2017-09-17 16:24:09 +0800631 /* TODO: Double-DLCX (retransmission) */
Harald Weltef53f1642017-11-18 19:57:11 +0100632 testcase TC_crcx_and_dlcx_retrans() runs on dummy_CT {
633 var template MgcpCommand cmd;
634 var MgcpResponse resp;
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100635 var MgcpEndpoint ep := c_mgw_ep_rtpbridge & "5@" & c_mgw_domain;
Harald Weltef53f1642017-11-18 19:57:11 +0100636 var MgcpCallId call_id := '51229'H;
637 var template MgcpResponse rtmpl := {
638 line := {
639 code := "200",
640 string := "OK"
641 },
642 params:= { },
643 sdp := omit
644 };
645
646 f_init(ep);
647
648 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
649 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
650
651 cmd := ts_DLCX(get_next_trans_id(), ep, call_id);
652 resp := mgcp_transceive_mgw(cmd, rtmpl);
653 resp := mgcp_transceive_mgw(cmd, rtmpl);
654
655 setverdict(pass);
656 }
657
658
659
Harald Weltee636afd2017-09-17 16:24:09 +0800660 /* TODO: Double-DLCX (no retransmission) */
661
662
663
664 /* TODO: AUEP (various) */
665 /* TODO: RSIP (various) */
666 /* TODO: RQNT (various) */
667 /* TODO: EPCF (various) */
668 /* TODO: AUCX (various) */
669 /* TODO: invalid verb (various) */
670
Harald Welte00a067f2017-09-13 23:27:17 +0200671 control {
672 execute(TC_selftest());
Harald Welte3c6ebb92017-09-16 00:56:57 +0800673 execute(TC_crcx());
Philipp Maierbb7a01c2018-02-01 12:32:57 +0100674 execute(TC_crcx_noprefix());
Harald Weltee636afd2017-09-17 16:24:09 +0800675 execute(TC_crcx_unsupp_mode());
676 execute(TC_crcx_early_bidir_mode());
677 execute(TC_crcx_unsupp_param());
678 execute(TC_crcx_missing_callid());
679 execute(TC_crcx_missing_mode());
680 execute(TC_crcx_unsupp_packet_intv());
681 execute(TC_crcx_illegal_double_lco());
682 execute(TC_crcx_sdp());
Philipp Maier5e06cee2018-02-01 18:28:08 +0100683 execute(TC_crcx_wildcarded());
684 execute(TC_crcx_wildcarded_exhaust());
Harald Weltee636afd2017-09-17 16:24:09 +0800685 execute(TC_mdcx_without_crcx());
686 execute(TC_dlcx_without_crcx());
Harald Welte79181ff2017-11-18 19:26:11 +0100687 execute(TC_crcx_and_dlcx_ep_callid_connid());
688 execute(TC_crcx_and_dlcx_ep_callid());
689 execute(TC_crcx_and_dlcx_ep());
Harald Welte6d167f82017-11-18 19:41:35 +0100690 execute(TC_crcx_and_dlcx_ep_callid_inval());
691 execute(TC_crcx_and_dlcx_ep_callid_connid_inval());
Harald Weltef53f1642017-11-18 19:57:11 +0100692 execute(TC_crcx_and_dlcx_retrans());
Harald Welte33d82162017-12-28 03:21:57 +0100693
694 execute(TC_crcx_dlcx_30ep());
Harald Welte00a067f2017-09-13 23:27:17 +0200695 }
696}