blob: 10f8b4d9a878008fd69b295906e992a83385d14c [file] [log] [blame]
Harald Welteafec4712018-03-19 22:52:17 +01001module SIP_Tests {
2
Harald Welte34b5a952019-05-27 11:54:11 +02003/* osmo-sip-connector test suite in TTCN-3
4 * (C) 2018-2019 Harald Welte <laforge@gnumonks.org>
5 * All rights reserved.
6 *
7 * Released under the terms of GNU General Public License, Version 2 or
8 * (at your option) any later version.
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
Harald Welteafec4712018-03-19 22:52:17 +010013import from General_Types all;
14import from Osmocom_Types all;
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +020015import from Native_Functions all;
16import from Misc_Helpers all;
Harald Welteafec4712018-03-19 22:52:17 +010017
18import from Osmocom_CTRL_Functions all;
19import from Osmocom_CTRL_Types all;
20import from Osmocom_CTRL_Adapter all;
21
22import from TELNETasp_PortType all;
23import from Osmocom_VTY_Functions all;
24
25import from MNCC_Emulation all;
26import from MNCC_Types all;
27
28import from SDP_Types all;
Pau Espin Pedrolf3713752024-03-21 17:32:55 +010029import from SDP_Templates all;
Harald Welteafec4712018-03-19 22:52:17 +010030
31import from SIP_Emulation all;
32import from SIPmsg_Types all;
Harald Welteb0d93602018-03-20 18:09:34 +010033import from SIP_Templates all;
Harald Welteafec4712018-03-19 22:52:17 +010034
35modulepar {
Harald Welteb0d93602018-03-20 18:09:34 +010036 charstring mp_local_host := "127.0.0.2";
Harald Welteafec4712018-03-19 22:52:17 +010037 charstring mp_osmosip_host := "127.0.0.1";
38 integer mp_osmosip_port_ctrl := -1; /* RFU */
39 charstring mp_mncc := "/tmp/mncc";
40}
41
42type component test_CT extends CTRL_Adapter_CT {
43 var MNCC_Emulation_CT vc_MNCC;
44 var SIP_Emulation_CT vc_SIP;
45
46 port TELNETasp_PT SIPVTY;
47}
48
49type component ConnHdlr extends SIP_ConnHdlr, MNCC_ConnHdlr {
50 var ConnHdlrPars g_pars;
51 timer g_Tguard;
52}
53
54type record ConnHdlrPars {
Harald Welteb0d93602018-03-20 18:09:34 +010055 float t_guard,
56 CallPars g_cp optional
57}
58
59type record CallPars {
60 boolean is_mo,
61 charstring calling,
62 charstring called,
63
64 uint32_t mncc_call_id optional,
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +020065 CallParsComputed comp optional,
Harald Welteb0d93602018-03-20 18:09:34 +010066
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +020067 charstring sip_rtp_addr,
68 uint16_t sip_rtp_port,
69 charstring cn_rtp_addr,
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +020070 uint16_t cn_rtp_port,
71
72 /* Send SDP to MNCC, and expect to receive SDP from MNCC. mncc_with_sdp := false tests legacy compatibility to
73 * the time when we did not include SDP in MNCC messages. mncc_with_sdp := true expects SDP to pass through the
74 * SUT osmo-sip-connector unchanged. */
75 boolean mncc_with_sdp
Harald Welteb0d93602018-03-20 18:09:34 +010076}
77
78type record CallParsComputed {
79 CallidString sip_call_id,
80 SipAddr sip_url_ext,
81 SipAddr sip_url_gsm,
82 charstring sip_body,
83 integer sip_seq_nr
84}
85
Neels Hofmeyra0d015b2023-09-13 04:32:14 +020086private template (value) CallPars t_CallPars(boolean is_mo, boolean mncc_with_sdp := true) := {
Harald Welteb0d93602018-03-20 18:09:34 +010087 is_mo := is_mo,
88 calling := "12345",
89 called := "98766",
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +020090
Harald Welteb0d93602018-03-20 18:09:34 +010091 mncc_call_id := omit,
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +020092 comp := omit,
93 sip_rtp_addr := "1.2.3.4",
94 sip_rtp_port := 1234,
95 cn_rtp_addr := "5.6.7.8",
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +020096 cn_rtp_port := 5678,
97 mncc_with_sdp := mncc_with_sdp
Harald Welteb0d93602018-03-20 18:09:34 +010098}
99
100private function f_CallPars_compute(inout CallPars cp) {
101 if (cp.is_mo) {
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100102 cp.comp.sip_url_ext := valueof(ts_SipAddr(ts_HostPort(mp_local_host, 5060),
103 ts_UserInfo(cp.called)));
104 cp.comp.sip_url_gsm := valueof(ts_SipAddr(ts_HostPort(mp_osmosip_host, 5060),
105 ts_UserInfo(cp.calling)));
Pau Espin Pedrol6052a342024-03-28 20:20:46 +0100106 cp.mncc_call_id := f_sip_rand_seq_nr();
Harald Welteb0d93602018-03-20 18:09:34 +0100107 } else {
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100108 cp.comp.sip_url_ext := valueof(ts_SipAddr(ts_HostPort(mp_local_host, 5060),
109 ts_UserInfo(cp.calling)));
110 cp.comp.sip_url_gsm := valueof(ts_SipAddr(ts_HostPort(mp_osmosip_host, 5060),
111 ts_UserInfo(cp.called)));
Harald Welteb0d93602018-03-20 18:09:34 +0100112 cp.comp.sip_call_id := hex2str(f_rnd_hexstring(15));
113 }
Pau Espin Pedrol6052a342024-03-28 20:20:46 +0100114 cp.comp.sip_seq_nr := f_sip_rand_seq_nr();
Harald Welteb0d93602018-03-20 18:09:34 +0100115 cp.comp.sip_body := "";
Harald Welteafec4712018-03-19 22:52:17 +0100116}
117
Harald Welteafec4712018-03-19 22:52:17 +0100118function f_init_mncc(charstring id) runs on test_CT {
119 id := id & "-MNCC";
120 var MnccOps ops := {
121 create_cb := refers(MNCC_Emulation.ExpectedCreateCallback),
122 unitdata_cb := refers(MNCC_Emulation.DummyUnitdataCallback)
123 };
124
Pau Espin Pedrole94a6482024-04-10 13:37:55 +0200125 vc_MNCC := MNCC_Emulation_CT.create(id) alive;
Harald Welteafec4712018-03-19 22:52:17 +0100126 map(vc_MNCC:MNCC, system:MNCC_CODEC_PT);
127 vc_MNCC.start(MNCC_Emulation.main(ops, id, mp_mncc, true));
128}
129
130function f_init() runs on test_CT {
Pau Espin Pedrol9a5b8ff2021-01-04 19:01:31 +0100131 //f_ipa_ctrl_start_client(mp_osmosip_host, mp_osmosip_port_ctrl);
Harald Welteafec4712018-03-19 22:52:17 +0100132 f_init_mncc("SIP_Test");
133 log("end of f_init_mncc");
Pau Espin Pedrol1a771342024-04-25 14:42:50 +0200134 f_init_sip(vc_SIP, "SIP_Test_SIP_EMU");
Harald Welteafec4712018-03-19 22:52:17 +0100135 log("end of f_init_sip");
136
137 map(self:SIPVTY, system:SIPVTY);
138 f_vty_set_prompts(SIPVTY);
139 f_vty_transceive(SIPVTY, "enable");
140 log("end of f_init");
141}
142
143type function void_fn(charstring id) runs on ConnHdlr;
144
145function f_start_handler(void_fn fn, ConnHdlrPars pars)
146runs on test_CT return ConnHdlr {
147 var ConnHdlr vc_conn;
148 var charstring id := testcasename();
149
Pau Espin Pedrole94a6482024-04-10 13:37:55 +0200150 vc_conn := ConnHdlr.create(id) alive;
Harald Welteafec4712018-03-19 22:52:17 +0100151
152 connect(vc_conn:SIP, vc_SIP:CLIENT);
153 connect(vc_conn:SIP_PROC, vc_SIP:CLIENT_PROC);
154
155 connect(vc_conn:MNCC, vc_MNCC:MNCC_CLIENT);
156 connect(vc_conn:MNCC_PROC, vc_MNCC:MNCC_PROC);
157
158 vc_conn.start(f_handler_init(fn, id, pars));
159 return vc_conn;
160}
161
162private altstep as_Tguard() runs on ConnHdlr {
163 [] g_Tguard.timeout {
164 setverdict(fail, "Tguard timeout");
Daniel Willmannafce8662018-07-06 23:11:32 +0200165 mtc.stop;
Harald Welteafec4712018-03-19 22:52:17 +0100166 }
167}
168
169private function f_handler_init(void_fn fn, charstring id, ConnHdlrPars pars)
170runs on ConnHdlr {
171 g_pars := pars;
172 g_Tguard.start(pars.t_guard);
173 activate(as_Tguard());
174
175 /* call the user-supied test case function */
176 fn.apply(id);
177}
178
179
180template (value) ConnHdlrPars t_Pars := {
Harald Welteb0d93602018-03-20 18:09:34 +0100181 t_guard := 30.0,
182 g_cp := omit
Harald Welteafec4712018-03-19 22:52:17 +0100183}
184
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200185altstep as_SIP_expect_resp(template PDU_SIP_Response sip_expect) runs on ConnHdlr
186{
187 [] SIP.receive(sip_expect);
188 [] SIP.receive {
189 log("FAIL: expected SIP message ", sip_expect);
190 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received unexpected SIP message");
191 }
192}
193
194function f_SIP_expect_req(template PDU_SIP_Request sip_expect) runs on ConnHdlr return PDU_SIP_Request
195{
196 var PDU_SIP_Request rx;
197 alt {
198 [] SIP.receive(sip_expect) -> value rx;
199 [] SIP.receive {
200 log("FAIL: expected SIP message ", sip_expect);
201 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received unexpected SIP message");
202 }
203 }
204 return rx;
205}
206
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200207/* Update 'last_sdp', and match with expectation of what the current SDP should be.
208 * Useful to ensure that MNCC or SIP send and possibly resend only the expected SDP.
209 * last_sdp keeps the last non-empty rx_sdp, across multiple check_sdp() invocations.
210 * rx_sdp is the SDP charstring just received. If it is nonempty, update last_sdp to rx_sdp.
211 * After updating last_sdp as appropriate, match last_sdp with expect_sdp. */
212private function check_sdp(inout charstring last_sdp,
213 charstring rx_sdp,
214 template charstring expect_sdp)
215{
216 /* If there is new SDP, store it. */
217 if (lengthof(rx_sdp) > 0) {
218 if (last_sdp != rx_sdp) {
219 log("SDP update from ", last_sdp, " to ", rx_sdp);
220 }
221
222 /* If MNCC sent SDP data, remember it as the last valid SDP */
223 last_sdp := rx_sdp;
224 }
225 /* Validate expectations of the SDP data */
226 if (not match(last_sdp, expect_sdp)) {
227 log("FAIL: expected SDP ", expect_sdp, " but got ", last_sdp);
228 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "unexpected SDP");
229 }
230}
231
Harald Welteb0d93602018-03-20 18:09:34 +0100232/* Establish a mobile terminated call described in 'cp' */
233function f_establish_mt(inout CallPars cp) runs on ConnHdlr {
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200234 var template (value) From from_addr := ts_From(cp.comp.sip_url_ext.addr, cp.comp.sip_url_ext.params);
235 var template (value) To to_addr := ts_To(cp.comp.sip_url_gsm.addr, cp.comp.sip_url_gsm.params);
236 var template (value) Via via := ts_Via_from(cp.comp.sip_url_ext.addr.nameAddr.addrSpec.hostPort);
237 var template (present) From from_addr_exp := tr_From(tr_Addr_Union_from_val(cp.comp.sip_url_ext.addr), *);
238 var template (present) To to_addr_exp := tr_To(tr_Addr_Union_from_val(cp.comp.sip_url_gsm.addr), *);
239 var template (present) Via via_exp := tr_Via_from(f_tr_HostPort_opt_defport(from_addr_exp.addressField.nameAddr.addrSpec.hostPort));
Harald Welteb0d93602018-03-20 18:09:34 +0100240 var MNCC_PDU mncc;
Harald Welteafec4712018-03-19 22:52:17 +0100241
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200242 /* The last SDP that the MSC received via MNCC from osmo-sip-connector */
243 var charstring sdp_to_msc := "";
244 /* At first, allow any empty and nonempty SDP. As the test progresses, this may expect specific SDP instead. */
245 var template charstring expect_sdp_to_msc := *;
246
247 /* If cp.mncc_with_sdp == true, expect SDP forwarding like this:
248 *
249 * SDP1: SIP agent's RTP and codec info
250 * SDP2: osmo-msc's RTP and codec info
251 *
252 * MNCC osmo-sip-connector SIP
253 * |<--SDP1----- SIP Invite
254 * |-----------> SIP (Invite) Trying
255 * <--SDP1-------| MNCC SETUP req
256 * ------------->| MNCC CALL CONF ind
257 * <-------------| MNCC RTP CREATE (SDP optional, still unchanged from SDP1)
258 * -------SDP2-->| MNCC RTP CREATE
259 * ------------->| MNCC ALERT ind
260 * |--------------> SIP (Invite) Ringing
261 * (MT picks up) |
262 * ------------->| MNCC SETUP CNF
263 * <-------------| MNCC RTP CONNECT (SDP optional, still unchanged from SDP1)
264 * |--------SDP2--> SIP (Invite) OK
265 * |<-------------- SIP ACK
266 * <-------------| MNCC SETUP COMPL (SDP optional, still unchanged from SDP1)
267 */
268
Harald Welteb0d93602018-03-20 18:09:34 +0100269 /* Ask MNCC_Emulation to "expect" a call to the given called number */
270 f_create_mncc_expect(cp.called);
Harald Welteafec4712018-03-19 22:52:17 +0100271
Harald Welteb0d93602018-03-20 18:09:34 +0100272 /* OSC <- SIP: A party sends SIP invite for a MT-call into OSC */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200273 SIP.send(ts_SIP_INVITE(cp.comp.sip_call_id, from_addr, to_addr,
274 via,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200275 ts_Contact_SipAddr(cp.comp.sip_url_ext),
Pau Espin Pedrolce370df2024-06-18 13:45:53 +0200276 cp.comp.sip_seq_nr,
277 body := cp.comp.sip_body));
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200278 if (cp.mncc_with_sdp) {
279 /* We just sent SDP via SIP, now expect the same SDP in MNCC to the MSC */
280 expect_sdp_to_msc := cp.comp.sip_body;
281 }
282
Harald Welteb0d93602018-03-20 18:09:34 +0100283 /* OSC -> SIP */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200284 as_SIP_expect_resp(tr_SIP_Response(cp.comp.sip_call_id, from_addr_exp, to_addr_exp,
285 via_exp,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200286 *,
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200287 "INVITE", 100, ?, "Trying", *));
Harald Welteafec4712018-03-19 22:52:17 +0100288
Pau Espin Pedrol37cf4082020-09-23 16:59:16 +0200289 alt {
290 /* MSC <- OSC: OSC generates MNCC_SETUP_REQ from INVITE */
291 [] MNCC.receive(tr_MNCC_SETUP_req) -> value mncc {
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200292 cp.mncc_call_id := mncc.u.signal.callref;
293 /* Expect the SDP sent via SIP to arrive in MNCC */
294 check_sdp(sdp_to_msc, mncc.u.signal.sdp, expect_sdp_to_msc);
Pau Espin Pedrol37cf4082020-09-23 16:59:16 +0200295 }
296 [] SIP.receive {
Neels Hofmeyrbaf02722023-09-12 02:10:11 +0200297 setverdict(fail, "Received unexpected SIP response");
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200298 SIP.send(ts_SIP_ACK(cp.comp.sip_call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200299 from_addr, to_addr,
300 via,
Pau Espin Pedrol37cf4082020-09-23 16:59:16 +0200301 cp.comp.sip_seq_nr, omit));
302 mtc.stop;
303 }
304 }
305
Harald Welteb0d93602018-03-20 18:09:34 +0100306 /* MSC -> OSC: After MS sends CALL CONF in response to SETUP */
307 MNCC.send(ts_MNCC_CALL_CONF_ind(cp.mncc_call_id));
308 /* MSC <- OSC: OSC asks MSC to create RTP socket */
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200309 MNCC.receive(tr_MNCC_RTP_CREATE(cp.mncc_call_id)) -> value mncc {
310 check_sdp(sdp_to_msc, mncc.u.rtp.sdp, expect_sdp_to_msc);
311 }
312
313 /* MSC -> OSC: SDP that the MSC will send via MNCC */
314 var charstring cn_sdp := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
Pau Espin Pedrolf3713752024-03-21 17:32:55 +0100315 f_sdp_addr2addrtype(cp.cn_rtp_addr) & " " & cp.cn_rtp_addr &
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200316 "\r\nt=0 0\r\nm=audio " & int2str(cp.cn_rtp_port) &
317 " RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
318 /* OSC -> SIP: what SDP to expect in SIP from osmo-sip-connector */
319 var template charstring expect_sdp_to_sip := pattern "*" & cp.cn_rtp_addr & "*";
320
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200321 mncc := valueof(ts_MNCC_RTP_CREATE(cp.mncc_call_id));
322 mncc.u.rtp.is_ipv6 := f_addr_is_ipv6(cp.cn_rtp_addr);
323 mncc.u.rtp.ip := f_addrstr2addr(cp.cn_rtp_addr);
324 mncc.u.rtp.rtp_port := cp.cn_rtp_port;
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200325 if (cp.mncc_with_sdp) {
326 /* MSC -> OSC: tell OSC our RTP info in SDP form */
327 mncc.u.rtp.sdp := cn_sdp;
328 /* OSC -> SIP: and expect it unchanged on SIP later, but allow osmo-sip-connector to append an
329 * "a=sendrecv;" */
330 expect_sdp_to_sip := pattern cn_sdp & "*";
331 }
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200332 MNCC.send(mncc);
Harald Welteafec4712018-03-19 22:52:17 +0100333
Harald Welteb0d93602018-03-20 18:09:34 +0100334 /* MSC -> OSC: After MS is ringing and sent CC ALERTING */
335 MNCC.send(ts_MNCC_ALERT_ind(cp.mncc_call_id));
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200336
337 /* Now expect SIP response "Ringing" back to MO, containing the same SDP information as in the MNCC RTP CREATE
338 * sent to OSC above */
Harald Welteb0d93602018-03-20 18:09:34 +0100339 SIP.clear;
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200340
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200341 /* 180 Ringing should not contain any SDP. */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200342 as_SIP_expect_resp(tr_SIP_Response(cp.comp.sip_call_id, from_addr_exp, to_addr_exp,
343 via_exp,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200344 *,
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200345 "INVITE", 180, ?, "Ringing", omit));
Harald Welteafec4712018-03-19 22:52:17 +0100346
Harald Welteb0d93602018-03-20 18:09:34 +0100347 /* MSC -> OSC: After MT user has picked up and sent CC CONNECT */
348 MNCC.send(ts_MNCC_SETUP_CNF(cp.mncc_call_id));
349
350 SIP.clear;
Harald Welteb0d93602018-03-20 18:09:34 +0100351 /* MSC <- OSC: OSC asks MSC to connect its RTP stream to remote end */
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200352 MNCC.receive(tr_MNCC_RTP_CONNECT(cp.mncc_call_id, f_addrstr2addr(cp.sip_rtp_addr), cp.sip_rtp_port))
353 -> value mncc {
354 check_sdp(sdp_to_msc, mncc.u.rtp.sdp, expect_sdp_to_msc);
355 }
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200356
Harald Welteb0d93602018-03-20 18:09:34 +0100357 /* OSC -> SIP: OSC confirms call establishment to SIP side */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200358 as_SIP_expect_resp(tr_SIP_Response(cp.comp.sip_call_id, from_addr_exp, to_addr_exp,
359 via_exp,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200360 contact := ?,
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200361 method := "INVITE", status_code := 200,
362 seq_nr := ?, reason := "OK",
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200363 body := expect_sdp_to_sip));
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200364
Harald Welteb0d93602018-03-20 18:09:34 +0100365 /* OSC <- SIP: SIP world acknowledges "200 OK" */
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200366 SIP.send(ts_SIP_ACK(cp.comp.sip_call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200367 from_addr, to_addr,
368 via,
Harald Welteb0d93602018-03-20 18:09:34 +0100369 cp.comp.sip_seq_nr, omit));
370 /* MSC <- OSC: OSC sends SETUP COMPL to MNCC (which triggers CC CONNECT ACK */
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200371 MNCC.receive(tr_MNCC_SETUP_COMPL_req(cp.mncc_call_id)) -> value mncc {
372 check_sdp(sdp_to_msc, mncc.u.signal.sdp, expect_sdp_to_msc);
373 }
Harald Welteafec4712018-03-19 22:52:17 +0100374}
375
Harald Welteb0d93602018-03-20 18:09:34 +0100376/* Establish a mobile originated call described in 'cp' */
377function f_establish_mo(inout CallPars cp) runs on ConnHdlr {
378 var MNCC_number dst := valueof(ts_MNCC_number(cp.called, GSM48_TON_UNKNOWN));
379 var MNCC_number src := valueof(ts_MNCC_number(cp.calling, GSM48_TON_UNKNOWN));
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200380
381 var template (value) From from_addr := ts_From(cp.comp.sip_url_gsm.addr, cp.comp.sip_url_gsm.params);
382 var template (value) To to_addr := ts_To(cp.comp.sip_url_ext.addr, cp.comp.sip_url_ext.params);
383 var template (value) Via via := ts_Via_from(cp.comp.sip_url_gsm.addr.nameAddr.addrSpec.hostPort);
384 var template (present) From from_addr_exp := tr_From(tr_Addr_Union_from_val(cp.comp.sip_url_gsm.addr), *);
385 var template (present) To to_addr_exp := tr_To(tr_Addr_Union_from_val(cp.comp.sip_url_ext.addr), *);
386 var template (present) Via via_exp := tr_Via_from(f_tr_HostPort_opt_defport(from_addr_exp.addressField.nameAddr.addrSpec.hostPort));
387
388
Harald Welteb0d93602018-03-20 18:09:34 +0100389 var PDU_SIP_Request sip_req;
390 var integer seq_nr;
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200391 var MNCC_PDU mncc;
392
393 /* The last SDP that the MSC received via MNCC from osmo-sip-connector */
394 var charstring sdp_to_msc := "";
395 /* At first, allow any empty and nonempty SDP. As the test progresses, this may expect specific SDP instead. */
396 var template charstring expect_sdp_to_msc := *;
397
398 /* If cp.mncc_with_sdp == true, expect SDP forwarding like this:
399 *
400 * SDP1: osmo-msc's RTP and codec info
401 * SDP2: SIP agent's RTP and codec info
402 *
403 * MNCC osmo-sip-connector SIP
404 * -------SDP1-->| MNCC SETUP ind
405 * <-------------| MNCC RTP CREATE (?)
406 * |-----SDP1--> SIP Invite
407 * |<----------- SIP (Invite) Trying
408 * <-------------| MNCC CALL PROC req
409 * |<----------- SIP (Invite) Ringing
410 * <-------------| MNCC ALERT req
411 * | (MT picks up)
412 * |<--SDP2----- SIP (Invite) OK
413 * <--SDP2-------| MNCC RTP CONNECT (SDP optional, still unchanged from SDP2)
414 * <-------------| MNCC SETUP rsp (SDP optional, still unchanged from SDP2)
415 * ------------->| MNCC SETUP COMPL ind (SDP optional, still unchanged from SDP1)
416 * |------------> SIP ACK
417 */
418
419 var charstring cn_sdp := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
Pau Espin Pedrolf3713752024-03-21 17:32:55 +0100420 f_sdp_addr2addrtype(cp.cn_rtp_addr) & " " & cp.cn_rtp_addr &
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200421 "\r\nt=0 0\r\nm=audio " & int2str(cp.cn_rtp_port) &
422 " RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
Harald Welteb0d93602018-03-20 18:09:34 +0100423
424 f_create_sip_expect(cp.comp.sip_url_ext.addr.nameAddr.addrSpec);
425
426 /* MSC -> OSC: MSC sends SETUP.ind after CC SETUP was received from MS */
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200427 mncc := valueof(ts_MNCC_SETUP_ind(cp.mncc_call_id, dst, src, "262420123456789"));
428 if (cp.mncc_with_sdp) {
429 mncc.u.signal.sdp := cn_sdp;
430 }
431 MNCC.send(mncc);
432
Harald Welteb0d93602018-03-20 18:09:34 +0100433 /* MSC <- OSC: Create GSM side RTP socket */
434 MNCC.receive(tr_MNCC_RTP_CREATE(cp.mncc_call_id)) {
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200435 mncc := valueof(ts_MNCC_RTP_CREATE(cp.mncc_call_id));
Harald Welteb0d93602018-03-20 18:09:34 +0100436 mncc.u.rtp.payload_msg_type := oct2int('0300'O);
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200437 /* FIXME: makes no sense to send cp.cn_rtp_addr back to the cn. */
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200438 mncc.u.rtp.is_ipv6 := f_addr_is_ipv6(cp.cn_rtp_addr);
439 mncc.u.rtp.ip := f_addrstr2addr(cp.cn_rtp_addr);
440 mncc.u.rtp.rtp_port := cp.cn_rtp_port;
441 MNCC.send(mncc);
Harald Welteb0d93602018-03-20 18:09:34 +0100442 }
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200443
Harald Welteb0d93602018-03-20 18:09:34 +0100444 /* OSC -> SIP: Send INVITE with GSM side IP/Port in SDP */
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200445 var template charstring expect_sdp_to_sip := ?;
446 if (cp.mncc_with_sdp) {
447 /* Expect the same SDP as sent to osmo-sip-connector in MNCC, and allow osmo-sip-connector to append an
448 * "a=sendrecv;" */
449 expect_sdp_to_sip := pattern cn_sdp & "*";
450 }
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200451 sip_req := f_SIP_expect_req(tr_SIP_INVITE(to_addr_exp.addressField.nameAddr.addrSpec, ?,
452 from_addr_exp, to_addr_exp,
453 via_exp,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200454 ?, expect_sdp_to_sip));
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200455 from_addr.fromParams := sip_req.msgHeader.fromField.fromParams;
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200456 cp.comp.sip_call_id := sip_req.msgHeader.callId.callid;
457 seq_nr := sip_req.msgHeader.cSeq.seqNumber;
458
Harald Welteb0d93602018-03-20 18:09:34 +0100459 /* OSC <- SIP: Notify call is proceeding */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200460 SIP.send(ts_SIP_Response(cp.comp.sip_call_id, from_addr, to_addr,
Harald Welteb0d93602018-03-20 18:09:34 +0100461 "INVITE", 100, seq_nr, "Trying", sip_req.msgHeader.via));
462 /* MSC <- OSC: "100 Trying" translated to MNCC_CALL_PROC_REQ */
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200463 MNCC.receive(tr_MNCC_CALL_PROC_req(cp.mncc_call_id)) -> value mncc {
464 check_sdp(sdp_to_msc, mncc.u.signal.sdp, "");
465 }
Harald Welteb0d93602018-03-20 18:09:34 +0100466
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200467 /* OSC <- SIP: SIP-terminated user is ringing now. 180 Ringing should not contain any SDP. */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200468 SIP.send(ts_SIP_Response(cp.comp.sip_call_id, from_addr, to_addr,
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200469 "INVITE", 180, seq_nr, "Ringing", sip_req.msgHeader.via, omit));
Harald Welteb0d93602018-03-20 18:09:34 +0100470
471 /* MSC <- OSC: "180 Ringing" translated to MNCC_ALERT_REQ */
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200472 MNCC.receive(tr_MNCC_ALERT_req(cp.mncc_call_id)) -> value mncc {
473 check_sdp(sdp_to_msc, mncc.u.signal.sdp, expect_sdp_to_msc);
474 }
Harald Welteb0d93602018-03-20 18:09:34 +0100475
476 /* OSC <- SIP: SIP-terminated user has accepted the call */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200477 SIP.send(ts_SIP_Response(cp.comp.sip_call_id, from_addr, to_addr,
Harald Welteb0d93602018-03-20 18:09:34 +0100478 "INVITE", 200, seq_nr, "OK", sip_req.msgHeader.via,
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200479 body := cp.comp.sip_body));
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200480
481 if (cp.mncc_with_sdp) {
482 /* If we expect SDP forwarding, from now on expect MNCC to reflect the SDP that we just sent on SIP. */
483 expect_sdp_to_msc := cp.comp.sip_body;
484 }
485 /* If we don't expect SDP forwarding, just keep expect_sdp_to_msc := *. */
486
487 MNCC.receive(tr_MNCC_RTP_CONNECT(cp.mncc_call_id)) -> value mncc {
488 check_sdp(sdp_to_msc, mncc.u.rtp.sdp, expect_sdp_to_msc);
489 }
Harald Welteb0d93602018-03-20 18:09:34 +0100490 /* MSC <- OSC: "200 OK" translated to MNCC_SETUP_RSP */
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200491 MNCC.receive(tr_MNCC_SETUP_rsp(cp.mncc_call_id)) -> value mncc {
492 check_sdp(sdp_to_msc, mncc.u.signal.sdp, expect_sdp_to_msc);
493 }
Harald Welteb0d93602018-03-20 18:09:34 +0100494
495 /* MSC -> OSC: CC CONNECT ACK was received from MS */
496 MNCC.send(ts_MNCC_SETUP_COMPL_ind(cp.mncc_call_id));
497 /* OSC -> SIP: Acknowledge the call */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200498 SIP.receive(tr_SIP_ACK(to_addr_exp.addressField.nameAddr.addrSpec,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200499 cp.comp.sip_call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200500 from_addr_exp,
501 to_addr_exp,
502 via_exp,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200503 ?, omit));
Harald Welteb0d93602018-03-20 18:09:34 +0100504}
505
506/* Release call from the mobile side */
507function f_release_mobile(inout CallPars cp) runs on ConnHdlr {
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200508 var template (value) From from_addr := ts_From(cp.comp.sip_url_gsm.addr, cp.comp.sip_url_gsm.params);
509 var template (value) To to_addr := ts_To(cp.comp.sip_url_ext.addr, cp.comp.sip_url_ext.params);
510 var template (value) Via via := ts_Via_from(cp.comp.sip_url_gsm.addr.nameAddr.addrSpec.hostPort);
511 var template (present) From from_addr_exp := tr_From(tr_Addr_Union_from_val(cp.comp.sip_url_gsm.addr), *);
512 var template (present) To to_addr_exp := tr_To(tr_Addr_Union_from_val(cp.comp.sip_url_ext.addr), *);
513 var template (present) Via via_exp := tr_Via_from(f_tr_HostPort_opt_defport(from_addr_exp.addressField.nameAddr.addrSpec.hostPort));
Harald Welteb0d93602018-03-20 18:09:34 +0100514 var PDU_SIP_Request sip_req;
515 SIP.clear;
516 /* MSC -> OSC: Simulate a CC DISCONNET from the MT user */
517 MNCC.send(ts_MNCC_DISC_ind(cp.mncc_call_id, ts_MNCC_cause(0)));
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200518
Harald Welteb0d93602018-03-20 18:09:34 +0100519 /* OSC -> SIP: Expect BYE from OSC to SIP side */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200520 sip_req := f_SIP_expect_req(tr_SIP_BYE(to_addr_exp.addressField.nameAddr.addrSpec,
521 cp.comp.sip_call_id, from_addr_exp, to_addr_exp,
522 via_exp,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200523 ?, *));
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200524 from_addr.fromParams := sip_req.msgHeader.fromField.fromParams;
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200525
Harald Welteb0d93602018-03-20 18:09:34 +0100526 /* OSC <- SIP: Acknowledge the BYE */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200527 SIP.send(ts_SIP_Response(cp.comp.sip_call_id, from_addr, to_addr,
Harald Welteb0d93602018-03-20 18:09:34 +0100528 "BYE", 200, sip_req.msgHeader.cSeq.seqNumber, "OK",
529 sip_req.msgHeader.via));
530 /* MSC <- OSC: Send REL_REQ to MSC, triggers CC RELEASE REQ to MS */
531 MNCC.receive(tr_MNCC_REL_req(cp.mncc_call_id)); // CAUSE?
532 /* MSC -> OSC: MS has responded with CC CLEAR COMPL, triggers MNCC_REL_CNF */
533 MNCC.send(ts_MNCC_REL_cnf(cp.mncc_call_id, ts_MNCC_cause(0)));
534}
535
536/* Release call from the SIP side */
537function f_release_sip(inout CallPars cp) runs on ConnHdlr {
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200538 var template (value) From from_addr := ts_From(cp.comp.sip_url_ext.addr, cp.comp.sip_url_ext.params);
539 var template (value) To to_addr := ts_To(cp.comp.sip_url_gsm.addr, cp.comp.sip_url_gsm.params);
540 var template (value) Via via := ts_Via_from(cp.comp.sip_url_ext.addr.nameAddr.addrSpec.hostPort);
541 var template (present) From from_addr_exp := tr_From(tr_Addr_Union_from_val(cp.comp.sip_url_ext.addr), *);
542 var template (present) To to_addr_exp := tr_To(tr_Addr_Union_from_val(cp.comp.sip_url_gsm.addr), *);
543 var template (present) Via via_exp := tr_Via_from(f_tr_HostPort_opt_defport(from_addr_exp.addressField.nameAddr.addrSpec.hostPort));
Harald Welteb0d93602018-03-20 18:09:34 +0100544 /* OSC <- SIP: SIP-side sends a BYE to OSC */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200545 SIP.send(ts_SIP_BYE(cp.comp.sip_call_id, from_addr, to_addr,
546 via,
Harald Welteb0d93602018-03-20 18:09:34 +0100547 cp.comp.sip_seq_nr, omit));
548 /* MSC <- OSC: Expect OSC to cause MNCC Disconnect Request */
549 MNCC.receive(tr_MNCC_DISC_req(cp.mncc_call_id));
550 /* MSC -> OSC: Indicate GSM side release */
551 MNCC.send(ts_MNCC_REL_ind(cp.mncc_call_id, ts_MNCC_cause(0)));
552 /* OSC -> SIP: Confirmation to SIP side */
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200553 as_SIP_expect_resp(tr_SIP_Response(cp.comp.sip_call_id, from_addr_exp, to_addr_exp,
554 via_exp,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200555 *,
Neels Hofmeyrc35b6572023-09-12 02:16:43 +0200556 "BYE", 200, cp.comp.sip_seq_nr, "OK", omit));
Harald Welteb0d93602018-03-20 18:09:34 +0100557}
558
559/* Successful MT Call, which is subsequently released by GSM side */
560private function f_TC_mt_success_rel_gsm(charstring id) runs on ConnHdlr {
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200561 var CallPars cp := g_pars.g_cp;
Harald Welteb0d93602018-03-20 18:09:34 +0100562 f_CallPars_compute(cp);
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200563 cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
Pau Espin Pedrolf3713752024-03-21 17:32:55 +0100564 f_sdp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200565 "\r\nt=0 0\r\nm=audio " & int2str(cp.sip_rtp_port) &
566 " RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
Harald Welteb0d93602018-03-20 18:09:34 +0100567 f_sleep(3.0)
568
569 f_establish_mt(cp);
570 /* now call is fully established */
571 f_sleep(2.0);
572 f_release_mobile(cp);
573 setverdict(pass);
574}
575testcase TC_mt_success_rel_gsm() runs on test_CT {
Harald Welteafec4712018-03-19 22:52:17 +0100576 var ConnHdlrPars pars;
577 var ConnHdlr vc_conn;
Harald Welteafec4712018-03-19 22:52:17 +0100578 f_init();
Harald Welteafec4712018-03-19 22:52:17 +0100579 pars := valueof(t_Pars);
Neels Hofmeyra0d015b2023-09-13 04:32:14 +0200580 pars.g_cp := valueof(t_CallPars(false, false));
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200581 vc_conn := f_start_handler(refers(f_TC_mt_success_rel_gsm), pars);
582 vc_conn.done;
583}
584testcase TC_mt_success_rel_gsm_ipv6() runs on test_CT {
585 var ConnHdlrPars pars;
586 var ConnHdlr vc_conn;
587 f_init();
588 pars := valueof(t_Pars);
Neels Hofmeyra0d015b2023-09-13 04:32:14 +0200589 pars.g_cp := valueof(t_CallPars(false, false));
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200590 pars.g_cp.sip_rtp_addr := "::1";
591 pars.g_cp.cn_rtp_addr := "::2";
Harald Welteb0d93602018-03-20 18:09:34 +0100592 vc_conn := f_start_handler(refers(f_TC_mt_success_rel_gsm), pars);
593 vc_conn.done;
594}
595
596/* Successful MT Call, which is subsequently released by SIP side */
597private function f_TC_mt_success_rel_sip(charstring id) runs on ConnHdlr {
Neels Hofmeyrfb7f43b2023-09-13 05:42:41 +0200598 var CallPars cp := g_pars.g_cp;
Harald Welteb0d93602018-03-20 18:09:34 +0100599 f_CallPars_compute(cp);
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200600 cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
Pau Espin Pedrolf3713752024-03-21 17:32:55 +0100601 f_sdp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200602 "\r\nt=0 0\r\nm=audio " & int2str(cp.sip_rtp_port) &
603 " RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
Harald Welteb0d93602018-03-20 18:09:34 +0100604 f_sleep(3.0)
605
606 f_establish_mt(cp);
607 /* now call is fully established */
608 f_sleep(2.0);
609 f_release_sip(cp);
610 setverdict(pass);
611}
612testcase TC_mt_success_rel_sip() runs on test_CT {
613 var ConnHdlrPars pars;
614 var ConnHdlr vc_conn;
615 f_init();
616 pars := valueof(t_Pars);
Neels Hofmeyra0d015b2023-09-13 04:32:14 +0200617 pars.g_cp := valueof(t_CallPars(false, false));
Harald Welteb0d93602018-03-20 18:09:34 +0100618 vc_conn := f_start_handler(refers(f_TC_mt_success_rel_sip), pars);
Harald Welteafec4712018-03-19 22:52:17 +0100619 vc_conn.done;
620}
621
622
Harald Welteb0d93602018-03-20 18:09:34 +0100623/* Successful MO Call, which is subsequently released by GSM side */
624private function f_TC_mo_success_rel_gsm(charstring id) runs on ConnHdlr {
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200625 var CallPars cp := g_pars.g_cp;
Harald Welteb0d93602018-03-20 18:09:34 +0100626 f_CallPars_compute(cp);
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200627 cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
Pau Espin Pedrolf3713752024-03-21 17:32:55 +0100628 f_sdp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200629 "\r\nt=0 0\r\nm=audio " & int2str(cp.sip_rtp_port) &
630 " RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
Harald Welteb0d93602018-03-20 18:09:34 +0100631 f_sleep(3.0)
Harald Welteafec4712018-03-19 22:52:17 +0100632
Harald Welteb0d93602018-03-20 18:09:34 +0100633 f_establish_mo(cp);
634 /* now call is fully established */
635 f_sleep(2.0);
636 f_release_mobile(cp);
637 setverdict(pass);
638}
639testcase TC_mo_success_rel_gsm() runs on test_CT {
640 var ConnHdlrPars pars;
641 var ConnHdlr vc_conn;
642 f_init();
643 pars := valueof(t_Pars);
Neels Hofmeyra0d015b2023-09-13 04:32:14 +0200644 pars.g_cp := valueof(t_CallPars(true, false));
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200645 vc_conn := f_start_handler(refers(f_TC_mo_success_rel_gsm), pars);
646 vc_conn.done;
647}
648testcase TC_mo_success_rel_gsm_ipv6() runs on test_CT {
649 var ConnHdlrPars pars;
650 var ConnHdlr vc_conn;
651 f_init();
652 pars := valueof(t_Pars);
Neels Hofmeyra0d015b2023-09-13 04:32:14 +0200653 pars.g_cp := valueof(t_CallPars(true, false));
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200654 pars.g_cp.sip_rtp_addr := "::1";
655 pars.g_cp.cn_rtp_addr := "::2";
Harald Welteb0d93602018-03-20 18:09:34 +0100656 vc_conn := f_start_handler(refers(f_TC_mo_success_rel_gsm), pars);
657 vc_conn.done;
Harald Welteafec4712018-03-19 22:52:17 +0100658}
659
Harald Welteb0d93602018-03-20 18:09:34 +0100660/* Successful MO Call, which is subsequently released by SIP side */
661private function f_TC_mo_success_rel_sip(charstring id) runs on ConnHdlr {
Neels Hofmeyrfb7f43b2023-09-13 05:42:41 +0200662 var CallPars cp := g_pars.g_cp;
Harald Welteb0d93602018-03-20 18:09:34 +0100663 f_CallPars_compute(cp);
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200664 cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
Pau Espin Pedrolf3713752024-03-21 17:32:55 +0100665 f_sdp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200666 "\r\nt=0 0\r\nm=audio " & int2str(cp.sip_rtp_port) &
667 " RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
Harald Welteb0d93602018-03-20 18:09:34 +0100668 f_sleep(3.0)
Harald Welteafec4712018-03-19 22:52:17 +0100669
Harald Welteb0d93602018-03-20 18:09:34 +0100670 f_establish_mo(cp);
671 /* now call is fully established */
672 f_sleep(2.0);
673 f_release_sip(cp);
674 setverdict(pass);
675}
676testcase TC_mo_success_rel_sip() runs on test_CT {
677 var ConnHdlrPars pars;
678 var ConnHdlr vc_conn;
679 f_init();
680 pars := valueof(t_Pars);
Neels Hofmeyra0d015b2023-09-13 04:32:14 +0200681 pars.g_cp := valueof(t_CallPars(is_mo := true, mncc_with_sdp := false));
Harald Welteb0d93602018-03-20 18:09:34 +0100682 vc_conn := f_start_handler(refers(f_TC_mo_success_rel_sip), pars);
683 vc_conn.done;
684}
Harald Welteafec4712018-03-19 22:52:17 +0100685
Harald Welteddf011e2019-04-19 09:39:35 +0200686/* SETUP followed by DISC results in lingering B-leg (OS#3518)*/
687private function f_TC_mo_setup_disc_late_rtp(charstring id) runs on ConnHdlr {
Neels Hofmeyrfb7f43b2023-09-13 05:42:41 +0200688 var CallPars cp := g_pars.g_cp;
Harald Welteddf011e2019-04-19 09:39:35 +0200689 f_CallPars_compute(cp);
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200690 cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 1.1.1.1\r\ns=GSM Call\r\nc=IN " &
Pau Espin Pedrolf3713752024-03-21 17:32:55 +0100691 f_sdp_addr2addrtype(cp.sip_rtp_addr) & " " & cp.sip_rtp_addr &
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200692 "\r\nt=0 0\r\nm=audio " & int2str(cp.sip_rtp_port) &
693 " RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n";
Harald Welteddf011e2019-04-19 09:39:35 +0200694 f_sleep(3.0);
695
696 var MNCC_number dst := valueof(ts_MNCC_number(cp.called, GSM48_TON_UNKNOWN));
697 var MNCC_number src := valueof(ts_MNCC_number(cp.calling, GSM48_TON_UNKNOWN));
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200698 var template (value) From from_addr := ts_From(cp.comp.sip_url_gsm.addr, cp.comp.sip_url_gsm.params);
699 var template (value) To to_addr := ts_To(cp.comp.sip_url_ext.addr, cp.comp.sip_url_ext.params);
700 var template (value) Via via := ts_Via_from(cp.comp.sip_url_gsm.addr.nameAddr.addrSpec.hostPort);
701 var template (present) From from_addr_exp := tr_From(tr_Addr_Union_from_val(cp.comp.sip_url_gsm.addr), *);
702 var template (present) To to_addr_exp := tr_To(tr_Addr_Union_from_val(cp.comp.sip_url_ext.addr), *);
703 var template (present) Via via_exp := tr_Via_from(f_tr_HostPort_opt_defport(from_addr_exp.addressField.nameAddr.addrSpec.hostPort));
Harald Welteddf011e2019-04-19 09:39:35 +0200704
705 f_create_sip_expect(cp.comp.sip_url_ext.addr.nameAddr.addrSpec);
706
707 /* MSC -> OSC: MSC sends SETUP.ind after CC SETUP was received from MS */
708 MNCC.send(ts_MNCC_SETUP_ind(cp.mncc_call_id, dst, src, "262420123456789"));
709
710 /* MSC -> OSC: Simulate a CC DISCONNET from the MT user *before* responding to the RTP_CREATE */
711 MNCC.send(ts_MNCC_DISC_ind(cp.mncc_call_id, ts_MNCC_cause(0)));
712
713 /* MSC <- OSC: Create GSM side RTP socket (too late) */
714 MNCC.receive(tr_MNCC_RTP_CREATE(cp.mncc_call_id)) {
715 var MNCC_PDU mncc := valueof(ts_MNCC_RTP_CREATE(cp.mncc_call_id));
716 mncc.u.rtp.payload_msg_type := oct2int('0300'O);
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200717 mncc.u.rtp.is_ipv6 := f_addr_is_ipv6(cp.cn_rtp_addr);
718 mncc.u.rtp.ip := f_addrstr2addr(cp.cn_rtp_addr);
719 mncc.u.rtp.rtp_port := cp.cn_rtp_port;
720 MNCC.send(mncc);
Harald Welteddf011e2019-04-19 09:39:35 +0200721 }
722
723 /* OSC -> SIP: We should never receive INVITE */
724 timer T := 10.0;
725 T.start;
726 alt {
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200727 [] SIP.receive(tr_SIP_INVITE(to_addr_exp.addressField.nameAddr.addrSpec, ?,
728 from_addr_exp, to_addr_exp,
729 via_exp,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200730 ?, ?)) {
Harald Welteddf011e2019-04-19 09:39:35 +0200731 setverdict(fail, "Received unexpected INVITE");
732 }
733 [] T.timeout {
734 setverdict(pass);
735 }
736 }
737}
738testcase TC_mo_setup_disc_late_rtp() runs on test_CT {
739 var ConnHdlrPars pars;
740 var ConnHdlr vc_conn;
741 f_init();
742 pars := valueof(t_Pars);
Neels Hofmeyra0d015b2023-09-13 04:32:14 +0200743 pars.g_cp := valueof(t_CallPars(is_mo := true, mncc_with_sdp := false));
Harald Welteddf011e2019-04-19 09:39:35 +0200744 vc_conn := f_start_handler(refers(f_TC_mo_setup_disc_late_rtp), pars);
745 vc_conn.done;
746}
Harald Welteafec4712018-03-19 22:52:17 +0100747
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200748testcase TC_mt_with_sdp() runs on test_CT {
749 var ConnHdlrPars pars;
750 var ConnHdlr vc_conn;
751 f_init();
752 pars := valueof(t_Pars);
753 pars.g_cp := valueof(t_CallPars(is_mo := false, mncc_with_sdp := true));
754 vc_conn := f_start_handler(refers(f_TC_mt_success_rel_gsm), pars);
755 vc_conn.done;
756}
757
758testcase TC_mo_with_sdp() runs on test_CT {
759 var ConnHdlrPars pars;
760 var ConnHdlr vc_conn;
761 f_init();
762 pars := valueof(t_Pars);
763 pars.g_cp := valueof(t_CallPars(is_mo := true, mncc_with_sdp := true));
764 vc_conn := f_start_handler(refers(f_TC_mo_success_rel_sip), pars);
765 vc_conn.done;
766}
767
Harald Welteafec4712018-03-19 22:52:17 +0100768control {
Harald Welteb0d93602018-03-20 18:09:34 +0100769 execute( TC_mt_success_rel_gsm() );
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200770 execute( TC_mt_success_rel_gsm_ipv6() );
Harald Welteb0d93602018-03-20 18:09:34 +0100771 execute( TC_mt_success_rel_sip() );
772 execute( TC_mo_success_rel_gsm() );
Pau Espin Pedrolbdd874a2020-09-10 19:09:47 +0200773 execute( TC_mo_success_rel_gsm_ipv6() );
Harald Welteb0d93602018-03-20 18:09:34 +0100774 execute( TC_mo_success_rel_sip() );
Harald Welteddf011e2019-04-19 09:39:35 +0200775 execute( TC_mo_setup_disc_late_rtp() );
Neels Hofmeyr2e3a0e22023-09-12 02:09:48 +0200776 execute( TC_mt_with_sdp() );
777 execute( TC_mo_with_sdp() );
Harald Welteafec4712018-03-19 22:52:17 +0100778}
779
780
781
782}