blob: e6e03505a6f4a6e547a3b4dfac3f1a42f9a022bf [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 Welte3c6ebb92017-09-16 00:56:57 +08004 import from SDP_Types all;
5 import from MGCP_CodecPort all;
6 import from MGCP_CodecPort_CtrlFunct all;
Harald Weltef07c2862017-11-18 17:16:24 +01007 import from RTP_CodecPort all;
8 import from RTP_CodecPort_CtrlFunct all;
9 import from RTP_Endpoint all;
Harald Welte3c6ebb92017-09-16 00:56:57 +080010 import from IPL4asp_Types all;
Harald Welte00a067f2017-09-13 23:27:17 +020011
Harald Welte21ba5572017-09-19 17:55:05 +080012 /* any variables declared in the component will be available to
13 * all functions that 'run on' the named component, similar to
14 * class members in C++ */
Harald Welte00a067f2017-09-13 23:27:17 +020015 type component dummy_CT {
Harald Welte3c6ebb92017-09-16 00:56:57 +080016 port MGCP_CODEC_PT MGCP;
Harald Weltef07c2862017-11-18 17:16:24 +010017 port RTP_CODEC_PT RTP;
Harald Welte3c6ebb92017-09-16 00:56:57 +080018 var boolean initialized := false;
Harald Welte55015362017-11-18 16:02:42 +010019 var ConnectionId g_mgcp_conn_id := -1;
Harald Weltee1e18c52017-09-17 16:23:07 +080020 var integer g_trans_id;
Harald Weltef07c2862017-11-18 17:16:24 +010021
22 var RtpEndpoint g_rtp_ep[2];
Harald Welte00a067f2017-09-13 23:27:17 +020023 };
24
Harald Weltee1e18c52017-09-17 16:23:07 +080025 function get_next_trans_id() runs on dummy_CT return MgcpTransId {
26 var MgcpTransId tid := int2str(g_trans_id);
27 g_trans_id := g_trans_id + 1;
28 return tid;
29 }
30
Harald Welte21ba5572017-09-19 17:55:05 +080031 /* all parameters declared here can be modified / overridden by
32 * the config file in the [MODULE_PARAMETERS] section. If no
33 * config file is used or the file doesn't specify them, the
34 * default values assigned below are used */
Harald Welte3c6ebb92017-09-16 00:56:57 +080035 modulepar {
36 PortNumber mp_local_udp_port := 2727;
37 charstring mp_local_ip := "127.0.0.1";
38 PortNumber mp_remote_udp_port := 2427;
39 charstring mp_remote_ip := "127.0.0.1";
Harald Weltef07c2862017-11-18 17:16:24 +010040 PortNumber mp_local_rtp_port_base := 10000;
Harald Welte3c6ebb92017-09-16 00:56:57 +080041 }
42
Harald Welte21ba5572017-09-19 17:55:05 +080043 /* initialization function, called by each test case at the
44 * beginning, but 'initialized' variable ensures its body is
45 * only executed once */
Harald Welteedc45c12017-11-18 19:15:05 +010046 private function f_init(template MgcpEndpoint ep := omit) runs on dummy_CT {
Harald Welte3c6ebb92017-09-16 00:56:57 +080047 var Result res;
Harald Weltef07c2862017-11-18 17:16:24 +010048 var uint32_t ssrc;
Harald Welteedc45c12017-11-18 19:15:05 +010049 if (initialized == false) {
50 initialized := true;
51
52 /* some random number for the initial transaction id */
53 g_trans_id := float2int(rnd()*65535.0);
54 map(self:MGCP, system:MGCP_CODEC_PT);
55 /* connect the MGCP test port using the given
56 * source/destionation ip/port and store the connection id in g_mgcp_conn_id
57 * */
58 res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, mp_remote_ip, mp_remote_udp_port, mp_local_ip, mp_local_udp_port, 0, { udp := {} });
59 g_mgcp_conn_id := res.connId;
60
61 map(self:RTP, system:RTP_CODEC_PT);
62 ssrc := float2int(rnd()*4294967296.0);
63 rtp_endpoint_init(g_rtp_ep[0], mp_local_ip, mp_local_rtp_port_base, ssrc);
64 rtp_endpoint_bind(RTP, g_rtp_ep[0]);
65 rtp_endpoint_init(g_rtp_ep[1], mp_local_ip, mp_local_rtp_port_base+2, ssrc);
66 rtp_endpoint_bind(RTP, g_rtp_ep[1]);
Harald Welte3c6ebb92017-09-16 00:56:57 +080067 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080068
Harald Welteedc45c12017-11-18 19:15:05 +010069 if (isvalue(ep)) {
70 /* do a DLCX on all connections of the EP */
71 f_dlcx_ignore(valueof(ep));
72 }
Harald Welte3c6ebb92017-09-16 00:56:57 +080073 }
74
75 /* 3.2.2.6 Connection Mode (sendonly, recvonly, sendrecv, confrnce, inactive, loopback,
76 * conttest, netwloop, netwtest) */
77 template MgcpParameter t_MgcpParConnMode(template MgcpConnectionMode mode) := { "M", mode };
78
79 /* 3.2.2.2 CallId: maximum 32 hex chars */
80 template MgcpParameter ts_MgcpParCallId(MgcpCallId cid) := {
81 code := "C",
82 val := hex2str(cid)
83 };
84
85 /* 3.2.2.18 RequestIdentifier: Maximum 32 hex chars */
86 template MgcpParameter ts_MgcpParReqId(MgcpRequestId rid) := {
87 code := "X",
88 val := hex2str(rid)
89 };
90
91 /* 3.2.2.10: LocalConnectionOptions (codec, packetization, bandwidth, ToS, eco, gain, silence, ...) */
92 template MgcpParameter t_MgcpParLocConnOpt(template charstring lco) := { "L", lco };
93
94 /* 3.2.2.5: ConnectionId: maximum 32 hex chars */
95 template MgcpParameter ts_MgcpParConnectionId(MgcpConnectionId cid) := {
96 code := "I",
97 val := hex2str(cid)
98 };
99
100 /* osmo-bsc_mgcp implements L/C/M/X only, osmo-mgw adds 'I' */
101 /* SDP: osmo-bsc_mgcp implements Tx of v,o,s,c,t,m,a */
102
Harald Weltee636afd2017-09-17 16:24:09 +0800103 template MgcpResponse tr_MgcpResp_Err(template MgcpResponseCode code) := {
104 line := {
105 code := code,
106 trans_id := ?,
107 string := ?
108 },
109 params := {},
110 sdp := omit
111 }
112
Harald Welte3c6ebb92017-09-16 00:56:57 +0800113 template MgcpCommandLine t_MgcpCmdLine(template charstring verb, template MgcpTransId trans_id, template charstring ep) := {
114 verb := verb,
115 trans_id := trans_id,
116 ep := ep,
117 ver := "1.0"
118 };
119
120 template MgcpCommand ts_CRCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
121 line := t_MgcpCmdLine("CRCX", trans_id, ep),
122 params := {
123 t_MgcpParConnMode(mode),
124 ts_MgcpParCallId(call_id),
125 //t_MgcpParReqId(omit),
126 t_MgcpParLocConnOpt("p: 20")
127 },
128 sdp := sdp
129 }
130
Harald Weltee636afd2017-09-17 16:24:09 +0800131 template MgcpCommand ts_MDCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
132 line := t_MgcpCmdLine("MDCX", trans_id, ep),
133 params := {
134 t_MgcpParConnMode(mode),
135 ts_MgcpParCallId(call_id),
136 //t_MgcpParReqId(omit),
137 t_MgcpParLocConnOpt("p: 20")
138 },
139 sdp := sdp
140 }
141
Harald Weltec40e0c32017-11-18 19:08:22 +0100142 /* have a function that generates a template, rather than a template in order to handle
143 * optional parameters */
144 function ts_DLCX(MgcpTransId trans_id, charstring ep, template MgcpCallId call_id := omit,
145 template MgcpConnectionId conn_id := omit) return template MgcpCommand {
146 var template MgcpCommand cmd;
147 cmd.line := t_MgcpCmdLine("DLCX", trans_id, ep);
148 cmd.params := {};
149 cmd.sdp := omit;
150 if (isvalue(call_id)) {
151 f_mgcp_par_append(cmd.params, ts_MgcpParCallId(valueof(call_id)));
152 if (isvalue(conn_id)) {
153 f_mgcp_par_append(cmd.params, ts_MgcpParConnectionId(valueof(conn_id)));
154 }
155 }
156 return cmd;
Harald Weltee636afd2017-09-17 16:24:09 +0800157 }
158
159 /* SDP Templates */
160 template SDP_Origin ts_SDP_origin(charstring addr, charstring session_id,
161 charstring session_version := "1",
162 charstring addr_type := "IP4",
163 charstring user_name := "-") := {
164 user_name := user_name,
165 session_id := session_id,
166 session_version := session_version,
167 net_type := "IN",
168 addr_type := addr_type,
169 addr := addr
170 }
171
172 template SDP_connection ts_SDP_connection_IP(charstring addr, charstring addr_type := "IP4",
173 template integer ttl := omit,
174 template integer num_of_addr := omit) :={
175 net_type := "IN",
176 addr_type := addr_type,
177 conn_addr := {
178 addr := addr,
179 ttl := ttl,
180 num_of_addr := num_of_addr
181 }
182 }
183
184 template SDP_time ts_SDP_time(charstring beg, charstring end) := {
185 time_field := {
186 start_time := beg,
187 stop_time := end
188 },
189 time_repeat := omit
190 }
191
192 template SDP_media_desc ts_SDP_media_desc(integer port_number, SDP_fmt_list fmts,
193 SDP_attribute_list attributes) := {
194 media_field := {
195 media := "audio",
196 ports := {
197 port_number := port_number,
198 num_of_ports := omit
199 },
200 transport := "ARTP/AVP",
201 fmts := fmts
202 },
203 information := omit,
204 connections := omit,
205 bandwidth := omit,
206 key := omit,
207 attributes := attributes
208 }
209
Harald Welte21ba5572017-09-19 17:55:05 +0800210 /* master template for generating SDP based in template arguments */
Harald Weltee636afd2017-09-17 16:24:09 +0800211 template SDP_Message ts_SDP(charstring local_addr, charstring remote_addr,
212 charstring session_id, charstring session_version,
213 integer rtp_port, SDP_fmt_list fmts,
214 SDP_attribute_list attributes) := {
215 protocol_version := 0,
216 origin := ts_SDP_origin(local_addr, session_id, session_version),
217 session_name := "-",
218 information := omit,
219 uri := omit,
220 emails := omit,
221 phone_numbers := omit,
222 connection := ts_SDP_connection_IP(remote_addr),
223 bandwidth := omit,
224 times := { ts_SDP_time("0","0") },
225 timezone_adjustments := omit,
226 key := omit,
227 attributes := omit,
228 media_list := { ts_SDP_media_desc(rtp_port, fmts, attributes) }
229 }
230
231 template SDP_attribute ts_SDP_rtpmap(integer fmt, charstring val) := {
232 rtpmap := {
233 attr_value := int2str(fmt) & " " & val
234 }
235 }
236 template SDP_attribute ts_SDP_ptime(integer p) := {
237 ptime := {
238 attr_value := int2str(p)
239 }
240 }
241
Harald Welte00a067f2017-09-13 23:27:17 +0200242 testcase TC_selftest() runs on dummy_CT {
243 const charstring c_auep := "AUEP 158663169 ds/e1-1/2@172.16.6.66 MGCP 1.0\r\n";
244 const charstring c_mdcx3 := "MDCX 18983215 1@mgw MGCP 1.0\r\n";
245 const charstring c_mdcx3_ret := "200 18983215 OK\r\n" &
246 "I: 1\n" &
247 "\n" &
248 "v=0\r\n" &
249 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
250 "s=-\r\n" &
251 "c=IN IP4 0.0.0.0\r\n" &
252 "t=0 0\r\n" &
253 "m=audio 0 RTP/AVP 126\r\n" &
254 "a=rtpmap:126 AMR/8000\r\n" &
255 "a=ptime:20\r\n";
256 const charstring c_mdcx4 := "MDCX 18983216 1@mgw MGCP 1.0\r\n" &
257 "M: sendrecv\r" &
258 "C: 2\r\n" &
259 "I: 1\r\n" &
260 "L: p:20, a:AMR, nt:IN\r\n" &
261 "\n" &
262 "v=0\r\n" &
263 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
Harald Welte2871d0b2017-09-14 22:42:12 +0800264 "s=-\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200265 "c=IN IP4 0.0.0.0\r\n" &
266 "t=0 0\r\n" &
267 "m=audio 4441 RTP/AVP 99\r\n" &
268 "a=rtpmap:99 AMR/8000\r\n" &
269 "a=ptime:40\r\n";
Harald Welte3c6ebb92017-09-16 00:56:57 +0800270 const charstring c_crcx510_ret := "510 23 FAIL\r\n"
Harald Welte00a067f2017-09-13 23:27:17 +0200271
272 log(c_auep);
273 log(dec_MgcpCommand(c_auep));
274
275 log(c_mdcx3);
276 log(dec_MgcpCommand(c_mdcx3));
277
278 log(c_mdcx3_ret);
279 log(dec_MgcpResponse(c_mdcx3_ret));
280
281 log(c_mdcx4);
282 log(dec_MgcpCommand(c_mdcx4));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800283
284 log(ts_CRCX("23", "42@mgw", "sendrecv", '1234'H));
285 log(enc_MgcpCommand(valueof(ts_CRCX("23", "42@mgw", "sendrecv", '1234'H))));
286
287 log(c_crcx510_ret);
288 log(dec_MgcpResponse(c_crcx510_ret));
289 log(dec_MgcpMessage(c_crcx510_ret));
290 }
291
Harald Weltee636afd2017-09-17 16:24:09 +0800292 /* CRCX test ideas:
293 * - without mandatory CallId
294 * - without mandatory ConnectionId
295 * - with forbidden parameters (e.g. Capabilities, PackageList, ...
296 * - CRCX with remote session description and without
297 *
298 * general ideas:
299 * - packetization != 20ms
300 * - invalid mode
301 * x unsupported mode (517)
302 * x bidirectional mode before RemoteConnDesc: 527
303 * - invalid codec
304 * - retransmission of same transaction
305 * - unsupported LocalConnectionOptions ("b", "a", "e", "gc", "s", "r", "k", ..)
306 */
307
Harald Welte21ba5572017-09-19 17:55:05 +0800308 /* build a receive template for receiving a MGCP message. You
309 * pass the MGCP response template in, and it will generate an
310 * MGCP_RecvFrom template that can match the primitives arriving on the
311 * MGCP_CodecPort */
Harald Weltee636afd2017-09-17 16:24:09 +0800312 function tr_MGCP_RecvFrom_R(template MgcpResponse resp) runs on dummy_CT return template MGCP_RecvFrom {
313 var template MGCP_RecvFrom mrf := {
Harald Welte55015362017-11-18 16:02:42 +0100314 connId := g_mgcp_conn_id,
Harald Weltee636afd2017-09-17 16:24:09 +0800315 remName := mp_remote_ip,
316 remPort := mp_remote_udp_port,
317 locName := mp_local_ip,
318 locPort := mp_local_udp_port,
319 msg := { response := resp }
320 }
321 return mrf;
322 }
323
324 /* Send a MGCP request + receive a (matching!) response */
325 function mgcp_transceive_mgw(template MgcpCommand cmd, template MgcpResponse resp := ?) runs on dummy_CT return MgcpResponse {
326 var MgcpMessage msg := { command := valueof(cmd) };
327 resp.line.trans_id := cmd.line.trans_id;
328 var template MGCP_RecvFrom mrt := tr_MGCP_RecvFrom_R(resp);
Harald Welte3c6ebb92017-09-16 00:56:57 +0800329 var MGCP_RecvFrom mrf;
330 timer T := 5.0;
331
Harald Welte55015362017-11-18 16:02:42 +0100332 MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800333 T.start;
334 alt {
Harald Weltee636afd2017-09-17 16:24:09 +0800335 [] MGCP.receive(mrt) -> value mrf { }
336 [] MGCP.receive(tr_MGCP_RecvFrom_R(?)) { setverdict(fail); }
Harald Welte3c6ebb92017-09-16 00:56:57 +0800337 [] MGCP.receive { repeat; }
338 [] T.timeout { setverdict(fail); }
339 }
340 T.stop;
Harald Weltee636afd2017-09-17 16:24:09 +0800341
342 if (isbound(mrf) and isbound(mrf.msg) and ischosen(mrf.msg.response)) {
343 return mrf.msg.response;
344 } else {
345 var MgcpResponse r := { line := { code := "999", trans_id := valueof(cmd.line.trans_id) } };
346 return r;
347 }
Harald Welte00a067f2017-09-13 23:27:17 +0200348 }
349
Harald Welteba62c8c2017-11-18 18:26:49 +0100350 function extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
351 var integer i;
352 for (i := 0; i < lengthof(resp.params); i := i + 1) {
353 var MgcpParameter par := resp.params[i];
354 if (par.code == "I") {
355 return str2hex(par.val);
356 }
357 }
358 setverdict(fail);
359 return '00000000'H;
360 }
361
362 /* Send DLCX and expect OK response */
Harald Weltec40e0c32017-11-18 19:08:22 +0100363 function f_dlcx_ok(MgcpEndpoint ep, template MgcpCallId call_id := omit,
Harald Welteba62c8c2017-11-18 18:26:49 +0100364 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
365 var template MgcpCommand cmd;
366 var MgcpResponse resp;
367 var template MgcpResponse rtmpl := {
368 line := {
369 code := "200",
370 string := "OK"
371 },
372 params := *,
373 sdp := *
374 };
Harald Weltec40e0c32017-11-18 19:08:22 +0100375 cmd := ts_DLCX(get_next_trans_id(), ep, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100376 resp := mgcp_transceive_mgw(cmd, rtmpl);
377 }
378
379 /* Send DLCX and accept any response */
Harald Weltec40e0c32017-11-18 19:08:22 +0100380 function f_dlcx_ignore(MgcpEndpoint ep, template MgcpCallId call_id := omit,
Harald Welteba62c8c2017-11-18 18:26:49 +0100381 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
382 var template MgcpCommand cmd;
383 var MgcpResponse resp;
384 var template MgcpResponse rtmpl := {
385 line := {
386 code := ?,
387 string := ?
388 },
389 params := *,
390 sdp := *
391 };
Harald Weltec40e0c32017-11-18 19:08:22 +0100392 cmd := ts_DLCX(get_next_trans_id(), ep, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100393 resp := mgcp_transceive_mgw(cmd, rtmpl);
394 }
395
Harald Weltee636afd2017-09-17 16:24:09 +0800396 /* test valid CRCX without SDP */
397 testcase TC_crcx() runs on dummy_CT {
398 var template MgcpCommand cmd;
399 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100400 var MgcpEndpoint ep := "2@mgw";
401 var MgcpCallId call_id := '1234'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800402 var template MgcpResponse rtmpl := {
403 line := {
404 code := "200",
405 string := "OK"
406 },
Harald Welte6f960b12017-11-17 23:24:46 +0100407 params := { { "I", ? }, *},
Harald Weltee636afd2017-09-17 16:24:09 +0800408 sdp := ?
409 };
410
Harald Welteedc45c12017-11-18 19:15:05 +0100411 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800412
Harald Welteba62c8c2017-11-18 18:26:49 +0100413 /* create the connection on the MGW */
414 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800415 resp := mgcp_transceive_mgw(cmd, rtmpl);
Harald Welteba62c8c2017-11-18 18:26:49 +0100416 extract_conn_id(resp);
417
418 /* clean-up */
419 f_dlcx_ok(ep, call_id);
420
Harald Weltee636afd2017-09-17 16:24:09 +0800421 setverdict(pass);
422 }
423
424 /* test CRCX with unsupported mode, expect 517 */
425 testcase TC_crcx_unsupp_mode() runs on dummy_CT {
426 var template MgcpCommand cmd;
427 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100428 var MgcpEndpoint ep := "2@mgw";
429 var MgcpCallId call_id := '1233'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800430 var template MgcpResponse rtmpl := tr_MgcpResp_Err("517");
431
Harald Welteedc45c12017-11-18 19:15:05 +0100432 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800433
Harald Welteba62c8c2017-11-18 18:26:49 +0100434 cmd := ts_CRCX(get_next_trans_id(), ep, "netwtest", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800435 resp := mgcp_transceive_mgw(cmd, rtmpl);
436 setverdict(pass);
437 }
438
Harald Welte21ba5572017-09-19 17:55:05 +0800439 /* test CRCX with early bi-directional mode, expect 527 as
440 * bi-diretional media can only be established once both local and
441 * remote side are specified, see MGCP RFC */
Harald Weltee636afd2017-09-17 16:24:09 +0800442 testcase TC_crcx_early_bidir_mode() runs on dummy_CT {
443 var template MgcpCommand cmd;
444 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100445 var MgcpEndpoint ep := "2@mgw";
446 var MgcpCallId call_id := '1232'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800447 var template MgcpResponse rtmpl := tr_MgcpResp_Err("527");
448
Harald Welteedc45c12017-11-18 19:15:05 +0100449 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800450
Harald Welteba62c8c2017-11-18 18:26:49 +0100451 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800452 resp := mgcp_transceive_mgw(cmd, rtmpl);
453 setverdict(pass);
454 }
455
Harald Weltea01e38d2017-11-18 18:40:01 +0100456 function f_mgcp_par_append(inout template MgcpParameterList list, template MgcpParameter par) {
457 var integer len := lengthof(list);
458 list[len] := par;
459 }
460
Harald Weltee636afd2017-09-17 16:24:09 +0800461 /* test CRCX with unsupported Parameters */
462 testcase TC_crcx_unsupp_param() runs on dummy_CT {
463 var template MgcpCommand cmd;
464 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100465 var MgcpEndpoint ep := "2@mgw";
466 var MgcpCallId call_id := '1231'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800467 var template MgcpResponse rtmpl := tr_MgcpResp_Err("539");
468
Harald Welteedc45c12017-11-18 19:15:05 +0100469 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800470
Harald Welteba62c8c2017-11-18 18:26:49 +0100471 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100472 /* osmo-bsc_mgcp/mgw doesn't implement notifications */
473 f_mgcp_par_append(cmd.params, MgcpParameter:{ "N", "foobar" });
474
Harald Weltee636afd2017-09-17 16:24:09 +0800475 resp := mgcp_transceive_mgw(cmd, rtmpl);
476 setverdict(pass);
477 }
478
479 /* test CRCX with missing CallId */
480 testcase TC_crcx_missing_callid() runs on dummy_CT {
481 var template MgcpCommand cmd;
482 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100483 var MgcpEndpoint ep := "2@mgw";
Harald Weltee636afd2017-09-17 16:24:09 +0800484 var template MgcpResponse rtmpl := tr_MgcpResp_Err("400");
485
Harald Welteedc45c12017-11-18 19:15:05 +0100486 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800487
Harald Welteba62c8c2017-11-18 18:26:49 +0100488 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", '1230'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800489 cmd.params := {
490 t_MgcpParConnMode("recvonly"),
491 t_MgcpParLocConnOpt("p:20")
492 }
493 resp := mgcp_transceive_mgw(cmd, rtmpl);
494 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100495
Harald Weltee636afd2017-09-17 16:24:09 +0800496 }
497
498 /* test CRCX with missing Mode */
499 testcase TC_crcx_missing_mode() runs on dummy_CT {
500 var template MgcpCommand cmd;
501 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100502 var MgcpEndpoint ep := "2@mgw";
503 var MgcpCallId call_id := '1229'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800504 var template MgcpResponse rtmpl := tr_MgcpResp_Err("400");
505
Harald Welteedc45c12017-11-18 19:15:05 +0100506 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800507
Harald Welteba62c8c2017-11-18 18:26:49 +0100508 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800509 cmd.params := {
Harald Welteba62c8c2017-11-18 18:26:49 +0100510 ts_MgcpParCallId(call_id),
Harald Weltee636afd2017-09-17 16:24:09 +0800511 t_MgcpParLocConnOpt("p:20")
512 }
513 resp := mgcp_transceive_mgw(cmd, rtmpl);
514 setverdict(pass);
515 }
516
517 /* test CRCX with unsupported packetization interval */
518 testcase TC_crcx_unsupp_packet_intv() runs on dummy_CT {
519 var template MgcpCommand cmd;
520 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100521 var MgcpEndpoint ep := "2@mgw";
522 var MgcpCallId call_id := '1228'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800523 var template MgcpResponse rtmpl := tr_MgcpResp_Err("532");
524
Harald Welteedc45c12017-11-18 19:15:05 +0100525 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800526
Harald Welteba62c8c2017-11-18 18:26:49 +0100527 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100528 cmd.params[2] := t_MgcpParLocConnOpt("p:111");
Harald Weltee636afd2017-09-17 16:24:09 +0800529 resp := mgcp_transceive_mgw(cmd, rtmpl);
530 setverdict(pass);
531 }
532
533 /* test CRCX with illegal double presence of local connection option */
534 testcase TC_crcx_illegal_double_lco() runs on dummy_CT {
535 var template MgcpCommand cmd;
536 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100537 var MgcpEndpoint ep := "2@mgw";
538 var MgcpCallId call_id := '1227'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800539 var template MgcpResponse rtmpl := tr_MgcpResp_Err("524");
540
Harald Welteedc45c12017-11-18 19:15:05 +0100541 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800542
Harald Welteba62c8c2017-11-18 18:26:49 +0100543 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100544 /* p:20 is permitted only once and not twice! */
545 cmd.params[2] := t_MgcpParLocConnOpt("p:20, a:AMR, p:20");
Harald Weltee636afd2017-09-17 16:24:09 +0800546 resp := mgcp_transceive_mgw(cmd, rtmpl);
547 setverdict(pass);
548 }
549
550 /* test valid CRCX with valid SDP */
551 testcase TC_crcx_sdp() runs on dummy_CT {
552 var template MgcpCommand cmd;
553 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100554 var MgcpEndpoint ep := "2@mgw";
555 var MgcpCallId call_id := '1226'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800556 var template MgcpResponse rtmpl := {
557 line := {
558 code := "200",
559 string := "OK"
560 },
Harald Welte6f960b12017-11-17 23:24:46 +0100561 params := { { "I", ? }, *},
Harald Weltee636afd2017-09-17 16:24:09 +0800562 sdp := ?
563 };
564
Harald Welteedc45c12017-11-18 19:15:05 +0100565 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800566
Harald Welteba62c8c2017-11-18 18:26:49 +0100567 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800568 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
569 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
570 valueof(ts_SDP_ptime(20)) });
571 resp := mgcp_transceive_mgw(cmd, rtmpl);
572 setverdict(pass);
573 }
574
575 /* TODO: various SDP related bits */
576
577
578 /* TODO: CRCX with X-Osmux */
579 /* TODO: double CRCX without force_realloc */
580
581 /* TODO: MDCX (various) */
582
583 /* TODO: MDCX without CRCX first */
584 testcase TC_mdcx_without_crcx() runs on dummy_CT {
585 var template MgcpCommand cmd;
586 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100587 var MgcpEndpoint ep := "3@mgw";
588 var MgcpCallId call_id := '1225'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800589 var template MgcpResponse rtmpl := {
590 line := {
591 /* TODO: accept/enforce better error? */
592 code := "400",
593 string := ?
594 },
595 params:= { },
596 sdp := omit
597 };
598
Harald Welteedc45c12017-11-18 19:15:05 +0100599 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800600
Harald Welteba62c8c2017-11-18 18:26:49 +0100601 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800602 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
603 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
604 valueof(ts_SDP_ptime(20)) });
605 resp := mgcp_transceive_mgw(cmd, rtmpl);
606 setverdict(pass);
607 }
608
609 /* DLCX without CRCX first */
610 testcase TC_dlcx_without_crcx() runs on dummy_CT {
611 var template MgcpCommand cmd;
612 var MgcpResponse resp;
Harald Welteedc45c12017-11-18 19:15:05 +0100613 var MgcpEndpoint ep := "4@mgw";
Harald Weltee636afd2017-09-17 16:24:09 +0800614 var template MgcpResponse rtmpl := {
615 line := {
616 /* TODO: accept/enforce better error? */
617 code := "400",
618 string := ?
619 },
620 params:= { },
621 sdp := omit
622 };
623
Harald Welteedc45c12017-11-18 19:15:05 +0100624 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800625
Harald Welteedc45c12017-11-18 19:15:05 +0100626 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800627 resp := mgcp_transceive_mgw(cmd, rtmpl);
628 setverdict(pass);
629 }
630
Harald Welte21ba5572017-09-19 17:55:05 +0800631 /* Test (valid) CRCX followed by (valid) DLCX */
Harald Welte5b4c44e2017-09-17 16:35:27 +0800632 testcase TC_crcx_and_dlcx() runs on dummy_CT {
633 var template MgcpCommand cmd;
634 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100635 var MgcpEndpoint ep := "5@mgw";
636 var MgcpCallId call_id := '51234'H;
Harald Welte5b4c44e2017-09-17 16:35:27 +0800637 var template MgcpResponse rtmpl := {
638 line := {
639 code := ("200", "250"),
640 string := "OK"
641 },
Harald Welte6f960b12017-11-17 23:24:46 +0100642 params:= { { "I", ? }, *},
Harald Welte5b4c44e2017-09-17 16:35:27 +0800643 sdp := ?
644 };
645
Harald Welteedc45c12017-11-18 19:15:05 +0100646 f_init(ep);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800647
Harald Welteba62c8c2017-11-18 18:26:49 +0100648 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800649 resp := mgcp_transceive_mgw(cmd, rtmpl);
650
Harald Welteba62c8c2017-11-18 18:26:49 +0100651 f_dlcx_ok(ep, call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800652
653 setverdict(pass);
654 }
655
Harald Weltee636afd2017-09-17 16:24:09 +0800656 /* TODO: DLCX of valid endpoint but invalid call-id */
657 /* TODO: Double-DLCX (retransmission) */
658 /* TODO: Double-DLCX (no retransmission) */
659
660
661
662 /* TODO: AUEP (various) */
663 /* TODO: RSIP (various) */
664 /* TODO: RQNT (various) */
665 /* TODO: EPCF (various) */
666 /* TODO: AUCX (various) */
667 /* TODO: invalid verb (various) */
668
Harald Welte00a067f2017-09-13 23:27:17 +0200669 control {
670 execute(TC_selftest());
Harald Welte3c6ebb92017-09-16 00:56:57 +0800671 execute(TC_crcx());
Harald Weltee636afd2017-09-17 16:24:09 +0800672 execute(TC_crcx_unsupp_mode());
673 execute(TC_crcx_early_bidir_mode());
674 execute(TC_crcx_unsupp_param());
675 execute(TC_crcx_missing_callid());
676 execute(TC_crcx_missing_mode());
677 execute(TC_crcx_unsupp_packet_intv());
678 execute(TC_crcx_illegal_double_lco());
679 execute(TC_crcx_sdp());
680 execute(TC_mdcx_without_crcx());
681 execute(TC_dlcx_without_crcx());
Harald Welte5b4c44e2017-09-17 16:35:27 +0800682 execute(TC_crcx_and_dlcx());
Harald Welte00a067f2017-09-13 23:27:17 +0200683 }
684}