blob: 856b20a0954f52451327dd378c00339268593ce0 [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;
29
30/* this component represents a single subscriber connection */
Harald Welte4aa970c2018-01-26 10:38:09 +010031type component BSC_ConnHdlr extends BSSAP_ConnHdlr, MNCC_ConnHdlr, GSUP_ConnHdlr, MGCP_ConnHdlr {
Harald Weltea49e36e2018-01-21 19:29:33 +010032 var BSC_ConnHdlrPars g_pars;
Harald Weltea10db902018-01-27 12:44:49 +010033 timer g_Tguard := 60.0;
Harald Weltea49e36e2018-01-21 19:29:33 +010034}
35
Harald Welte148a7082018-01-26 18:56:43 +010036type record AuthVector {
37 OCT16 rand,
38 OCT4 sres,
39 OCT8 kc
40 /* FIXME: 3G elements */
41}
42
Harald Weltede371492018-01-27 23:44:41 +010043type record BSC_ConnHdlrNetworkPars {
44 OCT1 kc_support,
45 boolean expect_tmsi,
46 boolean expect_auth,
47 boolean expect_ciph
48}
49
Harald Weltea49e36e2018-01-21 19:29:33 +010050type record BSC_ConnHdlrPars {
51 SCCP_PAR_Address sccp_addr_own,
52 SCCP_PAR_Address sccp_addr_peer,
53 BSSMAP_IE_CellIdentifier cell_id,
Harald Welte256571e2018-01-24 18:47:19 +010054 hexstring imei,
Harald Weltea49e36e2018-01-21 19:29:33 +010055 hexstring imsi,
Harald Welte82600572018-01-21 20:54:08 +010056 hexstring msisdn,
Harald Welte256571e2018-01-24 18:47:19 +010057 OCT4 tmsi optional,
Harald Welte9de84792018-01-28 01:06:35 +010058 MobileStationClassmark1_V cm1,
Harald Welte82600572018-01-21 20:54:08 +010059 BSSMAP_IE_ClassmarkInformationType2 cm2,
Harald Welte16114282018-01-24 22:41:21 +010060 BSSMAP_IE_ClassmarkInformationType3 cm3 optional,
Harald Weltede371492018-01-27 23:44:41 +010061 AuthVector vec optional,
62 BSC_ConnHdlrNetworkPars net
Harald Weltea49e36e2018-01-21 19:29:33 +010063};
64
Harald Welte9de84792018-01-28 01:06:35 +010065/* get a one-octet bitmaks of supported algorithms based on Classmark information */
66function f_alg_mask_from_cm(BSSMAP_IE_ClassmarkInformationType2 cm2) return OCT1 {
67 var BIT8 res := '00000001'B; /* A5/0 always supported */
68
69 if (cm2.a5_1 == '0'B) {
70 res := res or4b '00000010'B;
71 }
72 if (cm2.classmarkInformationType2_oct5.a5_2 == '1'B ) {
73 res := res or4b '00000100'B;
74 }
75 if (cm2.classmarkInformationType2_oct5.a5_3 == '1'B) {
76 res := res or4b '00001000'B;
77 }
78 /* TODO: CM3 for A5/4 and beyond */
79 return bit2oct(res);
80}
81
82/* determine the best algorithm available within the bit-mask */
83function f_best_alg_from_mask(OCT1 alg_in) return OCT1 {
84 var BIT8 alg := oct2bit(alg_in);
85 var BIT8 ordered_algs[8] := {
86 '10000000'B, '01000000'B, '00100000'B, '00010000'B,
87 '00001000'B, /* A5/3 */
88 '00000010'B, /* A5/1 */
89 '00000100'B, /* A5/2 */
90 '00000001'B /* A5/0 */ }
91 for (var integer i := 0; i < sizeof(ordered_algs); i := i+1) {
92 if (alg and4b ordered_algs[i] != '00000000'B) {
93 return bit2oct(ordered_algs[i]);
94 }
95 }
96 return '00'O;
97}
98
99/* return an integer like '1' for A5/1 based on a mask (with only one bit set */
100function f_alg_from_mask(OCT1 mask_in) return integer {
101 var BIT8 mask := oct2bit(mask_in);
102 for (var integer i := 0; i < 8; i := i+1) {
103 if (mask and4b ('00000001'B << i) != '00000000'B) {
104 return i;
105 }
106 }
107 return -1;
108}
109
Harald Weltea10db902018-01-27 12:44:49 +0100110/* altstep for the global guard timer */
111private altstep as_Tguard() runs on BSC_ConnHdlr {
112 [] g_Tguard.timeout {
113 setverdict(inconc, "Tguard timeout");
114 self.stop;
115 }
116}
117
118/* init function, called as first function in new BSC_ConnHdlr */
Harald Weltead2952e2018-01-27 14:12:46 +0100119function f_init_handler(BSC_ConnHdlrPars pars, float t_guard := 60.0) runs on BSC_ConnHdlr {
Harald Weltea10db902018-01-27 12:44:49 +0100120 /* make parameters available via component variable */
121 g_pars := pars;
122 /* Start guard timer and activate it as default */
Harald Weltead2952e2018-01-27 14:12:46 +0100123 g_Tguard.start(t_guard);
Harald Weltea10db902018-01-27 12:44:49 +0100124 activate(as_Tguard());
125}
126
Harald Weltea49e36e2018-01-21 19:29:33 +0100127
128/* Callback function from general BSSMAP_Emulation whenever a connectionless
129 * BSSMAP message arrives. Canreturn a PDU_BSSAPthat should be sent in return */
130private function BscUnitdataCallback(PDU_BSSAP bssap)
131runs on BSSMAP_Emulation_CT return template PDU_BSSAP {
132 var template PDU_BSSAP resp := omit;
133
134 log("BSSMAP_BscUnitdataCallback");
135 /* answer all RESET with RESET ACK */
136 if (match(bssap, tr_BSSMAP_Reset)){
137 log("BSSMAP_BscUnitdataCallback: Responding to RESET with RESET-ACK");
138 resp := ts_BSSMAP_ResetAck;
139 }
140
141 /* FIXME: Handle paging, etc. */
142 return resp;
143}
144
145const BssmapOps BSC_BssmapOps := {
146 /* Create call-back for inbound connections from MSC (hand-over) */
147 create_cb := refers(BSSMAP_Emulation.ExpectedCreateCallback),
148 unitdata_cb := refers(BscUnitdataCallback),
149 decode_dtap := true,
150 role_ms := true
151}
152
153
154private function MnccUnitdataCallback(MNCC_PDU mncc)
155runs on MNCC_Emulation_CT return template MNCC_PDU {
156 log("Ignoring MNCC", mncc);
157 return omit;
158}
159
160const MnccOps BCC_MnccOps := {
161 create_cb := refers(MNCC_Emulation.ExpectedCreateCallback),
162 unitdata_cb := refers(MnccUnitdataCallback)
163}
164
165
166
167template BSSAP_Conn_Req ts_BSSAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, PDU_BSSAP bssap) := {
168 addr_peer := peer,
169 addr_own := own,
170 bssap := bssap
171};
172
Harald Weltea49e36e2018-01-21 19:29:33 +0100173/* Encode 'l3' and ask BSSMAP_Emulation to create new connection with COMPL L3 INFO */
174function f_bssap_compl_l3(PDU_ML3_MS_NW l3)
175runs on BSC_ConnHdlr {
176 log("Sending COMPL L3: ", l3);
177 var octetstring l3_enc := enc_PDU_ML3_MS_NW(l3);
178 BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_own,
179 valueof(ts_BSSMAP_ComplL3(g_pars.cell_id, l3_enc))));
Harald Welte71b69332018-01-21 20:43:53 +0100180 alt {
181 [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_CONF_IND) {}
182 [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
183 setverdict(fail, "DISC.ind from SCCP");
184 self.stop;
185 }
186 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100187}
188
Harald Welte081b19a2018-02-10 09:11:13 +0100189type enumerated EstablishType {
190 EST_TYPE_MO_CALL,
Harald Welte0bef21e2018-02-10 09:48:23 +0100191 EST_TYPE_EMERG_CALL,
Harald Welte081b19a2018-02-10 09:11:13 +0100192 EST_TYPE_PAG_RESP
193};
194
Harald Weltea49e36e2018-01-21 19:29:33 +0100195/* helper function to fully establish a dedicated channel */
Harald Welte081b19a2018-02-10 09:11:13 +0100196function f_establish_fully(MobileIdentityLV mi, EstablishType etype := EST_TYPE_MO_CALL)
Harald Weltea49e36e2018-01-21 19:29:33 +0100197runs on BSC_ConnHdlr {
Harald Welte081b19a2018-02-10 09:11:13 +0100198 var PDU_ML3_MS_NW l3_info;
199 select (etype) {
200 case (EST_TYPE_MO_CALL) {
201 l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, mi));
202 }
Harald Welte0bef21e2018-02-10 09:48:23 +0100203 case (EST_TYPE_EMERG_CALL) {
204 l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_EMERG_CALL, mi));
205 }
Harald Welte081b19a2018-02-10 09:11:13 +0100206 case (EST_TYPE_PAG_RESP) {
207 l3_info := valueof(ts_PAG_RESP(mi));
208 }
209 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100210
211 /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */
212 f_bssap_compl_l3(l3_info);
213
Harald Weltede371492018-01-27 23:44:41 +0100214 f_mm_common();
215 if (g_pars.net.expect_ciph) {
Harald Welte148a7082018-01-26 18:56:43 +0100216 /* implicit CM SERVICE ACCEPT? */
217 } else {
Harald Welte0bef21e2018-02-10 09:48:23 +0100218 if (etype != EST_TYPE_PAG_RESP) {
Harald Welte081b19a2018-02-10 09:11:13 +0100219 /* explicit CM SERVICE ACCEPT */
220 BSSAP.receive(tr_PDU_DTAP_MT(tr_CM_SERV_ACC));
221 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100222 }
Harald Weltea49e36e2018-01-21 19:29:33 +0100223}
224
225/* build a PDU_ML3_MS_NW containing a Location Update by IMSI */
Harald Welte9de84792018-01-28 01:06:35 +0100226function f_build_lu_imsi(hexstring imsi) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Weltea49e36e2018-01-21 19:29:33 +0100227{
228 var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(imsi));
229 return f_build_lu(mi);
230}
Harald Welte9de84792018-01-28 01:06:35 +0100231function f_build_lu_imei(hexstring imei) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Welteba7b6d92018-01-23 21:32:34 +0100232{
233 var MobileIdentityLV mi := valueof(ts_MI_IMEI_LV(imei));
234 return f_build_lu(mi);
235}
Harald Welte9de84792018-01-28 01:06:35 +0100236function f_build_lu_tmsi(OCT4 tmsi) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Welteba7b6d92018-01-23 21:32:34 +0100237{
238 var MobileIdentityLV mi := valueof(ts_MI_TMSI_LV(tmsi));
239 return f_build_lu(mi);
240}
Harald Welte9de84792018-01-28 01:06:35 +0100241private function f_build_lu(MobileIdentityLV mi) runs on BSC_ConnHdlr return PDU_ML3_MS_NW
Harald Weltea49e36e2018-01-21 19:29:33 +0100242{
243 var LocationAreaIdentification_V old_lai := { '62F220'O, '9999'O };
244 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 +0100245 old_lai, mi, g_pars.cm1));
Harald Weltea49e36e2018-01-21 19:29:33 +0100246 return l3_info;
247}
248
Harald Weltecf66d5a2018-01-23 19:24:28 +0100249private function f_rnd_oct(integer len) return octetstring {
250 var integer i;
251 var octetstring res;
252 for (i := 0; i < len; i := i + 1) {
253 res[i] := int2oct(float2int(rnd()*256.0), 1);
254 }
255 return res;
256}
257
258function f_gen_auth_vec_2g() return AuthVector {
259 var AuthVector vec;
260 vec.rand := f_rnd_oct(16);
261 vec.sres := f_rnd_oct(4);
262 vec.kc := f_rnd_oct(8);
263 return vec;
264}
265
Harald Welte148a7082018-01-26 18:56:43 +0100266
Harald Welte9de84792018-01-28 01:06:35 +0100267function f_mm_auth() runs on BSC_ConnHdlr
Harald Welte148a7082018-01-26 18:56:43 +0100268{
Harald Weltede371492018-01-27 23:44:41 +0100269 if (g_pars.net.expect_auth) {
Harald Welte148a7082018-01-26 18:56:43 +0100270 g_pars.vec := f_gen_auth_vec_2g();
271 var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(g_pars.vec.rand,
272 g_pars.vec.sres,
273 g_pars.vec.kc));
274 GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi));
275 GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple));
276
277 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_MM_AUTH_REQ(g_pars.vec.rand)));
278 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MT_MM_AUTH_RESP_2G(g_pars.vec.sres)));
279 }
Harald Welte9de84792018-01-28 01:06:35 +0100280}
Harald Welte148a7082018-01-26 18:56:43 +0100281
Harald Welte9de84792018-01-28 01:06:35 +0100282function f_mm_common() runs on BSC_ConnHdlr
283{
284 f_mm_auth();
Harald Weltede371492018-01-27 23:44:41 +0100285 if (g_pars.net.expect_ciph) {
Harald Welte9de84792018-01-28 01:06:35 +0100286 var OCT1 a5_net := f_alg_mask_from_cm(g_pars.cm2);
287 var OCT1 a5_intersect := g_pars.net.kc_support and4b a5_net;
288 alt {
289 [] BSSAP.receive(tr_BSSMAP_CipherModeCmd(a5_intersect, g_pars.vec.kc)) {
290 var OCT1 a5_chosen := f_best_alg_from_mask(a5_intersect);
291 var integer a5_nr := f_alg_from_mask(a5_chosen);
292 BSSAP.send(ts_BSSMAP_CipherModeCompl(int2oct(a5_nr+1, 1)));
293 }
294 [] BSSAP.receive(tr_BSSMAP_CipherModeCmd(?, g_pars.vec.kc)) {
295 setverdict(fail, "Wrong ciphering algorithm mask in CiphModCmd");
296 self.stop;
297 }
298 }
299 /* FIXME: Send the best available algorithm */
Harald Welte148a7082018-01-26 18:56:43 +0100300 }
301}
302
Harald Weltede371492018-01-27 23:44:41 +0100303function f_perform_lu(boolean send_early_cm)
Harald Weltea49e36e2018-01-21 19:29:33 +0100304runs on BSC_ConnHdlr {
305 var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi)
306 var PDU_DTAP_MT dtap_mt;
307
308 /* tell GSUP dispatcher to send this IMSI to us */
309 f_create_gsup_expect(hex2str(g_pars.imsi));
310
311 /* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */
312 f_bssap_compl_l3(l3_lu);
313
Harald Welte8a121b32018-01-22 03:00:41 +0100314 if (send_early_cm) {
315 BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3));
316 }
Harald Welte5c2622c2018-01-21 20:45:20 +0100317
Harald Weltede371492018-01-27 23:44:41 +0100318 f_mm_common();
Harald Welte16114282018-01-24 22:41:21 +0100319
Harald Weltea49e36e2018-01-21 19:29:33 +0100320 /* Expect MSC to perform LU with HLR */
321 GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi));
322 GSUP.send(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn));
323 GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi));
324 GSUP.send(ts_GSUP_UL_RES(g_pars.imsi));
325
326 alt {
327 [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Acc)) -> value dtap_mt {
328 var PDU_ML3_LocationUpdateAccept lu_acc := dtap_mt.dtap.msgs.mm.locationUpdateAccept;
Harald Weltede371492018-01-27 23:44:41 +0100329 if (g_pars.net.expect_tmsi) {
Harald Weltea49e36e2018-01-21 19:29:33 +0100330 if (not ispresent(lu_acc.mobileIdentityTLV) or
331 not ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) {
332 setverdict(fail, "Expected TMSI but no TMSI was allocated");
333 self.stop;
334 } else {
Harald Welte256571e2018-01-24 18:47:19 +0100335 g_pars.tmsi := lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi.octets;
Harald Weltea49e36e2018-01-21 19:29:33 +0100336 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_TmsiRealloc_Cmpl));
337 }
338 } else {
339 if (ispresent(lu_acc.mobileIdentityTLV) and
340 ischosen(lu_acc.mobileIdentityTLV.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi)) {
341 setverdict(fail, "Expected no TMSI but TMSI was allocated");
342 self.stop;
343 }
344 }
345 }
346 [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) {
347 setverdict(fail, "Expected LU ACK, but received LU REJ");
348 self.stop;
349 }
350 }
351 /* FIXME: there could be pending SMS or other common procedures by the MSC, let's ignore them */
352 BSSAP.receive(tr_BSSMAP_ClearCommand);
353 BSSAP.send(ts_BSSMAP_ClearComplete);
354 BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND);
355 setverdict(pass);
356}
357
358function f_foo() runs on BSC_ConnHdlr{
359 /* SCCP CC handled by BSSMAP_Emulation_CT.main() */
360 /* Expect auth, if enabled */
361
362 /* TODO: ISD */
363 /* Expect encr, if enabled */
364 /* Expect encr, if enabled */
365 /* Expect ASS CMD, if chan_type != requested */
366 /* Send ASS CMPL in successful case */
367
368 /* Expect AoIP port/ip information for RTP stream */
369 /* Expect MSC-originated MGCP to our simulated MGW */
370 /* Verify Counters via CTRL */
371 /* re-configure MSC behaviour via VTY */
372}
373
Harald Welteb71901a2018-01-26 19:16:05 +0100374/* parameters related to a (MO?) voice call */
375type record CallParameters {
Harald Welteb71901a2018-01-26 19:16:05 +0100376 /* CC related parameters */
377 hexstring called_party, /* whom are we calling */
378 integer transaction_id optional, /* which TS 04.08 CC transaction ID to use */
379 BearerCapability_TLV bearer_cap, /* which bearer capabilities to claim */
Harald Welte0bef21e2018-02-10 09:48:23 +0100380 boolean emergency, /* is this an emergency call? */
Harald Welteb71901a2018-01-26 19:16:05 +0100381
382 /* MNCC related parameters */
383 uint32_t mncc_callref optional, /* call reference on the MNCC side */
384 MNCC_bearer_cap mncc_bearer_cap optional, /* MNCC-side bearer capabilities */
385
386 /* RTP related parameters */
387 HostName bss_rtp_ip optional, /* BSS Side RTP IP */
388 PortNumber bss_rtp_port optional, /* BSS Side RTP Port */
389 HostName mss_rtp_ip optional, /* MSS Side RTP IP */
390 PortNumber mss_rtp_port optional, /* MSS Side RTP Port */
Harald Welte4017d552018-01-26 21:40:05 +0100391 HostName mgw_rtp_ip_bss, /* BSS-facing MGW RTP IP */
392 PortNumber mgw_rtp_port_bss, /* BSS-facing MGW RTP Port */
393 HostName mgw_rtp_ip_mss, /* MSS-facing MGW RTP IP */
394 PortNumber mgw_rtp_port_mss, /* MSS-facing MGW RTP Port */
Harald Welteb71901a2018-01-26 19:16:05 +0100395 uint7_t rtp_payload_type, /* dynamic RTP payload type */
396 charstring rtp_sdp_format, /* AMR/8000 or the like */
397
398 MgcpCallId mgcp_call_id optional, /* MGCP Call ID; CallAgent allocated */
399 MgcpEndpoint mgcp_ep optional /* MGCP Endpoint, CallAgent or MGW allocated */,
400 MgcpConnectionId mgcp_connection_id_bss, /* MGCP Connection ID BSS Side */
401 MgcpConnectionId mgcp_connection_id_mss /* MGCP Connection ID MSS Side */
402}
403
404template (value) CallParameters t_CallParams(hexstring called, integer tid) := {
Harald Welteb71901a2018-01-26 19:16:05 +0100405 called_party := called,
406 transaction_id := tid,
407 bearer_cap := valueof(ts_Bcap_voice),
Harald Welte0bef21e2018-02-10 09:48:23 +0100408 emergency := false,
Harald Welteb71901a2018-01-26 19:16:05 +0100409 mncc_callref := omit,
410 mncc_bearer_cap := valueof(ts_MNCC_bcap_voice),
Harald Welte4017d552018-01-26 21:40:05 +0100411 bss_rtp_ip := "9.8.7.6",
412 bss_rtp_port := 9000,
Harald Welteb71901a2018-01-26 19:16:05 +0100413 mss_rtp_ip := omit,
414 mss_rtp_port := omit,
Harald Welte4017d552018-01-26 21:40:05 +0100415 mgw_rtp_ip_bss := "1.1.1.1",
416 mgw_rtp_port_bss := 10000,
417 mgw_rtp_ip_mss := "1.1.1.1",
418 mgw_rtp_port_mss := 11000,
Harald Welteb71901a2018-01-26 19:16:05 +0100419 rtp_payload_type := 98,
420 rtp_sdp_format := "AMR/8000",
421 mgcp_call_id := omit,
422 mgcp_ep := omit,
423 mgcp_connection_id_bss := '0'H,//
424 mgcp_connection_id_mss := '0'H //
425};
426
427
Harald Welte33ec09b2018-02-10 15:34:46 +0100428function f_mt_call(inout CallParameters cpars)
429runs on BSC_ConnHdlr {
430
431 var MobileIdentityLV mi;
432 var MNCC_PDU mncc;
433 var MgcpCommand mgcp_cmd;
434
435 f_bssmap_register_imsi(g_pars.imsi, g_pars.tmsi);
436
437 /* Allocate a call reference and send SETUP via MNCC to MSC */
438 cpars.mncc_callref := f_rnd_int(2147483648);
439 MNCC.send(ts_MNCC_SETUP_req(cpars.mncc_callref, hex2str(g_pars.msisdn),
440 hex2str(cpars.called_party), hex2str(g_pars.imsi)));
441 /* BSC <- MSC: Expect paging. FIXME: By TMSI or not? */
442 BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi));
443
444 /* If we have a TMSI, use TMSI instead of IMSI */
445 if (ispresent(g_pars.tmsi)) {
446 mi := valueof(ts_MI_TMSI_LV(g_pars.tmsi));
447 } else {
448 mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
449 }
450 f_establish_fully(mi, EST_TYPE_PAG_RESP);
451
452 /* MS <- MSC: Expect CC SETUP */
453 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_SETUP(cpars.transaction_id, *, cpars.called_party)));
454
455 /* MS -> MSC: ALERTING */
456 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_ALERTING(cpars.transaction_id)));
457 MNCC.receive(tr_MNCC_ALERT_ind(cpars.mncc_callref));
458
459
460 /* Create MGCP expect */
461 f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit});
462 /* Ask MSC via MNCC to create the RTP socket on the MSC/MGW side */
463 MNCC.send(ts_MNCC_RTP_CREATE(cpars.mncc_callref));
464
465 /* First MGCP CRCX (for BSS/RAN side) */
466 MGCP.receive(tr_CRCX) -> value mgcp_cmd {
467 cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd);
468 /* TODO: dynamic EP allocation case */
469 cpars.mgcp_ep := mgcp_cmd.line.ep;
470 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_bss, cpars.mgw_rtp_ip_bss,
471 hex2str(cpars.mgcp_call_id), "42",
472 cpars.mgw_rtp_port_bss,
473 { int2str(cpars.rtp_payload_type) },
474 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
475 cpars.rtp_sdp_format)),
476 valueof(ts_SDP_ptime(20)) }));
477 MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_bss, sdp));
478 }
479 /* Second MGCP CRCX (this time for MSS/CN side) */
480 MGCP.receive(tr_CRCX(cpars.mgcp_ep)) -> value mgcp_cmd {
481 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_mss, cpars.mgw_rtp_ip_mss,
482 hex2str(cpars.mgcp_call_id), "42",
483 cpars.mgw_rtp_port_mss,
484 { int2str(cpars.rtp_payload_type) },
485 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
486 cpars.rtp_sdp_format)),
487 valueof(ts_SDP_ptime(20)) }));
488 MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_mss, sdp));
489 /* MSC acknowledges the MNCC_CREATE to the MNCC handler */
490 MNCC.receive(tr_MNCC_RTP_CREATE(cpars.mncc_callref));
491 }
492
493 /* expect the MSC to trigger a BSSMAP ASSIGNMENT */
494 var BSSMAP_IE_AoIP_TransportLayerAddress tla_ass :=
495 valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.mgw_rtp_ip_bss),cpars.mgw_rtp_port_bss));
496 BSSAP.receive(tr_BSSMAP_AssignmentReq(omit, tla_ass)) {
497 var BSSMAP_IE_AoIP_TransportLayerAddress tla;
498 tla := valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.bss_rtp_ip), cpars.bss_rtp_port));
499 BSSAP.send(ts_BSSMAP_AssignmentComplete(omit, tla));
500 }
501
502 /* MS -> MSC: ALERTING */
503 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CONNECT(cpars.transaction_id)));
504 MNCC.receive(tr_MNCC_SETUP_cnf(cpars.mncc_callref));
505
506 /* FIXME */
507 f_sleep(3.0);
508
509 /* Hangup by "A" side */
510 MNCC.send(ts_MNCC_DISC_req(cpars.mncc_callref, valueof(ts_MNCC_cause(23))));
511 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(cpars.transaction_id)));
512
513 if (false) {
514 /* A-side (PLMN) Release of call */
515 MNCC.send(ts_MNCC_REL_req(cpars.mncc_callref, valueof(ts_MNCC_cause(42))));
516 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(cpars.transaction_id)));
517 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id)));
518 } else {
519 /* B-side (MS) Release of call */
520 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_RELEASE(cpars.transaction_id, '1'B, '0000000'B)));
521 MNCC.receive(tr_MNCC_REL_ind(cpars.mncc_callref));
522 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_REL_COMPL(cpars.transaction_id)));
523 }
524
525 /* clearing of radio channel */
526 interleave {
527 [] BSSAP.receive(tr_BSSMAP_ClearCommand) {
528 BSSAP.send(ts_BSSMAP_ClearComplete);
529 BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND);
530 }
531 [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd {
532 /* TODO: For one or all connections on EP? */
533 MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id));
534 f_create_mgcp_delete_ep(cpars.mgcp_ep);
535 }
536 }
537 setverdict(pass);
538}
539
Harald Welteb71901a2018-01-26 19:16:05 +0100540function f_mo_call(inout CallParameters cpars)
541runs on BSC_ConnHdlr {
542
543 var MobileIdentityLV mi;
544 var MNCC_PDU mncc;
545 var MgcpCommand mgcp_cmd;
546
547 /* If we have a TMSI, use TMSI instead of IMSI */
548 if (ispresent(g_pars.tmsi)) {
549 mi := valueof(ts_MI_TMSI_LV(g_pars.tmsi));
550 } else {
551 mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
552 }
Harald Welte0bef21e2018-02-10 09:48:23 +0100553 if (cpars.emergency) {
554 f_establish_fully(mi, EST_TYPE_EMERG_CALL);
555 } else {
556 f_establish_fully(mi, EST_TYPE_MO_CALL);
557 }
Harald Welteb71901a2018-01-26 19:16:05 +0100558
559 /* Create MNCC and MGCP expect */
560 f_create_mncc_expect(hex2str(cpars.called_party));
561 f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit});
562
Harald Welte0bef21e2018-02-10 09:48:23 +0100563 if (cpars.emergency) {
564 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_EMERG_SETUP(cpars.transaction_id)));
565 } else {
566 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_SETUP(cpars.transaction_id, cpars.called_party)));
567 }
Harald Welteb71901a2018-01-26 19:16:05 +0100568 interleave {
569 [] MNCC.receive(tr_MNCC_SETUP_ind(?, tr_MNCC_number(hex2str(cpars.called_party)))) -> value mncc {
570 cpars.mncc_callref := mncc.u.signal.callref;
571 /* Call Proceeding */
572 MNCC.send(ts_MNCC_CALL_PROC_req(cpars.mncc_callref, cpars.mncc_bearer_cap));
573 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CALL_PROC(cpars.transaction_id)));
574 };
Harald Welte4017d552018-01-26 21:40:05 +0100575 /* First MGCP CRCX (for BSS/RAN side) */
Harald Welteb71901a2018-01-26 19:16:05 +0100576 [] MGCP.receive(tr_CRCX) -> value mgcp_cmd {
577 cpars.mgcp_call_id := f_MgcpCmd_extract_call_id(mgcp_cmd);
578 /* TODO: dynamic EP allocation case */
579 cpars.mgcp_ep := mgcp_cmd.line.ep;
Harald Welte4017d552018-01-26 21:40:05 +0100580 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_bss, cpars.mgw_rtp_ip_bss,
Harald Welteb71901a2018-01-26 19:16:05 +0100581 hex2str(cpars.mgcp_call_id), "42",
Harald Welte4017d552018-01-26 21:40:05 +0100582 cpars.mgw_rtp_port_bss,
Harald Welteb71901a2018-01-26 19:16:05 +0100583 { int2str(cpars.rtp_payload_type) },
584 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
585 cpars.rtp_sdp_format)),
586 valueof(ts_SDP_ptime(20)) }));
587 MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_bss, sdp));
588 }
589 }
Harald Welte4017d552018-01-26 21:40:05 +0100590 /* Second MGCP CRCX (this time for MSS/CN side) */
591 MGCP.receive(tr_CRCX(cpars.mgcp_ep)) -> value mgcp_cmd {
592 var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_mss, cpars.mgw_rtp_ip_mss,
593 hex2str(cpars.mgcp_call_id), "42",
594 cpars.mgw_rtp_port_mss,
595 { int2str(cpars.rtp_payload_type) },
596 { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
597 cpars.rtp_sdp_format)),
598 valueof(ts_SDP_ptime(20)) }));
599 MGCP.send(ts_CRCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_mss, sdp));
600 }
Harald Welteb71901a2018-01-26 19:16:05 +0100601
602 /* Alerting */
603 MNCC.send(ts_MNCC_ALERT_req(cpars.mncc_callref));
Harald Welteb71901a2018-01-26 19:16:05 +0100604
Harald Welte4017d552018-01-26 21:40:05 +0100605 var BSSMAP_IE_AoIP_TransportLayerAddress tla_ass :=
606 valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.mgw_rtp_ip_bss),cpars.mgw_rtp_port_bss));
607 interleave {
608 [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_ALERTING(cpars.transaction_id))) {}
609 /* expect AoIP IP/Port to match what we returned in CRCX_ACK above */
610 [] BSSAP.receive(tr_BSSMAP_AssignmentReq(omit, tla_ass)) {
Harald Welteb71901a2018-01-26 19:16:05 +0100611 var BSSMAP_IE_AoIP_TransportLayerAddress tla;
612 tla := valueof(ts_BSSMAP_IE_AoIP_TLA4(f_inet_addr(cpars.bss_rtp_ip), cpars.bss_rtp_port));
613 BSSAP.send(ts_BSSMAP_AssignmentComplete(omit, tla));
614 }
615 }
616
Harald Welte4017d552018-01-26 21:40:05 +0100617 /* Answer. MNCC_SETUP_RSP -> CONNECT to MS; CONNECT_ACK from MS */
618 MNCC.send(ts_MNCC_SETUP_rsp(cpars.mncc_callref));
619 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_CONNECT(cpars.transaction_id)));
620 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_CONNECT_ACK(cpars.transaction_id)));
Harald Welteb71901a2018-01-26 19:16:05 +0100621
622 f_sleep(3.0);
623
624 /* Hangup by "B" side */
625 MNCC.send(ts_MNCC_DISC_req(cpars.mncc_callref, valueof(ts_MNCC_cause(23))));
626 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_DISC(cpars.transaction_id)));
627
628 /* Release of call */
629 MNCC.send(ts_MNCC_REL_req(cpars.mncc_callref, valueof(ts_MNCC_cause(42))));
630 BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_CC_RELEASE(cpars.transaction_id)));
631 BSSAP.send(ts_PDU_DTAP_MO(ts_ML3_MO_CC_REL_COMPL(cpars.transaction_id)));
632
633 /* clearing of radio channel */
634 interleave {
635 [] BSSAP.receive(tr_BSSMAP_ClearCommand) {
636 BSSAP.send(ts_BSSMAP_ClearComplete);
637 BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND);
638 }
639 [] MGCP.receive(tr_DLCX(?)) -> value mgcp_cmd {
640 /* TODO: For one or all connections on EP? */
641 MGCP.send(ts_DLCX_ACK2(mgcp_cmd.line.trans_id));
642 f_create_mgcp_delete_ep(cpars.mgcp_ep);
643 }
644 }
645 setverdict(pass);
646}
Harald Weltea49e36e2018-01-21 19:29:33 +0100647
Harald Welte1ddc7162018-01-27 14:25:46 +0100648/* expect a clear command */
649function f_expect_clear(float t := 5.0) runs on BSC_ConnHdlr {
650 timer T := t;
651
652 T.start;
653 alt {
654 [] BSSAP.receive(tr_BSSMAP_ClearCommand) { }
655 [] BSSAP.receive {
656 setverdict(fail, "Unexpected BSSMAP while waiting for ClearCommand");
657 self.stop;
658 }
659 [] T.timeout {
660 setverdict(inconc, "Timeout waiting for ClearCommand");
661 self.stop;
662 }
663 }
664
665 BSSAP.send(ts_BSSMAP_ClearComplete);
666
667 T.start;
668 alt {
669 [] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
670 setverdict(pass);
671 }
672 [] BSSAP.receive {
673 setverdict(fail, "Unexpected BSSMAP while waiting for SCCP Release");
674 self.stop;
675 }
676 [] T.timeout {
677 setverdict(inconc, "Timeout waiting for SCCP Release");
678 self.stop;
679 }
680 }
681}
682
Harald Weltea49e36e2018-01-21 19:29:33 +0100683
684
685
686}
687
688