blob: 844980f219dfbe6dce3d6aa276b9476ed719c381 [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 Welte3c6ebb92017-09-16 00:56:57 +080046 private function f_init()runs on dummy_CT {
47 var Result res;
Harald Weltef07c2862017-11-18 17:16:24 +010048 var uint32_t ssrc;
Harald Welte3c6ebb92017-09-16 00:56:57 +080049 if (initialized == true) {
50 return;
51 }
52 initialized := true;
53
Harald Welte21ba5572017-09-19 17:55:05 +080054 /* some random number for the initial transaction id */
Harald Weltee1e18c52017-09-17 16:23:07 +080055 g_trans_id := float2int(rnd()*65535.0);
Harald Welte3c6ebb92017-09-16 00:56:57 +080056 map(self:MGCP, system:MGCP_CODEC_PT);
Harald Welte21ba5572017-09-19 17:55:05 +080057 /* connect the MGCP test port using the given
Harald Welte55015362017-11-18 16:02:42 +010058 * source/destionation ip/port and store the connection id in g_mgcp_conn_id
Harald Welte21ba5572017-09-19 17:55:05 +080059 * */
Harald Welte55015362017-11-18 16:02:42 +010060 res := MGCP_CodecPort_CtrlFunct.f_IPL4_connect(MGCP, mp_remote_ip, mp_remote_udp_port, mp_local_ip, mp_local_udp_port, 0, { udp := {} });
61 g_mgcp_conn_id := res.connId;
Harald Weltef07c2862017-11-18 17:16:24 +010062
63 map(self:RTP, system:RTP_CODEC_PT);
64 ssrc := float2int(rnd()*4294967296.0);
65 rtp_endpoint_init(g_rtp_ep[0], mp_local_ip, mp_local_rtp_port_base, ssrc);
66 rtp_endpoint_bind(RTP, g_rtp_ep[0]);
67 rtp_endpoint_init(g_rtp_ep[1], mp_local_ip, mp_local_rtp_port_base+2, ssrc);
68 rtp_endpoint_bind(RTP, g_rtp_ep[1]);
Harald Welte3c6ebb92017-09-16 00:56:57 +080069 }
70
71 /* 3.2.2.6 Connection Mode (sendonly, recvonly, sendrecv, confrnce, inactive, loopback,
72 * conttest, netwloop, netwtest) */
73 template MgcpParameter t_MgcpParConnMode(template MgcpConnectionMode mode) := { "M", mode };
74
75 /* 3.2.2.2 CallId: maximum 32 hex chars */
76 template MgcpParameter ts_MgcpParCallId(MgcpCallId cid) := {
77 code := "C",
78 val := hex2str(cid)
79 };
80
81 /* 3.2.2.18 RequestIdentifier: Maximum 32 hex chars */
82 template MgcpParameter ts_MgcpParReqId(MgcpRequestId rid) := {
83 code := "X",
84 val := hex2str(rid)
85 };
86
87 /* 3.2.2.10: LocalConnectionOptions (codec, packetization, bandwidth, ToS, eco, gain, silence, ...) */
88 template MgcpParameter t_MgcpParLocConnOpt(template charstring lco) := { "L", lco };
89
90 /* 3.2.2.5: ConnectionId: maximum 32 hex chars */
91 template MgcpParameter ts_MgcpParConnectionId(MgcpConnectionId cid) := {
92 code := "I",
93 val := hex2str(cid)
94 };
95
96 /* osmo-bsc_mgcp implements L/C/M/X only, osmo-mgw adds 'I' */
97 /* SDP: osmo-bsc_mgcp implements Tx of v,o,s,c,t,m,a */
98
Harald Weltee636afd2017-09-17 16:24:09 +080099 template MgcpResponse tr_MgcpResp_Err(template MgcpResponseCode code) := {
100 line := {
101 code := code,
102 trans_id := ?,
103 string := ?
104 },
105 params := {},
106 sdp := omit
107 }
108
Harald Welte3c6ebb92017-09-16 00:56:57 +0800109 template MgcpCommandLine t_MgcpCmdLine(template charstring verb, template MgcpTransId trans_id, template charstring ep) := {
110 verb := verb,
111 trans_id := trans_id,
112 ep := ep,
113 ver := "1.0"
114 };
115
116 template MgcpCommand ts_CRCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
117 line := t_MgcpCmdLine("CRCX", trans_id, ep),
118 params := {
119 t_MgcpParConnMode(mode),
120 ts_MgcpParCallId(call_id),
121 //t_MgcpParReqId(omit),
122 t_MgcpParLocConnOpt("p: 20")
123 },
124 sdp := sdp
125 }
126
Harald Weltee636afd2017-09-17 16:24:09 +0800127 template MgcpCommand ts_MDCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
128 line := t_MgcpCmdLine("MDCX", trans_id, ep),
129 params := {
130 t_MgcpParConnMode(mode),
131 ts_MgcpParCallId(call_id),
132 //t_MgcpParReqId(omit),
133 t_MgcpParLocConnOpt("p: 20")
134 },
135 sdp := sdp
136 }
137
Harald Weltec40e0c32017-11-18 19:08:22 +0100138 /* have a function that generates a template, rather than a template in order to handle
139 * optional parameters */
140 function ts_DLCX(MgcpTransId trans_id, charstring ep, template MgcpCallId call_id := omit,
141 template MgcpConnectionId conn_id := omit) return template MgcpCommand {
142 var template MgcpCommand cmd;
143 cmd.line := t_MgcpCmdLine("DLCX", trans_id, ep);
144 cmd.params := {};
145 cmd.sdp := omit;
146 if (isvalue(call_id)) {
147 f_mgcp_par_append(cmd.params, ts_MgcpParCallId(valueof(call_id)));
148 if (isvalue(conn_id)) {
149 f_mgcp_par_append(cmd.params, ts_MgcpParConnectionId(valueof(conn_id)));
150 }
151 }
152 return cmd;
Harald Weltee636afd2017-09-17 16:24:09 +0800153 }
154
155 /* SDP Templates */
156 template SDP_Origin ts_SDP_origin(charstring addr, charstring session_id,
157 charstring session_version := "1",
158 charstring addr_type := "IP4",
159 charstring user_name := "-") := {
160 user_name := user_name,
161 session_id := session_id,
162 session_version := session_version,
163 net_type := "IN",
164 addr_type := addr_type,
165 addr := addr
166 }
167
168 template SDP_connection ts_SDP_connection_IP(charstring addr, charstring addr_type := "IP4",
169 template integer ttl := omit,
170 template integer num_of_addr := omit) :={
171 net_type := "IN",
172 addr_type := addr_type,
173 conn_addr := {
174 addr := addr,
175 ttl := ttl,
176 num_of_addr := num_of_addr
177 }
178 }
179
180 template SDP_time ts_SDP_time(charstring beg, charstring end) := {
181 time_field := {
182 start_time := beg,
183 stop_time := end
184 },
185 time_repeat := omit
186 }
187
188 template SDP_media_desc ts_SDP_media_desc(integer port_number, SDP_fmt_list fmts,
189 SDP_attribute_list attributes) := {
190 media_field := {
191 media := "audio",
192 ports := {
193 port_number := port_number,
194 num_of_ports := omit
195 },
196 transport := "ARTP/AVP",
197 fmts := fmts
198 },
199 information := omit,
200 connections := omit,
201 bandwidth := omit,
202 key := omit,
203 attributes := attributes
204 }
205
Harald Welte21ba5572017-09-19 17:55:05 +0800206 /* master template for generating SDP based in template arguments */
Harald Weltee636afd2017-09-17 16:24:09 +0800207 template SDP_Message ts_SDP(charstring local_addr, charstring remote_addr,
208 charstring session_id, charstring session_version,
209 integer rtp_port, SDP_fmt_list fmts,
210 SDP_attribute_list attributes) := {
211 protocol_version := 0,
212 origin := ts_SDP_origin(local_addr, session_id, session_version),
213 session_name := "-",
214 information := omit,
215 uri := omit,
216 emails := omit,
217 phone_numbers := omit,
218 connection := ts_SDP_connection_IP(remote_addr),
219 bandwidth := omit,
220 times := { ts_SDP_time("0","0") },
221 timezone_adjustments := omit,
222 key := omit,
223 attributes := omit,
224 media_list := { ts_SDP_media_desc(rtp_port, fmts, attributes) }
225 }
226
227 template SDP_attribute ts_SDP_rtpmap(integer fmt, charstring val) := {
228 rtpmap := {
229 attr_value := int2str(fmt) & " " & val
230 }
231 }
232 template SDP_attribute ts_SDP_ptime(integer p) := {
233 ptime := {
234 attr_value := int2str(p)
235 }
236 }
237
Harald Welte00a067f2017-09-13 23:27:17 +0200238 testcase TC_selftest() runs on dummy_CT {
239 const charstring c_auep := "AUEP 158663169 ds/e1-1/2@172.16.6.66 MGCP 1.0\r\n";
240 const charstring c_mdcx3 := "MDCX 18983215 1@mgw MGCP 1.0\r\n";
241 const charstring c_mdcx3_ret := "200 18983215 OK\r\n" &
242 "I: 1\n" &
243 "\n" &
244 "v=0\r\n" &
245 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
246 "s=-\r\n" &
247 "c=IN IP4 0.0.0.0\r\n" &
248 "t=0 0\r\n" &
249 "m=audio 0 RTP/AVP 126\r\n" &
250 "a=rtpmap:126 AMR/8000\r\n" &
251 "a=ptime:20\r\n";
252 const charstring c_mdcx4 := "MDCX 18983216 1@mgw MGCP 1.0\r\n" &
253 "M: sendrecv\r" &
254 "C: 2\r\n" &
255 "I: 1\r\n" &
256 "L: p:20, a:AMR, nt:IN\r\n" &
257 "\n" &
258 "v=0\r\n" &
259 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
Harald Welte2871d0b2017-09-14 22:42:12 +0800260 "s=-\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200261 "c=IN IP4 0.0.0.0\r\n" &
262 "t=0 0\r\n" &
263 "m=audio 4441 RTP/AVP 99\r\n" &
264 "a=rtpmap:99 AMR/8000\r\n" &
265 "a=ptime:40\r\n";
Harald Welte3c6ebb92017-09-16 00:56:57 +0800266 const charstring c_crcx510_ret := "510 23 FAIL\r\n"
Harald Welte00a067f2017-09-13 23:27:17 +0200267
268 log(c_auep);
269 log(dec_MgcpCommand(c_auep));
270
271 log(c_mdcx3);
272 log(dec_MgcpCommand(c_mdcx3));
273
274 log(c_mdcx3_ret);
275 log(dec_MgcpResponse(c_mdcx3_ret));
276
277 log(c_mdcx4);
278 log(dec_MgcpCommand(c_mdcx4));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800279
280 log(ts_CRCX("23", "42@mgw", "sendrecv", '1234'H));
281 log(enc_MgcpCommand(valueof(ts_CRCX("23", "42@mgw", "sendrecv", '1234'H))));
282
283 log(c_crcx510_ret);
284 log(dec_MgcpResponse(c_crcx510_ret));
285 log(dec_MgcpMessage(c_crcx510_ret));
286 }
287
Harald Weltee636afd2017-09-17 16:24:09 +0800288 /* CRCX test ideas:
289 * - without mandatory CallId
290 * - without mandatory ConnectionId
291 * - with forbidden parameters (e.g. Capabilities, PackageList, ...
292 * - CRCX with remote session description and without
293 *
294 * general ideas:
295 * - packetization != 20ms
296 * - invalid mode
297 * x unsupported mode (517)
298 * x bidirectional mode before RemoteConnDesc: 527
299 * - invalid codec
300 * - retransmission of same transaction
301 * - unsupported LocalConnectionOptions ("b", "a", "e", "gc", "s", "r", "k", ..)
302 */
303
Harald Welte21ba5572017-09-19 17:55:05 +0800304 /* build a receive template for receiving a MGCP message. You
305 * pass the MGCP response template in, and it will generate an
306 * MGCP_RecvFrom template that can match the primitives arriving on the
307 * MGCP_CodecPort */
Harald Weltee636afd2017-09-17 16:24:09 +0800308 function tr_MGCP_RecvFrom_R(template MgcpResponse resp) runs on dummy_CT return template MGCP_RecvFrom {
309 var template MGCP_RecvFrom mrf := {
Harald Welte55015362017-11-18 16:02:42 +0100310 connId := g_mgcp_conn_id,
Harald Weltee636afd2017-09-17 16:24:09 +0800311 remName := mp_remote_ip,
312 remPort := mp_remote_udp_port,
313 locName := mp_local_ip,
314 locPort := mp_local_udp_port,
315 msg := { response := resp }
316 }
317 return mrf;
318 }
319
320 /* Send a MGCP request + receive a (matching!) response */
321 function mgcp_transceive_mgw(template MgcpCommand cmd, template MgcpResponse resp := ?) runs on dummy_CT return MgcpResponse {
322 var MgcpMessage msg := { command := valueof(cmd) };
323 resp.line.trans_id := cmd.line.trans_id;
324 var template MGCP_RecvFrom mrt := tr_MGCP_RecvFrom_R(resp);
Harald Welte3c6ebb92017-09-16 00:56:57 +0800325 var MGCP_RecvFrom mrf;
326 timer T := 5.0;
327
Harald Welte55015362017-11-18 16:02:42 +0100328 MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800329 T.start;
330 alt {
Harald Weltee636afd2017-09-17 16:24:09 +0800331 [] MGCP.receive(mrt) -> value mrf { }
332 [] MGCP.receive(tr_MGCP_RecvFrom_R(?)) { setverdict(fail); }
Harald Welte3c6ebb92017-09-16 00:56:57 +0800333 [] MGCP.receive { repeat; }
334 [] T.timeout { setverdict(fail); }
335 }
336 T.stop;
Harald Weltee636afd2017-09-17 16:24:09 +0800337
338 if (isbound(mrf) and isbound(mrf.msg) and ischosen(mrf.msg.response)) {
339 return mrf.msg.response;
340 } else {
341 var MgcpResponse r := { line := { code := "999", trans_id := valueof(cmd.line.trans_id) } };
342 return r;
343 }
Harald Welte00a067f2017-09-13 23:27:17 +0200344 }
345
Harald Welteba62c8c2017-11-18 18:26:49 +0100346 function extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
347 var integer i;
348 for (i := 0; i < lengthof(resp.params); i := i + 1) {
349 var MgcpParameter par := resp.params[i];
350 if (par.code == "I") {
351 return str2hex(par.val);
352 }
353 }
354 setverdict(fail);
355 return '00000000'H;
356 }
357
358 /* Send DLCX and expect OK response */
Harald Weltec40e0c32017-11-18 19:08:22 +0100359 function f_dlcx_ok(MgcpEndpoint ep, template MgcpCallId call_id := omit,
Harald Welteba62c8c2017-11-18 18:26:49 +0100360 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
361 var template MgcpCommand cmd;
362 var MgcpResponse resp;
363 var template MgcpResponse rtmpl := {
364 line := {
365 code := "200",
366 string := "OK"
367 },
368 params := *,
369 sdp := *
370 };
Harald Weltec40e0c32017-11-18 19:08:22 +0100371 cmd := ts_DLCX(get_next_trans_id(), ep, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100372 resp := mgcp_transceive_mgw(cmd, rtmpl);
373 }
374
375 /* Send DLCX and accept any response */
Harald Weltec40e0c32017-11-18 19:08:22 +0100376 function f_dlcx_ignore(MgcpEndpoint ep, template MgcpCallId call_id := omit,
Harald Welteba62c8c2017-11-18 18:26:49 +0100377 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
378 var template MgcpCommand cmd;
379 var MgcpResponse resp;
380 var template MgcpResponse rtmpl := {
381 line := {
382 code := ?,
383 string := ?
384 },
385 params := *,
386 sdp := *
387 };
Harald Weltec40e0c32017-11-18 19:08:22 +0100388 cmd := ts_DLCX(get_next_trans_id(), ep, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100389 resp := mgcp_transceive_mgw(cmd, rtmpl);
390 }
391
Harald Weltee636afd2017-09-17 16:24:09 +0800392 /* test valid CRCX without SDP */
393 testcase TC_crcx() runs on dummy_CT {
394 var template MgcpCommand cmd;
395 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100396 var MgcpEndpoint ep := "2@mgw";
397 var MgcpCallId call_id := '1234'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800398 var template MgcpResponse rtmpl := {
399 line := {
400 code := "200",
401 string := "OK"
402 },
Harald Welte6f960b12017-11-17 23:24:46 +0100403 params := { { "I", ? }, *},
Harald Weltee636afd2017-09-17 16:24:09 +0800404 sdp := ?
405 };
406
407 f_init();
408
Harald Welteba62c8c2017-11-18 18:26:49 +0100409 /* create the connection on the MGW */
410 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800411 resp := mgcp_transceive_mgw(cmd, rtmpl);
Harald Welteba62c8c2017-11-18 18:26:49 +0100412 extract_conn_id(resp);
413
414 /* clean-up */
415 f_dlcx_ok(ep, call_id);
416
Harald Weltee636afd2017-09-17 16:24:09 +0800417 setverdict(pass);
418 }
419
420 /* test CRCX with unsupported mode, expect 517 */
421 testcase TC_crcx_unsupp_mode() runs on dummy_CT {
422 var template MgcpCommand cmd;
423 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100424 var MgcpEndpoint ep := "2@mgw";
425 var MgcpCallId call_id := '1233'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800426 var template MgcpResponse rtmpl := tr_MgcpResp_Err("517");
427
428 f_init();
429
Harald Welteba62c8c2017-11-18 18:26:49 +0100430 cmd := ts_CRCX(get_next_trans_id(), ep, "netwtest", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800431 resp := mgcp_transceive_mgw(cmd, rtmpl);
432 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100433
434 f_dlcx_ignore(ep, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800435 }
436
Harald Welte21ba5572017-09-19 17:55:05 +0800437 /* test CRCX with early bi-directional mode, expect 527 as
438 * bi-diretional media can only be established once both local and
439 * remote side are specified, see MGCP RFC */
Harald Weltee636afd2017-09-17 16:24:09 +0800440 testcase TC_crcx_early_bidir_mode() runs on dummy_CT {
441 var template MgcpCommand cmd;
442 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100443 var MgcpEndpoint ep := "2@mgw";
444 var MgcpCallId call_id := '1232'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800445 var template MgcpResponse rtmpl := tr_MgcpResp_Err("527");
446
447 f_init();
448
Harald Welteba62c8c2017-11-18 18:26:49 +0100449 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800450 resp := mgcp_transceive_mgw(cmd, rtmpl);
451 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100452
453 f_dlcx_ignore(ep, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800454 }
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
469 f_init();
470
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);
Harald Welteba62c8c2017-11-18 18:26:49 +0100477
478 f_dlcx_ignore(ep, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800479 }
480
481 /* test CRCX with missing CallId */
482 testcase TC_crcx_missing_callid() runs on dummy_CT {
483 var template MgcpCommand cmd;
484 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100485 var MgcpEndpoint ep := "2@mgw";
Harald Weltee636afd2017-09-17 16:24:09 +0800486 var template MgcpResponse rtmpl := tr_MgcpResp_Err("400");
487
488 f_init();
489
Harald Welteba62c8c2017-11-18 18:26:49 +0100490 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", '1230'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800491 cmd.params := {
492 t_MgcpParConnMode("recvonly"),
493 t_MgcpParLocConnOpt("p:20")
494 }
495 resp := mgcp_transceive_mgw(cmd, rtmpl);
496 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100497
Harald Weltee636afd2017-09-17 16:24:09 +0800498 }
499
500 /* test CRCX with missing Mode */
501 testcase TC_crcx_missing_mode() runs on dummy_CT {
502 var template MgcpCommand cmd;
503 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100504 var MgcpEndpoint ep := "2@mgw";
505 var MgcpCallId call_id := '1229'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800506 var template MgcpResponse rtmpl := tr_MgcpResp_Err("400");
507
508 f_init();
509
Harald Welteba62c8c2017-11-18 18:26:49 +0100510 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800511 cmd.params := {
Harald Welteba62c8c2017-11-18 18:26:49 +0100512 ts_MgcpParCallId(call_id),
Harald Weltee636afd2017-09-17 16:24:09 +0800513 t_MgcpParLocConnOpt("p:20")
514 }
515 resp := mgcp_transceive_mgw(cmd, rtmpl);
516 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100517
518 f_dlcx_ignore(ep, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800519 }
520
521 /* test CRCX with unsupported packetization interval */
522 testcase TC_crcx_unsupp_packet_intv() runs on dummy_CT {
523 var template MgcpCommand cmd;
524 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100525 var MgcpEndpoint ep := "2@mgw";
526 var MgcpCallId call_id := '1228'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800527 var template MgcpResponse rtmpl := tr_MgcpResp_Err("532");
528
529 f_init();
530
Harald Welteba62c8c2017-11-18 18:26:49 +0100531 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100532 cmd.params[2] := t_MgcpParLocConnOpt("p:111");
Harald Weltee636afd2017-09-17 16:24:09 +0800533 resp := mgcp_transceive_mgw(cmd, rtmpl);
534 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100535
536 f_dlcx_ignore(ep, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800537 }
538
539 /* test CRCX with illegal double presence of local connection option */
540 testcase TC_crcx_illegal_double_lco() runs on dummy_CT {
541 var template MgcpCommand cmd;
542 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100543 var MgcpEndpoint ep := "2@mgw";
544 var MgcpCallId call_id := '1227'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800545 var template MgcpResponse rtmpl := tr_MgcpResp_Err("524");
546
547 f_init();
548
Harald Welteba62c8c2017-11-18 18:26:49 +0100549 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100550 /* p:20 is permitted only once and not twice! */
551 cmd.params[2] := t_MgcpParLocConnOpt("p:20, a:AMR, p:20");
Harald Weltee636afd2017-09-17 16:24:09 +0800552 resp := mgcp_transceive_mgw(cmd, rtmpl);
553 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100554
555 f_dlcx_ignore(ep, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800556 }
557
558 /* test valid CRCX with valid SDP */
559 testcase TC_crcx_sdp() runs on dummy_CT {
560 var template MgcpCommand cmd;
561 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100562 var MgcpEndpoint ep := "2@mgw";
563 var MgcpCallId call_id := '1226'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800564 var template MgcpResponse rtmpl := {
565 line := {
566 code := "200",
567 string := "OK"
568 },
Harald Welte6f960b12017-11-17 23:24:46 +0100569 params := { { "I", ? }, *},
Harald Weltee636afd2017-09-17 16:24:09 +0800570 sdp := ?
571 };
572
573 f_init();
574
Harald Welteba62c8c2017-11-18 18:26:49 +0100575 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800576 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
577 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
578 valueof(ts_SDP_ptime(20)) });
579 resp := mgcp_transceive_mgw(cmd, rtmpl);
580 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100581
582 f_dlcx_ignore(ep, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800583 }
584
585 /* TODO: various SDP related bits */
586
587
588 /* TODO: CRCX with X-Osmux */
589 /* TODO: double CRCX without force_realloc */
590
591 /* TODO: MDCX (various) */
592
593 /* TODO: MDCX without CRCX first */
594 testcase TC_mdcx_without_crcx() runs on dummy_CT {
595 var template MgcpCommand cmd;
596 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100597 var MgcpEndpoint ep := "3@mgw";
598 var MgcpCallId call_id := '1225'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800599 var template MgcpResponse rtmpl := {
600 line := {
601 /* TODO: accept/enforce better error? */
602 code := "400",
603 string := ?
604 },
605 params:= { },
606 sdp := omit
607 };
608
609 f_init();
610
Harald Welteba62c8c2017-11-18 18:26:49 +0100611 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800612 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
613 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
614 valueof(ts_SDP_ptime(20)) });
615 resp := mgcp_transceive_mgw(cmd, rtmpl);
616 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100617
618 f_dlcx_ignore(ep, call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800619 }
620
621 /* DLCX without CRCX first */
622 testcase TC_dlcx_without_crcx() runs on dummy_CT {
623 var template MgcpCommand cmd;
624 var MgcpResponse resp;
625 var template MgcpResponse rtmpl := {
626 line := {
627 /* TODO: accept/enforce better error? */
628 code := "400",
629 string := ?
630 },
631 params:= { },
632 sdp := omit
633 };
634
635 f_init();
636
637 cmd := ts_DLCX(get_next_trans_id(), "4@mgw", '41234'H);
638 resp := mgcp_transceive_mgw(cmd, rtmpl);
639 setverdict(pass);
640 }
641
Harald Welte21ba5572017-09-19 17:55:05 +0800642 /* Test (valid) CRCX followed by (valid) DLCX */
Harald Welte5b4c44e2017-09-17 16:35:27 +0800643 testcase TC_crcx_and_dlcx() runs on dummy_CT {
644 var template MgcpCommand cmd;
645 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100646 var MgcpEndpoint ep := "5@mgw";
647 var MgcpCallId call_id := '51234'H;
Harald Welte5b4c44e2017-09-17 16:35:27 +0800648 var template MgcpResponse rtmpl := {
649 line := {
650 code := ("200", "250"),
651 string := "OK"
652 },
Harald Welte6f960b12017-11-17 23:24:46 +0100653 params:= { { "I", ? }, *},
Harald Welte5b4c44e2017-09-17 16:35:27 +0800654 sdp := ?
655 };
656
657 f_init();
658
Harald Welteba62c8c2017-11-18 18:26:49 +0100659 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800660 resp := mgcp_transceive_mgw(cmd, rtmpl);
661
Harald Welteba62c8c2017-11-18 18:26:49 +0100662 f_dlcx_ok(ep, call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800663
664 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100665
666 f_dlcx_ignore(ep, call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800667 }
668
Harald Weltee636afd2017-09-17 16:24:09 +0800669 /* TODO: DLCX of valid endpoint but invalid call-id */
670 /* TODO: Double-DLCX (retransmission) */
671 /* TODO: Double-DLCX (no retransmission) */
672
673
674
675 /* TODO: AUEP (various) */
676 /* TODO: RSIP (various) */
677 /* TODO: RQNT (various) */
678 /* TODO: EPCF (various) */
679 /* TODO: AUCX (various) */
680 /* TODO: invalid verb (various) */
681
Harald Welte00a067f2017-09-13 23:27:17 +0200682 control {
683 execute(TC_selftest());
Harald Welte3c6ebb92017-09-16 00:56:57 +0800684 execute(TC_crcx());
Harald Weltee636afd2017-09-17 16:24:09 +0800685 execute(TC_crcx_unsupp_mode());
686 execute(TC_crcx_early_bidir_mode());
687 execute(TC_crcx_unsupp_param());
688 execute(TC_crcx_missing_callid());
689 execute(TC_crcx_missing_mode());
690 execute(TC_crcx_unsupp_packet_intv());
691 execute(TC_crcx_illegal_double_lco());
692 execute(TC_crcx_sdp());
693 execute(TC_mdcx_without_crcx());
694 execute(TC_dlcx_without_crcx());
Harald Welte5b4c44e2017-09-17 16:35:27 +0800695 execute(TC_crcx_and_dlcx());
Harald Welte00a067f2017-09-13 23:27:17 +0200696 }
697}