blob: d7730c3a8f86a9176a75bb155839c1caef8e5ae5 [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
Harald Welte8d2fbb42017-11-18 20:34:21 +010075 function f_mgcp_par_append(inout template MgcpParameterList list, template MgcpParameter par) {
76 var integer len := lengthof(list);
77 list[len] := par;
78 }
79
Harald Welte3c6ebb92017-09-16 00:56:57 +080080 /* 3.2.2.6 Connection Mode (sendonly, recvonly, sendrecv, confrnce, inactive, loopback,
81 * conttest, netwloop, netwtest) */
82 template MgcpParameter t_MgcpParConnMode(template MgcpConnectionMode mode) := { "M", mode };
83
84 /* 3.2.2.2 CallId: maximum 32 hex chars */
85 template MgcpParameter ts_MgcpParCallId(MgcpCallId cid) := {
86 code := "C",
87 val := hex2str(cid)
88 };
89
90 /* 3.2.2.18 RequestIdentifier: Maximum 32 hex chars */
91 template MgcpParameter ts_MgcpParReqId(MgcpRequestId rid) := {
92 code := "X",
93 val := hex2str(rid)
94 };
95
96 /* 3.2.2.10: LocalConnectionOptions (codec, packetization, bandwidth, ToS, eco, gain, silence, ...) */
97 template MgcpParameter t_MgcpParLocConnOpt(template charstring lco) := { "L", lco };
98
99 /* 3.2.2.5: ConnectionId: maximum 32 hex chars */
100 template MgcpParameter ts_MgcpParConnectionId(MgcpConnectionId cid) := {
101 code := "I",
102 val := hex2str(cid)
103 };
104
105 /* osmo-bsc_mgcp implements L/C/M/X only, osmo-mgw adds 'I' */
106 /* SDP: osmo-bsc_mgcp implements Tx of v,o,s,c,t,m,a */
107
Harald Weltee636afd2017-09-17 16:24:09 +0800108 template MgcpResponse tr_MgcpResp_Err(template MgcpResponseCode code) := {
109 line := {
110 code := code,
111 trans_id := ?,
112 string := ?
113 },
114 params := {},
115 sdp := omit
116 }
117
Harald Welte3c6ebb92017-09-16 00:56:57 +0800118 template MgcpCommandLine t_MgcpCmdLine(template charstring verb, template MgcpTransId trans_id, template charstring ep) := {
119 verb := verb,
120 trans_id := trans_id,
121 ep := ep,
122 ver := "1.0"
123 };
124
125 template MgcpCommand ts_CRCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
126 line := t_MgcpCmdLine("CRCX", trans_id, ep),
127 params := {
128 t_MgcpParConnMode(mode),
129 ts_MgcpParCallId(call_id),
130 //t_MgcpParReqId(omit),
131 t_MgcpParLocConnOpt("p: 20")
132 },
133 sdp := sdp
134 }
135
Harald Welte9988d282017-11-18 19:22:00 +0100136 template MgcpResponse tr_CRCX_ACK := {
137 line := {
138 code := "200",
139 string := "OK"
140 },
141 params:= { { "I", ? }, *},
142 sdp := ?
143 }
144
Harald Weltee636afd2017-09-17 16:24:09 +0800145 template MgcpCommand ts_MDCX(MgcpTransId trans_id, charstring ep, MgcpConnectionMode mode, MgcpCallId call_id, template SDP_Message sdp := omit) := {
146 line := t_MgcpCmdLine("MDCX", trans_id, ep),
147 params := {
148 t_MgcpParConnMode(mode),
149 ts_MgcpParCallId(call_id),
150 //t_MgcpParReqId(omit),
151 t_MgcpParLocConnOpt("p: 20")
152 },
153 sdp := sdp
154 }
155
Harald Weltec40e0c32017-11-18 19:08:22 +0100156 /* have a function that generates a template, rather than a template in order to handle
157 * optional parameters */
158 function ts_DLCX(MgcpTransId trans_id, charstring ep, template MgcpCallId call_id := omit,
159 template MgcpConnectionId conn_id := omit) return template MgcpCommand {
160 var template MgcpCommand cmd;
161 cmd.line := t_MgcpCmdLine("DLCX", trans_id, ep);
162 cmd.params := {};
163 cmd.sdp := omit;
164 if (isvalue(call_id)) {
165 f_mgcp_par_append(cmd.params, ts_MgcpParCallId(valueof(call_id)));
166 if (isvalue(conn_id)) {
167 f_mgcp_par_append(cmd.params, ts_MgcpParConnectionId(valueof(conn_id)));
168 }
169 }
170 return cmd;
Harald Weltee636afd2017-09-17 16:24:09 +0800171 }
172
173 /* SDP Templates */
174 template SDP_Origin ts_SDP_origin(charstring addr, charstring session_id,
175 charstring session_version := "1",
176 charstring addr_type := "IP4",
177 charstring user_name := "-") := {
178 user_name := user_name,
179 session_id := session_id,
180 session_version := session_version,
181 net_type := "IN",
182 addr_type := addr_type,
183 addr := addr
184 }
185
186 template SDP_connection ts_SDP_connection_IP(charstring addr, charstring addr_type := "IP4",
187 template integer ttl := omit,
188 template integer num_of_addr := omit) :={
189 net_type := "IN",
190 addr_type := addr_type,
191 conn_addr := {
192 addr := addr,
193 ttl := ttl,
194 num_of_addr := num_of_addr
195 }
196 }
197
198 template SDP_time ts_SDP_time(charstring beg, charstring end) := {
199 time_field := {
200 start_time := beg,
201 stop_time := end
202 },
203 time_repeat := omit
204 }
205
206 template SDP_media_desc ts_SDP_media_desc(integer port_number, SDP_fmt_list fmts,
207 SDP_attribute_list attributes) := {
208 media_field := {
209 media := "audio",
210 ports := {
211 port_number := port_number,
212 num_of_ports := omit
213 },
214 transport := "ARTP/AVP",
215 fmts := fmts
216 },
217 information := omit,
218 connections := omit,
219 bandwidth := omit,
220 key := omit,
221 attributes := attributes
222 }
223
Harald Welte21ba5572017-09-19 17:55:05 +0800224 /* master template for generating SDP based in template arguments */
Harald Weltee636afd2017-09-17 16:24:09 +0800225 template SDP_Message ts_SDP(charstring local_addr, charstring remote_addr,
226 charstring session_id, charstring session_version,
227 integer rtp_port, SDP_fmt_list fmts,
228 SDP_attribute_list attributes) := {
229 protocol_version := 0,
230 origin := ts_SDP_origin(local_addr, session_id, session_version),
231 session_name := "-",
232 information := omit,
233 uri := omit,
234 emails := omit,
235 phone_numbers := omit,
236 connection := ts_SDP_connection_IP(remote_addr),
237 bandwidth := omit,
238 times := { ts_SDP_time("0","0") },
239 timezone_adjustments := omit,
240 key := omit,
241 attributes := omit,
242 media_list := { ts_SDP_media_desc(rtp_port, fmts, attributes) }
243 }
244
245 template SDP_attribute ts_SDP_rtpmap(integer fmt, charstring val) := {
246 rtpmap := {
247 attr_value := int2str(fmt) & " " & val
248 }
249 }
250 template SDP_attribute ts_SDP_ptime(integer p) := {
251 ptime := {
252 attr_value := int2str(p)
253 }
254 }
255
Harald Welte00a067f2017-09-13 23:27:17 +0200256 testcase TC_selftest() runs on dummy_CT {
257 const charstring c_auep := "AUEP 158663169 ds/e1-1/2@172.16.6.66 MGCP 1.0\r\n";
258 const charstring c_mdcx3 := "MDCX 18983215 1@mgw MGCP 1.0\r\n";
259 const charstring c_mdcx3_ret := "200 18983215 OK\r\n" &
260 "I: 1\n" &
261 "\n" &
262 "v=0\r\n" &
263 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
264 "s=-\r\n" &
265 "c=IN IP4 0.0.0.0\r\n" &
266 "t=0 0\r\n" &
267 "m=audio 0 RTP/AVP 126\r\n" &
268 "a=rtpmap:126 AMR/8000\r\n" &
269 "a=ptime:20\r\n";
270 const charstring c_mdcx4 := "MDCX 18983216 1@mgw MGCP 1.0\r\n" &
271 "M: sendrecv\r" &
272 "C: 2\r\n" &
273 "I: 1\r\n" &
274 "L: p:20, a:AMR, nt:IN\r\n" &
275 "\n" &
276 "v=0\r\n" &
277 "o=- 1 23 IN IP4 0.0.0.0\r\n" &
Harald Welte2871d0b2017-09-14 22:42:12 +0800278 "s=-\r\n" &
Harald Welte00a067f2017-09-13 23:27:17 +0200279 "c=IN IP4 0.0.0.0\r\n" &
280 "t=0 0\r\n" &
281 "m=audio 4441 RTP/AVP 99\r\n" &
282 "a=rtpmap:99 AMR/8000\r\n" &
283 "a=ptime:40\r\n";
Harald Welte3c6ebb92017-09-16 00:56:57 +0800284 const charstring c_crcx510_ret := "510 23 FAIL\r\n"
Harald Welte00a067f2017-09-13 23:27:17 +0200285
286 log(c_auep);
287 log(dec_MgcpCommand(c_auep));
288
289 log(c_mdcx3);
290 log(dec_MgcpCommand(c_mdcx3));
291
292 log(c_mdcx3_ret);
293 log(dec_MgcpResponse(c_mdcx3_ret));
294
295 log(c_mdcx4);
296 log(dec_MgcpCommand(c_mdcx4));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800297
298 log(ts_CRCX("23", "42@mgw", "sendrecv", '1234'H));
299 log(enc_MgcpCommand(valueof(ts_CRCX("23", "42@mgw", "sendrecv", '1234'H))));
300
301 log(c_crcx510_ret);
302 log(dec_MgcpResponse(c_crcx510_ret));
303 log(dec_MgcpMessage(c_crcx510_ret));
304 }
305
Harald Weltee636afd2017-09-17 16:24:09 +0800306 /* CRCX test ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100307 * x without mandatory CallId
Harald Weltee636afd2017-09-17 16:24:09 +0800308 * - with forbidden parameters (e.g. Capabilities, PackageList, ...
309 * - CRCX with remote session description and without
310 *
311 * general ideas:
Harald Weltee0b331f2017-11-18 20:34:33 +0100312 * x packetization != 20ms
313 * x invalid mode
Harald Weltee636afd2017-09-17 16:24:09 +0800314 * x unsupported mode (517)
315 * x bidirectional mode before RemoteConnDesc: 527
316 * - invalid codec
Harald Weltee0b331f2017-11-18 20:34:33 +0100317 * x retransmission of same transaction
Harald Weltee636afd2017-09-17 16:24:09 +0800318 * - unsupported LocalConnectionOptions ("b", "a", "e", "gc", "s", "r", "k", ..)
319 */
320
Harald Welte21ba5572017-09-19 17:55:05 +0800321 /* build a receive template for receiving a MGCP message. You
322 * pass the MGCP response template in, and it will generate an
323 * MGCP_RecvFrom template that can match the primitives arriving on the
324 * MGCP_CodecPort */
Harald Weltee636afd2017-09-17 16:24:09 +0800325 function tr_MGCP_RecvFrom_R(template MgcpResponse resp) runs on dummy_CT return template MGCP_RecvFrom {
326 var template MGCP_RecvFrom mrf := {
Harald Welte55015362017-11-18 16:02:42 +0100327 connId := g_mgcp_conn_id,
Harald Weltee636afd2017-09-17 16:24:09 +0800328 remName := mp_remote_ip,
329 remPort := mp_remote_udp_port,
330 locName := mp_local_ip,
331 locPort := mp_local_udp_port,
332 msg := { response := resp }
333 }
334 return mrf;
335 }
336
337 /* Send a MGCP request + receive a (matching!) response */
338 function mgcp_transceive_mgw(template MgcpCommand cmd, template MgcpResponse resp := ?) runs on dummy_CT return MgcpResponse {
339 var MgcpMessage msg := { command := valueof(cmd) };
340 resp.line.trans_id := cmd.line.trans_id;
341 var template MGCP_RecvFrom mrt := tr_MGCP_RecvFrom_R(resp);
Harald Welte3c6ebb92017-09-16 00:56:57 +0800342 var MGCP_RecvFrom mrf;
343 timer T := 5.0;
344
Harald Welte55015362017-11-18 16:02:42 +0100345 MGCP.send(t_MGCP_Send(g_mgcp_conn_id, msg));
Harald Welte3c6ebb92017-09-16 00:56:57 +0800346 T.start;
347 alt {
Harald Weltee636afd2017-09-17 16:24:09 +0800348 [] MGCP.receive(mrt) -> value mrf { }
349 [] MGCP.receive(tr_MGCP_RecvFrom_R(?)) { setverdict(fail); }
Harald Welte3c6ebb92017-09-16 00:56:57 +0800350 [] MGCP.receive { repeat; }
351 [] T.timeout { setverdict(fail); }
352 }
353 T.stop;
Harald Weltee636afd2017-09-17 16:24:09 +0800354
355 if (isbound(mrf) and isbound(mrf.msg) and ischosen(mrf.msg.response)) {
356 return mrf.msg.response;
357 } else {
358 var MgcpResponse r := { line := { code := "999", trans_id := valueof(cmd.line.trans_id) } };
359 return r;
360 }
Harald Welte00a067f2017-09-13 23:27:17 +0200361 }
362
Harald Welteba62c8c2017-11-18 18:26:49 +0100363 function extract_conn_id(MgcpResponse resp) return MgcpConnectionId {
364 var integer i;
365 for (i := 0; i < lengthof(resp.params); i := i + 1) {
366 var MgcpParameter par := resp.params[i];
367 if (par.code == "I") {
368 return str2hex(par.val);
369 }
370 }
371 setverdict(fail);
372 return '00000000'H;
373 }
374
Harald Welte10889c12017-11-18 19:40:31 +0100375 function f_dlcx(MgcpEndpoint ep, template MgcpResponseCode ret_code, template charstring ret_val,
376 template MgcpCallId call_id := omit,
377 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welteba62c8c2017-11-18 18:26:49 +0100378 var template MgcpCommand cmd;
379 var MgcpResponse resp;
380 var template MgcpResponse rtmpl := {
381 line := {
Harald Welte10889c12017-11-18 19:40:31 +0100382 code := ret_code,
383 string := ret_val
Harald Welteba62c8c2017-11-18 18:26:49 +0100384 },
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 Welte10889c12017-11-18 19:40:31 +0100392 /* Send DLCX and expect OK response */
393 function f_dlcx_ok(MgcpEndpoint ep, template MgcpCallId call_id := omit,
394 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
395 f_dlcx(ep, "200", "OK", call_id, conn_id);
396 }
397
Harald Welteba62c8c2017-11-18 18:26:49 +0100398 /* Send DLCX and accept any response */
Harald Weltec40e0c32017-11-18 19:08:22 +0100399 function f_dlcx_ignore(MgcpEndpoint ep, template MgcpCallId call_id := omit,
Harald Welteba62c8c2017-11-18 18:26:49 +0100400 template MgcpConnectionId conn_id := omit) runs on dummy_CT {
Harald Welte10889c12017-11-18 19:40:31 +0100401 f_dlcx(ep, ?, *, call_id, conn_id);
Harald Welteba62c8c2017-11-18 18:26:49 +0100402 }
403
Harald Weltee636afd2017-09-17 16:24:09 +0800404 /* test valid CRCX without SDP */
405 testcase TC_crcx() runs on dummy_CT {
406 var template MgcpCommand cmd;
407 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100408 var MgcpEndpoint ep := "2@mgw";
409 var MgcpCallId call_id := '1234'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800410
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 Welte9988d282017-11-18 19:22:00 +0100415 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
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
456 /* test CRCX with unsupported Parameters */
457 testcase TC_crcx_unsupp_param() runs on dummy_CT {
458 var template MgcpCommand cmd;
459 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100460 var MgcpEndpoint ep := "2@mgw";
461 var MgcpCallId call_id := '1231'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800462 var template MgcpResponse rtmpl := tr_MgcpResp_Err("539");
463
Harald Welteedc45c12017-11-18 19:15:05 +0100464 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800465
Harald Welteba62c8c2017-11-18 18:26:49 +0100466 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100467 /* osmo-bsc_mgcp/mgw doesn't implement notifications */
468 f_mgcp_par_append(cmd.params, MgcpParameter:{ "N", "foobar" });
469
Harald Weltee636afd2017-09-17 16:24:09 +0800470 resp := mgcp_transceive_mgw(cmd, rtmpl);
471 setverdict(pass);
472 }
473
474 /* test CRCX with missing CallId */
475 testcase TC_crcx_missing_callid() runs on dummy_CT {
476 var template MgcpCommand cmd;
477 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100478 var MgcpEndpoint ep := "2@mgw";
Harald Weltee636afd2017-09-17 16:24:09 +0800479 var template MgcpResponse rtmpl := tr_MgcpResp_Err("400");
480
Harald Welteedc45c12017-11-18 19:15:05 +0100481 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800482
Harald Welteba62c8c2017-11-18 18:26:49 +0100483 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", '1230'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800484 cmd.params := {
485 t_MgcpParConnMode("recvonly"),
486 t_MgcpParLocConnOpt("p:20")
487 }
488 resp := mgcp_transceive_mgw(cmd, rtmpl);
489 setverdict(pass);
Harald Welteba62c8c2017-11-18 18:26:49 +0100490
Harald Weltee636afd2017-09-17 16:24:09 +0800491 }
492
493 /* test CRCX with missing Mode */
494 testcase TC_crcx_missing_mode() runs on dummy_CT {
495 var template MgcpCommand cmd;
496 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100497 var MgcpEndpoint ep := "2@mgw";
498 var MgcpCallId call_id := '1229'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800499 var template MgcpResponse rtmpl := tr_MgcpResp_Err("400");
500
Harald Welteedc45c12017-11-18 19:15:05 +0100501 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800502
Harald Welteba62c8c2017-11-18 18:26:49 +0100503 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800504 cmd.params := {
Harald Welteba62c8c2017-11-18 18:26:49 +0100505 ts_MgcpParCallId(call_id),
Harald Weltee636afd2017-09-17 16:24:09 +0800506 t_MgcpParLocConnOpt("p:20")
507 }
508 resp := mgcp_transceive_mgw(cmd, rtmpl);
509 setverdict(pass);
510 }
511
512 /* test CRCX with unsupported packetization interval */
513 testcase TC_crcx_unsupp_packet_intv() runs on dummy_CT {
514 var template MgcpCommand cmd;
515 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100516 var MgcpEndpoint ep := "2@mgw";
517 var MgcpCallId call_id := '1228'H;
Harald Welte0d198612017-11-18 19:58:31 +0100518 var template MgcpResponse rtmpl := tr_MgcpResp_Err("535");
Harald Weltee636afd2017-09-17 16:24:09 +0800519
Harald Welteedc45c12017-11-18 19:15:05 +0100520 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800521
Harald Welteba62c8c2017-11-18 18:26:49 +0100522 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100523 cmd.params[2] := t_MgcpParLocConnOpt("p:111");
Harald Weltee636afd2017-09-17 16:24:09 +0800524 resp := mgcp_transceive_mgw(cmd, rtmpl);
525 setverdict(pass);
526 }
527
528 /* test CRCX with illegal double presence of local connection option */
529 testcase TC_crcx_illegal_double_lco() runs on dummy_CT {
530 var template MgcpCommand cmd;
531 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100532 var MgcpEndpoint ep := "2@mgw";
533 var MgcpCallId call_id := '1227'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800534 var template MgcpResponse rtmpl := tr_MgcpResp_Err("524");
535
Harald Welteedc45c12017-11-18 19:15:05 +0100536 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800537
Harald Welteba62c8c2017-11-18 18:26:49 +0100538 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Weltea01e38d2017-11-18 18:40:01 +0100539 /* p:20 is permitted only once and not twice! */
540 cmd.params[2] := t_MgcpParLocConnOpt("p:20, a:AMR, p:20");
Harald Weltee636afd2017-09-17 16:24:09 +0800541 resp := mgcp_transceive_mgw(cmd, rtmpl);
542 setverdict(pass);
543 }
544
545 /* test valid CRCX with valid SDP */
546 testcase TC_crcx_sdp() runs on dummy_CT {
547 var template MgcpCommand cmd;
548 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100549 var MgcpEndpoint ep := "2@mgw";
550 var MgcpCallId call_id := '1226'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800551
Harald Welteedc45c12017-11-18 19:15:05 +0100552 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800553
Harald Welteba62c8c2017-11-18 18:26:49 +0100554 cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800555 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
556 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
557 valueof(ts_SDP_ptime(20)) });
Harald Welte9988d282017-11-18 19:22:00 +0100558 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Weltee636afd2017-09-17 16:24:09 +0800559 setverdict(pass);
560 }
561
562 /* TODO: various SDP related bits */
563
564
565 /* TODO: CRCX with X-Osmux */
566 /* TODO: double CRCX without force_realloc */
567
568 /* TODO: MDCX (various) */
569
570 /* TODO: MDCX without CRCX first */
571 testcase TC_mdcx_without_crcx() runs on dummy_CT {
572 var template MgcpCommand cmd;
573 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100574 var MgcpEndpoint ep := "3@mgw";
575 var MgcpCallId call_id := '1225'H;
Harald Weltee636afd2017-09-17 16:24:09 +0800576 var template MgcpResponse rtmpl := {
577 line := {
578 /* TODO: accept/enforce better error? */
579 code := "400",
580 string := ?
581 },
582 params:= { },
583 sdp := omit
584 };
585
Harald Welteedc45c12017-11-18 19:15:05 +0100586 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800587
Harald Welteba62c8c2017-11-18 18:26:49 +0100588 cmd := ts_MDCX(get_next_trans_id(), ep, "sendrecv", call_id);
Harald Weltee636afd2017-09-17 16:24:09 +0800589 cmd.sdp := ts_SDP("127.0.0.1", "127.0.0.2", "23", "42", 2344, { "98" },
590 { valueof(ts_SDP_rtpmap(98, "AMR/8000")),
591 valueof(ts_SDP_ptime(20)) });
592 resp := mgcp_transceive_mgw(cmd, rtmpl);
593 setverdict(pass);
594 }
595
596 /* DLCX without CRCX first */
597 testcase TC_dlcx_without_crcx() runs on dummy_CT {
598 var template MgcpCommand cmd;
599 var MgcpResponse resp;
Harald Welteedc45c12017-11-18 19:15:05 +0100600 var MgcpEndpoint ep := "4@mgw";
Harald Weltee636afd2017-09-17 16:24:09 +0800601 var template MgcpResponse rtmpl := {
602 line := {
603 /* TODO: accept/enforce better error? */
604 code := "400",
605 string := ?
606 },
607 params:= { },
608 sdp := omit
609 };
610
Harald Welteedc45c12017-11-18 19:15:05 +0100611 f_init(ep);
Harald Weltee636afd2017-09-17 16:24:09 +0800612
Harald Welteedc45c12017-11-18 19:15:05 +0100613 cmd := ts_DLCX(get_next_trans_id(), ep, '41234'H);
Harald Weltee636afd2017-09-17 16:24:09 +0800614 resp := mgcp_transceive_mgw(cmd, rtmpl);
615 setverdict(pass);
616 }
617
Harald Welte79181ff2017-11-18 19:26:11 +0100618 /* Test (valid) CRCX followed by (valid) DLCX containig EP+CallId+ConnId */
619 testcase TC_crcx_and_dlcx_ep_callid_connid() runs on dummy_CT {
620 var template MgcpCommand cmd;
621 var MgcpResponse resp;
622 var MgcpEndpoint ep := "5@mgw";
623 var MgcpCallId call_id := '51234'H;
624
625 f_init(ep);
626
627 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
628 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
629
630 f_dlcx_ok(ep, call_id, extract_conn_id(resp));
631
632 setverdict(pass);
633 }
634
635 /* Test (valid) CRCX followed by (valid) DLCX containing EP+CallId */
636 testcase TC_crcx_and_dlcx_ep_callid() runs on dummy_CT {
Harald Welte5b4c44e2017-09-17 16:35:27 +0800637 var template MgcpCommand cmd;
638 var MgcpResponse resp;
Harald Welteba62c8c2017-11-18 18:26:49 +0100639 var MgcpEndpoint ep := "5@mgw";
Harald Welte6d167f82017-11-18 19:41:35 +0100640 var MgcpCallId call_id := '51233'H;
Harald Welte5b4c44e2017-09-17 16:35:27 +0800641
Harald Welteedc45c12017-11-18 19:15:05 +0100642 f_init(ep);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800643
Harald Welteba62c8c2017-11-18 18:26:49 +0100644 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
Harald Welte9988d282017-11-18 19:22:00 +0100645 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800646
Harald Welteba62c8c2017-11-18 18:26:49 +0100647 f_dlcx_ok(ep, call_id);
Harald Welte5b4c44e2017-09-17 16:35:27 +0800648
649 setverdict(pass);
650 }
651
Harald Welte79181ff2017-11-18 19:26:11 +0100652 /* Test (valid) CRCX followed by (valid) DLCX containing EP */
653 testcase TC_crcx_and_dlcx_ep() runs on dummy_CT {
654 var template MgcpCommand cmd;
655 var MgcpResponse resp;
656 var MgcpEndpoint ep := "5@mgw";
Harald Welte6d167f82017-11-18 19:41:35 +0100657 var MgcpCallId call_id := '51232'H;
Harald Welte79181ff2017-11-18 19:26:11 +0100658
659 f_init(ep);
660
661 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
662 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
663
664 f_dlcx_ok(ep);
665
666 setverdict(pass);
667 }
668
669
Harald Welte6d167f82017-11-18 19:41:35 +0100670 /* CRCX + DLCX of valid endpoint but invalid call-id */
671 testcase TC_crcx_and_dlcx_ep_callid_inval() runs on dummy_CT {
672 var template MgcpCommand cmd;
673 var MgcpResponse resp;
674 var MgcpEndpoint ep := "5@mgw";
675 var MgcpCallId call_id := '51231'H;
676
677 f_init(ep);
678
679 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
680 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
681
682 f_dlcx(ep, "516", *, 'ffff'H);
683
684 setverdict(pass);
685 }
686
687
688 /* CRCX + DLCX of valid endpoint and call-id but invalid conn-id */
689 testcase TC_crcx_and_dlcx_ep_callid_connid_inval() runs on dummy_CT {
690 var template MgcpCommand cmd;
691 var MgcpResponse resp;
692 var MgcpEndpoint ep := "5@mgw";
693 var MgcpCallId call_id := '51230'H;
694
695 f_init(ep);
696
697 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
698 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
699
700 f_dlcx(ep, "515", *, call_id, 'ffff'H);
701
702 setverdict(pass);
703 }
704
705
Harald Weltee636afd2017-09-17 16:24:09 +0800706 /* TODO: Double-DLCX (retransmission) */
Harald Weltef53f1642017-11-18 19:57:11 +0100707 testcase TC_crcx_and_dlcx_retrans() runs on dummy_CT {
708 var template MgcpCommand cmd;
709 var MgcpResponse resp;
710 var MgcpEndpoint ep := "5@mgw";
711 var MgcpCallId call_id := '51229'H;
712 var template MgcpResponse rtmpl := {
713 line := {
714 code := "200",
715 string := "OK"
716 },
717 params:= { },
718 sdp := omit
719 };
720
721 f_init(ep);
722
723 cmd := ts_CRCX(get_next_trans_id(), ep, "recvonly", call_id);
724 resp := mgcp_transceive_mgw(cmd, tr_CRCX_ACK);
725
726 cmd := ts_DLCX(get_next_trans_id(), ep, call_id);
727 resp := mgcp_transceive_mgw(cmd, rtmpl);
728 resp := mgcp_transceive_mgw(cmd, rtmpl);
729
730 setverdict(pass);
731 }
732
733
734
Harald Weltee636afd2017-09-17 16:24:09 +0800735 /* TODO: Double-DLCX (no retransmission) */
736
737
738
739 /* TODO: AUEP (various) */
740 /* TODO: RSIP (various) */
741 /* TODO: RQNT (various) */
742 /* TODO: EPCF (various) */
743 /* TODO: AUCX (various) */
744 /* TODO: invalid verb (various) */
745
Harald Welte00a067f2017-09-13 23:27:17 +0200746 control {
747 execute(TC_selftest());
Harald Welte3c6ebb92017-09-16 00:56:57 +0800748 execute(TC_crcx());
Harald Weltee636afd2017-09-17 16:24:09 +0800749 execute(TC_crcx_unsupp_mode());
750 execute(TC_crcx_early_bidir_mode());
751 execute(TC_crcx_unsupp_param());
752 execute(TC_crcx_missing_callid());
753 execute(TC_crcx_missing_mode());
754 execute(TC_crcx_unsupp_packet_intv());
755 execute(TC_crcx_illegal_double_lco());
756 execute(TC_crcx_sdp());
757 execute(TC_mdcx_without_crcx());
758 execute(TC_dlcx_without_crcx());
Harald Welte79181ff2017-11-18 19:26:11 +0100759 execute(TC_crcx_and_dlcx_ep_callid_connid());
760 execute(TC_crcx_and_dlcx_ep_callid());
761 execute(TC_crcx_and_dlcx_ep());
Harald Welte6d167f82017-11-18 19:41:35 +0100762 execute(TC_crcx_and_dlcx_ep_callid_inval());
763 execute(TC_crcx_and_dlcx_ep_callid_connid_inval());
Harald Weltef53f1642017-11-18 19:57:11 +0100764 execute(TC_crcx_and_dlcx_retrans());
Harald Welte00a067f2017-09-13 23:27:17 +0200765 }
766}