blob: 6cacff7ffb53f6ca4cce45fdc6b64030d0170a65 [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 Weltea49e36e2018-01-21 19:29:33 +010028import from L3_Templates all;
Harald Welte158a7ca2018-02-16 18:11:31 +010029import from L3_Common all;
Harald Weltea49e36e2018-01-21 19:29:33 +010030
31/* this component represents a single subscriber connection */
Harald Welte4aa970c2018-01-26 10:38:09 +010032type component BSC_ConnHdlr extends BSSAP_ConnHdlr, MNCC_ConnHdlr, GSUP_ConnHdlr, MGCP_ConnHdlr {
Harald Weltea49e36e2018-01-21 19:29:33 +010033 var BSC_ConnHdlrPars g_pars;
Harald Weltea10db902018-01-27 12:44:49 +010034 timer g_Tguard := 60.0;
Harald Weltea49e36e2018-01-21 19:29:33 +010035}
36
Harald Weltede371492018-01-27 23:44:41 +010037type record BSC_ConnHdlrNetworkPars {
38 OCT1 kc_support,
39 boolean expect_tmsi,
40 boolean expect_auth,
41 boolean expect_ciph
42}
43
Harald Weltea49e36e2018-01-21 19:29:33 +010044type record BSC_ConnHdlrPars {
45 SCCP_PAR_Address sccp_addr_own,
46 SCCP_PAR_Address sccp_addr_peer,
47 BSSMAP_IE_CellIdentifier cell_id,
Harald Welte256571e2018-01-24 18:47:19 +010048 hexstring imei,
Harald Weltea49e36e2018-01-21 19:29:33 +010049 hexstring imsi,
Harald Welte82600572018-01-21 20:54:08 +010050 hexstring msisdn,
Harald Welte256571e2018-01-24 18:47:19 +010051 OCT4 tmsi optional,
Harald Welte9de84792018-01-28 01:06:35 +010052 MobileStationClassmark1_V cm1,
Harald Welte82600572018-01-21 20:54:08 +010053 BSSMAP_IE_ClassmarkInformationType2 cm2,
Harald Welte16114282018-01-24 22:41:21 +010054 BSSMAP_IE_ClassmarkInformationType3 cm3 optional,
Harald Weltede371492018-01-27 23:44:41 +010055 AuthVector vec optional,
56 BSC_ConnHdlrNetworkPars net
Harald Weltea49e36e2018-01-21 19:29:33 +010057};
58
Harald Welte9de84792018-01-28 01:06:35 +010059/* get a one-octet bitmaks of supported algorithms based on Classmark information */
60function f_alg_mask_from_cm(BSSMAP_IE_ClassmarkInformationType2 cm2) return OCT1 {
61 var BIT8 res := '00000001'B; /* A5/0 always supported */
62
63 if (cm2.a5_1 == '0'B) {
64 res := res or4b '00000010'B;
65 }
66 if (cm2.classmarkInformationType2_oct5.a5_2 == '1'B ) {
67 res := res or4b '00000100'B;
68 }
69 if (cm2.classmarkInformationType2_oct5.a5_3 == '1'B) {
70 res := res or4b '00001000'B;
71 }
72 /* TODO: CM3 for A5/4 and beyond */
73 return bit2oct(res);
74}
75
76/* determine the best algorithm available within the bit-mask */
77function f_best_alg_from_mask(OCT1 alg_in) return OCT1 {
78 var BIT8 alg := oct2bit(alg_in);
79 var BIT8 ordered_algs[8] := {
80 '10000000'B, '01000000'B, '00100000'B, '00010000'B,
81 '00001000'B, /* A5/3 */
82 '00000010'B, /* A5/1 */
83 '00000100'B, /* A5/2 */
84 '00000001'B /* A5/0 */ }
85 for (var integer i := 0; i < sizeof(ordered_algs); i := i+1) {
86 if (alg and4b ordered_algs[i] != '00000000'B) {
87 return bit2oct(ordered_algs[i]);
88 }
89 }
90 return '00'O;
91}
92
93/* return an integer like '1' for A5/1 based on a mask (with only one bit set */
94function f_alg_from_mask(OCT1 mask_in) return integer {
95 var BIT8 mask := oct2bit(mask_in);
96 for (var integer i := 0; i < 8; i := i+1) {
97 if (mask and4b ('00000001'B << i) != '00000000'B) {
98 return i;
99 }
100 }
101 return -1;
102}
103
Harald Weltea10db902018-01-27 12:44:49 +0100104/* altstep for the global guard timer */
105private altstep as_Tguard() runs on BSC_ConnHdlr {
106 [] g_Tguard.timeout {
Daniel Willmann90829d62018-02-15 17:45:14 +0100107 setverdict(fail, "Tguard timeout");
Harald Weltea10db902018-01-27 12:44:49 +0100108 self.stop;
109 }
110}
111
112/* init function, called as first function in new BSC_ConnHdlr */
Harald Weltead2952e2018-01-27 14:12:46 +0100113function f_init_handler(BSC_ConnHdlrPars pars, float t_guard := 60.0) runs on BSC_ConnHdlr {
Harald Weltea10db902018-01-27 12:44:49 +0100114 /* make parameters available via component variable */
115 g_pars := pars;
116 /* Start guard timer and activate it as default */
Harald Weltead2952e2018-01-27 14:12:46 +0100117 g_Tguard.start(t_guard);
Harald Weltea10db902018-01-27 12:44:49 +0100118 activate(as_Tguard());
119}
120
Harald Weltea49e36e2018-01-21 19:29:33 +0100121
122/* Callback function from general BSSMAP_Emulation whenever a connectionless
123 * BSSMAP message arrives. Canreturn a PDU_BSSAPthat should be sent in return */
124private function BscUnitdataCallback(PDU_BSSAP bssap)
125runs on BSSMAP_Emulation_CT return template PDU_BSSAP {
126 var template PDU_BSSAP resp := omit;
127
128 log("BSSMAP_BscUnitdataCallback");
129 /* answer all RESET with RESET ACK */
130 if (match(bssap, tr_BSSMAP_Reset)){
131 log("BSSMAP_BscUnitdataCallback: Responding to RESET with RESET-ACK");
132 resp := ts_BSSMAP_ResetAck;
133 }
134
135 /* FIXME: Handle paging, etc. */
136 return resp;
137}
138
139const BssmapOps BSC_BssmapOps := {
140 /* Create call-back for inbound connections from MSC (hand-over) */
141 create_cb := refers(BSSMAP_Emulation.ExpectedCreateCallback),
142 unitdata_cb := refers(BscUnitdataCallback),
143 decode_dtap := true,
Harald Weltea4ca4462018-02-09 00:17:14 +0100144 role_ms := true,
145 sccp_addr_local := omit,
146 sccp_addr_peer := omit
Harald Weltea49e36e2018-01-21 19:29:33 +0100147}
148
149
150private function MnccUnitdataCallback(MNCC_PDU mncc)
151runs on MNCC_Emulation_CT return template MNCC_PDU {
152 log("Ignoring MNCC", mncc);
153 return omit;
154}
155
156const MnccOps BCC_MnccOps := {
157 create_cb := refers(MNCC_Emulation.ExpectedCreateCallback),
158 unitdata_cb := refers(MnccUnitdataCallback)
159}
160
161
162
163template BSSAP_Conn_Req ts_BSSAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, PDU_BSSAP bssap) := {
164 addr_peer := peer,
165 addr_own := own,
166 bssap := bssap
167};
168
Harald Weltea49e36e2018-01-21 19:29:33 +0100169/* Encode 'l3' and ask BSSMAP_Emulation to create new connection with COMPL L3 INFO */
170function f_bssap_compl_l3(PDU_ML3_MS_NW l3)
171runs on BSC_ConnHdlr {
172 log("Sending COMPL L3: ", l3);
173 var octetstring l3_enc := enc_PDU_ML3_MS_NW(l3);
174 BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_own,
175 valueof(ts_BSSMAP_ComplL3(g_pars.cell_id, l3_enc))));
Harald Welte71b69332018-01-21 20:43:53 +0100176 alt {
177 [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_CONF_IND) {}
178 [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
179 setverdict(fail, "DISC.ind from SCCP");
180 self.stop;
181 }
182 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100183}
184
Harald Welte081b19a2018-02-10 09:11:13 +0100185type enumerated EstablishType {
186 EST_TYPE_MO_CALL,
Harald Welte0bef21e2018-02-10 09:48:23 +0100187 EST_TYPE_EMERG_CALL,
Harald Welte081b19a2018-02-10 09:11:13 +0100188 EST_TYPE_PAG_RESP
189};
190
Harald Weltea49e36e2018-01-21 19:29:33 +0100191/* helper function to fully establish a dedicated channel */
Harald Welte081b19a2018-02-10 09:11:13 +0100192function f_establish_fully(MobileIdentityLV mi, EstablishType etype := EST_TYPE_MO_CALL)
Harald Weltea49e36e2018-01-21 19:29:33 +0100193runs on BSC_ConnHdlr {
Harald Welte081b19a2018-02-10 09:11:13 +0100194 var PDU_ML3_MS_NW l3_info;
195 select (etype) {
196 case (EST_TYPE_MO_CALL) {
197 l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, mi));
198 }
Harald Welte0bef21e2018-02-10 09:48:23 +0100199 case (EST_TYPE_EMERG_CALL) {
200 l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_EMERG_CALL, mi));
201 }
Harald Welte081b19a2018-02-10 09:11:13 +0100202 case (EST_TYPE_PAG_RESP) {
203 l3_info := valueof(ts_PAG_RESP(mi));
204 }
205 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100206
207 /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */
208 f_bssap_compl_l3(l3_info);
209
Harald Weltede371492018-01-27 23:44:41 +0100210 f_mm_common();
211 if (g_pars.net.expect_ciph) {
Harald Welte148a7082018-01-26 18:56:43 +0100212 /* implicit CM SERVICE ACCEPT? */
213 } else {
Harald Welte0bef21e2018-02-10 09:48:23 +0100214 if (etype != EST_TYPE_PAG_RESP) {
Harald Welte081b19a2018-02-10 09:11:13 +0100215 /* explicit CM SERVICE ACCEPT */
216 BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_ACC));
217 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100218 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100219}
220
221/* build a PDU_ML3_MS_NW containing a Location Update by IMSI */
Harald Welte9de84792018-01-28 01:06:35 +0100222function f_build_lu_imsi(hexstring imsi) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Weltea49e36e2018-01-21 19:29:33 +0100223{
224 var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(imsi));
225 return f_build_lu(mi);
226}
Harald Welte9de84792018-01-28 01:06:35 +0100227function f_build_lu_imei(hexstring imei) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Welteba7b6d92018-01-23 21:32:34 +0100228{
229 var MobileIdentityLV mi := valueof(ts_MI_IMEI_LV(imei));
230 return f_build_lu(mi);
231}
Harald Welte9de84792018-01-28 01:06:35 +0100232function f_build_lu_tmsi(OCT4 tmsi) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Welteba7b6d92018-01-23 21:32:34 +0100233{
234 var MobileIdentityLV mi := valueof(ts_MI_TMSI_LV(tmsi));
235 return f_build_lu(mi);
236}
Harald Welte9de84792018-01-28 01:06:35 +0100237private function f_build_lu(MobileIdentityLV mi) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Weltea49e36e2018-01-21 19:29:33 +0100238{
239 var LocationAreaIdentification_V old_lai := { '62F220'O, '9999'O };
240 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 +0100241 old_lai, mi, g_pars.cm1));
Harald Weltea49e36e2018-01-21 19:29:33 +0100242 return l3_info;
243}
244
Harald Welte9de84792018-01-28 01:06:35 +0100245function f_mm_auth() runs on BSC_ConnHdlr
Harald Welte148a7082018-01-26 18:56:43 +0100246{
Harald Weltede371492018-01-27 23:44:41 +0100247 if (g_pars.net.expect_auth) {
Harald Welte148a7082018-01-26 18:56:43 +0100248 g_pars.vec := f_gen_auth_vec_2g();
249 var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(g_pars.vec.rand,
250 g_pars.vec.sres,
251 g_pars.vec.kc));
252 GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi));
253 GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple));
254
255 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_AUTH_REQ(g_pars.vec.rand)));
256 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MT_MM_AUTH_RESP_2G(g_pars.vec.sres)));
257 }
Harald Welte9de84792018-01-28 01:06:35 +0100258}
Harald Welte148a7082018-01-26 18:56:43 +0100259
Harald Welte9de84792018-01-28 01:06:35 +0100260function f_mm_common() runs on BSC_ConnHdlr
261{
262 f_mm_auth();
Harald Weltede371492018-01-27 23:44:41 +0100263 if (g_pars.net.expect_ciph) {
Harald Welte9de84792018-01-28 01:06:35 +0100264 var OCT1 a5_net := f_alg_mask_from_cm(g_pars.cm2);
265 var OCT1 a5_intersect := g_pars.net.kc_support and4b a5_net;
266 alt {
267 [] BSSAP.receive(tr_BSSMAP_CipherModeCmd(a5_intersect, g_pars.vec.kc)) {
268 var OCT1 a5_chosen := f_best_alg_from_mask(a5_intersect);
269 var integer a5_nr := f_alg_from_mask(a5_chosen);
270 BSSAP.send(ts_BSSMAP_CipherModeCompl(int2oct(a5_nr+1, 1)));
271 }
272 [] BSSAP.receive(tr_BSSMAP_CipherModeCmd(?, g_pars.vec.kc)) {
273 setverdict(fail, "Wrong ciphering algorithm mask in CiphModCmd");
274 self.stop;
275 }
276 }
277 /* FIXME: Send the best available algorithm */
Harald Welte148a7082018-01-26 18:56:43 +0100278 }
279}
280
Harald Weltede371492018-01-27 23:44:41 +0100281function f_perform_lu(boolean send_early_cm)
Harald Weltea49e36e2018-01-21 19:29:33 +0100282runs on BSC_ConnHdlr {
283 var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi)
284 var PDU_DTAP_MT dtap_mt;
285
286 /* tell GSUP dispatcher to send this IMSI to us */
287 f_create_gsup_expect(hex2str(g_pars.imsi));
288
289 /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */
290 f_bssap_compl_l3(l3_lu);
291
Harald Welte8a121b32018-01-22 03:00:41 +0100292 if (send_early_cm) {
293 BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3));
294 }
Harald Welte5c2622c2018-01-21 20:45:20 +0100295
Harald Weltede371492018-01-27 23:44:41 +0100296 f_mm_common();
Harald Welte16114282018-01-24 22:41:21 +0100297
Harald Weltea49e36e2018-01-21 19:29:33 +0100298 /* Expect MSC to perform LU with HLR */
299 GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi));
300 GSUP.send(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn));
301 GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi));
302 GSUP.send(ts_GSUP_UL_RES(g_pars.imsi));
303
304 alt {
305 [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) -> value dtap_mt {
306 var PDU_ML3_LocationUpdateAccept lu_acc := dtap_mt.dtap.msgs.mm.locationUpdateAccept;
Harald Weltede371492018-01-27 23:44:41 +0100307 if (g_pars.net.expect_tmsi) {
Harald Weltea49e36e2018-01-21 19:29:33 +0100308 if (not ispresent(lu_acc.mobileIdentityTLV) or
309 not ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) {
310 setverdict(fail, "Expected TMSI but no TMSI was allocated");
311 self.stop;
312 } else {
Harald Welte256571e2018-01-24 18:47:19 +0100313 g_pars.tmsi := lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi.octets;
Harald Weltea49e36e2018-01-21 19:29:33 +0100314 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_TmsiRealloc_Cmpl));
315 }
316 } else {
317 if (ispresent(lu_acc.mobileIdentityTLV) and
318 ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) {
319 setverdict(fail, "Expected no TMSI but TMSI was allocated");
320 self.stop;
321 }
322 }
323 }
324 [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) {
325 setverdict(fail, "Expected LU ACK, but received LU REJ");
326 self.stop;
327 }
328 }
329 /* FIXME: there could be pending SMS or other common procedures by the MSC, let's ignore them */
330 BSSAP.receive(tr_BSSMAP_ClearCommand);
331 BSSAP.send(ts_BSSMAP_ClearComplete);
332 BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND);
333 setverdict(pass);
334}
335
336function f_foo() runs on BSC_ConnHdlr{
337 /* SCCP CC handled by BSSMAP_Emulation_CT.main() */
338 /* Expect auth, if enabled */
339
340 /* TODO: ISD */
341 /* Expect encr, if enabled */
342 /* Expect encr, if enabled */
343 /* Expect ASS CMD, if chan_type != requested */
344 /* Send ASS CMPL in successful case */
345
346 /* Expect AoIP port/ip information for RTP stream */
347 /* Expect MSC-originated MGCP to our simulated MGW */
348 /* Verify Counters via CTRL */
349 /* re-configure MSC behaviour via VTY */
350}
351
Harald Welteb71901a2018-01-26 19:16:05 +0100352/* parameters related to a (MO?) voice call */
353type record CallParameters {
Harald Welteb71901a2018-01-26 19:16:05 +0100354 /* CC related parameters */
355 hexstring called_party, /* whom are we calling */
356 integer transaction_id optional, /* which TS 04.08 CC transaction ID to use */
357 BearerCapability_TLV bearer_cap, /* which bearer capabilities to claim */
Harald Welte0bef21e2018-02-10 09:48:23 +0100358 boolean emergency, /* is this an emergency call? */
Harald Welteb71901a2018-01-26 19:16:05 +0100359
360 /* MNCC related parameters */
361 uint32_t mncc_callref optional, /* call reference on the MNCC side */
362 MNCC_bearer_cap mncc_bearer_cap optional, /* MNCC-side bearer capabilities */
363
364 /* RTP related parameters */
365 HostName bss_rtp_ip optional, /* BSS Side RTP IP */
366 PortNumber bss_rtp_port optional, /* BSS Side RTP Port */
367 HostName mss_rtp_ip optional, /* MSS Side RTP IP */
368 PortNumber mss_rtp_port optional, /* MSS Side RTP Port */
Harald Welte4017d552018-01-26 21:40:05 +0100369 HostName mgw_rtp_ip_bss, /* BSS-facing MGW RTP IP */
370 PortNumber mgw_rtp_port_bss, /* BSS-facing MGW RTP Port */
371 HostName mgw_rtp_ip_mss, /* MSS-facing MGW RTP IP */
372 PortNumber mgw_rtp_port_mss, /* MSS-facing MGW RTP Port */
Harald Welteb71901a2018-01-26 19:16:05 +0100373 uint7_t rtp_payload_type, /* dynamic RTP payload type */
374 charstring rtp_sdp_format, /* AMR/8000 or the like */
375
376 MgcpCallId mgcp_call_id optional, /* MGCP Call ID; CallAgent allocated */
377 MgcpEndpoint mgcp_ep optional /* MGCP Endpoint, CallAgent or MGW allocated */,
378 MgcpConnectionId mgcp_connection_id_bss, /* MGCP Connection ID BSS Side */
379 MgcpConnectionId mgcp_connection_id_mss /* MGCP Connection ID MSS Side */
380}
381
382template (value) CallParameters t_CallParams(hexstring called, integer tid) := {
Harald Welteb71901a2018-01-26 19:16:05 +0100383 called_party := called,
384 transaction_id := tid,
385 bearer_cap := valueof(ts_Bcap_voice),
Harald Welte0bef21e2018-02-10 09:48:23 +0100386 emergency := false,
Harald Welteb71901a2018-01-26 19:16:05 +0100387 mncc_callref := omit,
388 mncc_bearer_cap := valueof(ts_MNCC_bcap_voice),
Harald Welte4017d552018-01-26 21:40:05 +0100389 bss_rtp_ip := "9.8.7.6",
390 bss_rtp_port := 9000,
Harald Welteb71901a2018-01-26 19:16:05 +0100391 mss_rtp_ip := omit,
392 mss_rtp_port := omit,
Harald Welte4017d552018-01-26 21:40:05 +0100393 mgw_rtp_ip_bss := "1.1.1.1",
394 mgw_rtp_port_bss := 10000,
395 mgw_rtp_ip_mss := "1.1.1.1",
396 mgw_rtp_port_mss := 11000,
Harald Welteb71901a2018-01-26 19:16:05 +0100397 rtp_payload_type := 98,
398 rtp_sdp_format := "AMR/8000",
399 mgcp_call_id := omit,
400 mgcp_ep := omit,
401 mgcp_connection_id_bss := '0'H,//
402 mgcp_connection_id_mss := '0'H //
403};
404
405
Harald Welte33ec09b2018-02-10 15:34:46 +0100406function f_mt_call(inout CallParameters cpars)
407runs on BSC_ConnHdlr {
408
409 var MobileIdentityLV mi;
410 var MNCC_PDU mncc;
411 var MgcpCommand mgcp_cmd;
412
413 f_bssmap_register_imsi(g_pars.imsi, g_pars.tmsi);
414
415 /* Allocate a call reference and send SETUP via MNCC to MSC */
416 cpars.mncc_callref := f_rnd_int(2147483648);
417 MNCC.send(ts_MNCC_SETUP_req(cpars.mncc_callref, hex2str(g_pars.msisdn),
418 hex2str(cpars.called_party), hex2str(g_pars.imsi)));
419 /* BSC <- MSC: Expect paging. FIXME: By TMSI or not? */
420 BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi));
421
422 /* If we have a TMSI, use TMSI instead of IMSI */
423 if (ispresent(g_pars.tmsi)) {
424 mi := valueof(ts_MI_TMSI_LV(g_pars.tmsi));
425 } else {
426 mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
427 }
428 f_establish_fully(mi, EST_TYPE_PAG_RESP);
429
430 /* MS <- MSC: Expect CC SETUP */
431 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_SETUP(cpars.transaction_id, *, cpars.called_party)));
432
433 /* MS -> MSC: ALERTING */
434 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_ALERTING(cpars.transaction_id)));
435 MNCC.receive(tr_MNCC_ALERT_ind(cpars.mncc_callref));
436
437
438 /* Create MGCP expect */
439 f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit});
440 /* Ask MSC via MNCC to create the RTP socket on the MSC/MGW side */
441 MNCC.send(ts_MNCC_RTP_CREATE(cpars.mncc_callref));
442
443 /* First MGCP CRCX (for BSS/RAN side) */
444 MGCP.receive(tr_CRCX) -> value mgcp_cmd {
445 cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd);
446 /* TODO: dynamic EP allocation case */
447 cpars.mgcp_ep := mgcp_cmd.line.ep;
448 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_bss, cpars.mgw_rtp_ip_bss,
449 hex2str(cpars.mgcp_call_id), "42",
450 cpars.mgw_rtp_port_bss,
451 { int2str(cpars.rtp_payload_type) },
452 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
453 cpars.rtp_sdp_format)),
454 valueof(ts_SDP_ptime(20)) }));
455 MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_bss, sdp));
456 }
457 /* Second MGCP CRCX (this time for MSS/CN side) */
458 MGCP.receive(tr_CRCX(cpars.mgcp_ep)) -> value mgcp_cmd {
459 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_mss, cpars.mgw_rtp_ip_mss,
460 hex2str(cpars.mgcp_call_id), "42",
461 cpars.mgw_rtp_port_mss,
462 { int2str(cpars.rtp_payload_type) },
463 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
464 cpars.rtp_sdp_format)),
465 valueof(ts_SDP_ptime(20)) }));
466 MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_mss, sdp));
467 /* MSC acknowledges the MNCC_CREATE to the MNCC handler */
468 MNCC.receive(tr_MNCC_RTP_CREATE(cpars.mncc_callref));
469 }
470
471 /* expect the MSC to trigger a BSSMAP ASSIGNMENT */
472 var BSSMAP_IE_AoIP_TransportLayerAddress tla_ass :=
473 valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.mgw_rtp_ip_bss),cpars.mgw_rtp_port_bss));
474 BSSAP.receive(tr_BSSMAP_AssignmentReq(omit, tla_ass)) {
475 var BSSMAP_IE_AoIP_TransportLayerAddress tla;
476 tla := valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.bss_rtp_ip), cpars.bss_rtp_port));
477 BSSAP.send(ts_BSSMAP_AssignmentComplete(omit, tla));
478 }
479
480 /* MS -> MSC: ALERTING */
481 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CONNECT(cpars.transaction_id)));
482 MNCC.receive(tr_MNCC_SETUP_cnf(cpars.mncc_callref));
483
484 /* FIXME */
485 f_sleep(3.0);
486
487 /* Hangup by "A" side */
488 MNCC.send(ts_MNCC_DISC_req(cpars.mncc_callref, valueof(ts_MNCC_cause(23))));
489 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(cpars.transaction_id)));
490
491 if (false) {
492 /* A-side (PLMN) Release of call */
493 MNCC.send(ts_MNCC_REL_req(cpars.mncc_callref, valueof(ts_MNCC_cause(42))));
494 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(cpars.transaction_id)));
495 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id)));
496 } else {
497 /* B-side (MS) Release of call */
498 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_RELEASE(cpars.transaction_id, '1'B, '0000000'B)));
499 MNCC.receive(tr_MNCC_REL_ind(cpars.mncc_callref));
500 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_REL_COMPL(cpars.transaction_id)));
501 }
502
503 /* clearing of radio channel */
504 interleave {
505 [] BSSAP.receive(tr_BSSMAP_ClearCommand) {
506 BSSAP.send(ts_BSSMAP_ClearComplete);
507 BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND);
508 }
509 [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd {
510 /* TODO: For one or all connections on EP? */
511 MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id));
512 f_create_mgcp_delete_ep(cpars.mgcp_ep);
513 }
514 }
515 setverdict(pass);
516}
517
Harald Welteb71901a2018-01-26 19:16:05 +0100518function f_mo_call(inout CallParameters cpars)
519runs on BSC_ConnHdlr {
520
521 var MobileIdentityLV mi;
522 var MNCC_PDU mncc;
523 var MgcpCommand mgcp_cmd;
524
525 /* If we have a TMSI, use TMSI instead of IMSI */
526 if (ispresent(g_pars.tmsi)) {
527 mi := valueof(ts_MI_TMSI_LV(g_pars.tmsi));
528 } else {
529 mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
530 }
Harald Welte0bef21e2018-02-10 09:48:23 +0100531 if (cpars.emergency) {
532 f_establish_fully(mi, EST_TYPE_EMERG_CALL);
533 } else {
534 f_establish_fully(mi, EST_TYPE_MO_CALL);
535 }
Harald Welteb71901a2018-01-26 19:16:05 +0100536
537 /* Create MNCC and MGCP expect */
538 f_create_mncc_expect(hex2str(cpars.called_party));
539 f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit});
540
Harald Welte0bef21e2018-02-10 09:48:23 +0100541 if (cpars.emergency) {
542 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_EMERG_SETUP(cpars.transaction_id)));
543 } else {
544 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party)));
545 }
Harald Welteb71901a2018-01-26 19:16:05 +0100546 interleave {
547 [] MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc {
548 cpars.mncc_callref := mncc.u.signal.callref;
549 /* Call Proceeding */
550 MNCC.send(ts_MNCC_CALL_PROC_req(cpars.mncc_callref, cpars.mncc_bearer_cap));
551 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(cpars.transaction_id)));
552 };
Harald Welte4017d552018-01-26 21:40:05 +0100553 /* First MGCP CRCX (for BSS/RAN side) */
Harald Welteb71901a2018-01-26 19:16:05 +0100554 [] MGCP.receive(tr_CRCX) -> value mgcp_cmd {
555 cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd);
556 /* TODO: dynamic EP allocation case */
557 cpars.mgcp_ep := mgcp_cmd.line.ep;
Harald Welte4017d552018-01-26 21:40:05 +0100558 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_bss, cpars.mgw_rtp_ip_bss,
Harald Welteb71901a2018-01-26 19:16:05 +0100559 hex2str(cpars.mgcp_call_id), "42",
Harald Welte4017d552018-01-26 21:40:05 +0100560 cpars.mgw_rtp_port_bss,
Harald Welteb71901a2018-01-26 19:16:05 +0100561 { int2str(cpars.rtp_payload_type) },
562 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
563 cpars.rtp_sdp_format)),
564 valueof(ts_SDP_ptime(20)) }));
565 MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_bss, sdp));
566 }
567 }
Harald Welte4017d552018-01-26 21:40:05 +0100568 /* Second MGCP CRCX (this time for MSS/CN side) */
569 MGCP.receive(tr_CRCX(cpars.mgcp_ep)) -> value mgcp_cmd {
570 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_mss, cpars.mgw_rtp_ip_mss,
571 hex2str(cpars.mgcp_call_id), "42",
572 cpars.mgw_rtp_port_mss,
573 { int2str(cpars.rtp_payload_type) },
574 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
575 cpars.rtp_sdp_format)),
576 valueof(ts_SDP_ptime(20)) }));
577 MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_mss, sdp));
578 }
Harald Welteb71901a2018-01-26 19:16:05 +0100579
580 /* Alerting */
581 MNCC.send(ts_MNCC_ALERT_req(cpars.mncc_callref));
Harald Welteb71901a2018-01-26 19:16:05 +0100582
Harald Welte4017d552018-01-26 21:40:05 +0100583 var BSSMAP_IE_AoIP_TransportLayerAddress tla_ass :=
584 valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.mgw_rtp_ip_bss),cpars.mgw_rtp_port_bss));
585 interleave {
586 [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_ALERTING(cpars.transaction_id))) {}
587 /* expect AoIP IP/Port to match what we returned in CRCX_ACK above */
588 [] BSSAP.receive(tr_BSSMAP_AssignmentReq(omit, tla_ass)) {
Harald Welteb71901a2018-01-26 19:16:05 +0100589 var BSSMAP_IE_AoIP_TransportLayerAddress tla;
590 tla := valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.bss_rtp_ip), cpars.bss_rtp_port));
591 BSSAP.send(ts_BSSMAP_AssignmentComplete(omit, tla));
592 }
593 }
594
Harald Welte4017d552018-01-26 21:40:05 +0100595 /* Answer. MNCC_SETUP_RSP -> CONNECT to MS; CONNECT_ACK from MS */
596 MNCC.send(ts_MNCC_SETUP_rsp(cpars.mncc_callref));
597 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CONNECT(cpars.transaction_id)));
598 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CONNECT_ACK(cpars.transaction_id)));
Harald Welteb71901a2018-01-26 19:16:05 +0100599
600 f_sleep(3.0);
601
602 /* Hangup by "B" side */
603 MNCC.send(ts_MNCC_DISC_req(cpars.mncc_callref, valueof(ts_MNCC_cause(23))));
604 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(cpars.transaction_id)));
605
606 /* Release of call */
607 MNCC.send(ts_MNCC_REL_req(cpars.mncc_callref, valueof(ts_MNCC_cause(42))));
608 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(cpars.transaction_id)));
609 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id)));
610
611 /* clearing of radio channel */
612 interleave {
613 [] BSSAP.receive(tr_BSSMAP_ClearCommand) {
614 BSSAP.send(ts_BSSMAP_ClearComplete);
615 BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND);
616 }
617 [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd {
618 /* TODO: For one or all connections on EP? */
619 MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id));
620 f_create_mgcp_delete_ep(cpars.mgcp_ep);
621 }
622 }
623 setverdict(pass);
624}
Harald Weltea49e36e2018-01-21 19:29:33 +0100625
Daniel Willmann8b084372018-02-04 13:35:26 +0100626function f_mo_seq_dtmf_dup(inout CallParameters cpars)
627runs on BSC_ConnHdlr {
628
629 timer T := 1.0;
630 var MobileIdentityLV mi;
631 var MNCC_PDU mncc;
632 var MgcpCommand mgcp_cmd;
633 var template PDU_ML3_MS_NW dtmf_dtap;
634
635 /* If we have a TMSI, use TMSI instead of IMSI */
636 if (ispresent(g_pars.tmsi)) {
637 mi := valueof(ts_MI_TMSI_LV(g_pars.tmsi));
638 } else {
639 mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
640 }
641 f_establish_fully(mi);
642
643 /* Create MNCC and MGCP expect */
644 f_create_mncc_expect(hex2str(cpars.called_party));
645 f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit});
646
647 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party)));
648 MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc;
649 cpars.mncc_callref := mncc.u.signal.callref;
650
651 /* Send DTMF */
652 dtmf_dtap := ts_ML3_MO_CC_START_DTMF(cpars.transaction_id, "2");
653 dtmf_dtap.msgs.cc.startDTMF.nsd := int2bit(2, 2);
Daniel Willmann92f66272018-02-06 15:50:52 +0100654 BSSAP.send(ts_PDU_DTAP_MO(dtmf_dtap, '00'O, true));
Daniel Willmann8b084372018-02-04 13:35:26 +0100655 T.start;
656 alt {
657 [] MNCC.receive(tr_MNCC_START_DTMF_ind(cpars.mncc_callref, "2")) {}
658 [] T.timeout {
659 setverdict(fail, "Timeout waiting for START_DTMF_ind");
660 self.stop;
661 }
662 }
663
Daniel Willmann92f66272018-02-06 15:50:52 +0100664 BSSAP.send(ts_PDU_DTAP_MO(dtmf_dtap, '00'O, true));
Daniel Willmann8b084372018-02-04 13:35:26 +0100665 T.start;
666 alt {
667 [] MNCC.receive(tr_MNCC_START_DTMF_ind(cpars.mncc_callref, "2")) {
668 setverdict(fail, "Received duplicate START_DTMF_ind");
669 self.stop;
670 }
671 [] T.timeout { }
672 }
673
674 dtmf_dtap := ts_ML3_MO_CC_START_DTMF(cpars.transaction_id, "3");
675 dtmf_dtap.msgs.cc.startDTMF.nsd := int2bit(3, 2);
Daniel Willmann92f66272018-02-06 15:50:52 +0100676 BSSAP.send(ts_PDU_DTAP_MO(dtmf_dtap, '00'O, true));
Daniel Willmann8b084372018-02-04 13:35:26 +0100677 alt {
678 [] MNCC.receive(tr_MNCC_START_DTMF_ind(cpars.mncc_callref, "3")) { }
679 [] T.timeout {
680 setverdict(fail, "Received duplicate START_DTMF_ind");
681 self.stop;
682 }
683 }
684
685 setverdict(pass);
686}
Harald Welte1ddc7162018-01-27 14:25:46 +0100687/* expect a clear command */
688function f_expect_clear(float t := 5.0) runs on BSC_ConnHdlr {
689 timer T := t;
690
691 T.start;
692 alt {
693 [] BSSAP.receive(tr_BSSMAP_ClearCommand) { }
694 [] BSSAP.receive {
695 setverdict(fail, "Unexpected BSSMAP while waiting for ClearCommand");
696 self.stop;
697 }
698 [] T.timeout {
Daniel Willmann90829d62018-02-15 17:45:14 +0100699 setverdict(fail, "Timeout waiting for ClearCommand");
Harald Welte1ddc7162018-01-27 14:25:46 +0100700 self.stop;
701 }
702 }
703
704 BSSAP.send(ts_BSSMAP_ClearComplete);
705
706 T.start;
707 alt {
708 [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
709 setverdict(pass);
710 }
711 [] BSSAP.receive {
712 setverdict(fail, "Unexpected BSSMAP while waiting for SCCP Release");
713 self.stop;
714 }
715 [] T.timeout {
Daniel Willmann90829d62018-02-15 17:45:14 +0100716 setverdict(fail, "Timeout waiting for SCCP Release");
Harald Welte1ddc7162018-01-27 14:25:46 +0100717 self.stop;
718 }
719 }
720}
721
Harald Weltea49e36e2018-01-21 19:29:33 +0100722
723
724
725}
726
727