blob: fbe921d670680685dac72374694fe7dae7a1013b [file] [log] [blame]
Harald Welte6811d102019-04-14 22:23:14 +02001module RAN_Emulation {
Harald Welte365f4ed2017-11-23 00:00:43 +01002
Harald Welte6811d102019-04-14 22:23:14 +02003/* RAN Emulation, runs on top of BSSAP_CodecPort. It multiplexes/demultiplexes
Harald Welte35bb7162018-01-03 21:07:52 +01004 * the individual connections, so there can be separate TTCN-3 components handling
5 * each of the connections.
6 *
Harald Welte6811d102019-04-14 22:23:14 +02007 * The RAN_Emulation.main() function processes SCCP primitives from the SCCP
Harald Welte35bb7162018-01-03 21:07:52 +01008 * stack via the BSSAP_CodecPort, and dispatches them to the per-connection components.
9 *
10 * Outbound BSSAP/SCCP connections are initiated by sending a BSSAP_Conn_Req primitive
Harald Welte6811d102019-04-14 22:23:14 +020011 * to the component running the RAN_Emulation.main() function.
Harald Welte35bb7162018-01-03 21:07:52 +010012 *
Harald Welte6811d102019-04-14 22:23:14 +020013 * For each new inbound connections, the RanOps.create_cb() is called. It can create
Harald Welte35bb7162018-01-03 21:07:52 +010014 * or resolve a TTCN-3 component, and returns a component reference to which that inbound
15 * connection is routed/dispatched.
16 *
17 * If a pre-existing component wants to register to handle a future inbound connection, it can
18 * do so by registering an "expect" with the expected Layer 3 (DTAP) payload. This is e.g. useful
19 * if you are simulating BTS + MSC, and first trigger a connection from BTS/RSL side in a
20 * component which then subsequently should also handle the MSC emulation.
21 *
Harald Welte6811d102019-04-14 22:23:14 +020022 * Inbound Unit Data messages (such as are dispatched to the RanOps.unitdata_cb() callback,
Harald Welte35bb7162018-01-03 21:07:52 +010023 * which is registered with an argument to the main() function below.
24 *
Harald Welte2fce7882019-04-15 11:48:05 +020025 * (C) 2017-2019 by Harald Welte <laforge@gnumonks.org>
Harald Welte35bb7162018-01-03 21:07:52 +010026 * All rights reserved.
27 *
28 * Released under the terms of GNU General Public License, Version 2 or
29 * (at your option) any later version.
30 */
31
32
Harald Welte0b476062018-01-21 19:07:32 +010033import from General_Types all;
Harald Welte9dadc522018-02-06 13:56:04 +010034import from Osmocom_Types all;
Harald Welteb3414b22017-11-23 18:22:10 +010035import from SCCP_Emulation all;
Harald Welte365f4ed2017-11-23 00:00:43 +010036import from SCCPasp_Types all;
Harald Welte2fce7882019-04-15 11:48:05 +020037import from IPA_Emulation all;
38import from MobileL3_Types all;
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +020039import from Misc_Helpers all;
Harald Welte2fce7882019-04-15 11:48:05 +020040
41#ifdef RAN_EMULATION_BSSAP
Harald Welte365f4ed2017-11-23 00:00:43 +010042import from BSSAP_Types all;
Harald Welte004f5fb2017-12-16 17:54:40 +010043import from BSSAP_CodecPort all;
Harald Welte365f4ed2017-11-23 00:00:43 +010044import from BSSMAP_Templates all;
Harald Welte2fce7882019-04-15 11:48:05 +020045#endif
46
47#ifdef RAN_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +010048import from MGCP_Types all;
49import from MGCP_Templates all;
Harald Welte2fce7882019-04-15 11:48:05 +020050#endif
Harald Welte365f4ed2017-11-23 00:00:43 +010051
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +020052#ifdef RAN_EMULATION_CTRL
53import from Osmocom_CTRL_Types all;
54import from Osmocom_CTRL_Adapter all;
55#endif
56
Harald Welte5b027622019-04-14 23:40:17 +020057#ifdef RAN_EMULATION_RANAP
58import from RANAP_CodecPort all;
59import from RANAP_PDU_Descriptions all;
60import from RANAP_Constants all;
61import from RANAP_IEs all;
62import from RANAP_Templates all;
63#endif
64
Harald Welte365f4ed2017-11-23 00:00:43 +010065/* General "base class" component definition, of which specific implementations
66 * derive themselves by means of the "extends" feature */
Harald Welte6811d102019-04-14 22:23:14 +020067type component RAN_ConnHdlr {
Harald Welte365f4ed2017-11-23 00:00:43 +010068 /* port towards MSC Emulator core / SCCP connection dispatchar */
Harald Welte6811d102019-04-14 22:23:14 +020069 port RAN_Conn_PT BSSAP;
Harald Welteca519982018-01-21 19:28:26 +010070 /* procedure based port to register for incoming connections */
Harald Welte6811d102019-04-14 22:23:14 +020071 port RAN_PROC_PT BSSAP_PROC;
Harald Welte365f4ed2017-11-23 00:00:43 +010072}
73
74/* Auxiliary primitive that can happen on the port between per-connection client and this dispatcher */
Harald Welte6811d102019-04-14 22:23:14 +020075type enumerated RAN_Conn_Prim {
Harald Welte365f4ed2017-11-23 00:00:43 +010076 /* SCCP tell us that connection was released */
77 MSC_CONN_PRIM_DISC_IND,
78 /* we tell SCCP to release connection */
Harald Welte71b69332018-01-21 20:43:53 +010079 MSC_CONN_PRIM_DISC_REQ,
80 /* Connection confirmed indication */
81 MSC_CONN_PRIM_CONF_IND
Harald Welte365f4ed2017-11-23 00:00:43 +010082}
83
Pau Espin Pedrolc6b78ff2019-06-06 15:58:17 +020084type enumerated RAN_Transport {
85 BSSAP_TRANSPORT_AoIP, /* 3GPP AoIP: SCCP over M3UA over SCTP */
86 BSSAP_TRANSPORT_SCCPlite_SERVER, /* SCCPlite: SCCP over IPA over TCP */
87 BSSAP_TRANSPORT_SCCPlite_CLIENT, /* SCCPlite: SCCP over IPA over TCP */
88 RANAP_TRANSPORT_IuCS /* 3GPP IuCS: SCCP over M3UA over SCTP */
89};
90
Harald Welte0b476062018-01-21 19:07:32 +010091/* similar to PDU_BSSAP with DTAP, but DTAP is already decoded! */
92type record PDU_DTAP_MO {
93 OCT1 dlci optional,
Daniel Willmann92f66272018-02-06 15:50:52 +010094 boolean skip_seq_patching optional,
Harald Welte0b476062018-01-21 19:07:32 +010095 PDU_ML3_MS_NW dtap
96}
97
98/* similar to PDU_BSSAP with DTAP, but DTAP is already decoded! */
99type record PDU_DTAP_MT {
100 OCT1 dlci optional,
101 PDU_ML3_NW_MS dtap
102}
103
Harald Welte717c7302019-04-23 20:31:55 +0200104type record PDU_DTAP_PS_MO {
105 OCT1 dlci optional,
106 boolean skip_seq_patching optional,
107 PDU_L3_MS_SGSN dtap
108}
109
110type record PDU_DTAP_PS_MT {
111 OCT1 dlci optional,
112 PDU_L3_SGSN_MS dtap
113}
114
Harald Welte0b476062018-01-21 19:07:32 +0100115template PDU_DTAP_MT ts_PDU_DTAP_MT(template PDU_ML3_NW_MS dtap, template OCT1 dlci := omit) := {
116 dlci := dlci,
117 dtap := dtap
118}
119
Daniel Willmann92f66272018-02-06 15:50:52 +0100120template PDU_DTAP_MO ts_PDU_DTAP_MO(template PDU_ML3_MS_NW dtap, template OCT1 dlci := '00'O, boolean skip_seq_patching := false) := {
Harald Welte0b476062018-01-21 19:07:32 +0100121 dlci := dlci,
Daniel Willmann92f66272018-02-06 15:50:52 +0100122 skip_seq_patching := skip_seq_patching,
Harald Welte0b476062018-01-21 19:07:32 +0100123 dtap := dtap
124}
125
126template PDU_DTAP_MT tr_PDU_DTAP_MT(template PDU_ML3_NW_MS dtap, template OCT1 dlci := *) := {
127 dlci := dlci,
128 dtap := dtap
129}
130
131template PDU_DTAP_MO tr_PDU_DTAP_MO(template PDU_ML3_MS_NW dtap, template OCT1 dlci := *) := {
132 dlci := dlci,
Harald Welte930d0a72018-03-22 22:08:40 +0100133 skip_seq_patching := ?,
Harald Welte0b476062018-01-21 19:07:32 +0100134 dtap := dtap
135}
136
Harald Welte717c7302019-04-23 20:31:55 +0200137template (value) PDU_DTAP_PS_MT ts_PDU_DTAP_PS_MT(template (value) PDU_L3_SGSN_MS dtap, template (omit) OCT1 dlci := omit) := {
138 dlci := dlci,
139 dtap := dtap
140}
141
142template (value) PDU_DTAP_PS_MO ts_PDU_DTAP_PS_MO(template (value) PDU_L3_MS_SGSN dtap, template (value) OCT1 dlci := '00'O,
143 boolean skip_seq_patching := false) := {
144 dlci := dlci,
145 skip_seq_patching := skip_seq_patching,
146 dtap := dtap
147}
148
149template PDU_DTAP_PS_MT tr_PDU_DTAP_PS_MT(template PDU_L3_SGSN_MS dtap, template OCT1 dlci := *) := {
150 dlci := dlci,
151 dtap := dtap
152}
153
154template PDU_DTAP_PS_MO tr_PDU_DTAP_PS_MO(template PDU_L3_MS_SGSN dtap, template OCT1 dlci := *) := {
155 dlci := dlci,
156 skip_seq_patching := ?,
157 dtap := dtap
158}
159
Harald Welte365f4ed2017-11-23 00:00:43 +0100160/* port between individual per-connection components and this dispatcher */
Harald Welte6811d102019-04-14 22:23:14 +0200161type port RAN_Conn_PT message {
Harald Welte2fce7882019-04-15 11:48:05 +0200162 inout
163#ifdef RAN_EMULATION_BSSAP
164 PDU_BSSAP,
Neels Hofmeyra8264612020-06-08 20:40:22 +0200165 BSSAP_N_UNITDATA_req,
Harald Weltea4ca4462018-02-09 00:17:14 +0100166 /* Client requests us to create SCCP Connection */
167 BSSAP_Conn_Req,
Harald Welte2fce7882019-04-15 11:48:05 +0200168#endif
Harald Welte5b027622019-04-14 23:40:17 +0200169#ifdef RAN_EMULATION_RANAP
170 RANAP_PDU,
Neels Hofmeyrb1bf16d2023-06-27 02:10:04 +0200171 RANAP_N_UNITDATA_req,
Harald Welte5b027622019-04-14 23:40:17 +0200172 /* Client requests us to create SCCP Connection */
173 RANAP_Conn_Req,
174#endif
Harald Welte2fce7882019-04-15 11:48:05 +0200175#ifdef RAN_EMULATION_MGCP
Harald Weltea4ca4462018-02-09 00:17:14 +0100176 /* MGCP, only used for IPA SCCPlite (MGCP in IPA mux) */
Harald Welte2fce7882019-04-15 11:48:05 +0200177 MgcpCommand, MgcpResponse,
178#endif
179 /* direct DTAP messages from/to clients */
180 PDU_DTAP_MO, PDU_DTAP_MT,
Harald Welte717c7302019-04-23 20:31:55 +0200181 PDU_DTAP_PS_MO, PDU_DTAP_PS_MT,
Harald Welte2fce7882019-04-15 11:48:05 +0200182 /* misc indications / requests between SCCP and client */
183 RAN_Conn_Prim;
Harald Welte365f4ed2017-11-23 00:00:43 +0100184} with { extension "internal" };
185
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200186type uint2_t N_Sd_Array[4];
Harald Welte365f4ed2017-11-23 00:00:43 +0100187
188/* represents a single BSSAP connection over SCCP */
189type record ConnectionData {
190 /* reference to the instance of the per-connection component */
Harald Welte6811d102019-04-14 22:23:14 +0200191 RAN_ConnHdlr comp_ref,
Harald Weltec82eef42017-11-24 20:40:12 +0100192 integer sccp_conn_id,
Harald Welte2fce7882019-04-15 11:48:05 +0200193#ifdef RAN_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100194 /* most recent MGCP transaction ID (Used on MSC side) */
195 MgcpTransId mgcp_trans_id optional,
Harald Welte2fce7882019-04-15 11:48:05 +0200196#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100197 /* CIC that has been used for voice of this channel (BSC side) */
Harald Welte9dadc522018-02-06 13:56:04 +0100198 integer cic optional,
199 /* array of N(SD) values for MO DTAP messages, indexed by discriminator */
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200200 N_Sd_Array n_sd
Harald Welte365f4ed2017-11-23 00:00:43 +0100201}
202
Harald Welte17d21152018-01-27 00:47:11 +0100203type record ImsiMapping {
Harald Welte6811d102019-04-14 22:23:14 +0200204 RAN_ConnHdlr comp_ref,
Harald Welte17d21152018-01-27 00:47:11 +0100205 hexstring imsi optional,
206 OCT4 tmsi
207}
208
Harald Welte6811d102019-04-14 22:23:14 +0200209type component RAN_Emulation_CT {
Harald Welte2fce7882019-04-15 11:48:05 +0200210 /* SCCP ports on the bottom side, using ASP primitives */
211#ifdef RAN_EMULATION_BSSAP
Harald Welte004f5fb2017-12-16 17:54:40 +0100212 port BSSAP_CODEC_PT BSSAP;
Harald Welte2fce7882019-04-15 11:48:05 +0200213#endif
Harald Welte5b027622019-04-14 23:40:17 +0200214#ifdef RAN_EMULATION_RANAP
215 port RANAP_CODEC_PT RANAP;
216#endif
Harald Welte365f4ed2017-11-23 00:00:43 +0100217 /* BSSAP port to the per-connection clients */
Harald Welte6811d102019-04-14 22:23:14 +0200218 port RAN_Conn_PT CLIENT;
Harald Welte2fce7882019-04-15 11:48:05 +0200219#ifdef RAN_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100220 /* MGCP port */
221 port IPA_MGCP_PT MGCP;
Harald Welte2fce7882019-04-15 11:48:05 +0200222#endif
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +0200223#ifdef RAN_EMULATION_CTRL
224 /* CTRL port */
225 port IPA_CTRL_PT CTRL;
226 port IPA_CTRL_PT CTRL_CLIENT;
227#endif
Harald Welte365f4ed2017-11-23 00:00:43 +0100228
229 /* use 16 as this is also the number of SCCP connections that SCCP_Emulation can handle */
230 var ConnectionData ConnectionTable[16];
Harald Welte66fecd42017-11-24 23:53:23 +0100231
Harald Welte624f9632017-12-16 19:26:04 +0100232 /* pending expected incoming connections */
233 var ExpectData ExpectTable[8];
Harald Welte17d21152018-01-27 00:47:11 +0100234
235 /* tables for mapping inbound unitdata (like paging) */
236 var ImsiMapping ImsiTable[16];
237
Harald Welte624f9632017-12-16 19:26:04 +0100238 /* procedure based port to register for incoming connections */
Harald Welte6811d102019-04-14 22:23:14 +0200239 port RAN_PROC_PT PROC;
Harald Welte624f9632017-12-16 19:26:04 +0100240
Harald Welte6811d102019-04-14 22:23:14 +0200241 var charstring g_ran_id;
Harald Welte66fecd42017-11-24 23:53:23 +0100242 var integer g_next_e1_ts := 1;
Harald Welte6811d102019-04-14 22:23:14 +0200243 var RanOps g_ran_ops;
Harald Welte365f4ed2017-11-23 00:00:43 +0100244};
245
Harald Welteb3414b22017-11-23 18:22:10 +0100246private function f_conn_id_known(integer sccp_conn_id)
Harald Welte6811d102019-04-14 22:23:14 +0200247runs on RAN_Emulation_CT return boolean {
Harald Welteb3414b22017-11-23 18:22:10 +0100248 var integer i;
249 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
250 if (ConnectionTable[i].sccp_conn_id == sccp_conn_id){
251 return true;
252 }
253 }
254 return false;
255}
256
Harald Welte6811d102019-04-14 22:23:14 +0200257private function f_comp_known(RAN_ConnHdlr client)
258runs on RAN_Emulation_CT return boolean {
Harald Welteb3414b22017-11-23 18:22:10 +0100259 var integer i;
260 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
261 if (ConnectionTable[i].comp_ref == client) {
262 return true;
263 }
264 }
265 return false;
266}
Harald Welte365f4ed2017-11-23 00:00:43 +0100267
Harald Weltee98bb2e2017-11-29 12:09:48 +0100268private function f_cic_known(integer cic)
Harald Welte6811d102019-04-14 22:23:14 +0200269runs on RAN_Emulation_CT return boolean {
Harald Weltee98bb2e2017-11-29 12:09:48 +0100270 var integer i;
271 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
272 if (ConnectionTable[i].cic == cic) {
273 return true;
274 }
275 }
276 return false;
277}
278
Harald Welte365f4ed2017-11-23 00:00:43 +0100279/* resolve component reference by connection ID */
280private function f_comp_by_conn_id(integer sccp_conn_id)
Harald Welte6811d102019-04-14 22:23:14 +0200281runs on RAN_Emulation_CT return RAN_ConnHdlr {
Harald Welte365f4ed2017-11-23 00:00:43 +0100282 var integer i;
283 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
284 if (ConnectionTable[i].sccp_conn_id == sccp_conn_id) {
285 return ConnectionTable[i].comp_ref;
286 }
287 }
Harald Welte6811d102019-04-14 22:23:14 +0200288 setverdict(fail, "RAN Connection table not found by SCCP Connection ID ", sccp_conn_id);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200289 mtc.stop;
Harald Welte365f4ed2017-11-23 00:00:43 +0100290}
291
Harald Welte2fce7882019-04-15 11:48:05 +0200292
293#ifdef RAN_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100294/* resolve component reference by CIC */
295private function f_comp_by_mgcp_tid(MgcpTransId tid)
Harald Welte6811d102019-04-14 22:23:14 +0200296runs on RAN_Emulation_CT return RAN_ConnHdlr {
Harald Weltec82eef42017-11-24 20:40:12 +0100297 var integer i;
298 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
299 if (ConnectionTable[i].mgcp_trans_id == tid) {
300 return ConnectionTable[i].comp_ref;
301 }
302 }
Harald Welte6811d102019-04-14 22:23:14 +0200303 setverdict(fail, "RAN Connection table not found by MGCP Transaction ID ", tid);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200304 mtc.stop;
Harald Weltec82eef42017-11-24 20:40:12 +0100305}
306
Harald Welte6811d102019-04-14 22:23:14 +0200307private function f_comp_store_mgcp_tid(RAN_ConnHdlr client, MgcpTransId tid)
308runs on RAN_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100309 var integer i;
310 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
311 if (ConnectionTable[i].comp_ref == client) {
312 ConnectionTable[i].mgcp_trans_id := tid;
313 return;
314 }
315 }
Harald Welte6811d102019-04-14 22:23:14 +0200316 setverdict(fail, "RAN Connection table not found by component ", client);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200317 mtc.stop;
Harald Weltec82eef42017-11-24 20:40:12 +0100318}
Harald Welte2fce7882019-04-15 11:48:05 +0200319#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100320
321private function f_comp_by_cic(integer cic)
Harald Welte6811d102019-04-14 22:23:14 +0200322runs on RAN_Emulation_CT return RAN_ConnHdlr {
Harald Weltec82eef42017-11-24 20:40:12 +0100323 var integer i;
324 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
325 if (ConnectionTable[i].cic == cic) {
326 return ConnectionTable[i].comp_ref;
327 }
328 }
Harald Welte6811d102019-04-14 22:23:14 +0200329 setverdict(fail, "RAN Connection table not found by CIC ", cic);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200330 mtc.stop;
Harald Weltec82eef42017-11-24 20:40:12 +0100331}
332
Harald Welte6811d102019-04-14 22:23:14 +0200333private function f_comp_store_cic(RAN_ConnHdlr client, integer cic)
334runs on RAN_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100335 var integer i;
336 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
337 if (ConnectionTable[i].comp_ref == client) {
338 ConnectionTable[i].cic := cic;
339 return;
340 }
341 }
Harald Welte6811d102019-04-14 22:23:14 +0200342 setverdict(fail, "RAN Connection table not found by component ", client);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200343 mtc.stop;
Harald Weltec82eef42017-11-24 20:40:12 +0100344}
345
Harald Welte365f4ed2017-11-23 00:00:43 +0100346/* resolve connection ID by component reference */
Harald Welte6811d102019-04-14 22:23:14 +0200347private function f_conn_id_by_comp(RAN_ConnHdlr client)
348runs on RAN_Emulation_CT return integer {
Harald Welte365f4ed2017-11-23 00:00:43 +0100349 for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
350 if (ConnectionTable[i].comp_ref == client) {
351 return ConnectionTable[i].sccp_conn_id;
352 }
353 }
Harald Welte6811d102019-04-14 22:23:14 +0200354 setverdict(fail, "RAN Connection table not found by component ", client);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200355 mtc.stop;
Harald Welte365f4ed2017-11-23 00:00:43 +0100356}
357
Harald Welte9dadc522018-02-06 13:56:04 +0100358/* resolve ConnectionTable index component reference */
Harald Welte6811d102019-04-14 22:23:14 +0200359private function f_idx_by_comp(RAN_ConnHdlr client)
360runs on RAN_Emulation_CT return integer {
Harald Welte9dadc522018-02-06 13:56:04 +0100361 for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
362 if (ConnectionTable[i].comp_ref == client) {
363 return i;
364 }
365 }
Harald Welte6811d102019-04-14 22:23:14 +0200366 setverdict(fail, "RAN Connection table not found by component ", client);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200367 mtc.stop;
Harald Welte9dadc522018-02-06 13:56:04 +0100368}
369
Harald Welteb3414b22017-11-23 18:22:10 +0100370private function f_gen_conn_id()
Harald Welte6811d102019-04-14 22:23:14 +0200371runs on RAN_Emulation_CT return integer {
Harald Welteb3414b22017-11-23 18:22:10 +0100372 var integer conn_id;
373
374 do {
375 conn_id := float2int(rnd()*SCCP_Emulation.tsp_max_ConnectionId);
376 } while (f_conn_id_known(conn_id) == true);
377
378 return conn_id;
379}
380
Harald Welte365f4ed2017-11-23 00:00:43 +0100381private function f_conn_table_init()
Harald Welte6811d102019-04-14 22:23:14 +0200382runs on RAN_Emulation_CT {
Harald Welte365f4ed2017-11-23 00:00:43 +0100383 for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
384 ConnectionTable[i].comp_ref := null;
385 ConnectionTable[i].sccp_conn_id := -1;
Harald Welte2fce7882019-04-15 11:48:05 +0200386#ifdef RAN_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100387 ConnectionTable[i].mgcp_trans_id := omit;
Harald Welte2fce7882019-04-15 11:48:05 +0200388#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100389 ConnectionTable[i].cic := omit;
Harald Welte9dadc522018-02-06 13:56:04 +0100390 ConnectionTable[i].n_sd := { 0, 0, 0, 0 };
Harald Welte365f4ed2017-11-23 00:00:43 +0100391 }
Harald Welte17d21152018-01-27 00:47:11 +0100392 for (var integer i := 0; i < sizeof(ImsiTable); i := i+1) {
393 ImsiTable[i].comp_ref := null;
394 ImsiTable[i].imsi := omit;
395 ImsiTable[i].tmsi := 'FFFFFFFF'O;
396 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100397}
398
Harald Welte6811d102019-04-14 22:23:14 +0200399private function f_conn_table_add(RAN_ConnHdlr comp_ref, integer sccp_conn_id)
400runs on RAN_Emulation_CT {
Harald Welte365f4ed2017-11-23 00:00:43 +0100401 for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
402 if (ConnectionTable[i].sccp_conn_id == -1) {
403 ConnectionTable[i].comp_ref := comp_ref;
404 ConnectionTable[i].sccp_conn_id := sccp_conn_id;
Harald Welte9dadc522018-02-06 13:56:04 +0100405 ConnectionTable[i].n_sd := { 0, 0, 0, 0 };
Harald Welteb3414b22017-11-23 18:22:10 +0100406 log("Added conn table entry ", i, comp_ref, sccp_conn_id);
Harald Welte365f4ed2017-11-23 00:00:43 +0100407 return;
408 }
409 }
Oliver Smith07ebf962023-07-07 12:11:58 +0200410 setverdict(fail, "RAN Connection table full!");
411 mtc.stop;
Harald Welte365f4ed2017-11-23 00:00:43 +0100412}
413
414private function f_conn_table_del(integer sccp_conn_id)
Harald Welte6811d102019-04-14 22:23:14 +0200415runs on RAN_Emulation_CT {
Harald Welte365f4ed2017-11-23 00:00:43 +0100416 for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
417 if (ConnectionTable[i].sccp_conn_id == sccp_conn_id) {
Harald Welteb3414b22017-11-23 18:22:10 +0100418 log("Deleted conn table entry ", i,
419 ConnectionTable[i].comp_ref, sccp_conn_id);
Harald Welte365f4ed2017-11-23 00:00:43 +0100420 ConnectionTable[i].sccp_conn_id := -1;
421 ConnectionTable[i].comp_ref := null;
Harald Welte0a4317a2017-11-25 00:32:46 +0100422 return
Harald Welte365f4ed2017-11-23 00:00:43 +0100423 }
424 }
Harald Welte6811d102019-04-14 22:23:14 +0200425 setverdict(fail, "RAN Connection table attempt to delete non-existant ", sccp_conn_id);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200426 mtc.stop;
Harald Welte365f4ed2017-11-23 00:00:43 +0100427}
428
Harald Welte17d21152018-01-27 00:47:11 +0100429private function f_imsi_table_find(hexstring imsi, template OCT4 tmsi)
Harald Welte6811d102019-04-14 22:23:14 +0200430runs on RAN_Emulation_CT return RAN_ConnHdlr {
Harald Welte17d21152018-01-27 00:47:11 +0100431 for (var integer i := 0; i < sizeof(ImsiTable); i := i+1) {
432 if (ImsiTable[i].imsi == imsi or
433 isvalue(tmsi) and match(ImsiTable[i].tmsi, tmsi)) {
434 return ImsiTable[i].comp_ref;
435 }
436 }
437 return null;
438}
439
Harald Welte2fce7882019-04-15 11:48:05 +0200440#ifdef RAN_EMULATION_BSSAP
441type record BSSAP_Conn_Req {
442 SCCP_PAR_Address addr_peer,
443 SCCP_PAR_Address addr_own,
Neels Hofmeyra23f3b12022-03-02 19:57:12 +0100444 PDU_BSSAP bssap optional
Harald Welte2fce7882019-04-15 11:48:05 +0200445}
Neels Hofmeyra23f3b12022-03-02 19:57:12 +0100446template BSSAP_Conn_Req ts_BSSAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, template (omit) PDU_BSSAP bssap) := {
Harald Welte2fce7882019-04-15 11:48:05 +0200447 addr_peer := peer,
448 addr_own := own,
449 bssap := bssap
450};
451
Harald Welte365f4ed2017-11-23 00:00:43 +0100452/* handle (optional) userData portion of various primitives and dispatch it to the client */
Harald Welte6811d102019-04-14 22:23:14 +0200453private function f_handle_userData(RAN_ConnHdlr client, PDU_BSSAP bssap)
454runs on RAN_Emulation_CT {
Harald Welte365f4ed2017-11-23 00:00:43 +0100455 /* decode + send decoded BSSAP to client */
Harald Welte1b2748e2017-11-24 23:40:16 +0100456
Harald Welte473676b2018-01-27 20:38:01 +0100457 if (ischosen(bssap.pdu.bssmap)) {
458 /* BSC Side: If this is an assignment command, store CIC */
459 if (ischosen(bssap.pdu.bssmap.assignmentRequest) and
460 ispresent(bssap.pdu.bssmap.assignmentRequest.circuitIdentityCode)) {
461 var BSSMAP_IE_CircuitIdentityCode cic_ie :=
462 bssap.pdu.bssmap.assignmentRequest.circuitIdentityCode;
Pau Espin Pedrol43021cb2019-06-18 17:32:15 +0200463 var integer cic := f_bssmap_ie_cic_2_int(cic_ie);
Harald Welte473676b2018-01-27 20:38:01 +0100464 f_comp_store_cic(client, cic);
465 }
Harald Welte1b2748e2017-11-24 23:40:16 +0100466 }
467
Harald Welte6811d102019-04-14 22:23:14 +0200468 if (ischosen(bssap.pdu.dtap) and g_ran_ops.decode_dtap) {
469 if (g_ran_ops.role_ms) {
Harald Welte0b476062018-01-21 19:07:32 +0100470 /* we are the MS, so any message to us must be MT */
471 var PDU_DTAP_MT mt := {
472 dlci := bssap.dlci,
473 dtap := dec_PDU_ML3_NW_MS(bssap.pdu.dtap)
474 };
475 CLIENT.send(mt) to client;
476 } else {
477 /* we are the Network, so any message to us must be MO */
478 var PDU_DTAP_MO mo := {
479 dlci := bssap.dlci,
480 dtap := dec_PDU_ML3_MS_NW(bssap.pdu.dtap)
481 };
482 CLIENT.send(mo) to client;
483 }
484 } else {
485 CLIENT.send(bssap) to client;
486 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100487}
488
489/* call-back type, to be provided by specific implementation; called when new SCCP connection
490 * arrives */
Harald Welte004f5fb2017-12-16 17:54:40 +0100491type function BssmapCreateCallback(BSSAP_N_CONNECT_ind conn_ind, charstring id)
Harald Welte6811d102019-04-14 22:23:14 +0200492runs on RAN_Emulation_CT return RAN_ConnHdlr;
Harald Welte365f4ed2017-11-23 00:00:43 +0100493
494type function BssmapUnitdataCallback(PDU_BSSAP bssap)
Harald Welte6811d102019-04-14 22:23:14 +0200495runs on RAN_Emulation_CT return template PDU_BSSAP;
Harald Welte365f4ed2017-11-23 00:00:43 +0100496
Pau Espin Pedrol95549182019-06-06 16:17:30 +0200497private function append_osmux_ie()
498runs on RAN_Emulation_CT return boolean {
499 return g_ran_ops.use_osmux and (g_ran_ops.transport == BSSAP_TRANSPORT_AoIP);
500}
501
Harald Welte17d21152018-01-27 00:47:11 +0100502/* handle common Unitdata such as Paging */
503private function CommonBssmapUnitdataCallback(PDU_BSSAP bssap)
Harald Welte6811d102019-04-14 22:23:14 +0200504runs on RAN_Emulation_CT return template PDU_BSSAP {
Harald Welte17d21152018-01-27 00:47:11 +0100505 if (match(bssap, tr_BSSMAP_Paging)) {
Harald Welte6811d102019-04-14 22:23:14 +0200506 var RAN_ConnHdlr client := null;
Neels Hofmeyrd076e932024-03-26 03:30:41 +0100507 var template OCT4 tmsi := omit;
508 if (ispresent(bssap.pdu.bssmap.paging.tMSI)) {
509 tmsi := bssap.pdu.bssmap.paging.tMSI.tmsiOctets;
510 }
511 client := f_imsi_table_find(bssap.pdu.bssmap.paging.iMSI.digits, tmsi);
Daniel Willmannabc73e12019-04-15 17:25:56 +0200512 if (client != null) {
Harald Welte17d21152018-01-27 00:47:11 +0100513 log("CommonBssmapUnitdataCallback: IMSI/TMSI found in table, dispatching to ",
514 client);
515 CLIENT.send(bssap) to client;
516 return omit;
517 }
518 log("CommonBssmapUnitdataCallback: IMSI/TMSI not found in table");
519 } else {
520 log("CommonBssmapUnitdataCallback: Not a paging message");
521 }
522 /* ELSE: handle in user callback */
Neels Hofmeyr79896c02023-06-23 03:45:40 +0200523 if (not ispresent(g_ran_ops.unitdata_cb)) {
524 return omit;
525 }
Harald Welte6811d102019-04-14 22:23:14 +0200526 return g_ran_ops.unitdata_cb.apply(bssap);
Harald Welte17d21152018-01-27 00:47:11 +0100527}
528
Harald Welte6811d102019-04-14 22:23:14 +0200529function f_bssap_reset(SCCP_PAR_Address peer, SCCP_PAR_Address own) runs on RAN_Emulation_CT {
Harald Weltea4ca4462018-02-09 00:17:14 +0100530 timer T := 5.0;
Pau Espin Pedrol95549182019-06-06 16:17:30 +0200531 var boolean append_osmux_support := append_osmux_ie();
Eric Wild49888a62022-03-30 03:16:11 +0200532 var integer attempts := g_ran_ops.bssap_reset_retries;
Harald Weltea4ca4462018-02-09 00:17:14 +0100533
Eric Wild49888a62022-03-30 03:16:11 +0200534 while (attempts > 0) {
535 attempts := attempts - 1;
536
537 BSSAP.send(ts_BSSAP_UNITDATA_req(peer, own, ts_BSSMAP_Reset(0, append_osmux_support)));
538 T.start;
539 alt {
540 [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(own, peer, tr_BSSMAP_ResetAck(append_osmux_support))) {
541 log("BSSMAP: Received RESET-ACK in response to RESET, we're ready to go!");
542 return;
543 }
544 [] as_reset_ack(append_osmux_support);
545 [] BSSAP.receive { repeat };
546 [] T.timeout {
547 continue;
548 }
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200549 }
Harald Weltea4ca4462018-02-09 00:17:14 +0100550 }
Eric Wild49888a62022-03-30 03:16:11 +0200551
552 setverdict(fail, "BSSMAP: Timeout waiting for RESET-ACK after sending RESET");
553 mtc.stop;
Harald Weltea4ca4462018-02-09 00:17:14 +0100554}
555
Harald Welte2fce7882019-04-15 11:48:05 +0200556private function f_bssap_l3_is_rr(PDU_BSSAP bssap) return boolean {
557 var template octetstring l3 := f_bssap_extract_l3(bssap);
558 return f_L3_is_rr(l3);
559}
560#endif
Harald Welte365f4ed2017-11-23 00:00:43 +0100561
Harald Welte5b027622019-04-14 23:40:17 +0200562#ifdef RAN_EMULATION_RANAP
563type record RANAP_Conn_Req {
564 SCCP_PAR_Address addr_peer,
565 SCCP_PAR_Address addr_own,
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +0200566 RANAP_PDU ranap optional
Harald Welte5b027622019-04-14 23:40:17 +0200567}
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +0200568template (value) RANAP_Conn_Req ts_RANAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own,
569 template (omit) RANAP_PDU ranap) := {
570 addr_peer := peer,
571 addr_own := own,
572 ranap := ranap
573};
574
575template RANAP_Conn_Req tr_RANAP_Conn_Req(template SCCP_PAR_Address peer := ?,
576 template SCCP_PAR_Address own := ?,
577 template (omit) RANAP_PDU ranap := omit) := {
Harald Welte5b027622019-04-14 23:40:17 +0200578 addr_peer := peer,
579 addr_own := own,
580 ranap := ranap
581};
582
583private function fake_dlci_from_sapi(template (omit) SAPI sapi) return template (omit) OCT1
584{
585 if (istemplatekind(sapi, "omit")) {
586 return omit;
587 } else if (valueof(sapi) == sapi_3) {
588 return '03'O;
589 }
590 return '00'O;
591}
592
593private function f_handle_userData_RANAP(RAN_ConnHdlr client, RANAP_PDU ranap)
594runs on RAN_Emulation_CT {
595 /* decode + send decoded RANAP to client */
596 var template (omit) octetstring l3 := f_ranap_extract_l3(ranap);
Harald Welte0af76152022-01-11 23:02:38 +0100597 if (istemplatekind(l3, "omit") or not g_ran_ops.decode_dtap) {
Harald Welte5b027622019-04-14 23:40:17 +0200598 CLIENT.send(ranap) to client;
599 } else {
600 var template (omit) SAPI sapi := f_ranap_extract_sapi(ranap);
601 var template (omit) OCT1 dlci := fake_dlci_from_sapi(sapi);
602 if (g_ran_ops.role_ms) {
603 /* we are the MS, so any message to us must be MT */
Harald Welte717c7302019-04-23 20:31:55 +0200604 if (g_ran_ops.ps_domain) {
605 var PDU_DTAP_PS_MT mt := {
606 dlci := omit,
607 dtap := dec_PDU_L3_SGSN_MS(valueof(l3))
608 };
609 if (isvalue(dlci)) {
610 mt.dlci := valueof(dlci);
611 }
612 CLIENT.send(mt) to client;
613 } else {
614 var PDU_DTAP_MT mt := {
615 dlci := omit,
616 dtap := dec_PDU_ML3_NW_MS(valueof(l3))
617 };
618 if (isvalue(dlci)) {
619 mt.dlci := valueof(dlci)
620 }
621 CLIENT.send(mt) to client;
Harald Welte5b027622019-04-14 23:40:17 +0200622 }
Harald Welte5b027622019-04-14 23:40:17 +0200623 } else {
624 /* we are the Network, so any message to us must be MO */
Harald Welte717c7302019-04-23 20:31:55 +0200625 if (g_ran_ops.ps_domain) {
626 var PDU_DTAP_PS_MO mo := {
627 dlci := omit,
628 dtap := dec_PDU_L3_MS_SGSN(valueof(l3))
629 };
630 if (isvalue(dlci)) {
631 mo.dlci := valueof(dlci);
632 }
633 CLIENT.send(mo) to client;
634 } else {
635 var PDU_DTAP_MO mo := {
636 dlci := omit,
637 dtap := dec_PDU_ML3_MS_NW(valueof(l3))
638 };
639 if (isvalue(dlci)) {
640 mo.dlci := valueof(dlci)
641 }
642 CLIENT.send(mo) to client;
Harald Welte5b027622019-04-14 23:40:17 +0200643 }
Harald Welte5b027622019-04-14 23:40:17 +0200644 }
645 }
646}
647
648/* call-back type, to be provided by specific implementation; called when new SCCP connection
649 * arrives */
650type function RanapCreateCallback(RANAP_N_CONNECT_ind conn_ind, charstring id)
651runs on RAN_Emulation_CT return RAN_ConnHdlr;
652
653type function RanapUnitdataCallback(RANAP_PDU ranap)
654runs on RAN_Emulation_CT return template RANAP_PDU;
655
656private function CommonRanapUnitdataCallback(RANAP_PDU ranap)
657runs on RAN_Emulation_CT return template RANAP_PDU {
658 if (match(ranap, tr_RANAP_Paging(?, ?))) {
659 var RAN_ConnHdlr client := null;
660 /* extract IMSI and (if present) TMSI */
661 var IMSI imsi := ranap.initiatingMessage.value_.paging.protocolIEs[1].value_.permanentNAS_UE_ID.iMSI;
662 var template OCT4 tmsi := omit;
663 if (lengthof(ranap.initiatingMessage.value_.paging.protocolIEs) > 2 and
664 ranap.initiatingMessage.value_.paging.protocolIEs[2].id == id_TemporaryUE_ID) {
665 var TemporaryUE_ID ue_id;
666 ue_id := ranap.initiatingMessage.value_.paging.protocolIEs[2].value_.temporaryUE_ID;
667 if (ischosen(ue_id.tMSI)) {
668 tmsi := ue_id.tMSI;
669 } else {
670 tmsi := ue_id.p_TMSI;
671 }
672 }
673 client := f_imsi_table_find(oct2hex(imsi), tmsi);
Harald Welte03d4e2b2019-05-10 00:42:33 +0200674 if (client != null) {
Harald Welte5b027622019-04-14 23:40:17 +0200675 log("CommonRanapUnitdataCallback: IMSI/TMSI found in table, dispatching to ",
676 client);
677 CLIENT.send(ranap) to client;
678 return omit;
679 }
680 log("CommonRanapUnitdataCallback: IMSI/TMSI not found in table");
681 } else {
682 log("CommonRanapUnitdataCallback: Not a paging message");
683 }
684
685 /* ELSE: handle in user callback */
Neels Hofmeyr79896c02023-06-23 03:45:40 +0200686 if (not ispresent(g_ran_ops.ranap_unitdata_cb)) {
687 return omit;
688 }
Harald Welte5b027622019-04-14 23:40:17 +0200689 return g_ran_ops.ranap_unitdata_cb.apply(ranap);
690}
691
692private function f_ranap_l3_is_rr(RANAP_PDU ranap) return boolean {
693 var template (omit) SAPI sapi;
694 var template octetstring l3 := f_ranap_extract_l3(ranap);
695 return f_L3_is_rr(l3);
696}
697
698function f_ranap_reset(SCCP_PAR_Address peer, SCCP_PAR_Address own) runs on RAN_Emulation_CT {
699 timer T := 5.0;
700 var CN_DomainIndicator dom;
701 if (g_ran_ops.ps_domain) {
702 dom := ps_domain;
703 } else {
704 dom := cs_domain;
705 }
706
707 RANAP.send(ts_RANAP_UNITDATA_req(peer, own, ts_RANAP_Reset(ts_RanapCause_om_intervention, dom)));
708 T.start;
709 alt {
710 [] RANAP.receive(tr_RANAP_UNITDATA_ind(own, peer, tr_RANAP_ResetAck)) {
Neels Hofmeyr4f5d7be2020-10-16 16:28:16 +0200711 log("RANAP: Received RESET-ACK in response to RESET, we're ready to go!");
Harald Welte5b027622019-04-14 23:40:17 +0200712 }
713 [] as_reset_ack();
714 [] RANAP.receive { repeat };
715 [] T.timeout {
Neels Hofmeyr4f5d7be2020-10-16 16:28:16 +0200716 setverdict(fail, "RANAP: Timeout waiting for RESET-ACK after sending RESET");
Harald Welte5b027622019-04-14 23:40:17 +0200717 mtc.stop;
718 }
719 }
720}
721#endif
Harald Welte365f4ed2017-11-23 00:00:43 +0100722
Harald Welte2fce7882019-04-15 11:48:05 +0200723
724type enumerated RanProtocol {
Harald Welte5b027622019-04-14 23:40:17 +0200725 RAN_PROTOCOL_BSSAP,
726 RAN_PROTOCOL_RANAP
Harald Welte2fce7882019-04-15 11:48:05 +0200727}
728
729type record RanOps {
730#ifdef RAN_EMULATION_BSSAP
731 BssmapCreateCallback create_cb optional,
732 BssmapUnitdataCallback unitdata_cb optional,
733#endif
Harald Welte5b027622019-04-14 23:40:17 +0200734#ifdef RAN_EMULATION_RANAP
735 RanapCreateCallback ranap_create_cb optional,
736 RanapUnitdataCallback ranap_unitdata_cb optional,
737 boolean ps_domain,
738#endif
Harald Welte2fce7882019-04-15 11:48:05 +0200739 boolean decode_dtap,
740 boolean role_ms,
741 RanProtocol protocol,
Pau Espin Pedrolc6b78ff2019-06-06 15:58:17 +0200742 RAN_Transport transport,
Pau Espin Pedrolc6a53db2019-05-20 19:31:47 +0200743 boolean use_osmux,
Eric Wild49888a62022-03-30 03:16:11 +0200744 integer bssap_reset_retries,
Harald Welte2fce7882019-04-15 11:48:05 +0200745 /* needed for performing BSSMAP RESET */
746 SCCP_PAR_Address sccp_addr_local optional,
747 SCCP_PAR_Address sccp_addr_peer optional
748}
749
750template BIT4 t_ML3_DISC_CC_MM_SS := ('0011'B, '0101'B, '1011'B);
751
Harald Weltea803b722020-08-21 15:42:26 +0200752function f_L3_is_rr(template octetstring l3) return boolean {
Harald Welte2fce7882019-04-15 11:48:05 +0200753 if (not isvalue(l3)) {
754 return false;
Harald Weltea4ca4462018-02-09 00:17:14 +0100755 }
Harald Welte2fce7882019-04-15 11:48:05 +0200756 var octetstring l3v := valueof(l3);
757 if (lengthof(l3v) < 1) {
758 return false;
759 }
760 /* lower 4 bits of first octet are protocol discriminator */
761 if ((oct2bit(l3v[0]) and4b '00001111'B) == '00000110'B) {
762 return true;
763 }
764 return false;
765}
Harald Weltea4ca4462018-02-09 00:17:14 +0100766
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200767function f_next_n_sd(inout N_Sd_Array n_sd, in integer n_sd_idx) return uint2_t {
Harald Welte2fce7882019-04-15 11:48:05 +0200768 var uint2_t seq_nr;
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200769 if (n_sd_idx == 0) {
770 seq_nr := n_sd[0];
771 n_sd[0] := (n_sd[0] + 1) mod 4;
772 } else if (n_sd_idx >= 1 and n_sd_idx <= 3) {
773 seq_nr := n_sd[n_sd_idx];
774 n_sd[n_sd_idx] := (n_sd[n_sd_idx] + 1) mod 2;
Harald Welte2fce7882019-04-15 11:48:05 +0200775 } else {
776 /* no sequence number to patch */
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200777 seq_nr := 0;
Harald Welte2fce7882019-04-15 11:48:05 +0200778 }
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200779 return seq_nr;
780}
781
782/* patch N(SD) into enc_l3, according to 24.007 11.2.3.2 */
783function f_ML3_patch_seq_nr(in uint2_t seq_nr, inout octetstring enc_l3) {
Harald Welte2fce7882019-04-15 11:48:05 +0200784 log("patching N(SD)=", seq_nr, " into dtap ", enc_l3);
785 enc_l3[1] := (enc_l3[1] and4b '3f'O) or4b bit2oct(int2bit(seq_nr, 8) << 6);
786 log("patched enc_l3: ", enc_l3);
787}
788
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200789function f_ML3_n_sd_idx(in PDU_ML3_MS_NW dtap) return integer {
790 var uint2_t seq_nr;
791 if (ischosen(dtap.msgs.cc) or ischosen(dtap.msgs.mm) or ischosen(dtap.msgs.ss)) {
792 return 0;
793 } else if (ischosen(dtap.msgs.gcc)) {
794 return 1;
795 } else if (ischosen(dtap.msgs.bcc)) {
796 return 2;
797 } else if (ischosen(dtap.msgs.loc)) {
798 return 3;
799 }
800 /* no sequence number to patch */
801 return -1;
802}
803
804/* patch N(SD) into enc_l3, according to 24.007 11.2.3.2 */
Harald Weltea803b722020-08-21 15:42:26 +0200805private function f_ML3_patch_seq(inout ConnectionData cd, in PDU_ML3_MS_NW dtap, inout octetstring enc_l3) {
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200806 var integer n_sd_idx := f_ML3_n_sd_idx(dtap);
807 if (n_sd_idx < 0) {
808 return;
809 }
810 var uint2_t seq_nr := f_next_n_sd(cd.n_sd, n_sd_idx);
811 f_ML3_patch_seq_nr(seq_nr, enc_l3);
812}
813
Pau Espin Pedrol95549182019-06-06 16:17:30 +0200814private altstep as_reset_ack(boolean append_osmux_support := false) runs on RAN_Emulation_CT {
Harald Welte2fce7882019-04-15 11:48:05 +0200815#ifdef RAN_EMULATION_BSSAP
816 var BSSAP_N_UNITDATA_ind ud_ind;
817#endif
Harald Welte5b027622019-04-14 23:40:17 +0200818#ifdef RAN_EMULATION_RANAP
819 var RANAP_N_UNITDATA_ind rud_ind;
820#endif
Harald Welte2fce7882019-04-15 11:48:05 +0200821#ifdef RAN_EMULATION_BSSAP
Pau Espin Pedrol95549182019-06-06 16:17:30 +0200822 [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(append_osmux_support))) -> value ud_ind {
Neels Hofmeyr4f5d7be2020-10-16 16:28:16 +0200823 log("BSSMAP: Responding to inbound RESET with RESET-ACK");
Harald Welte2fce7882019-04-15 11:48:05 +0200824 BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
Pau Espin Pedrol95549182019-06-06 16:17:30 +0200825 ts_BSSMAP_ResetAck(append_osmux_support)));
Harald Welte2fce7882019-04-15 11:48:05 +0200826 repeat;
827 }
828#endif
Harald Welte5b027622019-04-14 23:40:17 +0200829#ifdef RAN_EMULATION_RANAP
830 [] RANAP.receive(tr_RANAP_UNITDATA_ind(?, ?, tr_RANAP_Reset)) -> value rud_ind {
Neels Hofmeyr4f5d7be2020-10-16 16:28:16 +0200831 log("RANAP: Responding to inbound IuRESET with IuRESET-ACK");
Harald Welte5b027622019-04-14 23:40:17 +0200832 var CN_DomainIndicator dom;
833 dom := rud_ind.userData.initiatingMessage.value_.Reset.protocolIEs[1].value_.cN_DomainIndicator;
834 RANAP.send(ts_RANAP_UNITDATA_req(rud_ind.callingAddress, rud_ind.calledAddress,
835 ts_RANAP_ResetAck(dom)));
836 }
837#endif
Harald Welte2fce7882019-04-15 11:48:05 +0200838}
839
840
841private altstep as_main_bssap() runs on RAN_Emulation_CT {
842#ifdef RAN_EMULATION_BSSAP
Harald Welte004f5fb2017-12-16 17:54:40 +0100843 var BSSAP_N_UNITDATA_ind ud_ind;
844 var BSSAP_N_CONNECT_ind conn_ind;
845 var BSSAP_N_CONNECT_cfm conn_cfm;
846 var BSSAP_N_DATA_ind data_ind;
847 var BSSAP_N_DISCONNECT_ind disc_ind;
Harald Welteb3414b22017-11-23 18:22:10 +0100848 var BSSAP_Conn_Req creq;
Harald Welte365f4ed2017-11-23 00:00:43 +0100849 var PDU_BSSAP bssap;
Neels Hofmeyra8264612020-06-08 20:40:22 +0200850 var BSSAP_N_UNITDATA_req bssap_ud;
Harald Welte2fce7882019-04-15 11:48:05 +0200851 var RAN_ConnHdlr vc_conn;
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200852 var integer targetPointCode;
853 var N_Sd_Array last_n_sd;
Harald Welte365f4ed2017-11-23 00:00:43 +0100854
Harald Welte365f4ed2017-11-23 00:00:43 +0100855 /* SCCP -> Client: UNIT-DATA (connectionless SCCP) from a BSC */
Harald Welte004f5fb2017-12-16 17:54:40 +0100856 [] BSSAP.receive(BSSAP_N_UNITDATA_ind:?) -> value ud_ind {
Harald Welte365f4ed2017-11-23 00:00:43 +0100857 /* Connectionless Procedures like RESET */
858 var template PDU_BSSAP resp;
Harald Welte17d21152018-01-27 00:47:11 +0100859 resp := CommonBssmapUnitdataCallback(ud_ind.userData);
Harald Welte365f4ed2017-11-23 00:00:43 +0100860 if (isvalue(resp)) {
Harald Welte004f5fb2017-12-16 17:54:40 +0100861 BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress,
862 ud_ind.calledAddress, resp));
Harald Welte365f4ed2017-11-23 00:00:43 +0100863 }
864 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100865 /* SCCP -> Client: new connection from BSC */
Harald Welte004f5fb2017-12-16 17:54:40 +0100866 [] BSSAP.receive(BSSAP_N_CONNECT_ind:?) -> value conn_ind {
Harald Welte2fce7882019-04-15 11:48:05 +0200867 vc_conn := g_ran_ops.create_cb.apply(conn_ind, g_ran_id);
Harald Welte365f4ed2017-11-23 00:00:43 +0100868 /* store mapping between client components and SCCP connectionId */
869 f_conn_table_add(vc_conn, conn_ind.connectionId);
870 /* handle user payload */
871 f_handle_userData(vc_conn, conn_ind.userData);
872 /* confirm connection establishment */
Harald Welte004f5fb2017-12-16 17:54:40 +0100873 BSSAP.send(ts_BSSAP_CONNECT_res(conn_ind.connectionId, omit));
Harald Welte365f4ed2017-11-23 00:00:43 +0100874 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100875 /* SCCP -> Client: connection-oriented data in existing connection */
Harald Welte004f5fb2017-12-16 17:54:40 +0100876 [] BSSAP.receive(BSSAP_N_DATA_ind:?) -> value data_ind {
Harald Welte365f4ed2017-11-23 00:00:43 +0100877 vc_conn := f_comp_by_conn_id(data_ind.connectionId);
Harald Welte5cc4aa22017-11-23 18:51:28 +0100878 if (ispresent(data_ind.userData)) {
879 f_handle_userData(vc_conn, data_ind.userData);
880 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100881 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100882 /* SCCP -> Client: disconnect of an existing connection */
Harald Welte004f5fb2017-12-16 17:54:40 +0100883 [] BSSAP.receive(BSSAP_N_DISCONNECT_ind:?) -> value disc_ind {
Harald Welte365f4ed2017-11-23 00:00:43 +0100884 vc_conn := f_comp_by_conn_id(disc_ind.connectionId);
Harald Welte5cc4aa22017-11-23 18:51:28 +0100885 if (ispresent(disc_ind.userData)) {
886 f_handle_userData(vc_conn, disc_ind.userData);
887 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100888 /* notify client about termination */
Harald Welte6811d102019-04-14 22:23:14 +0200889 var RAN_Conn_Prim prim := MSC_CONN_PRIM_DISC_IND;
Harald Welte365f4ed2017-11-23 00:00:43 +0100890 CLIENT.send(prim) to vc_conn;
891 f_conn_table_del(disc_ind.connectionId);
892 /* TOOD: return confirm to other side? */
893 }
Harald Welteb3414b22017-11-23 18:22:10 +0100894 /* SCCP -> Client: connection confirm for outbound connection */
Harald Welte004f5fb2017-12-16 17:54:40 +0100895 [] BSSAP.receive(BSSAP_N_CONNECT_cfm:?) -> value conn_cfm {
Harald Welte71b69332018-01-21 20:43:53 +0100896 vc_conn := f_comp_by_conn_id(conn_cfm.connectionId);
Harald Welte6811d102019-04-14 22:23:14 +0200897 var RAN_Conn_Prim prim := MSC_CONN_PRIM_CONF_IND;
Harald Welte71b69332018-01-21 20:43:53 +0100898 CLIENT.send(prim) to vc_conn;
Harald Welteb3414b22017-11-23 18:22:10 +0100899 /* handle user payload */
Harald Welte5cc4aa22017-11-23 18:51:28 +0100900 if (ispresent(conn_cfm.userData)) {
901 f_handle_userData(vc_conn, conn_cfm.userData);
902 }
Harald Welteb3414b22017-11-23 18:22:10 +0100903 }
Harald Welte2fce7882019-04-15 11:48:05 +0200904 [] CLIENT.receive(PDU_BSSAP:?) -> value bssap sender vc_conn {
905 var integer conn_id := f_conn_id_by_comp(vc_conn);
906 /* send it to dispatcher */
907 BSSAP.send(ts_BSSAP_DATA_req(conn_id, bssap));
908 }
Harald Welteb3414b22017-11-23 18:22:10 +0100909
Neels Hofmeyra8264612020-06-08 20:40:22 +0200910 [] CLIENT.receive(BSSAP_N_UNITDATA_req:?) -> value bssap_ud sender vc_conn {
911 BSSAP.send(bssap_ud);
912 }
913
Harald Welte365f4ed2017-11-23 00:00:43 +0100914 /* Disconnect request client -> SCCP */
Harald Welte6811d102019-04-14 22:23:14 +0200915 [] CLIENT.receive(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ) -> sender vc_conn {
Harald Welte365f4ed2017-11-23 00:00:43 +0100916 var integer conn_id := f_conn_id_by_comp(vc_conn);
Harald Welte004f5fb2017-12-16 17:54:40 +0100917 BSSAP.send(ts_BSSAP_DISC_req(conn_id, 0));
Harald Welte365f4ed2017-11-23 00:00:43 +0100918 f_conn_table_del(conn_id);
919 }
920
921 /* BSSAP from client -> SCCP */
Harald Welteb3414b22017-11-23 18:22:10 +0100922 [] CLIENT.receive(BSSAP_Conn_Req:?) -> value creq sender vc_conn {
923 var integer conn_id;
Harald Welte004f5fb2017-12-16 17:54:40 +0100924 /* send to dispatcher */
Harald Welteb3414b22017-11-23 18:22:10 +0100925
926 if (f_comp_known(vc_conn) == false) {
927 /* unknown client, create new connection */
928 conn_id := f_gen_conn_id();
929
930 /* store mapping between client components and SCCP connectionId */
931 f_conn_table_add(vc_conn, conn_id);
932
Harald Welte004f5fb2017-12-16 17:54:40 +0100933 BSSAP.send(ts_BSSAP_CONNECT_req(creq.addr_peer, creq.addr_own, conn_id,
934 creq.bssap));
Harald Welteb3414b22017-11-23 18:22:10 +0100935 } else {
936 /* known client, send via existing connection */
937 conn_id := f_conn_id_by_comp(vc_conn);
Harald Welte004f5fb2017-12-16 17:54:40 +0100938 BSSAP.send(ts_BSSAP_DATA_req(conn_id, creq.bssap));
Harald Welteb3414b22017-11-23 18:22:10 +0100939 }
940
Harald Welte49518bf2018-02-10 11:39:19 +0100941 /* InitialL3 contains RR (PAG RESP) or MM (CM SRV REQ), we must increment
942 * counter only on MM/CC/SS, but not on RR */
Harald Welte6811d102019-04-14 22:23:14 +0200943 if (g_ran_ops.role_ms and not f_bssap_l3_is_rr(creq.bssap)) {
Harald Welte9dadc522018-02-06 13:56:04 +0100944 /* we have just sent the first MM message, increment the counter */
945 var integer idx := f_idx_by_comp(vc_conn);
946 ConnectionTable[idx].n_sd[0] := 1;
947 log("patch: N(SD) for ConnIdx ", idx, " set to 1");
948 }
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200949 }
Harald Welte9dadc522018-02-06 13:56:04 +0100950
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200951 [] PROC.getcall(RAN_last_n_sd:{?,-}) -> param(vc_conn) {
952 var integer idx := f_idx_by_comp(vc_conn);
953 last_n_sd := ConnectionTable[idx].n_sd;
954 PROC.reply(RAN_last_n_sd:{vc_conn, last_n_sd}) to vc_conn;
955 }
956
957 [] PROC.getcall(RAN_continue_after_n_sd:{?,?}) -> param(last_n_sd, vc_conn) {
958 var integer idx := f_idx_by_comp(vc_conn);
959 ConnectionTable[idx].n_sd := last_n_sd;
960 PROC.reply(RAN_continue_after_n_sd:{last_n_sd, vc_conn}) to vc_conn;
Harald Welteb3414b22017-11-23 18:22:10 +0100961 }
Harald Welte2fce7882019-04-15 11:48:05 +0200962#else
Harald Welte5b027622019-04-14 23:40:17 +0200963 [false] CLIENT.receive {}
964#endif
965}
966
967private altstep as_main_ranap() runs on RAN_Emulation_CT {
968#ifdef RAN_EMULATION_RANAP
969 var RANAP_N_UNITDATA_ind rud_ind;
970 var RANAP_N_CONNECT_ind rconn_ind;
971 var RANAP_N_CONNECT_cfm rconn_cfm;
972 var RANAP_N_DATA_ind rdata_ind;
973 var RANAP_N_DISCONNECT_ind rdisc_ind;
974 var RANAP_Conn_Req creq;
975 var RANAP_PDU ranap;
Neels Hofmeyrb1bf16d2023-06-27 02:10:04 +0200976 var RANAP_N_UNITDATA_req ranap_ud;
Harald Welte5b027622019-04-14 23:40:17 +0200977 var RAN_ConnHdlr vc_conn;
Harald Welte717c7302019-04-23 20:31:55 +0200978 var PDU_DTAP_PS_MO ps_mo;
979 var PDU_DTAP_PS_MT ps_mt;
Harald Welte5b027622019-04-14 23:40:17 +0200980
981 /* SCCP -> Client: UNIT-DATA (connectionless SCCP) from a BSC */
982 [] RANAP.receive(RANAP_N_UNITDATA_ind:?) -> value rud_ind {
983 /* Connectionless Procedures like RESET */
984 var template RANAP_PDU resp;
985 resp := CommonRanapUnitdataCallback(rud_ind.userData);
986 if (isvalue(resp)) {
987 RANAP.send(ts_RANAP_UNITDATA_req(rud_ind.callingAddress,
988 rud_ind.calledAddress, resp));
989 }
990 }
991 /* SCCP -> Client: new connection from BSC */
992 [] RANAP.receive(RANAP_N_CONNECT_ind:?) -> value rconn_ind {
993 vc_conn := g_ran_ops.ranap_create_cb.apply(rconn_ind, g_ran_id);
994 /* store mapping between client components and SCCP connectionId */
995 f_conn_table_add(vc_conn, rconn_ind.connectionId);
996 /* handle user payload */
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +0200997 if (ispresent(rconn_ind.userData)) {
998 f_handle_userData_RANAP(vc_conn, rconn_ind.userData);
999 } else {
1000 /* Notify client that we received an SCCP CR without user data */
1001 CLIENT.send(ts_RANAP_Conn_Req(rconn_ind.callingAddress, rconn_ind.calledAddress, omit));
1002 }
Harald Welte5b027622019-04-14 23:40:17 +02001003 /* confirm connection establishment */
1004 RANAP.send(ts_RANAP_CONNECT_res(rconn_ind.connectionId, omit));
1005 }
1006 /* SCCP -> Client: connection-oriented data in existing connection */
1007 [] RANAP.receive(RANAP_N_DATA_ind:?) -> value rdata_ind {
1008 vc_conn := f_comp_by_conn_id(rdata_ind.connectionId);
1009 if (ispresent(rdata_ind.userData)) {
1010 f_handle_userData_RANAP(vc_conn, rdata_ind.userData);
1011 }
1012 }
1013 /* SCCP -> Client: disconnect of an existing connection */
1014 [] RANAP.receive(RANAP_N_DISCONNECT_ind:?) -> value rdisc_ind {
1015 vc_conn := f_comp_by_conn_id(rdisc_ind.connectionId);
1016 if (ispresent(rdisc_ind.userData)) {
1017 f_handle_userData_RANAP(vc_conn, rdisc_ind.userData);
1018 }
1019 /* notify client about termination */
1020 var RAN_Conn_Prim prim := MSC_CONN_PRIM_DISC_IND;
1021 CLIENT.send(prim) to vc_conn;
1022 f_conn_table_del(rdisc_ind.connectionId);
1023 /* TOOD: return confirm to other side? */
1024 }
1025 /* SCCP -> Client: connection confirm for outbound connection */
1026 [] RANAP.receive(RANAP_N_CONNECT_cfm:?) -> value rconn_cfm {
1027 vc_conn := f_comp_by_conn_id(rconn_cfm.connectionId);
1028 var RAN_Conn_Prim prim := MSC_CONN_PRIM_CONF_IND;
1029 CLIENT.send(prim) to vc_conn;
1030 /* handle user payload */
1031 if (ispresent(rconn_cfm.userData)) {
1032 f_handle_userData_RANAP(vc_conn, rconn_cfm.userData);
1033 }
1034 }
1035
1036 [] CLIENT.receive(RANAP_PDU:?) -> value ranap sender vc_conn {
1037 var integer conn_id := f_conn_id_by_comp(vc_conn);
1038 /* send it to dispatcher */
1039 RANAP.send(ts_RANAP_DATA_req(conn_id, ranap));
1040 }
1041
Neels Hofmeyrb1bf16d2023-06-27 02:10:04 +02001042 /* e.g. for Paging from virtual MSC/SGSN to SUT osmo-hnbgw */
1043 [] CLIENT.receive(RANAP_N_UNITDATA_req:?) -> value ranap_ud sender vc_conn {
1044 RANAP.send(ranap_ud);
1045 }
1046
Harald Welte5b027622019-04-14 23:40:17 +02001047 /* Disconnect request client -> SCCP */
1048 [] CLIENT.receive(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ) -> sender vc_conn {
1049 var integer conn_id := f_conn_id_by_comp(vc_conn);
1050 RANAP.send(ts_RANAP_DISC_req(conn_id, 0));
1051 f_conn_table_del(conn_id);
1052 }
1053
1054 /* BSSAP from client -> SCCP */
1055 [] CLIENT.receive(RANAP_Conn_Req:?) -> value creq sender vc_conn {
1056 var integer conn_id;
1057 /* send to dispatcher */
1058
1059 if (f_comp_known(vc_conn) == false) {
1060 /* unknown client, create new connection */
1061 conn_id := f_gen_conn_id();
1062
1063 /* store mapping between client components and SCCP connectionId */
1064 f_conn_table_add(vc_conn, conn_id);
1065
1066 RANAP.send(ts_RANAP_CONNECT_req(creq.addr_peer, creq.addr_own, conn_id,
1067 creq.ranap));
1068 } else {
1069 /* known client, send via existing connection */
1070 conn_id := f_conn_id_by_comp(vc_conn);
1071 RANAP.send(ts_RANAP_DATA_req(conn_id, creq.ranap));
1072 }
1073
1074 /* InitialL3 contains RR (PAG RESP) or MM (CM SRV REQ), we must increment
1075 * counter only on MM/CC/SS, but not on RR */
1076 if (g_ran_ops.role_ms and not f_ranap_l3_is_rr(creq.ranap)) {
1077 /* we have just sent the first MM message, increment the counter */
1078 var integer idx := f_idx_by_comp(vc_conn);
1079 ConnectionTable[idx].n_sd[0] := 1;
1080 log("patch: N(SD) for ConnIdx ", idx, " set to 1");
1081 }
1082 }
1083
Harald Welte717c7302019-04-23 20:31:55 +02001084 [g_ran_ops.role_ms] CLIENT.receive(PDU_DTAP_PS_MO:?) -> value ps_mo sender vc_conn {
1085 var integer idx := f_idx_by_comp(vc_conn);
1086 /* convert from decoded DTAP to encoded DTAP */
1087 var octetstring l3_enc := enc_PDU_L3_MS_SGSN(ps_mo.dtap);
1088 /* patch correct L3 send sequence number N(SD) into l3_enc */
1089 if (ps_mo.skip_seq_patching == false) {
1090 //f_ML3_patch_seq(ConnectionTable[idx], ps_mo.dtap, l3_enc);
1091 }
1092 f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, ps_mo.dlci, l3_enc);
1093 }
1094
1095 [not g_ran_ops.role_ms] CLIENT.receive(PDU_DTAP_PS_MT:?) -> value ps_mt sender vc_conn {
1096 var integer idx := f_idx_by_comp(vc_conn);
1097 /* convert from decoded DTAP to encoded DTAP */
1098 var octetstring l3_enc := enc_PDU_L3_SGSN_MS(ps_mt.dtap);
1099 f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, ps_mt.dlci, l3_enc);
1100 }
1101
1102
Harald Welte5b027622019-04-14 23:40:17 +02001103#else
1104 [false] CLIENT.receive {}
Harald Welte2fce7882019-04-15 11:48:05 +02001105#endif
1106}
Harald Welteb3414b22017-11-23 18:22:10 +01001107
Harald Welte2fce7882019-04-15 11:48:05 +02001108private altstep as_main_mgcp() runs on RAN_Emulation_CT {
1109#ifdef RAN_EMULATION_MGCP
1110 var MgcpCommand mgcp_req;
1111 var MgcpResponse mgcp_resp;
1112 var RAN_ConnHdlr vc_conn;
Harald Welte0b476062018-01-21 19:07:32 +01001113
Harald Weltec82eef42017-11-24 20:40:12 +01001114 /* Handling of MGCP in IPA SCCPLite case. This predates 3GPP AoIP
1115 * and uses a MGCP session in parallel to BSSAP. BSSAP uses CIC
1116 * as usual, and MGCP uses "CIC@mgw" endpoint naming, where CIC
1117 * is printed as hex string, e.g. a@mgw for CIC 10 */
1118
1119 /* CLIENT -> MGCP */
1120 [] CLIENT.receive(MgcpCommand:?) -> value mgcp_req sender vc_conn {
1121 /* MGCP request from Handler (we're MSC) */
1122 /* store the transaction ID we've seen */
1123 f_comp_store_mgcp_tid(vc_conn, mgcp_req.line.trans_id);
1124 /* simply forward any MGCP from the client to the port */
1125 MGCP.send(mgcp_req);
1126 }
1127 [] CLIENT.receive(MgcpResponse:?) -> value mgcp_resp sender vc_conn {
1128 /* MGCP response from Handler (we're BSC/MGW) */
1129 /* simply forward any MGCP from the client to the port */
1130 MGCP.send(mgcp_resp);
1131 }
1132
1133 /* MGCP -> CLIENT */
1134 [] MGCP.receive(MgcpCommand:?) -> value mgcp_req {
1135 /* MGCP request from network side (we're BSC/MGW) */
1136 /* Extract CIC from local part of endpoint name */
1137 var integer cic := f_mgcp_ep_extract_cic(mgcp_req.line.ep);
Harald Weltee98bb2e2017-11-29 12:09:48 +01001138 if (match(mgcp_req, tr_RSIP) and f_cic_known(cic) == false) {
1139 /* ignore RSIP for unknown CIC */
1140 } else {
1141 /* Resolve the vc_conn by the CIC */
1142 vc_conn := f_comp_by_cic(cic);
1143 CLIENT.send(mgcp_req) to vc_conn;
1144 }
Harald Weltec82eef42017-11-24 20:40:12 +01001145 }
1146 [] MGCP.receive(MgcpResponse:?) -> value mgcp_resp {
1147 /* MGCP response from network side (we're MSC) */
1148 /* Resolve the vc_conn by the transaction ID */
1149 vc_conn := f_comp_by_mgcp_tid(mgcp_resp.line.trans_id);
1150 CLIENT.send(mgcp_resp) to vc_conn;
1151 }
Harald Welte2fce7882019-04-15 11:48:05 +02001152#else
1153 [false] CLIENT.receive {}
1154#endif
1155}
Harald Weltec82eef42017-11-24 20:40:12 +01001156
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +02001157private altstep as_main_ctrl() runs on RAN_Emulation_CT {
1158#ifdef RAN_EMULATION_CTRL
1159 var CtrlMessage ctrl;
1160 var RAN_ConnHdlr vc_conn;
1161 var ASP_IPA_Event evt;
1162
1163 /* Handling of CTRL in IPA SCCPLite case. This predates 3GPP AoIP
1164 * and uses a CTRL session in parallel to BSSAP. */
1165
1166 /* CTRL_CLIENT -> CTRL */
1167 [] CTRL_CLIENT.receive(CtrlMessage:?) -> value ctrl sender vc_conn {
1168 CTRL.send(ctrl);
1169 }
1170
1171 /* CTRL -> CTRL_CLIENT */
1172 [] CTRL.receive(CtrlMessage:?) -> value ctrl {
1173 CTRL_CLIENT.send(ctrl);
1174 }
1175
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +07001176 [] CTRL.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) -> value evt {
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +02001177 CTRL_CLIENT.send(evt);
1178 }
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +07001179 [] CTRL.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN)) {
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +02001180 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Lost IPA connection!");
1181 }
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +07001182 [] CTRL.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK)) {}
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +02001183#else
1184 [false] CLIENT.receive {}
1185#endif
1186}
1187
Harald Welte2fce7882019-04-15 11:48:05 +02001188/* send a raw (encoded) L3 message over given SCCP connection */
1189private function f_xmit_raw_l3(integer sccp_conn_id, OCT1 dlci, octetstring l3_enc) runs on RAN_Emulation_CT
1190{
1191 select (g_ran_ops.protocol) {
1192#ifdef RAN_EMULATION_BSSAP
1193 case (RAN_PROTOCOL_BSSAP) {
1194 var PDU_BSSAP bssap;
1195 bssap := valueof(ts_BSSAP_DTAP(l3_enc, dlci));
1196 BSSAP.send(ts_BSSAP_DATA_req(sccp_conn_id, bssap));
1197 }
1198#endif
Harald Welte5b027622019-04-14 23:40:17 +02001199#ifdef RAN_EMULATION_RANAP
1200 case (RAN_PROTOCOL_RANAP) {
Vadim Yanitskiyf2c3fa92019-06-20 05:18:15 +07001201 var template (omit) RANAP_IEs.SAPI sapi := omit;
Harald Welte5b027622019-04-14 23:40:17 +02001202 var RANAP_PDU ranap;
Vadim Yanitskiyf2c3fa92019-06-20 05:18:15 +07001203
1204 /* Perform DLCI -> SAPI transformation (x & 0x07) */
1205 if (dlci and4b '07'O == '03'O) {
1206 sapi := sapi_3;
1207 }
1208
1209 ranap := valueof(ts_RANAP_DirectTransfer(l3_enc, sapi := sapi));
Harald Welte5b027622019-04-14 23:40:17 +02001210 RANAP.send(ts_RANAP_DATA_req(sccp_conn_id, ranap));
1211 }
1212#endif
Harald Welte2fce7882019-04-15 11:48:05 +02001213 }
1214}
1215
1216function main(RanOps ops, charstring id) runs on RAN_Emulation_CT {
1217
1218 g_ran_id := id;
1219 g_ran_ops := ops;
1220 f_conn_table_init();
1221 f_expect_table_init();
1222
1223 if (isvalue(ops.sccp_addr_peer) and isvalue(ops.sccp_addr_local)) {
1224 f_sleep(1.0); /* HACK to wait for M3UA/ASP to be ACTIVE */
Harald Welte5b027622019-04-14 23:40:17 +02001225 select (g_ran_ops.protocol) {
1226#ifdef RAN_EMULATION_BSSAP
1227 case (RAN_PROTOCOL_BSSAP) {
1228 f_bssap_reset(ops.sccp_addr_peer, ops.sccp_addr_local);
1229 }
1230#endif
1231#ifdef RAN_EMULATION_RANAP
1232 case (RAN_PROTOCOL_RANAP) {
1233 f_ranap_reset(ops.sccp_addr_peer, ops.sccp_addr_local);
1234 }
1235#endif
1236 }
Harald Welte2fce7882019-04-15 11:48:05 +02001237 }
1238
1239 while (true) {
1240 var RAN_ConnHdlr vc_conn;
1241 var PDU_DTAP_MO dtap_mo;
1242 var PDU_DTAP_MT dtap_mt;
1243 var RAN_ConnHdlr vc_hdlr;
1244 var octetstring l3_info;
1245 var hexstring imsi;
1246 var OCT4 tmsi;
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001247 var integer targetPointCode;
Harald Welte2fce7882019-04-15 11:48:05 +02001248
1249 alt {
1250 [g_ran_ops.protocol == RAN_PROTOCOL_BSSAP] as_main_bssap();
Harald Welte5b027622019-04-14 23:40:17 +02001251 [g_ran_ops.protocol == RAN_PROTOCOL_RANAP] as_main_ranap();
Harald Welte2fce7882019-04-15 11:48:05 +02001252
1253 [g_ran_ops.role_ms] CLIENT.receive(PDU_DTAP_MO:?) -> value dtap_mo sender vc_conn {
1254 var integer idx := f_idx_by_comp(vc_conn);
1255 /* convert from decoded DTAP to encoded DTAP */
1256 var octetstring l3_enc := enc_PDU_ML3_MS_NW(dtap_mo.dtap);
1257 /* patch correct L3 send sequence number N(SD) into l3_enc */
1258 if (dtap_mo.skip_seq_patching == false) {
1259 f_ML3_patch_seq(ConnectionTable[idx], dtap_mo.dtap, l3_enc);
1260 }
1261 f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, dtap_mo.dlci, l3_enc);
1262 }
1263
1264 [not g_ran_ops.role_ms] CLIENT.receive(PDU_DTAP_MT:?) -> value dtap_mt sender vc_conn {
1265 var integer idx := f_idx_by_comp(vc_conn);
1266 /* convert from decoded DTAP to encoded DTAP */
1267 var octetstring l3_enc := enc_PDU_ML3_NW_MS(dtap_mt.dtap);
1268 f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, dtap_mt.dlci, l3_enc);
1269 }
1270
1271 [] as_main_mgcp();
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +02001272 [] as_main_ctrl();
Harald Welte624f9632017-12-16 19:26:04 +01001273
Harald Welte6811d102019-04-14 22:23:14 +02001274 [] PROC.getcall(RAN_register:{?,?}) -> param(l3_info, vc_hdlr) {
Harald Welte624f9632017-12-16 19:26:04 +01001275 f_create_expect(l3_info, vc_hdlr);
Harald Welte6811d102019-04-14 22:23:14 +02001276 PROC.reply(RAN_register:{l3_info, vc_hdlr}) to vc_hdlr;
Harald Welte624f9632017-12-16 19:26:04 +01001277 }
1278
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001279 [] PROC.getcall(RAN_register_n_connect:{?,?}) -> param(targetPointCode, vc_hdlr) {
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001280 f_create_expect(omit, vc_hdlr, targetPointCode);
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001281 PROC.reply(RAN_register_n_connect:{targetPointCode, vc_hdlr}) to vc_hdlr;
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001282 }
1283
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001284 [] PROC.getcall(RAN_register_sccp_cr_without_payload:{?}) -> param(vc_hdlr) {
1285 f_create_expect(omit, vc_hdlr);
1286 PROC.reply(RAN_register_sccp_cr_without_payload:{vc_hdlr}) to vc_hdlr;
1287 }
1288
Harald Welte6811d102019-04-14 22:23:14 +02001289 [] PROC.getcall(RAN_register_imsi:{?,?,?}) -> param(imsi, tmsi, vc_hdlr) {
Harald Welte17d21152018-01-27 00:47:11 +01001290 f_create_imsi(imsi, tmsi, vc_hdlr);
Harald Welte6811d102019-04-14 22:23:14 +02001291 PROC.reply(RAN_register_imsi:{imsi, tmsi, vc_hdlr}) to vc_hdlr;
Harald Welte17d21152018-01-27 00:47:11 +01001292 }
Harald Welteee4d70c2022-05-16 21:29:19 +02001293 [] PROC.getcall(RAN_unregister_imsi:{?,?}) -> param(imsi, vc_hdlr) {
1294 f_destroy_imsi(imsi, vc_hdlr);
1295 PROC.reply(RAN_unregister_imsi:{imsi, vc_hdlr}) to vc_hdlr;
1296 }
Harald Welte17d21152018-01-27 00:47:11 +01001297
Harald Welte365f4ed2017-11-23 00:00:43 +01001298 }
1299 }
1300}
1301
Harald Welte2fce7882019-04-15 11:48:05 +02001302#ifdef RAN_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +01001303private function f_mgcp_ep_extract_cic(charstring inp) return integer {
Harald Welte525a9c12017-11-24 23:40:41 +01001304 var charstring local_part := regexp(inp, "(*)@*", 0);
Harald Weltec82eef42017-11-24 20:40:12 +01001305 return hex2int(str2hex(local_part));
1306
1307}
Harald Welte2fce7882019-04-15 11:48:05 +02001308#endif
Harald Welte365f4ed2017-11-23 00:00:43 +01001309
Harald Welte624f9632017-12-16 19:26:04 +01001310/***********************************************************************
1311 * "Expect" Handling (mapping for expected incoming SCCP connections)
1312 ***********************************************************************/
1313
1314/* data about an expected future incoming connection */
1315type record ExpectData {
1316 /* L3 payload based on which we can match it */
1317 octetstring l3_payload optional,
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001318 integer n_connectPointCode optional,
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001319 boolean sccp_cr_without_payload,
Harald Welte624f9632017-12-16 19:26:04 +01001320 /* component reference for this connection */
Harald Welte6811d102019-04-14 22:23:14 +02001321 RAN_ConnHdlr vc_conn
Harald Welte624f9632017-12-16 19:26:04 +01001322}
1323
1324/* procedure based port to register for incoming connections */
Harald Welte6811d102019-04-14 22:23:14 +02001325signature RAN_register(in octetstring l3, in RAN_ConnHdlr hdlr);
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001326signature RAN_register_n_connect(in integer targetPointCode, in RAN_ConnHdlr hdlr);
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001327signature RAN_register_sccp_cr_without_payload(in RAN_ConnHdlr hdlr);
Harald Welte624f9632017-12-16 19:26:04 +01001328
Harald Welte17d21152018-01-27 00:47:11 +01001329/* procedure based port to register for incoming IMSI/TMSI */
Harald Welte6811d102019-04-14 22:23:14 +02001330signature RAN_register_imsi(in hexstring imsi, in OCT4 tmsi, in RAN_ConnHdlr hdlr);
Harald Welteee4d70c2022-05-16 21:29:19 +02001331signature RAN_unregister_imsi(in hexstring imsi, in RAN_ConnHdlr hdlr);
Harald Welte17d21152018-01-27 00:47:11 +01001332
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001333/* If DTAP happens across other channels (e.g. GSUP), provide manual advancing of the n_sd sequence number */
1334signature RAN_last_n_sd(in RAN_ConnHdlr hdlr, out N_Sd_Array last_n_sd);
1335
1336/* Update conn's n_sd sequence nr after the connection was taken over from elsewhere */
1337signature RAN_continue_after_n_sd(N_Sd_Array last_n_sd, in RAN_ConnHdlr hdlr);
1338
Harald Welte6811d102019-04-14 22:23:14 +02001339type port RAN_PROC_PT procedure {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001340 inout RAN_register, RAN_register_imsi, RAN_unregister_imsi, RAN_register_n_connect,
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001341 RAN_register_sccp_cr_without_payload, RAN_last_n_sd, RAN_continue_after_n_sd;
Harald Welte624f9632017-12-16 19:26:04 +01001342} with { extension "internal" };
1343
Harald Welte5b027622019-04-14 23:40:17 +02001344#ifdef RAN_EMULATION_BSSAP
Harald Welte624f9632017-12-16 19:26:04 +01001345/* CreateCallback that can be used as create_cb and will use the expectation table */
1346function ExpectedCreateCallback(BSSAP_N_CONNECT_ind conn_ind, charstring id)
Harald Welte6811d102019-04-14 22:23:14 +02001347runs on RAN_Emulation_CT return RAN_ConnHdlr {
1348 var RAN_ConnHdlr ret := null;
Harald Welte624f9632017-12-16 19:26:04 +01001349 var octetstring l3_info;
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001350 var boolean n_connect := false;
1351 var integer n_connectPointCode;
Harald Welte624f9632017-12-16 19:26:04 +01001352 var integer i;
1353
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001354 if (ischosen(conn_ind.userData.pdu.bssmap.completeLayer3Information)) {
1355 l3_info := conn_ind.userData.pdu.bssmap.completeLayer3Information.layer3Information.layer3info;
1356 log("ExpectedCreateCallback completeLayer3Information");
1357 } else if (ischosen(conn_ind.userData.pdu.bssmap.handoverRequest)) {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001358 n_connect := true;
1359 n_connectPointCode := bit2int(conn_ind.calledAddress.signPointCode);
1360 log("ExpectedCreateCallback handoverRequest ", n_connectPointCode);
Andreas Eversbergd9a348c2023-07-27 16:08:23 +02001361 } else if (ischosen(conn_ind.userData.pdu.bssmap.vGCS_VBSSetup)) {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001362 n_connect := true;
1363 n_connectPointCode := bit2int(conn_ind.calledAddress.signPointCode);
1364 log("ExpectedCreateCallback VGCS/VBS Setup ", n_connectPointCode);
Andreas Eversbergd9a348c2023-07-27 16:08:23 +02001365 } else if (ischosen(conn_ind.userData.pdu.bssmap.vGCS_VBSAssignmentRequest)) {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001366 n_connect := true;
1367 n_connectPointCode := bit2int(conn_ind.calledAddress.signPointCode);
1368 log("ExpectedCreateCallback VGCS/VBS Assignment ", n_connectPointCode);
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001369 } else {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001370 setverdict(fail, "N-CONNECT.ind with L3 != COMPLETE L3 nor a new BSS connection");
Daniel Willmanne4ff5372018-07-05 17:35:03 +02001371 mtc.stop;
Harald Welte624f9632017-12-16 19:26:04 +01001372 }
Harald Welte624f9632017-12-16 19:26:04 +01001373
1374 for (i := 0; i < sizeof(ExpectTable); i:= i+1) {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001375 if (n_connect) {
1376 log("ExpectTable[", i, "].n_connectPointCode = ", ExpectTable[i].n_connectPointCode,
1377 " ==? ", n_connectPointCode);
1378 if (ExpectTable[i].n_connectPointCode == n_connectPointCode) {
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001379 ret := ExpectTable[i].vc_conn;
Andreas Eversbergd9a348c2023-07-27 16:08:23 +02001380 /* release this entry to be used again */
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001381 ExpectTable[i].n_connectPointCode := omit;
Andreas Eversbergd9a348c2023-07-27 16:08:23 +02001382 ExpectTable[i].vc_conn := null;
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001383 log("Found Expect[", i, "] for N-CONNECT handled at ", ret);
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001384 return ret;
1385 } else {
1386 continue;
1387 }
1388 }
Harald Welte624f9632017-12-16 19:26:04 +01001389 if (not ispresent(ExpectTable[i].l3_payload)) {
1390 continue;
1391 }
1392 if (l3_info == ExpectTable[i].l3_payload) {
1393 ret := ExpectTable[i].vc_conn;
1394 /* release this entry to be used again */
1395 ExpectTable[i].l3_payload := omit;
1396 ExpectTable[i].vc_conn := null;
1397 log("Found Expect[", i, "] for ", l3_info, " handled at ", ret);
1398 /* return the component reference */
1399 return ret;
1400 }
1401 }
1402 setverdict(fail, "Couldn't find Expect for incoming connection ", conn_ind);
Daniel Willmanne4ff5372018-07-05 17:35:03 +02001403 mtc.stop;
Harald Welte624f9632017-12-16 19:26:04 +01001404}
Harald Welte5b027622019-04-14 23:40:17 +02001405#endif
1406
1407#ifdef RAN_EMULATION_RANAP
1408/* CreateCallback that can be used as create_cb and will use the expectation table */
1409function RanapExpectedCreateCallback(RANAP_N_CONNECT_ind conn_ind, charstring id)
1410runs on RAN_Emulation_CT return RAN_ConnHdlr {
1411 var RAN_ConnHdlr ret := null;
1412 var template (omit) octetstring l3_info;
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001413 var boolean rx_sccp_cr_without_payload;
Harald Welte5b027622019-04-14 23:40:17 +02001414 var integer i;
1415
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001416 if (ispresent(conn_ind.userData)) {
1417 l3_info := f_ranap_extract_l3(conn_ind.userData);
1418 rx_sccp_cr_without_payload := false;
1419 if (istemplatekind(l3_info, "omit") and not rx_sccp_cr_without_payload) {
1420 setverdict(fail, "N-CONNECT.ind without NAS payload");
1421 mtc.stop;
1422 return ret;
1423 }
1424 } else {
1425 l3_info := omit;
1426 rx_sccp_cr_without_payload := true;
Harald Welte5b027622019-04-14 23:40:17 +02001427 }
1428
1429 for (i := 0; i < sizeof(ExpectTable); i:= i+1) {
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001430 if ((rx_sccp_cr_without_payload and ExpectTable[i].sccp_cr_without_payload)
1431 or (ispresent(ExpectTable[i].l3_payload) and valueof(l3_info) == ExpectTable[i].l3_payload)) {
Harald Welte5b027622019-04-14 23:40:17 +02001432 ret := ExpectTable[i].vc_conn;
1433 /* release this entry to be used again */
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001434 ExpectTable[i].sccp_cr_without_payload := false;
Harald Welte5b027622019-04-14 23:40:17 +02001435 ExpectTable[i].l3_payload := omit;
1436 ExpectTable[i].vc_conn := null;
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001437 log("Found Expect[", i, "] for l3=", l3_info, " handled at ", ret);
Harald Welte5b027622019-04-14 23:40:17 +02001438 /* return the component reference */
1439 return ret;
1440 }
1441 }
1442 setverdict(fail, "Couldn't find Expect for incoming connection ", conn_ind);
1443 mtc.stop;
1444 return ret;
1445}
1446#endif
Harald Welte624f9632017-12-16 19:26:04 +01001447
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001448private function f_create_expect(template octetstring l3, RAN_ConnHdlr hdlr,
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001449 template integer n_connectPointCode := omit)
Harald Welte6811d102019-04-14 22:23:14 +02001450runs on RAN_Emulation_CT {
Harald Welte624f9632017-12-16 19:26:04 +01001451 var integer i;
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001452 log("f_create_expect(l3 := ", l3, ", n_connectPointCode := ", n_connectPointCode);
Harald Welte624f9632017-12-16 19:26:04 +01001453 for (i := 0; i < sizeof(ExpectTable); i := i+1) {
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001454 if (not ispresent(ExpectTable[i].l3_payload)
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001455 and not ExpectTable[i].sccp_cr_without_payload
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001456 and not ispresent(ExpectTable[i].n_connectPointCode)) {
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001457 if (ispresent(l3)) {
1458 ExpectTable[i].l3_payload := valueof(l3);
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001459 } else {
1460 ExpectTable[i].sccp_cr_without_payload := true;
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001461 }
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001462 if (ispresent(n_connectPointCode)) {
1463 ExpectTable[i].n_connectPointCode := valueof(n_connectPointCode);
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001464 }
Harald Welte624f9632017-12-16 19:26:04 +01001465 ExpectTable[i].vc_conn := hdlr;
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001466 if (ispresent(n_connectPointCode)) {
1467 log("Created Expect[", i, "] for N-CONNECT to be handled at ", hdlr);
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001468 } else {
1469 log("Created Expect[", i, "] for ", l3, " to be handled at ", hdlr);
1470 }
Harald Welte624f9632017-12-16 19:26:04 +01001471 return;
1472 }
1473 }
Oliver Smith07ebf962023-07-07 12:11:58 +02001474 setverdict(fail, "No space left in ExpectTable");
1475 mtc.stop;
Harald Welte624f9632017-12-16 19:26:04 +01001476}
1477
Harald Welte6811d102019-04-14 22:23:14 +02001478private function f_create_imsi(hexstring imsi, OCT4 tmsi, RAN_ConnHdlr hdlr)
1479runs on RAN_Emulation_CT {
Harald Welte17d21152018-01-27 00:47:11 +01001480 for (var integer i := 0; i < sizeof(ImsiTable); i := i+1) {
1481 if (not ispresent(ImsiTable[i].imsi)) {
1482 ImsiTable[i].imsi := imsi;
1483 ImsiTable[i].tmsi := tmsi;
1484 ImsiTable[i].comp_ref := hdlr;
1485 log("Created IMSI[", i, "] for ", imsi, tmsi, " to be handled at ", hdlr);
1486 return;
1487 }
1488 }
Oliver Smith07ebf962023-07-07 12:11:58 +02001489 setverdict(fail, "No space left in ImsiTable");
1490 mtc.stop;
Harald Welte17d21152018-01-27 00:47:11 +01001491}
1492
Harald Welteee4d70c2022-05-16 21:29:19 +02001493private function f_destroy_imsi(hexstring imsi, RAN_ConnHdlr hdlr)
1494runs on RAN_Emulation_CT {
1495 for (var integer i := 0; i < sizeof(ImsiTable); i := i+1) {
1496 if (ImsiTable[i].imsi == imsi and ImsiTable[i].comp_ref == hdlr) {
1497 ImsiTable[i].comp_ref := null;
1498 ImsiTable[i].imsi := omit;
1499 ImsiTable[i].tmsi := 'FFFFFFFF'O;
1500 log("Removed IMSI[", i, "] for ", imsi, " to be handled at ", hdlr);
1501 return;
1502 }
1503 }
Oliver Smith07ebf962023-07-07 12:11:58 +02001504 setverdict(fail, "Unable to find to-be-destroyed IMSI in ImsiTable");
1505 mtc.stop;
Harald Welteee4d70c2022-05-16 21:29:19 +02001506}
Harald Welte17d21152018-01-27 00:47:11 +01001507
Daniel Willmannd47106b2018-01-17 12:20:56 +01001508private function f_expect_table_init()
Harald Welte6811d102019-04-14 22:23:14 +02001509runs on RAN_Emulation_CT {
Daniel Willmannd47106b2018-01-17 12:20:56 +01001510 for (var integer i := 0; i < sizeof(ExpectTable); i := i+1) {
1511 ExpectTable[i].l3_payload := omit;
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001512 ExpectTable[i].n_connectPointCode := omit;
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001513 ExpectTable[i].sccp_cr_without_payload := false;
Daniel Willmannd47106b2018-01-17 12:20:56 +01001514 }
1515}
Harald Welte624f9632017-12-16 19:26:04 +01001516
Harald Welte17d21152018-01-27 00:47:11 +01001517/* helper function for clients to register their IMSI/TMSI */
Vadim Yanitskiyae747742020-01-10 00:23:10 +01001518function f_ran_register_imsi(hexstring imsi, template (omit) OCT4 tmsi_or_omit)
Harald Welte6811d102019-04-14 22:23:14 +02001519runs on RAN_ConnHdlr {
Vadim Yanitskiyae747742020-01-10 00:23:10 +01001520 var OCT4 tmsi;
1521
1522 /* Resolve omit to a special reserved value */
1523 if (istemplatekind(tmsi_or_omit, "omit")) {
1524 tmsi := 'FFFFFFFF'O;
1525 } else {
1526 tmsi := valueof(tmsi_or_omit);
1527 }
1528
Harald Welte6811d102019-04-14 22:23:14 +02001529 BSSAP_PROC.call(RAN_register_imsi:{imsi, tmsi, self}) {
1530 [] BSSAP_PROC.getreply(RAN_register_imsi:{?,?,?}) {};
Harald Welte17d21152018-01-27 00:47:11 +01001531 }
1532}
1533
Harald Welteee4d70c2022-05-16 21:29:19 +02001534/* helper function for clients to register their IMSI/TMSI */
1535function f_ran_unregister_imsi(hexstring imsi)
1536runs on RAN_ConnHdlr {
1537
1538 BSSAP_PROC.call(RAN_unregister_imsi:{imsi, self}) {
1539 [] BSSAP_PROC.getreply(RAN_unregister_imsi:{?,?}) {};
1540 }
1541}
1542
Harald Welte1e3bbbe2022-01-11 23:04:33 +01001543/* register an expect with the BSSMAP core */
1544function f_ran_register_exp(octetstring l3_enc) runs on RAN_ConnHdlr {
1545 BSSAP_PROC.call(RAN_register:{l3_enc, self}) {
1546 [] BSSAP_PROC.getreply(RAN_register:{?, ?}) {};
1547 }
1548}
1549
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001550function f_ran_register_sccp_cr_without_payload() runs on RAN_ConnHdlr {
1551 BSSAP_PROC.call(RAN_register_sccp_cr_without_payload:{self}) {
1552 [] BSSAP_PROC.getreply(RAN_register_sccp_cr_without_payload:{?}) {};
1553 }
1554}
1555
Harald Welte475a2c12019-05-02 19:05:48 +02001556#ifdef RAN_EMULATION_RANAP
1557/* expect a IuReleaseCommand; Confirm that; expect SCCP-level N-DISCONNET.ind */
Vadim Yanitskiy7093a5d2024-03-27 16:10:25 +07001558altstep as_iu_release_compl_disc() runs on RAN_ConnHdlr {
Harald Welte475a2c12019-05-02 19:05:48 +02001559 var RANAP_PDU ranap;
1560 [] BSSAP.receive(tr_RANAP_IuReleaseCommand(?)) {
1561 BSSAP.send(ts_RANAP_IuReleaseComplete);
1562 alt {
1563 [] BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
1564 setverdict(pass);
1565 }
1566 [] BSSAP.receive {
1567 setverdict(fail, "Unexpected RANAP while waiting for SCCP Release ");
1568 mtc.stop;
1569 }
1570 }
1571 }
1572 [] BSSAP.receive(RANAP_PDU:?) -> value ranap{
1573 setverdict(fail, "Unexpected RANAP while waiting for IuReleaseCommand", ranap);
1574 mtc.stop;
1575 }
1576}
1577#endif
1578
Harald Welte17d21152018-01-27 00:47:11 +01001579
Harald Welte365f4ed2017-11-23 00:00:43 +01001580}