blob: 1b31f75d1a44878232947a44769adfb0e1dcb2f7 [file] [log] [blame]
Harald Weltea49e36e2018-01-21 19:29:33 +01001module BSC_ConnectionHandler {
2
3import from General_Types all;
4import from Osmocom_Types all;
Harald Welteb71901a2018-01-26 19:16:05 +01005import from Native_Functions all;
Harald Weltea49e36e2018-01-21 19:29:33 +01006import from GSM_Types all;
Harald Welteb71901a2018-01-26 19:16:05 +01007import from IPL4asp_Types all;
Harald Weltea49e36e2018-01-21 19:29:33 +01008import from SCCPasp_Types all;
9import from BSSAP_Types all;
10import from BSSMAP_Emulation all;
11import from BSSMAP_Templates all;
12
13import from GSUP_Types all;
14import from GSUP_Emulation all;
15
16import from MNCC_Types all;
17import from MNCC_Emulation all;
18
Harald Welte4aa970c2018-01-26 10:38:09 +010019import from MGCP_Types all;
20import from MGCP_Emulation all;
Harald Welteb71901a2018-01-26 19:16:05 +010021import from MGCP_Templates all;
22import from SDP_Types all;
Harald Welte4aa970c2018-01-26 10:38:09 +010023
Harald Weltea49e36e2018-01-21 19:29:33 +010024import from MobileL3_Types all;
25import from MobileL3_CommonIE_Types all;
26import from MobileL3_MM_Types all;
Harald Welteb71901a2018-01-26 19:16:05 +010027import from MobileL3_CC_Types all;
Harald Weltef45efeb2018-04-09 18:19:24 +020028import from MobileL3_SMS_Types all;
Harald Weltea49e36e2018-01-21 19:29:33 +010029import from L3_Templates all;
Harald Welte158a7ca2018-02-16 18:11:31 +010030import from L3_Common all;
Harald Weltea49e36e2018-01-21 19:29:33 +010031
Harald Weltef640a012018-04-14 17:49:21 +020032import from SMPP_Emulation all;
33
Philipp Maieraeb29a82018-11-08 17:40:53 +010034import from IPA_Emulation all;
35import from Osmocom_CTRL_Functions all;
36import from Osmocom_CTRL_Types all;
37import from Osmocom_CTRL_Adapter all;
38
Philipp Maierc39a9d82018-11-09 11:21:08 +010039import from TELNETasp_PortType all;
40import from Osmocom_VTY_Functions all;
41
Harald Weltea49e36e2018-01-21 19:29:33 +010042/* this component represents a single subscriber connection */
Philipp Maieraeb29a82018-11-08 17:40:53 +010043type component BSC_ConnHdlr extends BSSAP_ConnHdlr, MNCC_ConnHdlr, GSUP_ConnHdlr, MGCP_ConnHdlr, SMPP_ConnHdlr, CTRL_Adapter_CT {
Harald Weltea49e36e2018-01-21 19:29:33 +010044 var BSC_ConnHdlrPars g_pars;
Harald Weltea10db902018-01-27 12:44:49 +010045 timer g_Tguard := 60.0;
Philipp Maierc39a9d82018-11-09 11:21:08 +010046 port TELNETasp_PT MSCVTY;
Harald Weltea49e36e2018-01-21 19:29:33 +010047}
48
Harald Weltede371492018-01-27 23:44:41 +010049type record BSC_ConnHdlrNetworkPars {
50 OCT1 kc_support,
51 boolean expect_tmsi,
52 boolean expect_auth,
53 boolean expect_ciph
54}
55
Harald Weltea49e36e2018-01-21 19:29:33 +010056type record BSC_ConnHdlrPars {
57 SCCP_PAR_Address sccp_addr_own,
58 SCCP_PAR_Address sccp_addr_peer,
59 BSSMAP_IE_CellIdentifier cell_id,
Harald Welte256571e2018-01-24 18:47:19 +010060 hexstring imei,
Harald Weltea49e36e2018-01-21 19:29:33 +010061 hexstring imsi,
Harald Welte82600572018-01-21 20:54:08 +010062 hexstring msisdn,
Harald Welte256571e2018-01-24 18:47:19 +010063 OCT4 tmsi optional,
Harald Welte9de84792018-01-28 01:06:35 +010064 MobileStationClassmark1_V cm1,
Harald Welte82600572018-01-21 20:54:08 +010065 BSSMAP_IE_ClassmarkInformationType2 cm2,
Harald Welte16114282018-01-24 22:41:21 +010066 BSSMAP_IE_ClassmarkInformationType3 cm3 optional,
Harald Weltede371492018-01-27 23:44:41 +010067 AuthVector vec optional,
Neels Hofmeyrc1f105a2018-03-01 20:00:19 +010068 BSC_ConnHdlrNetworkPars net,
Philipp Maieraeb29a82018-11-08 17:40:53 +010069 boolean send_early_cm,
70 charstring ipa_ctrl_ip,
71 integer ipa_ctrl_port,
72 boolean ipa_ctrl_enable
Harald Weltea49e36e2018-01-21 19:29:33 +010073};
74
Harald Welte9de84792018-01-28 01:06:35 +010075/* get a one-octet bitmaks of supported algorithms based on Classmark information */
76function f_alg_mask_from_cm(BSSMAP_IE_ClassmarkInformationType2 cm2) return OCT1 {
77 var BIT8 res := '00000001'B; /* A5/0 always supported */
78
79 if (cm2.a5_1 == '0'B) {
80 res := res or4b '00000010'B;
81 }
82 if (cm2.classmarkInformationType2_oct5.a5_2 == '1'B ) {
83 res := res or4b '00000100'B;
84 }
85 if (cm2.classmarkInformationType2_oct5.a5_3 == '1'B) {
86 res := res or4b '00001000'B;
87 }
88 /* TODO: CM3 for A5/4 and beyond */
89 return bit2oct(res);
90}
91
92/* determine the best algorithm available within the bit-mask */
93function f_best_alg_from_mask(OCT1 alg_in) return OCT1 {
94 var BIT8 alg := oct2bit(alg_in);
95 var BIT8 ordered_algs[8] := {
96 '10000000'B, '01000000'B, '00100000'B, '00010000'B,
97 '00001000'B, /* A5/3 */
98 '00000010'B, /* A5/1 */
99 '00000100'B, /* A5/2 */
100 '00000001'B /* A5/0 */ }
101 for (var integer i := 0; i < sizeof(ordered_algs); i := i+1) {
102 if (alg and4b ordered_algs[i] != '00000000'B) {
103 return bit2oct(ordered_algs[i]);
104 }
105 }
106 return '00'O;
107}
108
109/* return an integer like '1' for A5/1 based on a mask (with only one bit set */
110function f_alg_from_mask(OCT1 mask_in) return integer {
111 var BIT8 mask := oct2bit(mask_in);
112 for (var integer i := 0; i < 8; i := i+1) {
113 if (mask and4b ('00000001'B << i) != '00000000'B) {
114 return i;
115 }
116 }
117 return -1;
118}
119
Harald Weltea10db902018-01-27 12:44:49 +0100120/* altstep for the global guard timer */
121private altstep as_Tguard() runs on BSC_ConnHdlr {
122 [] g_Tguard.timeout {
Daniel Willmann90829d62018-02-15 17:45:14 +0100123 setverdict(fail, "Tguard timeout");
Daniel Willmannafce8662018-07-06 23:11:32 +0200124 mtc.stop;
Harald Weltea10db902018-01-27 12:44:49 +0100125 }
126}
127
128/* init function, called as first function in new BSC_ConnHdlr */
Harald Weltead2952e2018-01-27 14:12:46 +0100129function f_init_handler(BSC_ConnHdlrPars pars, float t_guard := 60.0) runs on BSC_ConnHdlr {
Harald Weltea10db902018-01-27 12:44:49 +0100130 /* make parameters available via component variable */
131 g_pars := pars;
132 /* Start guard timer and activate it as default */
Harald Weltead2952e2018-01-27 14:12:46 +0100133 g_Tguard.start(t_guard);
Harald Weltea10db902018-01-27 12:44:49 +0100134 activate(as_Tguard());
Harald Weltef640a012018-04-14 17:49:21 +0200135 /* Route all SMPP messages for our MSISDN to us */
136 f_create_smpp_expect(hex2str(pars.msisdn));
Philipp Maieraeb29a82018-11-08 17:40:53 +0100137
138 if (g_pars.ipa_ctrl_enable == true) {
139 f_ipa_ctrl_start(g_pars.ipa_ctrl_ip, g_pars.ipa_ctrl_port);
140 }
Philipp Maierc39a9d82018-11-09 11:21:08 +0100141
142 map(self:MSCVTY, system:MSCVTY);
143 f_vty_set_prompts(MSCVTY);
144 f_vty_transceive(MSCVTY, "enable");
Harald Weltea10db902018-01-27 12:44:49 +0100145}
146
Harald Weltea49e36e2018-01-21 19:29:33 +0100147
148/* Callback function from general BSSMAP_Emulation whenever a connectionless
149 * BSSMAP message arrives. Canreturn a PDU_BSSAPthat should be sent in return */
150private function BscUnitdataCallback(PDU_BSSAP bssap)
151runs on BSSMAP_Emulation_CT return template PDU_BSSAP {
152 var template PDU_BSSAP resp := omit;
153
154 log("BSSMAP_BscUnitdataCallback");
155 /* answer all RESET with RESET ACK */
156 if (match(bssap, tr_BSSMAP_Reset)){
157 log("BSSMAP_BscUnitdataCallback: Responding to RESET with RESET-ACK");
158 resp := ts_BSSMAP_ResetAck;
159 }
160
161 /* FIXME: Handle paging, etc. */
162 return resp;
163}
164
165const BssmapOps BSC_BssmapOps := {
166 /* Create call-back for inbound connections from MSC (hand-over) */
167 create_cb := refers(BSSMAP_Emulation.ExpectedCreateCallback),
168 unitdata_cb := refers(BscUnitdataCallback),
169 decode_dtap := true,
Harald Weltea4ca4462018-02-09 00:17:14 +0100170 role_ms := true,
171 sccp_addr_local := omit,
172 sccp_addr_peer := omit
Harald Weltea49e36e2018-01-21 19:29:33 +0100173}
174
175
176private function MnccUnitdataCallback(MNCC_PDU mncc)
177runs on MNCC_Emulation_CT return template MNCC_PDU {
178 log("Ignoring MNCC", mncc);
179 return omit;
180}
181
182const MnccOps BCC_MnccOps := {
183 create_cb := refers(MNCC_Emulation.ExpectedCreateCallback),
184 unitdata_cb := refers(MnccUnitdataCallback)
185}
186
187
188
Harald Weltea49e36e2018-01-21 19:29:33 +0100189/* Encode 'l3' and ask BSSMAP_Emulation to create new connection with COMPL L3 INFO */
190function f_bssap_compl_l3(PDU_ML3_MS_NW l3)
191runs on BSC_ConnHdlr {
192 log("Sending COMPL L3: ", l3);
193 var octetstring l3_enc := enc_PDU_ML3_MS_NW(l3);
194 BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_own,
195 valueof(ts_BSSMAP_ComplL3(g_pars.cell_id, l3_enc))));
Harald Welte71b69332018-01-21 20:43:53 +0100196 alt {
197 [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_CONF_IND) {}
198 [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
199 setverdict(fail, "DISC.ind from SCCP");
Daniel Willmannafce8662018-07-06 23:11:32 +0200200 mtc.stop;
Harald Welte71b69332018-01-21 20:43:53 +0100201 }
202 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100203}
204
Harald Welte081b19a2018-02-10 09:11:13 +0100205type enumerated EstablishType {
206 EST_TYPE_MO_CALL,
Harald Welte0bef21e2018-02-10 09:48:23 +0100207 EST_TYPE_EMERG_CALL,
Harald Weltef45efeb2018-04-09 18:19:24 +0200208 EST_TYPE_PAG_RESP,
Vadim Yanitskiy20ee5e42018-05-27 17:54:21 +0700209 EST_TYPE_MO_SMS,
210 EST_TYPE_SS_ACT
Harald Welte081b19a2018-02-10 09:11:13 +0100211};
212
Harald Weltea49e36e2018-01-21 19:29:33 +0100213/* helper function to fully establish a dedicated channel */
Harald Welteb9e86fa2018-04-09 18:18:31 +0200214function f_establish_fully(EstablishType etype := EST_TYPE_MO_CALL)
Harald Weltea49e36e2018-01-21 19:29:33 +0100215runs on BSC_ConnHdlr {
Harald Welte081b19a2018-02-10 09:11:13 +0100216 var PDU_ML3_MS_NW l3_info;
Harald Welteb9e86fa2018-04-09 18:18:31 +0200217 var MobileIdentityLV mi;
218
219 /* If we have a TMSI, use TMSI instead of IMSI */
220 if (ispresent(g_pars.tmsi)) {
221 mi := valueof(ts_MI_TMSI_LV(g_pars.tmsi));
222 } else {
223 mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
224 }
225
Harald Welte081b19a2018-02-10 09:11:13 +0100226 select (etype) {
227 case (EST_TYPE_MO_CALL) {
228 l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, mi));
229 }
Harald Welte0bef21e2018-02-10 09:48:23 +0100230 case (EST_TYPE_EMERG_CALL) {
231 l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_EMERG_CALL, mi));
232 }
Harald Welte081b19a2018-02-10 09:11:13 +0100233 case (EST_TYPE_PAG_RESP) {
234 l3_info := valueof(ts_PAG_RESP(mi));
235 }
Harald Weltef45efeb2018-04-09 18:19:24 +0200236 case (EST_TYPE_MO_SMS) {
237 l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_SMS, mi));
238 }
Vadim Yanitskiy20ee5e42018-05-27 17:54:21 +0700239 case (EST_TYPE_SS_ACT) {
240 l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_SS_ACT, mi));
241 }
Harald Welte081b19a2018-02-10 09:11:13 +0100242 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100243
244 /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */
245 f_bssap_compl_l3(l3_info);
246
Harald Weltede371492018-01-27 23:44:41 +0100247 f_mm_common();
248 if (g_pars.net.expect_ciph) {
Harald Welte148a7082018-01-26 18:56:43 +0100249 /* implicit CM SERVICE ACCEPT? */
250 } else {
Harald Welte0bef21e2018-02-10 09:48:23 +0100251 if (etype != EST_TYPE_PAG_RESP) {
Harald Welte081b19a2018-02-10 09:11:13 +0100252 /* explicit CM SERVICE ACCEPT */
253 BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_ACC));
254 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100255 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100256}
257
258/* build a PDU_ML3_MS_NW containing a Location Update by IMSI */
Harald Welte9de84792018-01-28 01:06:35 +0100259function f_build_lu_imsi(hexstring imsi) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Weltea49e36e2018-01-21 19:29:33 +0100260{
261 var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(imsi));
262 return f_build_lu(mi);
263}
Harald Welte9de84792018-01-28 01:06:35 +0100264function f_build_lu_imei(hexstring imei) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Welteba7b6d92018-01-23 21:32:34 +0100265{
266 var MobileIdentityLV mi := valueof(ts_MI_IMEI_LV(imei));
267 return f_build_lu(mi);
268}
Harald Welte9de84792018-01-28 01:06:35 +0100269function f_build_lu_tmsi(OCT4 tmsi) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Welteba7b6d92018-01-23 21:32:34 +0100270{
271 var MobileIdentityLV mi := valueof(ts_MI_TMSI_LV(tmsi));
272 return f_build_lu(mi);
273}
Harald Welte9de84792018-01-28 01:06:35 +0100274private function f_build_lu(MobileIdentityLV mi) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Weltea49e36e2018-01-21 19:29:33 +0100275{
276 var LocationAreaIdentification_V old_lai := { '62F220'O, '9999'O };
277 var PDU_ML3_MS_NW l3_info := valueof(ts_ML3_MO_LU_Req(valueof(ts_ML3_IE_LuType_Attach),
Harald Welte9de84792018-01-28 01:06:35 +0100278 old_lai, mi, g_pars.cm1));
Harald Weltea49e36e2018-01-21 19:29:33 +0100279 return l3_info;
280}
281
Harald Welte9de84792018-01-28 01:06:35 +0100282function f_mm_auth() runs on BSC_ConnHdlr
Harald Welte148a7082018-01-26 18:56:43 +0100283{
Harald Weltede371492018-01-27 23:44:41 +0100284 if (g_pars.net.expect_auth) {
Harald Welte148a7082018-01-26 18:56:43 +0100285 g_pars.vec := f_gen_auth_vec_2g();
286 var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(g_pars.vec.rand,
287 g_pars.vec.sres,
288 g_pars.vec.kc));
289 GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi));
290 GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple));
291
292 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_AUTH_REQ(g_pars.vec.rand)));
293 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MT_MM_AUTH_RESP_2G(g_pars.vec.sres)));
294 }
Harald Welte9de84792018-01-28 01:06:35 +0100295}
Harald Welte148a7082018-01-26 18:56:43 +0100296
Harald Welte9de84792018-01-28 01:06:35 +0100297function f_mm_common() runs on BSC_ConnHdlr
298{
299 f_mm_auth();
Harald Weltede371492018-01-27 23:44:41 +0100300 if (g_pars.net.expect_ciph) {
Harald Welte9de84792018-01-28 01:06:35 +0100301 var OCT1 a5_net := f_alg_mask_from_cm(g_pars.cm2);
302 var OCT1 a5_intersect := g_pars.net.kc_support and4b a5_net;
303 alt {
304 [] BSSAP.receive(tr_BSSMAP_CipherModeCmd(a5_intersect, g_pars.vec.kc)) {
305 var OCT1 a5_chosen := f_best_alg_from_mask(a5_intersect);
306 var integer a5_nr := f_alg_from_mask(a5_chosen);
307 BSSAP.send(ts_BSSMAP_CipherModeCompl(int2oct(a5_nr+1, 1)));
308 }
309 [] BSSAP.receive(tr_BSSMAP_CipherModeCmd(?, g_pars.vec.kc)) {
310 setverdict(fail, "Wrong ciphering algorithm mask in CiphModCmd");
Daniel Willmannafce8662018-07-06 23:11:32 +0200311 mtc.stop;
Harald Welte9de84792018-01-28 01:06:35 +0100312 }
313 }
314 /* FIXME: Send the best available algorithm */
Harald Welte148a7082018-01-26 18:56:43 +0100315 }
316}
317
Neels Hofmeyrc1f105a2018-03-01 20:00:19 +0100318function f_perform_lu()
Harald Weltea49e36e2018-01-21 19:29:33 +0100319runs on BSC_ConnHdlr {
320 var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi)
321 var PDU_DTAP_MT dtap_mt;
322
323 /* tell GSUP dispatcher to send this IMSI to us */
324 f_create_gsup_expect(hex2str(g_pars.imsi));
325
326 /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */
327 f_bssap_compl_l3(l3_lu);
328
Neels Hofmeyrc1f105a2018-03-01 20:00:19 +0100329 if (g_pars.send_early_cm) {
Harald Welte8a121b32018-01-22 03:00:41 +0100330 BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3));
331 }
Harald Welte5c2622c2018-01-21 20:45:20 +0100332
Harald Weltede371492018-01-27 23:44:41 +0100333 f_mm_common();
Harald Welte16114282018-01-24 22:41:21 +0100334
Harald Weltea49e36e2018-01-21 19:29:33 +0100335 /* Expect MSC to perform LU with HLR */
336 GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi));
337 GSUP.send(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn));
338 GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi));
339 GSUP.send(ts_GSUP_UL_RES(g_pars.imsi));
340
341 alt {
342 [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) -> value dtap_mt {
343 var PDU_ML3_LocationUpdateAccept lu_acc := dtap_mt.dtap.msgs.mm.locationUpdateAccept;
Harald Weltede371492018-01-27 23:44:41 +0100344 if (g_pars.net.expect_tmsi) {
Harald Weltea49e36e2018-01-21 19:29:33 +0100345 if (not ispresent(lu_acc.mobileIdentityTLV) or
346 not ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) {
347 setverdict(fail, "Expected TMSI but no TMSI was allocated");
Daniel Willmannafce8662018-07-06 23:11:32 +0200348 mtc.stop;
Harald Weltea49e36e2018-01-21 19:29:33 +0100349 } else {
Harald Welte256571e2018-01-24 18:47:19 +0100350 g_pars.tmsi := lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi.octets;
Harald Weltea49e36e2018-01-21 19:29:33 +0100351 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_TmsiRealloc_Cmpl));
352 }
353 } else {
354 if (ispresent(lu_acc.mobileIdentityTLV) and
355 ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) {
356 setverdict(fail, "Expected no TMSI but TMSI was allocated");
Daniel Willmannafce8662018-07-06 23:11:32 +0200357 mtc.stop;
Harald Weltea49e36e2018-01-21 19:29:33 +0100358 }
359 }
360 }
361 [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) {
362 setverdict(fail, "Expected LU ACK, but received LU REJ");
Daniel Willmannafce8662018-07-06 23:11:32 +0200363 mtc.stop;
Harald Weltea49e36e2018-01-21 19:29:33 +0100364 }
365 }
366 /* FIXME: there could be pending SMS or other common procedures by the MSC, let's ignore them */
367 BSSAP.receive(tr_BSSMAP_ClearCommand);
368 BSSAP.send(ts_BSSMAP_ClearComplete);
369 BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND);
370 setverdict(pass);
371}
372
373function f_foo() runs on BSC_ConnHdlr{
374 /* SCCP CC handled by BSSMAP_Emulation_CT.main() */
375 /* Expect auth, if enabled */
376
377 /* TODO: ISD */
378 /* Expect encr, if enabled */
379 /* Expect encr, if enabled */
380 /* Expect ASS CMD, if chan_type != requested */
381 /* Send ASS CMPL in successful case */
382
383 /* Expect AoIP port/ip information for RTP stream */
384 /* Expect MSC-originated MGCP to our simulated MGW */
385 /* Verify Counters via CTRL */
386 /* re-configure MSC behaviour via VTY */
387}
388
Harald Welteb71901a2018-01-26 19:16:05 +0100389/* parameters related to a (MO?) voice call */
390type record CallParameters {
Harald Welteb71901a2018-01-26 19:16:05 +0100391 /* CC related parameters */
392 hexstring called_party, /* whom are we calling */
393 integer transaction_id optional, /* which TS 04.08 CC transaction ID to use */
394 BearerCapability_TLV bearer_cap, /* which bearer capabilities to claim */
Harald Welte0bef21e2018-02-10 09:48:23 +0100395 boolean emergency, /* is this an emergency call? */
Harald Welteb71901a2018-01-26 19:16:05 +0100396
397 /* MNCC related parameters */
398 uint32_t mncc_callref optional, /* call reference on the MNCC side */
399 MNCC_bearer_cap mncc_bearer_cap optional, /* MNCC-side bearer capabilities */
400
401 /* RTP related parameters */
402 HostName bss_rtp_ip optional, /* BSS Side RTP IP */
403 PortNumber bss_rtp_port optional, /* BSS Side RTP Port */
404 HostName mss_rtp_ip optional, /* MSS Side RTP IP */
405 PortNumber mss_rtp_port optional, /* MSS Side RTP Port */
Harald Welte4017d552018-01-26 21:40:05 +0100406 HostName mgw_rtp_ip_bss, /* BSS-facing MGW RTP IP */
407 PortNumber mgw_rtp_port_bss, /* BSS-facing MGW RTP Port */
408 HostName mgw_rtp_ip_mss, /* MSS-facing MGW RTP IP */
409 PortNumber mgw_rtp_port_mss, /* MSS-facing MGW RTP Port */
Harald Welteb71901a2018-01-26 19:16:05 +0100410 uint7_t rtp_payload_type, /* dynamic RTP payload type */
411 charstring rtp_sdp_format, /* AMR/8000 or the like */
Philipp Maier2a98a732018-03-19 16:06:12 +0100412 boolean mgw_drop_dlcx optional, /* Provoke errors by not responding to DLCX
413 (f_mt_call and f_mt_call) */
Harald Welteb71901a2018-01-26 19:16:05 +0100414
Philipp Maiercd668572018-03-19 16:11:52 +0100415 MgcpCallId mgcp_call_id optional, /* MGCP Call ID; CallAgent allocated */
Harald Welteb71901a2018-01-26 19:16:05 +0100416 MgcpEndpoint mgcp_ep optional /* MGCP Endpoint, CallAgent or MGW allocated */,
417 MgcpConnectionId mgcp_connection_id_bss, /* MGCP Connection ID BSS Side */
418 MgcpConnectionId mgcp_connection_id_mss /* MGCP Connection ID MSS Side */
419}
420
421template (value) CallParameters t_CallParams(hexstring called, integer tid) := {
Harald Welteb71901a2018-01-26 19:16:05 +0100422 called_party := called,
423 transaction_id := tid,
424 bearer_cap := valueof(ts_Bcap_voice),
Harald Welte0bef21e2018-02-10 09:48:23 +0100425 emergency := false,
Harald Welteb71901a2018-01-26 19:16:05 +0100426 mncc_callref := omit,
427 mncc_bearer_cap := valueof(ts_MNCC_bcap_voice),
Harald Welte4017d552018-01-26 21:40:05 +0100428 bss_rtp_ip := "9.8.7.6",
429 bss_rtp_port := 9000,
Harald Welteb71901a2018-01-26 19:16:05 +0100430 mss_rtp_ip := omit,
431 mss_rtp_port := omit,
Harald Welte4017d552018-01-26 21:40:05 +0100432 mgw_rtp_ip_bss := "1.1.1.1",
433 mgw_rtp_port_bss := 10000,
434 mgw_rtp_ip_mss := "1.1.1.1",
435 mgw_rtp_port_mss := 11000,
Harald Welteb71901a2018-01-26 19:16:05 +0100436 rtp_payload_type := 98,
437 rtp_sdp_format := "AMR/8000",
438 mgcp_call_id := omit,
439 mgcp_ep := omit,
440 mgcp_connection_id_bss := '0'H,//
441 mgcp_connection_id_mss := '0'H //
442};
443
Philipp Maier3716a5e2018-03-21 15:53:35 +0100444function f_mt_call_establish(inout CallParameters cpars)
Harald Welte33ec09b2018-02-10 15:34:46 +0100445runs on BSC_ConnHdlr {
446
Harald Welte33ec09b2018-02-10 15:34:46 +0100447 var MNCC_PDU mncc;
448 var MgcpCommand mgcp_cmd;
449
450 f_bssmap_register_imsi(g_pars.imsi, g_pars.tmsi);
451
452 /* Allocate a call reference and send SETUP via MNCC to MSC */
453 cpars.mncc_callref := f_rnd_int(2147483648);
454 MNCC.send(ts_MNCC_SETUP_req(cpars.mncc_callref, hex2str(g_pars.msisdn),
455 hex2str(cpars.called_party), hex2str(g_pars.imsi)));
456 /* BSC <- MSC: Expect paging. FIXME: By TMSI or not? */
457 BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi));
458
Harald Welteb9e86fa2018-04-09 18:18:31 +0200459 f_establish_fully(EST_TYPE_PAG_RESP);
Harald Welte33ec09b2018-02-10 15:34:46 +0100460
461 /* MS <- MSC: Expect CC SETUP */
462 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_SETUP(cpars.transaction_id, *, cpars.called_party)));
463
464 /* MS -> MSC: ALERTING */
465 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_ALERTING(cpars.transaction_id)));
466 MNCC.receive(tr_MNCC_ALERT_ind(cpars.mncc_callref));
467
468
469 /* Create MGCP expect */
470 f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit});
471 /* Ask MSC via MNCC to create the RTP socket on the MSC/MGW side */
472 MNCC.send(ts_MNCC_RTP_CREATE(cpars.mncc_callref));
473
474 /* First MGCP CRCX (for BSS/RAN side) */
475 MGCP.receive(tr_CRCX) -> value mgcp_cmd {
476 cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd);
Philipp Maier4b2692d2018-03-14 16:37:48 +0100477
478 /* When the endpoint contains a wildcard we keep the endpoint
479 * identifier we have set up in cpars. Otherwise we use the
480 * endpoint name that the call agent has supplied */
481 if (match(mgcp_cmd.line.ep, t_MGCP_EP_wildcard) == false) {
482 cpars.mgcp_ep := mgcp_cmd.line.ep;
483 }
484
Harald Welte33ec09b2018-02-10 15:34:46 +0100485 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_bss, cpars.mgw_rtp_ip_bss,
486 hex2str(cpars.mgcp_call_id), "42",
487 cpars.mgw_rtp_port_bss,
488 { int2str(cpars.rtp_payload_type) },
489 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
490 cpars.rtp_sdp_format)),
491 valueof(ts_SDP_ptime(20)) }));
Philipp Maier4b2692d2018-03-14 16:37:48 +0100492 var template MgcpResponse mgcp_resp;
493 mgcp_resp := ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_bss, sdp);
494 f_mgcp_par_append(mgcp_resp.params, ts_MgcpParSpecEP(cpars.mgcp_ep));
495 MGCP.send(mgcp_resp);
Harald Welte33ec09b2018-02-10 15:34:46 +0100496 }
497 /* Second MGCP CRCX (this time for MSS/CN side) */
498 MGCP.receive(tr_CRCX(cpars.mgcp_ep)) -> value mgcp_cmd {
499 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_mss, cpars.mgw_rtp_ip_mss,
500 hex2str(cpars.mgcp_call_id), "42",
501 cpars.mgw_rtp_port_mss,
502 { int2str(cpars.rtp_payload_type) },
503 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
504 cpars.rtp_sdp_format)),
505 valueof(ts_SDP_ptime(20)) }));
506 MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_mss, sdp));
507 /* MSC acknowledges the MNCC_CREATE to the MNCC handler */
508 MNCC.receive(tr_MNCC_RTP_CREATE(cpars.mncc_callref));
509 }
510
511 /* expect the MSC to trigger a BSSMAP ASSIGNMENT */
512 var BSSMAP_IE_AoIP_TransportLayerAddress tla_ass :=
513 valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.mgw_rtp_ip_bss),cpars.mgw_rtp_port_bss));
514 BSSAP.receive(tr_BSSMAP_AssignmentReq(omit, tla_ass)) {
515 var BSSMAP_IE_AoIP_TransportLayerAddress tla;
516 tla := valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.bss_rtp_ip), cpars.bss_rtp_port));
517 BSSAP.send(ts_BSSMAP_AssignmentComplete(omit, tla));
518 }
519
520 /* MS -> MSC: ALERTING */
521 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CONNECT(cpars.transaction_id)));
522 MNCC.receive(tr_MNCC_SETUP_cnf(cpars.mncc_callref));
523
Harald Welte33ec09b2018-02-10 15:34:46 +0100524 setverdict(pass);
525}
526
Philipp Maier3716a5e2018-03-21 15:53:35 +0100527function f_mo_call_establish(inout CallParameters cpars)
Harald Welteb71901a2018-01-26 19:16:05 +0100528runs on BSC_ConnHdlr {
529
Harald Welteb71901a2018-01-26 19:16:05 +0100530 var MNCC_PDU mncc;
531 var MgcpCommand mgcp_cmd;
Philipp Maier2a98a732018-03-19 16:06:12 +0100532 var boolean respond_to_dlcx;
Harald Welteb71901a2018-01-26 19:16:05 +0100533
Harald Welte0bef21e2018-02-10 09:48:23 +0100534 if (cpars.emergency) {
Harald Welteb9e86fa2018-04-09 18:18:31 +0200535 f_establish_fully(EST_TYPE_EMERG_CALL);
Harald Welte0bef21e2018-02-10 09:48:23 +0100536 } else {
Harald Welteb9e86fa2018-04-09 18:18:31 +0200537 f_establish_fully(EST_TYPE_MO_CALL);
Harald Welte0bef21e2018-02-10 09:48:23 +0100538 }
Harald Welteb71901a2018-01-26 19:16:05 +0100539
540 /* Create MNCC and MGCP expect */
541 f_create_mncc_expect(hex2str(cpars.called_party));
542 f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit});
543
Harald Welte0bef21e2018-02-10 09:48:23 +0100544 if (cpars.emergency) {
545 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_EMERG_SETUP(cpars.transaction_id)));
546 } else {
547 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party)));
548 }
Harald Welteb71901a2018-01-26 19:16:05 +0100549 interleave {
550 [] MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc {
551 cpars.mncc_callref := mncc.u.signal.callref;
552 /* Call Proceeding */
553 MNCC.send(ts_MNCC_CALL_PROC_req(cpars.mncc_callref, cpars.mncc_bearer_cap));
554 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(cpars.transaction_id)));
555 };
Harald Welte4017d552018-01-26 21:40:05 +0100556 /* First MGCP CRCX (for BSS/RAN side) */
Harald Welteb71901a2018-01-26 19:16:05 +0100557 [] MGCP.receive(tr_CRCX) -> value mgcp_cmd {
558 cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd);
Philipp Maierf1e02bb2018-03-15 16:30:00 +0100559
560 /* When the endpoint contains a wildcard we keep the endpoint
561 * identifier we have set up in cpars. Otherwise we use the
562 * endpoint name that the call agent has supplied */
563 if (match(mgcp_cmd.line.ep, t_MGCP_EP_wildcard) == false) {
564 cpars.mgcp_ep := mgcp_cmd.line.ep;
565 }
566
Harald Welte4017d552018-01-26 21:40:05 +0100567 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_bss, cpars.mgw_rtp_ip_bss,
Harald Welteb71901a2018-01-26 19:16:05 +0100568 hex2str(cpars.mgcp_call_id), "42",
Harald Welte4017d552018-01-26 21:40:05 +0100569 cpars.mgw_rtp_port_bss,
Harald Welteb71901a2018-01-26 19:16:05 +0100570 { int2str(cpars.rtp_payload_type) },
571 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
572 cpars.rtp_sdp_format)),
573 valueof(ts_SDP_ptime(20)) }));
Philipp Maierf1e02bb2018-03-15 16:30:00 +0100574
575 var template MgcpResponse mgcp_resp;
576 mgcp_resp := ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_bss, sdp);
577 f_mgcp_par_append(mgcp_resp.params, ts_MgcpParSpecEP(cpars.mgcp_ep));
578 MGCP.send(mgcp_resp);
Harald Welteb71901a2018-01-26 19:16:05 +0100579 }
580 }
Harald Welte4017d552018-01-26 21:40:05 +0100581 /* Second MGCP CRCX (this time for MSS/CN side) */
582 MGCP.receive(tr_CRCX(cpars.mgcp_ep)) -> value mgcp_cmd {
583 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_mss, cpars.mgw_rtp_ip_mss,
584 hex2str(cpars.mgcp_call_id), "42",
585 cpars.mgw_rtp_port_mss,
586 { int2str(cpars.rtp_payload_type) },
587 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
588 cpars.rtp_sdp_format)),
589 valueof(ts_SDP_ptime(20)) }));
590 MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_mss, sdp));
591 }
Harald Welteb71901a2018-01-26 19:16:05 +0100592
593 /* Alerting */
594 MNCC.send(ts_MNCC_ALERT_req(cpars.mncc_callref));
Harald Welteb71901a2018-01-26 19:16:05 +0100595
Harald Welte4017d552018-01-26 21:40:05 +0100596 var BSSMAP_IE_AoIP_TransportLayerAddress tla_ass :=
597 valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.mgw_rtp_ip_bss),cpars.mgw_rtp_port_bss));
598 interleave {
599 [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_ALERTING(cpars.transaction_id))) {}
600 /* expect AoIP IP/Port to match what we returned in CRCX_ACK above */
601 [] BSSAP.receive(tr_BSSMAP_AssignmentReq(omit, tla_ass)) {
Harald Welteb71901a2018-01-26 19:16:05 +0100602 var BSSMAP_IE_AoIP_TransportLayerAddress tla;
603 tla := valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.bss_rtp_ip), cpars.bss_rtp_port));
604 BSSAP.send(ts_BSSMAP_AssignmentComplete(omit, tla));
605 }
606 }
607
Harald Welte4017d552018-01-26 21:40:05 +0100608 /* Answer. MNCC_SETUP_RSP -> CONNECT to MS; CONNECT_ACK from MS */
609 MNCC.send(ts_MNCC_SETUP_rsp(cpars.mncc_callref));
610 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CONNECT(cpars.transaction_id)));
611 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CONNECT_ACK(cpars.transaction_id)));
Harald Welteb71901a2018-01-26 19:16:05 +0100612
Philipp Maier3716a5e2018-03-21 15:53:35 +0100613 setverdict(pass);
614}
Harald Welteb71901a2018-01-26 19:16:05 +0100615
Philipp Maier3716a5e2018-03-21 15:53:35 +0100616function f_call_hangup(inout CallParameters cpars, boolean release_by_ms)
617runs on BSC_ConnHdlr {
618
619 var MobileIdentityLV mi;
620 var MNCC_PDU mncc;
621 var MgcpCommand mgcp_cmd;
622 var boolean respond_to_dlcx;
623
Harald Welteb71901a2018-01-26 19:16:05 +0100624 MNCC.send(ts_MNCC_DISC_req(cpars.mncc_callref, valueof(ts_MNCC_cause(23))));
625 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(cpars.transaction_id)));
626
Philipp Maier3716a5e2018-03-21 15:53:35 +0100627 if (release_by_ms) {
628 /* B-side (MS) Release of call */
629 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_RELEASE(cpars.transaction_id, '1'B, '0000000'B)));
630 MNCC.receive(tr_MNCC_REL_ind(cpars.mncc_callref));
631 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_REL_COMPL(cpars.transaction_id)));
632 } else {
633 /* A-side (PLMN) Release of call */
634 MNCC.send(ts_MNCC_REL_req(cpars.mncc_callref, valueof(ts_MNCC_cause(42))));
635 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(cpars.transaction_id)));
636 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id)));
637 }
Harald Welteb71901a2018-01-26 19:16:05 +0100638
Philipp Maier2a98a732018-03-19 16:06:12 +0100639 respond_to_dlcx := not (isbound(cpars.mgw_drop_dlcx) and valueof(cpars.mgw_drop_dlcx));
640
Harald Welteb71901a2018-01-26 19:16:05 +0100641 /* clearing of radio channel */
642 interleave {
643 [] BSSAP.receive(tr_BSSMAP_ClearCommand) {
644 BSSAP.send(ts_BSSMAP_ClearComplete);
645 BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND);
646 }
647 [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd {
Philipp Maier2a98a732018-03-19 16:06:12 +0100648 if (respond_to_dlcx) {
649 /* TODO: For one or all connections on EP? */
650 MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id));
651 f_create_mgcp_delete_ep(cpars.mgcp_ep);
652 }
Harald Welteb71901a2018-01-26 19:16:05 +0100653 }
654 }
Philipp Maier3716a5e2018-03-21 15:53:35 +0100655
656 setverdict(pass);
657}
658
659function f_mt_call(inout CallParameters cpars)
660runs on BSC_ConnHdlr {
661
662 f_mt_call_establish(cpars);
663
664 /* Hold the call for some time */
665 f_sleep(3.0);
666
667 f_call_hangup(cpars, true);
668
669 setverdict(pass);
670}
671
672function f_mo_call(inout CallParameters cpars)
673runs on BSC_ConnHdlr {
674
675 f_mo_call_establish(cpars);
676
677 /* Hold the call for some time */
678 f_sleep(3.0);
679
680 f_call_hangup(cpars, false);
681
Harald Welteb71901a2018-01-26 19:16:05 +0100682 setverdict(pass);
683}
Harald Weltea49e36e2018-01-21 19:29:33 +0100684
Daniel Willmann8b084372018-02-04 13:35:26 +0100685function f_mo_seq_dtmf_dup(inout CallParameters cpars)
686runs on BSC_ConnHdlr {
687
688 timer T := 1.0;
Daniel Willmann8b084372018-02-04 13:35:26 +0100689 var MNCC_PDU mncc;
690 var MgcpCommand mgcp_cmd;
691 var template PDU_ML3_MS_NW dtmf_dtap;
692
Harald Welteb9e86fa2018-04-09 18:18:31 +0200693 f_establish_fully();
Daniel Willmann8b084372018-02-04 13:35:26 +0100694
695 /* Create MNCC and MGCP expect */
696 f_create_mncc_expect(hex2str(cpars.called_party));
697 f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit});
698
699 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party)));
700 MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc;
701 cpars.mncc_callref := mncc.u.signal.callref;
702
703 /* Send DTMF */
704 dtmf_dtap := ts_ML3_MO_CC_START_DTMF(cpars.transaction_id, "2");
705 dtmf_dtap.msgs.cc.startDTMF.nsd := int2bit(2, 2);
Daniel Willmann92f66272018-02-06 15:50:52 +0100706 BSSAP.send(ts_PDU_DTAP_MO(dtmf_dtap, '00'O, true));
Daniel Willmann8b084372018-02-04 13:35:26 +0100707 T.start;
708 alt {
709 [] MNCC.receive(tr_MNCC_START_DTMF_ind(cpars.mncc_callref, "2")) {}
710 [] T.timeout {
711 setverdict(fail, "Timeout waiting for START_DTMF_ind");
Daniel Willmannafce8662018-07-06 23:11:32 +0200712 mtc.stop;
Daniel Willmann8b084372018-02-04 13:35:26 +0100713 }
714 }
715
Daniel Willmann92f66272018-02-06 15:50:52 +0100716 BSSAP.send(ts_PDU_DTAP_MO(dtmf_dtap, '00'O, true));
Daniel Willmann8b084372018-02-04 13:35:26 +0100717 T.start;
718 alt {
719 [] MNCC.receive(tr_MNCC_START_DTMF_ind(cpars.mncc_callref, "2")) {
720 setverdict(fail, "Received duplicate START_DTMF_ind");
Daniel Willmannafce8662018-07-06 23:11:32 +0200721 mtc.stop;
Daniel Willmann8b084372018-02-04 13:35:26 +0100722 }
723 [] T.timeout { }
724 }
725
726 dtmf_dtap := ts_ML3_MO_CC_START_DTMF(cpars.transaction_id, "3");
727 dtmf_dtap.msgs.cc.startDTMF.nsd := int2bit(3, 2);
Daniel Willmann92f66272018-02-06 15:50:52 +0100728 BSSAP.send(ts_PDU_DTAP_MO(dtmf_dtap, '00'O, true));
Daniel Willmann8b084372018-02-04 13:35:26 +0100729 alt {
730 [] MNCC.receive(tr_MNCC_START_DTMF_ind(cpars.mncc_callref, "3")) { }
731 [] T.timeout {
732 setverdict(fail, "Received duplicate START_DTMF_ind");
Daniel Willmannafce8662018-07-06 23:11:32 +0200733 mtc.stop;
Daniel Willmann8b084372018-02-04 13:35:26 +0100734 }
735 }
736
737 setverdict(pass);
738}
Harald Welte1ddc7162018-01-27 14:25:46 +0100739/* expect a clear command */
Harald Welte5946b332018-03-18 23:32:21 +0100740altstep as_clear_cmd_compl_disc(float t := 5.0) runs on BSC_ConnHdlr {
741 [] BSSAP.receive(tr_BSSMAP_ClearCommand) {
742 BSSAP.send(ts_BSSMAP_ClearComplete);
743 alt {
744 [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
745 setverdict(pass);
746 }
747 [] BSSAP.receive {
748 setverdict(fail, "Unexpected BSSMAP while waiting for SCCP Release");
Daniel Willmannafce8662018-07-06 23:11:32 +0200749 mtc.stop;
Harald Welte5946b332018-03-18 23:32:21 +0100750 }
751 }
752 }
753 [] BSSAP.receive {
754 setverdict(fail, "Unexpected BSSMAP while waiting for ClearCommand");
Daniel Willmannafce8662018-07-06 23:11:32 +0200755 mtc.stop;
Harald Welte5946b332018-03-18 23:32:21 +0100756 }
757}
758
Harald Welte1ddc7162018-01-27 14:25:46 +0100759function f_expect_clear(float t := 5.0) runs on BSC_ConnHdlr {
760 timer T := t;
761
762 T.start;
763 alt {
Harald Welte5946b332018-03-18 23:32:21 +0100764 [] as_clear_cmd_compl_disc(t) { }
Harald Welte1ddc7162018-01-27 14:25:46 +0100765 [] T.timeout {
Harald Welte5946b332018-03-18 23:32:21 +0100766 setverdict(fail, "Timeout waiting for ClearCommand/Release");
Daniel Willmannafce8662018-07-06 23:11:32 +0200767 mtc.stop;
Harald Welte1ddc7162018-01-27 14:25:46 +0100768 }
769 }
770}
771
Harald Weltef45efeb2018-04-09 18:19:24 +0200772type record SmsParametersTp {
773 OCT1 msg_ref,
774 TP_DA da,
775 OCT1 pid,
776 OCT1 dcs,
777 integer udl,
778 octetstring ud
779}
780type record SmsParametersRp {
781 OCT1 msg_ref,
782 RP_NumberingPlan_and_NumberDigits orig optional,
783 RP_NumberingPlan_and_NumberDigits dest optional
784}
785type record SmsParameters {
786 SmsParametersTp tp,
787 SmsParametersRp rp,
788 uint3_t tid,
789 OCT1 dlci,
790 uint7_t exp_rp_err optional
791}
792
793template (value) TP_DA ts_TP_DA(BIT4 npl, BIT3 ton, hexstring addr) := {
794 tP_DA_NoPad := {
795 tP_LengthIndicator := 0, /* overwritten */
796 tP_NumberingPlanID := npl,
797 tP_TypeOfNumber := ton,
798 tp_Spare := '0'B,
799 tP_DAValue := addr
800 }
801}
802
803template (value) SmsParameters t_SmsPars(hexstring tp_daddr := '12345'H) := {
804 tp := {
805 msg_ref := '23'O,
806 da := ts_TP_DA('0000'B, '000'B, tp_daddr),
807 pid := '00'O,
808 dcs := '00'O,
809 udl := 0,
810 ud := ''O
811 },
812 rp := {
813 msg_ref := '42'O,
814 orig := omit,
815 dest := { '0000'B, '000'B, '0'B, '98765'H }
816 },
817 tid := 0,
818 dlci := '03'O,
819 exp_rp_err := omit
820}
821
822private altstep as_other_sms() runs on BSC_ConnHdlr {
823 [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_SMS(?, ?, ?), ?)) {
824 setverdict(fail, "Unexpected SMS related PDU from MSC");
Daniel Willmannafce8662018-07-06 23:11:32 +0200825 mtc.stop;
Harald Weltef45efeb2018-04-09 18:19:24 +0200826 }
827}
828
Vadim Yanitskiyd4cc1502018-11-12 01:46:21 +0700829/* Submit a MO-SMS over an already existing DTAP connection */
830function f_mo_sms_submit(inout SmsParameters spars)
Harald Weltef45efeb2018-04-09 18:19:24 +0200831runs on BSC_ConnHdlr {
832 var template (value) TPDU_RP_DATA_MS_SGSN tp_mo;
833 var template (value) RPDU_MS_SGSN rp_mo;
834 var template (value) PDU_ML3_MS_NW l3_mo;
835
Harald Weltef45efeb2018-04-09 18:19:24 +0200836 var default d := activate(as_other_sms());
837
Harald Weltef640a012018-04-14 17:49:21 +0200838 /* just in case this is routed to SMPP.. */
839 f_create_smpp_expect(hex2str(spars.tp.da.tP_DA_NoPad.tP_DAValue));
840
Harald Weltef45efeb2018-04-09 18:19:24 +0200841 tp_mo := ts_SMS_SUBMIT(spars.tp.msg_ref, spars.tp.da, spars.tp.pid, spars.tp.dcs,
842 spars.tp.udl, spars.tp.ud);
843 rp_mo := ts_RP_DATA_MO(spars.rp.msg_ref, spars.rp.orig, spars.rp.dest, tp_mo);
844 l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_ORIG, ts_CP_DATA_MO(rp_mo));
845 BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true));
846 /* receive CP-ACK for CP-DATA above */
847 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_SMS(spars.tid, c_TIF_REPL, tr_CP_ACK_MT), spars.dlci));
848
Vadim Yanitskiyd4cc1502018-11-12 01:46:21 +0700849 deactivate(d);
850 setverdict(pass);
851}
852
853/* Wait RP-ACK for MO-SMS on an already existing DTAP connection */
854function f_mo_sms_wait_rp_ack(inout SmsParameters spars)
855runs on BSC_ConnHdlr {
856 var template (value) PDU_ML3_MS_NW l3_mo;
857
858 var template TPDU_RP_DATA_SGSN_MS tp_mt;
859 var template RPDU_SGSN_MS rp_mt;
860 var template PDU_ML3_NW_MS l3_mt;
861
862 var default d := activate(as_other_sms());
863
864 /* just in case this is routed to SMPP.. */
865 f_create_smpp_expect(hex2str(spars.tp.da.tP_DA_NoPad.tP_DAValue));
866
Harald Weltef45efeb2018-04-09 18:19:24 +0200867 if (ispresent(spars.exp_rp_err)) {
868 /* expect an RP-ERROR message from MSC with given cause */
869 rp_mt := tr_RP_ERROR_MT(spars.rp.msg_ref, spars.exp_rp_err);
870 l3_mt := tr_ML3_MT_SMS(spars.tid, c_TIF_REPL, tr_CP_DATA_MT(rp_mt));
871 BSSAP.receive(tr_PDU_DTAP_MT(l3_mt, spars.dlci));
872 /* send CP-ACK for CP-DATA just received */
873 l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_ORIG, ts_CP_ACK_MO);
874 BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true));
875 } else {
876 /* expect RP-ACK for RP-DATA */
877 rp_mt := tr_RP_ACK_MT(spars.rp.msg_ref);
878 l3_mt := tr_ML3_MT_SMS(spars.tid, c_TIF_REPL, tr_CP_DATA_MT(rp_mt));
879 BSSAP.receive(tr_PDU_DTAP_MT(l3_mt, spars.dlci));
880 /* send CP-ACO for CP-DATA just received */
881 l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_ORIG, ts_CP_ACK_MO);
882 BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true));
883 }
Vadim Yanitskiyd4cc1502018-11-12 01:46:21 +0700884
Harald Weltef45efeb2018-04-09 18:19:24 +0200885 deactivate(d);
886 setverdict(pass);
887}
888
Vadim Yanitskiyd4cc1502018-11-12 01:46:21 +0700889/* Submit a MO-SMS, and wait for RP-ACK on an existing
890 * (and authenticated, ...) DTAP connection */
891function f_mo_sms(inout SmsParameters spars)
892runs on BSC_ConnHdlr {
893 f_mo_sms_submit(spars);
894 f_mo_sms_wait_rp_ack(spars);
895}
896
Vadim Yanitskiy2159acb2018-11-24 02:50:29 +0700897/* Wait for MT SMS on an already existing DTAP connection */
898function f_mt_sms_expect(inout SmsParameters spars)
Harald Weltef45efeb2018-04-09 18:19:24 +0200899runs on BSC_ConnHdlr {
Harald Weltef45efeb2018-04-09 18:19:24 +0200900 var template (value) PDU_ML3_MS_NW l3_mo;
Harald Weltef45efeb2018-04-09 18:19:24 +0200901 var template TPDU_RP_DATA_SGSN_MS tp_mt;
902 var template RPDU_SGSN_MS rp_mt;
903 var template PDU_ML3_NW_MS l3_mt;
Harald Weltef45efeb2018-04-09 18:19:24 +0200904 var PDU_DTAP_MT dtap_mt;
905
906 var default d := activate(as_other_sms());
907
908 /* Expect CP-DATA(RP-DATA(SMS-DELIVER)) */
909 tp_mt := tr_SMS_DELIVER(?, spars.tp.ud, spars.tp.pid, spars.tp.dcs, ?);
910 rp_mt := tr_RP_DATA_MT(?, ?, omit, tp_mt);
911 l3_mt := tr_ML3_MT_SMS(?, c_TIF_ORIG, tr_CP_DATA_MT(rp_mt));
912 BSSAP.receive(tr_PDU_DTAP_MT(l3_mt, spars.dlci)) -> value dtap_mt;
Vadim Yanitskiy2159acb2018-11-24 02:50:29 +0700913
Harald Weltef45efeb2018-04-09 18:19:24 +0200914 /* Extract relevant identifiers */
915 spars.tid := bit2int(dtap_mt.dtap.tiOrSkip.transactionId.tio);
916 spars.rp.msg_ref := dtap_mt.dtap.msgs.sms.cP_DATA.cP_User_Data.cP_RPDU.rP_DATA_SGSN_MS.rP_MessageReference;
917
918 /* send CP-ACK for CP-DATA just received */
919 l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_REPL, ts_CP_ACK_MO);
920 BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true));
921
Vadim Yanitskiy2159acb2018-11-24 02:50:29 +0700922 deactivate(d);
923 setverdict(pass);
924}
925
926/* Send RP-ACK for MT-SMS over an already existing DTAP connection */
927function f_mt_sms_send_rp_ack(inout SmsParameters spars)
928runs on BSC_ConnHdlr {
929 var template (value) RPDU_MS_SGSN rp_mo;
930 var template (value) PDU_ML3_MS_NW l3_mo;
931 var template PDU_ML3_NW_MS l3_mt;
932
933 var default d := activate(as_other_sms());
934
Harald Weltef45efeb2018-04-09 18:19:24 +0200935 /* send RP-ACK for RP-DATA */
936 rp_mo := ts_RP_ACK_MO(spars.rp.msg_ref);
937 l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_REPL, ts_CP_DATA_MO(rp_mo));
938 BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true));
939
940 /* expect CP-ACK for CP-DATA(RP-ACK) just sent */
Harald Weltee008eea2018-04-14 21:05:48 +0200941 l3_mt := tr_ML3_MT_SMS(spars.tid, c_TIF_ORIG, tr_CP_ACK_MT);
Harald Weltef45efeb2018-04-09 18:19:24 +0200942 BSSAP.receive(tr_PDU_DTAP_MT(l3_mt, spars.dlci));
943
944 deactivate(d);
945 setverdict(pass);
946}
947
Vadim Yanitskiy56318522018-11-24 03:40:47 +0700948/* Send RP-ERROR for MT-SMS over an already existing DTAP connection */
949function f_mt_sms_send_rp_error(inout SmsParameters spars, uint7_t cause)
950runs on BSC_ConnHdlr {
951 var template (value) RPDU_MS_SGSN rp_mo;
952 var template (value) PDU_ML3_MS_NW l3_mo;
953 var template PDU_ML3_NW_MS l3_mt;
954
955 var default d := activate(as_other_sms());
956
957 /* send RP-ACK for RP-DATA */
958 rp_mo := ts_RP_ERROR_MO(spars.rp.msg_ref, cause);
959 l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_REPL, ts_CP_DATA_MO(rp_mo));
960 BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true));
961
962 /* expect CP-ACK for CP-DATA(RP-ERROR) just sent */
963 l3_mt := tr_ML3_MT_SMS(spars.tid, c_TIF_ORIG, tr_CP_ACK_MT);
964 BSSAP.receive(tr_PDU_DTAP_MT(l3_mt, spars.dlci));
965
966 deactivate(d);
967 setverdict(pass);
968}
969
Vadim Yanitskiy2159acb2018-11-24 02:50:29 +0700970/* Wait for a MT-SMS and send RP-ACK over an already existing
971 * (and authenticated, ...) DTAP connection */
972function f_mt_sms(inout SmsParameters spars)
973runs on BSC_ConnHdlr {
974 f_mt_sms_expect(spars);
975 f_mt_sms_send_rp_ack(spars);
976}
Harald Weltea49e36e2018-01-21 19:29:33 +0100977
978
979
980}
981
982