blob: 25727f39ccc0eefe8121bc7771835d7d3b758c23 [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;
Harald Welte17d21152018-01-27 00:47:11 +0100507 client := f_imsi_table_find(bssap.pdu.bssmap.paging.iMSI.digits,
508 bssap.pdu.bssmap.paging.tMSI.tmsiOctets);
Daniel Willmannabc73e12019-04-15 17:25:56 +0200509 if (client != null) {
Harald Welte17d21152018-01-27 00:47:11 +0100510 log("CommonBssmapUnitdataCallback: IMSI/TMSI found in table, dispatching to ",
511 client);
512 CLIENT.send(bssap) to client;
513 return omit;
514 }
515 log("CommonBssmapUnitdataCallback: IMSI/TMSI not found in table");
516 } else {
517 log("CommonBssmapUnitdataCallback: Not a paging message");
518 }
519 /* ELSE: handle in user callback */
Neels Hofmeyr79896c02023-06-23 03:45:40 +0200520 if (not ispresent(g_ran_ops.unitdata_cb)) {
521 return omit;
522 }
Harald Welte6811d102019-04-14 22:23:14 +0200523 return g_ran_ops.unitdata_cb.apply(bssap);
Harald Welte17d21152018-01-27 00:47:11 +0100524}
525
Harald Welte6811d102019-04-14 22:23:14 +0200526function f_bssap_reset(SCCP_PAR_Address peer, SCCP_PAR_Address own) runs on RAN_Emulation_CT {
Harald Weltea4ca4462018-02-09 00:17:14 +0100527 timer T := 5.0;
Pau Espin Pedrol95549182019-06-06 16:17:30 +0200528 var boolean append_osmux_support := append_osmux_ie();
Eric Wild49888a62022-03-30 03:16:11 +0200529 var integer attempts := g_ran_ops.bssap_reset_retries;
Harald Weltea4ca4462018-02-09 00:17:14 +0100530
Eric Wild49888a62022-03-30 03:16:11 +0200531 while (attempts > 0) {
532 attempts := attempts - 1;
533
534 BSSAP.send(ts_BSSAP_UNITDATA_req(peer, own, ts_BSSMAP_Reset(0, append_osmux_support)));
535 T.start;
536 alt {
537 [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(own, peer, tr_BSSMAP_ResetAck(append_osmux_support))) {
538 log("BSSMAP: Received RESET-ACK in response to RESET, we're ready to go!");
539 return;
540 }
541 [] as_reset_ack(append_osmux_support);
542 [] BSSAP.receive { repeat };
543 [] T.timeout {
544 continue;
545 }
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200546 }
Harald Weltea4ca4462018-02-09 00:17:14 +0100547 }
Eric Wild49888a62022-03-30 03:16:11 +0200548
549 setverdict(fail, "BSSMAP: Timeout waiting for RESET-ACK after sending RESET");
550 mtc.stop;
Harald Weltea4ca4462018-02-09 00:17:14 +0100551}
552
Harald Welte2fce7882019-04-15 11:48:05 +0200553private function f_bssap_l3_is_rr(PDU_BSSAP bssap) return boolean {
554 var template octetstring l3 := f_bssap_extract_l3(bssap);
555 return f_L3_is_rr(l3);
556}
557#endif
Harald Welte365f4ed2017-11-23 00:00:43 +0100558
Harald Welte5b027622019-04-14 23:40:17 +0200559#ifdef RAN_EMULATION_RANAP
560type record RANAP_Conn_Req {
561 SCCP_PAR_Address addr_peer,
562 SCCP_PAR_Address addr_own,
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +0200563 RANAP_PDU ranap optional
Harald Welte5b027622019-04-14 23:40:17 +0200564}
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +0200565template (value) RANAP_Conn_Req ts_RANAP_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own,
566 template (omit) RANAP_PDU ranap) := {
567 addr_peer := peer,
568 addr_own := own,
569 ranap := ranap
570};
571
572template RANAP_Conn_Req tr_RANAP_Conn_Req(template SCCP_PAR_Address peer := ?,
573 template SCCP_PAR_Address own := ?,
574 template (omit) RANAP_PDU ranap := omit) := {
Harald Welte5b027622019-04-14 23:40:17 +0200575 addr_peer := peer,
576 addr_own := own,
577 ranap := ranap
578};
579
580private function fake_dlci_from_sapi(template (omit) SAPI sapi) return template (omit) OCT1
581{
582 if (istemplatekind(sapi, "omit")) {
583 return omit;
584 } else if (valueof(sapi) == sapi_3) {
585 return '03'O;
586 }
587 return '00'O;
588}
589
590private function f_handle_userData_RANAP(RAN_ConnHdlr client, RANAP_PDU ranap)
591runs on RAN_Emulation_CT {
592 /* decode + send decoded RANAP to client */
593 var template (omit) octetstring l3 := f_ranap_extract_l3(ranap);
Harald Welte0af76152022-01-11 23:02:38 +0100594 if (istemplatekind(l3, "omit") or not g_ran_ops.decode_dtap) {
Harald Welte5b027622019-04-14 23:40:17 +0200595 CLIENT.send(ranap) to client;
596 } else {
597 var template (omit) SAPI sapi := f_ranap_extract_sapi(ranap);
598 var template (omit) OCT1 dlci := fake_dlci_from_sapi(sapi);
599 if (g_ran_ops.role_ms) {
600 /* we are the MS, so any message to us must be MT */
Harald Welte717c7302019-04-23 20:31:55 +0200601 if (g_ran_ops.ps_domain) {
602 var PDU_DTAP_PS_MT mt := {
603 dlci := omit,
604 dtap := dec_PDU_L3_SGSN_MS(valueof(l3))
605 };
606 if (isvalue(dlci)) {
607 mt.dlci := valueof(dlci);
608 }
609 CLIENT.send(mt) to client;
610 } else {
611 var PDU_DTAP_MT mt := {
612 dlci := omit,
613 dtap := dec_PDU_ML3_NW_MS(valueof(l3))
614 };
615 if (isvalue(dlci)) {
616 mt.dlci := valueof(dlci)
617 }
618 CLIENT.send(mt) to client;
Harald Welte5b027622019-04-14 23:40:17 +0200619 }
Harald Welte5b027622019-04-14 23:40:17 +0200620 } else {
621 /* we are the Network, so any message to us must be MO */
Harald Welte717c7302019-04-23 20:31:55 +0200622 if (g_ran_ops.ps_domain) {
623 var PDU_DTAP_PS_MO mo := {
624 dlci := omit,
625 dtap := dec_PDU_L3_MS_SGSN(valueof(l3))
626 };
627 if (isvalue(dlci)) {
628 mo.dlci := valueof(dlci);
629 }
630 CLIENT.send(mo) to client;
631 } else {
632 var PDU_DTAP_MO mo := {
633 dlci := omit,
634 dtap := dec_PDU_ML3_MS_NW(valueof(l3))
635 };
636 if (isvalue(dlci)) {
637 mo.dlci := valueof(dlci)
638 }
639 CLIENT.send(mo) to client;
Harald Welte5b027622019-04-14 23:40:17 +0200640 }
Harald Welte5b027622019-04-14 23:40:17 +0200641 }
642 }
643}
644
645/* call-back type, to be provided by specific implementation; called when new SCCP connection
646 * arrives */
647type function RanapCreateCallback(RANAP_N_CONNECT_ind conn_ind, charstring id)
648runs on RAN_Emulation_CT return RAN_ConnHdlr;
649
650type function RanapUnitdataCallback(RANAP_PDU ranap)
651runs on RAN_Emulation_CT return template RANAP_PDU;
652
653private function CommonRanapUnitdataCallback(RANAP_PDU ranap)
654runs on RAN_Emulation_CT return template RANAP_PDU {
655 if (match(ranap, tr_RANAP_Paging(?, ?))) {
656 var RAN_ConnHdlr client := null;
657 /* extract IMSI and (if present) TMSI */
658 var IMSI imsi := ranap.initiatingMessage.value_.paging.protocolIEs[1].value_.permanentNAS_UE_ID.iMSI;
659 var template OCT4 tmsi := omit;
660 if (lengthof(ranap.initiatingMessage.value_.paging.protocolIEs) > 2 and
661 ranap.initiatingMessage.value_.paging.protocolIEs[2].id == id_TemporaryUE_ID) {
662 var TemporaryUE_ID ue_id;
663 ue_id := ranap.initiatingMessage.value_.paging.protocolIEs[2].value_.temporaryUE_ID;
664 if (ischosen(ue_id.tMSI)) {
665 tmsi := ue_id.tMSI;
666 } else {
667 tmsi := ue_id.p_TMSI;
668 }
669 }
670 client := f_imsi_table_find(oct2hex(imsi), tmsi);
Harald Welte03d4e2b2019-05-10 00:42:33 +0200671 if (client != null) {
Harald Welte5b027622019-04-14 23:40:17 +0200672 log("CommonRanapUnitdataCallback: IMSI/TMSI found in table, dispatching to ",
673 client);
674 CLIENT.send(ranap) to client;
675 return omit;
676 }
677 log("CommonRanapUnitdataCallback: IMSI/TMSI not found in table");
678 } else {
679 log("CommonRanapUnitdataCallback: Not a paging message");
680 }
681
682 /* ELSE: handle in user callback */
Neels Hofmeyr79896c02023-06-23 03:45:40 +0200683 if (not ispresent(g_ran_ops.ranap_unitdata_cb)) {
684 return omit;
685 }
Harald Welte5b027622019-04-14 23:40:17 +0200686 return g_ran_ops.ranap_unitdata_cb.apply(ranap);
687}
688
689private function f_ranap_l3_is_rr(RANAP_PDU ranap) return boolean {
690 var template (omit) SAPI sapi;
691 var template octetstring l3 := f_ranap_extract_l3(ranap);
692 return f_L3_is_rr(l3);
693}
694
695function f_ranap_reset(SCCP_PAR_Address peer, SCCP_PAR_Address own) runs on RAN_Emulation_CT {
696 timer T := 5.0;
697 var CN_DomainIndicator dom;
698 if (g_ran_ops.ps_domain) {
699 dom := ps_domain;
700 } else {
701 dom := cs_domain;
702 }
703
704 RANAP.send(ts_RANAP_UNITDATA_req(peer, own, ts_RANAP_Reset(ts_RanapCause_om_intervention, dom)));
705 T.start;
706 alt {
707 [] RANAP.receive(tr_RANAP_UNITDATA_ind(own, peer, tr_RANAP_ResetAck)) {
Neels Hofmeyr4f5d7be2020-10-16 16:28:16 +0200708 log("RANAP: Received RESET-ACK in response to RESET, we're ready to go!");
Harald Welte5b027622019-04-14 23:40:17 +0200709 }
710 [] as_reset_ack();
711 [] RANAP.receive { repeat };
712 [] T.timeout {
Neels Hofmeyr4f5d7be2020-10-16 16:28:16 +0200713 setverdict(fail, "RANAP: Timeout waiting for RESET-ACK after sending RESET");
Harald Welte5b027622019-04-14 23:40:17 +0200714 mtc.stop;
715 }
716 }
717}
718#endif
Harald Welte365f4ed2017-11-23 00:00:43 +0100719
Harald Welte2fce7882019-04-15 11:48:05 +0200720
721type enumerated RanProtocol {
Harald Welte5b027622019-04-14 23:40:17 +0200722 RAN_PROTOCOL_BSSAP,
723 RAN_PROTOCOL_RANAP
Harald Welte2fce7882019-04-15 11:48:05 +0200724}
725
726type record RanOps {
727#ifdef RAN_EMULATION_BSSAP
728 BssmapCreateCallback create_cb optional,
729 BssmapUnitdataCallback unitdata_cb optional,
730#endif
Harald Welte5b027622019-04-14 23:40:17 +0200731#ifdef RAN_EMULATION_RANAP
732 RanapCreateCallback ranap_create_cb optional,
733 RanapUnitdataCallback ranap_unitdata_cb optional,
734 boolean ps_domain,
735#endif
Harald Welte2fce7882019-04-15 11:48:05 +0200736 boolean decode_dtap,
737 boolean role_ms,
738 RanProtocol protocol,
Pau Espin Pedrolc6b78ff2019-06-06 15:58:17 +0200739 RAN_Transport transport,
Pau Espin Pedrolc6a53db2019-05-20 19:31:47 +0200740 boolean use_osmux,
Eric Wild49888a62022-03-30 03:16:11 +0200741 integer bssap_reset_retries,
Harald Welte2fce7882019-04-15 11:48:05 +0200742 /* needed for performing BSSMAP RESET */
743 SCCP_PAR_Address sccp_addr_local optional,
744 SCCP_PAR_Address sccp_addr_peer optional
745}
746
747template BIT4 t_ML3_DISC_CC_MM_SS := ('0011'B, '0101'B, '1011'B);
748
Harald Weltea803b722020-08-21 15:42:26 +0200749function f_L3_is_rr(template octetstring l3) return boolean {
Harald Welte2fce7882019-04-15 11:48:05 +0200750 if (not isvalue(l3)) {
751 return false;
Harald Weltea4ca4462018-02-09 00:17:14 +0100752 }
Harald Welte2fce7882019-04-15 11:48:05 +0200753 var octetstring l3v := valueof(l3);
754 if (lengthof(l3v) < 1) {
755 return false;
756 }
757 /* lower 4 bits of first octet are protocol discriminator */
758 if ((oct2bit(l3v[0]) and4b '00001111'B) == '00000110'B) {
759 return true;
760 }
761 return false;
762}
Harald Weltea4ca4462018-02-09 00:17:14 +0100763
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200764function 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 +0200765 var uint2_t seq_nr;
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200766 if (n_sd_idx == 0) {
767 seq_nr := n_sd[0];
768 n_sd[0] := (n_sd[0] + 1) mod 4;
769 } else if (n_sd_idx >= 1 and n_sd_idx <= 3) {
770 seq_nr := n_sd[n_sd_idx];
771 n_sd[n_sd_idx] := (n_sd[n_sd_idx] + 1) mod 2;
Harald Welte2fce7882019-04-15 11:48:05 +0200772 } else {
773 /* no sequence number to patch */
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200774 seq_nr := 0;
Harald Welte2fce7882019-04-15 11:48:05 +0200775 }
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200776 return seq_nr;
777}
778
779/* patch N(SD) into enc_l3, according to 24.007 11.2.3.2 */
780function f_ML3_patch_seq_nr(in uint2_t seq_nr, inout octetstring enc_l3) {
Harald Welte2fce7882019-04-15 11:48:05 +0200781 log("patching N(SD)=", seq_nr, " into dtap ", enc_l3);
782 enc_l3[1] := (enc_l3[1] and4b '3f'O) or4b bit2oct(int2bit(seq_nr, 8) << 6);
783 log("patched enc_l3: ", enc_l3);
784}
785
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200786function f_ML3_n_sd_idx(in PDU_ML3_MS_NW dtap) return integer {
787 var uint2_t seq_nr;
788 if (ischosen(dtap.msgs.cc) or ischosen(dtap.msgs.mm) or ischosen(dtap.msgs.ss)) {
789 return 0;
790 } else if (ischosen(dtap.msgs.gcc)) {
791 return 1;
792 } else if (ischosen(dtap.msgs.bcc)) {
793 return 2;
794 } else if (ischosen(dtap.msgs.loc)) {
795 return 3;
796 }
797 /* no sequence number to patch */
798 return -1;
799}
800
801/* patch N(SD) into enc_l3, according to 24.007 11.2.3.2 */
Harald Weltea803b722020-08-21 15:42:26 +0200802private 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 +0200803 var integer n_sd_idx := f_ML3_n_sd_idx(dtap);
804 if (n_sd_idx < 0) {
805 return;
806 }
807 var uint2_t seq_nr := f_next_n_sd(cd.n_sd, n_sd_idx);
808 f_ML3_patch_seq_nr(seq_nr, enc_l3);
809}
810
Pau Espin Pedrol95549182019-06-06 16:17:30 +0200811private altstep as_reset_ack(boolean append_osmux_support := false) runs on RAN_Emulation_CT {
Harald Welte2fce7882019-04-15 11:48:05 +0200812#ifdef RAN_EMULATION_BSSAP
813 var BSSAP_N_UNITDATA_ind ud_ind;
814#endif
Harald Welte5b027622019-04-14 23:40:17 +0200815#ifdef RAN_EMULATION_RANAP
816 var RANAP_N_UNITDATA_ind rud_ind;
817#endif
Harald Welte2fce7882019-04-15 11:48:05 +0200818#ifdef RAN_EMULATION_BSSAP
Pau Espin Pedrol95549182019-06-06 16:17:30 +0200819 [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(append_osmux_support))) -> value ud_ind {
Neels Hofmeyr4f5d7be2020-10-16 16:28:16 +0200820 log("BSSMAP: Responding to inbound RESET with RESET-ACK");
Harald Welte2fce7882019-04-15 11:48:05 +0200821 BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
Pau Espin Pedrol95549182019-06-06 16:17:30 +0200822 ts_BSSMAP_ResetAck(append_osmux_support)));
Harald Welte2fce7882019-04-15 11:48:05 +0200823 repeat;
824 }
825#endif
Harald Welte5b027622019-04-14 23:40:17 +0200826#ifdef RAN_EMULATION_RANAP
827 [] RANAP.receive(tr_RANAP_UNITDATA_ind(?, ?, tr_RANAP_Reset)) -> value rud_ind {
Neels Hofmeyr4f5d7be2020-10-16 16:28:16 +0200828 log("RANAP: Responding to inbound IuRESET with IuRESET-ACK");
Harald Welte5b027622019-04-14 23:40:17 +0200829 var CN_DomainIndicator dom;
830 dom := rud_ind.userData.initiatingMessage.value_.Reset.protocolIEs[1].value_.cN_DomainIndicator;
831 RANAP.send(ts_RANAP_UNITDATA_req(rud_ind.callingAddress, rud_ind.calledAddress,
832 ts_RANAP_ResetAck(dom)));
833 }
834#endif
Harald Welte2fce7882019-04-15 11:48:05 +0200835}
836
837
838private altstep as_main_bssap() runs on RAN_Emulation_CT {
839#ifdef RAN_EMULATION_BSSAP
Harald Welte004f5fb2017-12-16 17:54:40 +0100840 var BSSAP_N_UNITDATA_ind ud_ind;
841 var BSSAP_N_CONNECT_ind conn_ind;
842 var BSSAP_N_CONNECT_cfm conn_cfm;
843 var BSSAP_N_DATA_ind data_ind;
844 var BSSAP_N_DISCONNECT_ind disc_ind;
Harald Welteb3414b22017-11-23 18:22:10 +0100845 var BSSAP_Conn_Req creq;
Harald Welte365f4ed2017-11-23 00:00:43 +0100846 var PDU_BSSAP bssap;
Neels Hofmeyra8264612020-06-08 20:40:22 +0200847 var BSSAP_N_UNITDATA_req bssap_ud;
Harald Welte2fce7882019-04-15 11:48:05 +0200848 var RAN_ConnHdlr vc_conn;
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200849 var integer targetPointCode;
850 var N_Sd_Array last_n_sd;
Harald Welte365f4ed2017-11-23 00:00:43 +0100851
Harald Welte365f4ed2017-11-23 00:00:43 +0100852 /* SCCP -> Client: UNIT-DATA (connectionless SCCP) from a BSC */
Harald Welte004f5fb2017-12-16 17:54:40 +0100853 [] BSSAP.receive(BSSAP_N_UNITDATA_ind:?) -> value ud_ind {
Harald Welte365f4ed2017-11-23 00:00:43 +0100854 /* Connectionless Procedures like RESET */
855 var template PDU_BSSAP resp;
Harald Welte17d21152018-01-27 00:47:11 +0100856 resp := CommonBssmapUnitdataCallback(ud_ind.userData);
Harald Welte365f4ed2017-11-23 00:00:43 +0100857 if (isvalue(resp)) {
Harald Welte004f5fb2017-12-16 17:54:40 +0100858 BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress,
859 ud_ind.calledAddress, resp));
Harald Welte365f4ed2017-11-23 00:00:43 +0100860 }
861 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100862 /* SCCP -> Client: new connection from BSC */
Harald Welte004f5fb2017-12-16 17:54:40 +0100863 [] BSSAP.receive(BSSAP_N_CONNECT_ind:?) -> value conn_ind {
Harald Welte2fce7882019-04-15 11:48:05 +0200864 vc_conn := g_ran_ops.create_cb.apply(conn_ind, g_ran_id);
Harald Welte365f4ed2017-11-23 00:00:43 +0100865 /* store mapping between client components and SCCP connectionId */
866 f_conn_table_add(vc_conn, conn_ind.connectionId);
867 /* handle user payload */
868 f_handle_userData(vc_conn, conn_ind.userData);
869 /* confirm connection establishment */
Harald Welte004f5fb2017-12-16 17:54:40 +0100870 BSSAP.send(ts_BSSAP_CONNECT_res(conn_ind.connectionId, omit));
Harald Welte365f4ed2017-11-23 00:00:43 +0100871 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100872 /* SCCP -> Client: connection-oriented data in existing connection */
Harald Welte004f5fb2017-12-16 17:54:40 +0100873 [] BSSAP.receive(BSSAP_N_DATA_ind:?) -> value data_ind {
Harald Welte365f4ed2017-11-23 00:00:43 +0100874 vc_conn := f_comp_by_conn_id(data_ind.connectionId);
Harald Welte5cc4aa22017-11-23 18:51:28 +0100875 if (ispresent(data_ind.userData)) {
876 f_handle_userData(vc_conn, data_ind.userData);
877 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100878 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100879 /* SCCP -> Client: disconnect of an existing connection */
Harald Welte004f5fb2017-12-16 17:54:40 +0100880 [] BSSAP.receive(BSSAP_N_DISCONNECT_ind:?) -> value disc_ind {
Harald Welte365f4ed2017-11-23 00:00:43 +0100881 vc_conn := f_comp_by_conn_id(disc_ind.connectionId);
Harald Welte5cc4aa22017-11-23 18:51:28 +0100882 if (ispresent(disc_ind.userData)) {
883 f_handle_userData(vc_conn, disc_ind.userData);
884 }
Harald Welte365f4ed2017-11-23 00:00:43 +0100885 /* notify client about termination */
Harald Welte6811d102019-04-14 22:23:14 +0200886 var RAN_Conn_Prim prim := MSC_CONN_PRIM_DISC_IND;
Harald Welte365f4ed2017-11-23 00:00:43 +0100887 CLIENT.send(prim) to vc_conn;
888 f_conn_table_del(disc_ind.connectionId);
889 /* TOOD: return confirm to other side? */
890 }
Harald Welteb3414b22017-11-23 18:22:10 +0100891 /* SCCP -> Client: connection confirm for outbound connection */
Harald Welte004f5fb2017-12-16 17:54:40 +0100892 [] BSSAP.receive(BSSAP_N_CONNECT_cfm:?) -> value conn_cfm {
Harald Welte71b69332018-01-21 20:43:53 +0100893 vc_conn := f_comp_by_conn_id(conn_cfm.connectionId);
Harald Welte6811d102019-04-14 22:23:14 +0200894 var RAN_Conn_Prim prim := MSC_CONN_PRIM_CONF_IND;
Harald Welte71b69332018-01-21 20:43:53 +0100895 CLIENT.send(prim) to vc_conn;
Harald Welteb3414b22017-11-23 18:22:10 +0100896 /* handle user payload */
Harald Welte5cc4aa22017-11-23 18:51:28 +0100897 if (ispresent(conn_cfm.userData)) {
898 f_handle_userData(vc_conn, conn_cfm.userData);
899 }
Harald Welteb3414b22017-11-23 18:22:10 +0100900 }
Harald Welte2fce7882019-04-15 11:48:05 +0200901 [] CLIENT.receive(PDU_BSSAP:?) -> value bssap sender vc_conn {
902 var integer conn_id := f_conn_id_by_comp(vc_conn);
903 /* send it to dispatcher */
904 BSSAP.send(ts_BSSAP_DATA_req(conn_id, bssap));
905 }
Harald Welteb3414b22017-11-23 18:22:10 +0100906
Neels Hofmeyra8264612020-06-08 20:40:22 +0200907 [] CLIENT.receive(BSSAP_N_UNITDATA_req:?) -> value bssap_ud sender vc_conn {
908 BSSAP.send(bssap_ud);
909 }
910
Harald Welte365f4ed2017-11-23 00:00:43 +0100911 /* Disconnect request client -> SCCP */
Harald Welte6811d102019-04-14 22:23:14 +0200912 [] CLIENT.receive(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ) -> sender vc_conn {
Harald Welte365f4ed2017-11-23 00:00:43 +0100913 var integer conn_id := f_conn_id_by_comp(vc_conn);
Harald Welte004f5fb2017-12-16 17:54:40 +0100914 BSSAP.send(ts_BSSAP_DISC_req(conn_id, 0));
Harald Welte365f4ed2017-11-23 00:00:43 +0100915 f_conn_table_del(conn_id);
916 }
917
918 /* BSSAP from client -> SCCP */
Harald Welteb3414b22017-11-23 18:22:10 +0100919 [] CLIENT.receive(BSSAP_Conn_Req:?) -> value creq sender vc_conn {
920 var integer conn_id;
Harald Welte004f5fb2017-12-16 17:54:40 +0100921 /* send to dispatcher */
Harald Welteb3414b22017-11-23 18:22:10 +0100922
923 if (f_comp_known(vc_conn) == false) {
924 /* unknown client, create new connection */
925 conn_id := f_gen_conn_id();
926
927 /* store mapping between client components and SCCP connectionId */
928 f_conn_table_add(vc_conn, conn_id);
929
Harald Welte004f5fb2017-12-16 17:54:40 +0100930 BSSAP.send(ts_BSSAP_CONNECT_req(creq.addr_peer, creq.addr_own, conn_id,
931 creq.bssap));
Harald Welteb3414b22017-11-23 18:22:10 +0100932 } else {
933 /* known client, send via existing connection */
934 conn_id := f_conn_id_by_comp(vc_conn);
Harald Welte004f5fb2017-12-16 17:54:40 +0100935 BSSAP.send(ts_BSSAP_DATA_req(conn_id, creq.bssap));
Harald Welteb3414b22017-11-23 18:22:10 +0100936 }
937
Harald Welte49518bf2018-02-10 11:39:19 +0100938 /* InitialL3 contains RR (PAG RESP) or MM (CM SRV REQ), we must increment
939 * counter only on MM/CC/SS, but not on RR */
Harald Welte6811d102019-04-14 22:23:14 +0200940 if (g_ran_ops.role_ms and not f_bssap_l3_is_rr(creq.bssap)) {
Harald Welte9dadc522018-02-06 13:56:04 +0100941 /* we have just sent the first MM message, increment the counter */
942 var integer idx := f_idx_by_comp(vc_conn);
943 ConnectionTable[idx].n_sd[0] := 1;
944 log("patch: N(SD) for ConnIdx ", idx, " set to 1");
945 }
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200946 }
Harald Welte9dadc522018-02-06 13:56:04 +0100947
Neels Hofmeyr0ac63152019-05-07 01:20:17 +0200948 [] PROC.getcall(RAN_last_n_sd:{?,-}) -> param(vc_conn) {
949 var integer idx := f_idx_by_comp(vc_conn);
950 last_n_sd := ConnectionTable[idx].n_sd;
951 PROC.reply(RAN_last_n_sd:{vc_conn, last_n_sd}) to vc_conn;
952 }
953
954 [] PROC.getcall(RAN_continue_after_n_sd:{?,?}) -> param(last_n_sd, vc_conn) {
955 var integer idx := f_idx_by_comp(vc_conn);
956 ConnectionTable[idx].n_sd := last_n_sd;
957 PROC.reply(RAN_continue_after_n_sd:{last_n_sd, vc_conn}) to vc_conn;
Harald Welteb3414b22017-11-23 18:22:10 +0100958 }
Harald Welte2fce7882019-04-15 11:48:05 +0200959#else
Harald Welte5b027622019-04-14 23:40:17 +0200960 [false] CLIENT.receive {}
961#endif
962}
963
964private altstep as_main_ranap() runs on RAN_Emulation_CT {
965#ifdef RAN_EMULATION_RANAP
966 var RANAP_N_UNITDATA_ind rud_ind;
967 var RANAP_N_CONNECT_ind rconn_ind;
968 var RANAP_N_CONNECT_cfm rconn_cfm;
969 var RANAP_N_DATA_ind rdata_ind;
970 var RANAP_N_DISCONNECT_ind rdisc_ind;
971 var RANAP_Conn_Req creq;
972 var RANAP_PDU ranap;
Neels Hofmeyrb1bf16d2023-06-27 02:10:04 +0200973 var RANAP_N_UNITDATA_req ranap_ud;
Harald Welte5b027622019-04-14 23:40:17 +0200974 var RAN_ConnHdlr vc_conn;
Harald Welte717c7302019-04-23 20:31:55 +0200975 var PDU_DTAP_PS_MO ps_mo;
976 var PDU_DTAP_PS_MT ps_mt;
Harald Welte5b027622019-04-14 23:40:17 +0200977
978 /* SCCP -> Client: UNIT-DATA (connectionless SCCP) from a BSC */
979 [] RANAP.receive(RANAP_N_UNITDATA_ind:?) -> value rud_ind {
980 /* Connectionless Procedures like RESET */
981 var template RANAP_PDU resp;
982 resp := CommonRanapUnitdataCallback(rud_ind.userData);
983 if (isvalue(resp)) {
984 RANAP.send(ts_RANAP_UNITDATA_req(rud_ind.callingAddress,
985 rud_ind.calledAddress, resp));
986 }
987 }
988 /* SCCP -> Client: new connection from BSC */
989 [] RANAP.receive(RANAP_N_CONNECT_ind:?) -> value rconn_ind {
990 vc_conn := g_ran_ops.ranap_create_cb.apply(rconn_ind, g_ran_id);
991 /* store mapping between client components and SCCP connectionId */
992 f_conn_table_add(vc_conn, rconn_ind.connectionId);
993 /* handle user payload */
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +0200994 if (ispresent(rconn_ind.userData)) {
995 f_handle_userData_RANAP(vc_conn, rconn_ind.userData);
996 } else {
997 /* Notify client that we received an SCCP CR without user data */
998 CLIENT.send(ts_RANAP_Conn_Req(rconn_ind.callingAddress, rconn_ind.calledAddress, omit));
999 }
Harald Welte5b027622019-04-14 23:40:17 +02001000 /* confirm connection establishment */
1001 RANAP.send(ts_RANAP_CONNECT_res(rconn_ind.connectionId, omit));
1002 }
1003 /* SCCP -> Client: connection-oriented data in existing connection */
1004 [] RANAP.receive(RANAP_N_DATA_ind:?) -> value rdata_ind {
1005 vc_conn := f_comp_by_conn_id(rdata_ind.connectionId);
1006 if (ispresent(rdata_ind.userData)) {
1007 f_handle_userData_RANAP(vc_conn, rdata_ind.userData);
1008 }
1009 }
1010 /* SCCP -> Client: disconnect of an existing connection */
1011 [] RANAP.receive(RANAP_N_DISCONNECT_ind:?) -> value rdisc_ind {
1012 vc_conn := f_comp_by_conn_id(rdisc_ind.connectionId);
1013 if (ispresent(rdisc_ind.userData)) {
1014 f_handle_userData_RANAP(vc_conn, rdisc_ind.userData);
1015 }
1016 /* notify client about termination */
1017 var RAN_Conn_Prim prim := MSC_CONN_PRIM_DISC_IND;
1018 CLIENT.send(prim) to vc_conn;
1019 f_conn_table_del(rdisc_ind.connectionId);
1020 /* TOOD: return confirm to other side? */
1021 }
1022 /* SCCP -> Client: connection confirm for outbound connection */
1023 [] RANAP.receive(RANAP_N_CONNECT_cfm:?) -> value rconn_cfm {
1024 vc_conn := f_comp_by_conn_id(rconn_cfm.connectionId);
1025 var RAN_Conn_Prim prim := MSC_CONN_PRIM_CONF_IND;
1026 CLIENT.send(prim) to vc_conn;
1027 /* handle user payload */
1028 if (ispresent(rconn_cfm.userData)) {
1029 f_handle_userData_RANAP(vc_conn, rconn_cfm.userData);
1030 }
1031 }
1032
1033 [] CLIENT.receive(RANAP_PDU:?) -> value ranap sender vc_conn {
1034 var integer conn_id := f_conn_id_by_comp(vc_conn);
1035 /* send it to dispatcher */
1036 RANAP.send(ts_RANAP_DATA_req(conn_id, ranap));
1037 }
1038
Neels Hofmeyrb1bf16d2023-06-27 02:10:04 +02001039 /* e.g. for Paging from virtual MSC/SGSN to SUT osmo-hnbgw */
1040 [] CLIENT.receive(RANAP_N_UNITDATA_req:?) -> value ranap_ud sender vc_conn {
1041 RANAP.send(ranap_ud);
1042 }
1043
Harald Welte5b027622019-04-14 23:40:17 +02001044 /* Disconnect request client -> SCCP */
1045 [] CLIENT.receive(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ) -> sender vc_conn {
1046 var integer conn_id := f_conn_id_by_comp(vc_conn);
1047 RANAP.send(ts_RANAP_DISC_req(conn_id, 0));
1048 f_conn_table_del(conn_id);
1049 }
1050
1051 /* BSSAP from client -> SCCP */
1052 [] CLIENT.receive(RANAP_Conn_Req:?) -> value creq sender vc_conn {
1053 var integer conn_id;
1054 /* send to dispatcher */
1055
1056 if (f_comp_known(vc_conn) == false) {
1057 /* unknown client, create new connection */
1058 conn_id := f_gen_conn_id();
1059
1060 /* store mapping between client components and SCCP connectionId */
1061 f_conn_table_add(vc_conn, conn_id);
1062
1063 RANAP.send(ts_RANAP_CONNECT_req(creq.addr_peer, creq.addr_own, conn_id,
1064 creq.ranap));
1065 } else {
1066 /* known client, send via existing connection */
1067 conn_id := f_conn_id_by_comp(vc_conn);
1068 RANAP.send(ts_RANAP_DATA_req(conn_id, creq.ranap));
1069 }
1070
1071 /* InitialL3 contains RR (PAG RESP) or MM (CM SRV REQ), we must increment
1072 * counter only on MM/CC/SS, but not on RR */
1073 if (g_ran_ops.role_ms and not f_ranap_l3_is_rr(creq.ranap)) {
1074 /* we have just sent the first MM message, increment the counter */
1075 var integer idx := f_idx_by_comp(vc_conn);
1076 ConnectionTable[idx].n_sd[0] := 1;
1077 log("patch: N(SD) for ConnIdx ", idx, " set to 1");
1078 }
1079 }
1080
Harald Welte717c7302019-04-23 20:31:55 +02001081 [g_ran_ops.role_ms] CLIENT.receive(PDU_DTAP_PS_MO:?) -> value ps_mo sender vc_conn {
1082 var integer idx := f_idx_by_comp(vc_conn);
1083 /* convert from decoded DTAP to encoded DTAP */
1084 var octetstring l3_enc := enc_PDU_L3_MS_SGSN(ps_mo.dtap);
1085 /* patch correct L3 send sequence number N(SD) into l3_enc */
1086 if (ps_mo.skip_seq_patching == false) {
1087 //f_ML3_patch_seq(ConnectionTable[idx], ps_mo.dtap, l3_enc);
1088 }
1089 f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, ps_mo.dlci, l3_enc);
1090 }
1091
1092 [not g_ran_ops.role_ms] CLIENT.receive(PDU_DTAP_PS_MT:?) -> value ps_mt sender vc_conn {
1093 var integer idx := f_idx_by_comp(vc_conn);
1094 /* convert from decoded DTAP to encoded DTAP */
1095 var octetstring l3_enc := enc_PDU_L3_SGSN_MS(ps_mt.dtap);
1096 f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, ps_mt.dlci, l3_enc);
1097 }
1098
1099
Harald Welte5b027622019-04-14 23:40:17 +02001100#else
1101 [false] CLIENT.receive {}
Harald Welte2fce7882019-04-15 11:48:05 +02001102#endif
1103}
Harald Welteb3414b22017-11-23 18:22:10 +01001104
Harald Welte2fce7882019-04-15 11:48:05 +02001105private altstep as_main_mgcp() runs on RAN_Emulation_CT {
1106#ifdef RAN_EMULATION_MGCP
1107 var MgcpCommand mgcp_req;
1108 var MgcpResponse mgcp_resp;
1109 var RAN_ConnHdlr vc_conn;
Harald Welte0b476062018-01-21 19:07:32 +01001110
Harald Weltec82eef42017-11-24 20:40:12 +01001111 /* Handling of MGCP in IPA SCCPLite case. This predates 3GPP AoIP
1112 * and uses a MGCP session in parallel to BSSAP. BSSAP uses CIC
1113 * as usual, and MGCP uses "CIC@mgw" endpoint naming, where CIC
1114 * is printed as hex string, e.g. a@mgw for CIC 10 */
1115
1116 /* CLIENT -> MGCP */
1117 [] CLIENT.receive(MgcpCommand:?) -> value mgcp_req sender vc_conn {
1118 /* MGCP request from Handler (we're MSC) */
1119 /* store the transaction ID we've seen */
1120 f_comp_store_mgcp_tid(vc_conn, mgcp_req.line.trans_id);
1121 /* simply forward any MGCP from the client to the port */
1122 MGCP.send(mgcp_req);
1123 }
1124 [] CLIENT.receive(MgcpResponse:?) -> value mgcp_resp sender vc_conn {
1125 /* MGCP response from Handler (we're BSC/MGW) */
1126 /* simply forward any MGCP from the client to the port */
1127 MGCP.send(mgcp_resp);
1128 }
1129
1130 /* MGCP -> CLIENT */
1131 [] MGCP.receive(MgcpCommand:?) -> value mgcp_req {
1132 /* MGCP request from network side (we're BSC/MGW) */
1133 /* Extract CIC from local part of endpoint name */
1134 var integer cic := f_mgcp_ep_extract_cic(mgcp_req.line.ep);
Harald Weltee98bb2e2017-11-29 12:09:48 +01001135 if (match(mgcp_req, tr_RSIP) and f_cic_known(cic) == false) {
1136 /* ignore RSIP for unknown CIC */
1137 } else {
1138 /* Resolve the vc_conn by the CIC */
1139 vc_conn := f_comp_by_cic(cic);
1140 CLIENT.send(mgcp_req) to vc_conn;
1141 }
Harald Weltec82eef42017-11-24 20:40:12 +01001142 }
1143 [] MGCP.receive(MgcpResponse:?) -> value mgcp_resp {
1144 /* MGCP response from network side (we're MSC) */
1145 /* Resolve the vc_conn by the transaction ID */
1146 vc_conn := f_comp_by_mgcp_tid(mgcp_resp.line.trans_id);
1147 CLIENT.send(mgcp_resp) to vc_conn;
1148 }
Harald Welte2fce7882019-04-15 11:48:05 +02001149#else
1150 [false] CLIENT.receive {}
1151#endif
1152}
Harald Weltec82eef42017-11-24 20:40:12 +01001153
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +02001154private altstep as_main_ctrl() runs on RAN_Emulation_CT {
1155#ifdef RAN_EMULATION_CTRL
1156 var CtrlMessage ctrl;
1157 var RAN_ConnHdlr vc_conn;
1158 var ASP_IPA_Event evt;
1159
1160 /* Handling of CTRL in IPA SCCPLite case. This predates 3GPP AoIP
1161 * and uses a CTRL session in parallel to BSSAP. */
1162
1163 /* CTRL_CLIENT -> CTRL */
1164 [] CTRL_CLIENT.receive(CtrlMessage:?) -> value ctrl sender vc_conn {
1165 CTRL.send(ctrl);
1166 }
1167
1168 /* CTRL -> CTRL_CLIENT */
1169 [] CTRL.receive(CtrlMessage:?) -> value ctrl {
1170 CTRL_CLIENT.send(ctrl);
1171 }
1172
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +07001173 [] CTRL.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) -> value evt {
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +02001174 CTRL_CLIENT.send(evt);
1175 }
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +07001176 [] CTRL.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN)) {
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +02001177 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Lost IPA connection!");
1178 }
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +07001179 [] CTRL.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK)) {}
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +02001180#else
1181 [false] CLIENT.receive {}
1182#endif
1183}
1184
Harald Welte2fce7882019-04-15 11:48:05 +02001185/* send a raw (encoded) L3 message over given SCCP connection */
1186private function f_xmit_raw_l3(integer sccp_conn_id, OCT1 dlci, octetstring l3_enc) runs on RAN_Emulation_CT
1187{
1188 select (g_ran_ops.protocol) {
1189#ifdef RAN_EMULATION_BSSAP
1190 case (RAN_PROTOCOL_BSSAP) {
1191 var PDU_BSSAP bssap;
1192 bssap := valueof(ts_BSSAP_DTAP(l3_enc, dlci));
1193 BSSAP.send(ts_BSSAP_DATA_req(sccp_conn_id, bssap));
1194 }
1195#endif
Harald Welte5b027622019-04-14 23:40:17 +02001196#ifdef RAN_EMULATION_RANAP
1197 case (RAN_PROTOCOL_RANAP) {
Vadim Yanitskiyf2c3fa92019-06-20 05:18:15 +07001198 var template (omit) RANAP_IEs.SAPI sapi := omit;
Harald Welte5b027622019-04-14 23:40:17 +02001199 var RANAP_PDU ranap;
Vadim Yanitskiyf2c3fa92019-06-20 05:18:15 +07001200
1201 /* Perform DLCI -> SAPI transformation (x & 0x07) */
1202 if (dlci and4b '07'O == '03'O) {
1203 sapi := sapi_3;
1204 }
1205
1206 ranap := valueof(ts_RANAP_DirectTransfer(l3_enc, sapi := sapi));
Harald Welte5b027622019-04-14 23:40:17 +02001207 RANAP.send(ts_RANAP_DATA_req(sccp_conn_id, ranap));
1208 }
1209#endif
Harald Welte2fce7882019-04-15 11:48:05 +02001210 }
1211}
1212
1213function main(RanOps ops, charstring id) runs on RAN_Emulation_CT {
1214
1215 g_ran_id := id;
1216 g_ran_ops := ops;
1217 f_conn_table_init();
1218 f_expect_table_init();
1219
1220 if (isvalue(ops.sccp_addr_peer) and isvalue(ops.sccp_addr_local)) {
1221 f_sleep(1.0); /* HACK to wait for M3UA/ASP to be ACTIVE */
Harald Welte5b027622019-04-14 23:40:17 +02001222 select (g_ran_ops.protocol) {
1223#ifdef RAN_EMULATION_BSSAP
1224 case (RAN_PROTOCOL_BSSAP) {
1225 f_bssap_reset(ops.sccp_addr_peer, ops.sccp_addr_local);
1226 }
1227#endif
1228#ifdef RAN_EMULATION_RANAP
1229 case (RAN_PROTOCOL_RANAP) {
1230 f_ranap_reset(ops.sccp_addr_peer, ops.sccp_addr_local);
1231 }
1232#endif
1233 }
Harald Welte2fce7882019-04-15 11:48:05 +02001234 }
1235
1236 while (true) {
1237 var RAN_ConnHdlr vc_conn;
1238 var PDU_DTAP_MO dtap_mo;
1239 var PDU_DTAP_MT dtap_mt;
1240 var RAN_ConnHdlr vc_hdlr;
1241 var octetstring l3_info;
1242 var hexstring imsi;
1243 var OCT4 tmsi;
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001244 var integer targetPointCode;
Harald Welte2fce7882019-04-15 11:48:05 +02001245
1246 alt {
1247 [g_ran_ops.protocol == RAN_PROTOCOL_BSSAP] as_main_bssap();
Harald Welte5b027622019-04-14 23:40:17 +02001248 [g_ran_ops.protocol == RAN_PROTOCOL_RANAP] as_main_ranap();
Harald Welte2fce7882019-04-15 11:48:05 +02001249
1250 [g_ran_ops.role_ms] CLIENT.receive(PDU_DTAP_MO:?) -> value dtap_mo sender vc_conn {
1251 var integer idx := f_idx_by_comp(vc_conn);
1252 /* convert from decoded DTAP to encoded DTAP */
1253 var octetstring l3_enc := enc_PDU_ML3_MS_NW(dtap_mo.dtap);
1254 /* patch correct L3 send sequence number N(SD) into l3_enc */
1255 if (dtap_mo.skip_seq_patching == false) {
1256 f_ML3_patch_seq(ConnectionTable[idx], dtap_mo.dtap, l3_enc);
1257 }
1258 f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, dtap_mo.dlci, l3_enc);
1259 }
1260
1261 [not g_ran_ops.role_ms] CLIENT.receive(PDU_DTAP_MT:?) -> value dtap_mt sender vc_conn {
1262 var integer idx := f_idx_by_comp(vc_conn);
1263 /* convert from decoded DTAP to encoded DTAP */
1264 var octetstring l3_enc := enc_PDU_ML3_NW_MS(dtap_mt.dtap);
1265 f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, dtap_mt.dlci, l3_enc);
1266 }
1267
1268 [] as_main_mgcp();
Pau Espin Pedrol4d0e5e52019-06-07 19:38:28 +02001269 [] as_main_ctrl();
Harald Welte624f9632017-12-16 19:26:04 +01001270
Harald Welte6811d102019-04-14 22:23:14 +02001271 [] PROC.getcall(RAN_register:{?,?}) -> param(l3_info, vc_hdlr) {
Harald Welte624f9632017-12-16 19:26:04 +01001272 f_create_expect(l3_info, vc_hdlr);
Harald Welte6811d102019-04-14 22:23:14 +02001273 PROC.reply(RAN_register:{l3_info, vc_hdlr}) to vc_hdlr;
Harald Welte624f9632017-12-16 19:26:04 +01001274 }
1275
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001276 [] PROC.getcall(RAN_register_n_connect:{?,?}) -> param(targetPointCode, vc_hdlr) {
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001277 f_create_expect(omit, vc_hdlr, targetPointCode);
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001278 PROC.reply(RAN_register_n_connect:{targetPointCode, vc_hdlr}) to vc_hdlr;
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001279 }
1280
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001281 [] PROC.getcall(RAN_register_sccp_cr_without_payload:{?}) -> param(vc_hdlr) {
1282 f_create_expect(omit, vc_hdlr);
1283 PROC.reply(RAN_register_sccp_cr_without_payload:{vc_hdlr}) to vc_hdlr;
1284 }
1285
Harald Welte6811d102019-04-14 22:23:14 +02001286 [] PROC.getcall(RAN_register_imsi:{?,?,?}) -> param(imsi, tmsi, vc_hdlr) {
Harald Welte17d21152018-01-27 00:47:11 +01001287 f_create_imsi(imsi, tmsi, vc_hdlr);
Harald Welte6811d102019-04-14 22:23:14 +02001288 PROC.reply(RAN_register_imsi:{imsi, tmsi, vc_hdlr}) to vc_hdlr;
Harald Welte17d21152018-01-27 00:47:11 +01001289 }
Harald Welteee4d70c2022-05-16 21:29:19 +02001290 [] PROC.getcall(RAN_unregister_imsi:{?,?}) -> param(imsi, vc_hdlr) {
1291 f_destroy_imsi(imsi, vc_hdlr);
1292 PROC.reply(RAN_unregister_imsi:{imsi, vc_hdlr}) to vc_hdlr;
1293 }
Harald Welte17d21152018-01-27 00:47:11 +01001294
Harald Welte365f4ed2017-11-23 00:00:43 +01001295 }
1296 }
1297}
1298
Harald Welte2fce7882019-04-15 11:48:05 +02001299#ifdef RAN_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +01001300private function f_mgcp_ep_extract_cic(charstring inp) return integer {
Harald Welte525a9c12017-11-24 23:40:41 +01001301 var charstring local_part := regexp(inp, "(*)@*", 0);
Harald Weltec82eef42017-11-24 20:40:12 +01001302 return hex2int(str2hex(local_part));
1303
1304}
Harald Welte2fce7882019-04-15 11:48:05 +02001305#endif
Harald Welte365f4ed2017-11-23 00:00:43 +01001306
Harald Welte624f9632017-12-16 19:26:04 +01001307/***********************************************************************
1308 * "Expect" Handling (mapping for expected incoming SCCP connections)
1309 ***********************************************************************/
1310
1311/* data about an expected future incoming connection */
1312type record ExpectData {
1313 /* L3 payload based on which we can match it */
1314 octetstring l3_payload optional,
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001315 integer n_connectPointCode optional,
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001316 boolean sccp_cr_without_payload,
Harald Welte624f9632017-12-16 19:26:04 +01001317 /* component reference for this connection */
Harald Welte6811d102019-04-14 22:23:14 +02001318 RAN_ConnHdlr vc_conn
Harald Welte624f9632017-12-16 19:26:04 +01001319}
1320
1321/* procedure based port to register for incoming connections */
Harald Welte6811d102019-04-14 22:23:14 +02001322signature RAN_register(in octetstring l3, in RAN_ConnHdlr hdlr);
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001323signature RAN_register_n_connect(in integer targetPointCode, in RAN_ConnHdlr hdlr);
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001324signature RAN_register_sccp_cr_without_payload(in RAN_ConnHdlr hdlr);
Harald Welte624f9632017-12-16 19:26:04 +01001325
Harald Welte17d21152018-01-27 00:47:11 +01001326/* procedure based port to register for incoming IMSI/TMSI */
Harald Welte6811d102019-04-14 22:23:14 +02001327signature RAN_register_imsi(in hexstring imsi, in OCT4 tmsi, in RAN_ConnHdlr hdlr);
Harald Welteee4d70c2022-05-16 21:29:19 +02001328signature RAN_unregister_imsi(in hexstring imsi, in RAN_ConnHdlr hdlr);
Harald Welte17d21152018-01-27 00:47:11 +01001329
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001330/* If DTAP happens across other channels (e.g. GSUP), provide manual advancing of the n_sd sequence number */
1331signature RAN_last_n_sd(in RAN_ConnHdlr hdlr, out N_Sd_Array last_n_sd);
1332
1333/* Update conn's n_sd sequence nr after the connection was taken over from elsewhere */
1334signature RAN_continue_after_n_sd(N_Sd_Array last_n_sd, in RAN_ConnHdlr hdlr);
1335
Harald Welte6811d102019-04-14 22:23:14 +02001336type port RAN_PROC_PT procedure {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001337 inout RAN_register, RAN_register_imsi, RAN_unregister_imsi, RAN_register_n_connect,
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001338 RAN_register_sccp_cr_without_payload, RAN_last_n_sd, RAN_continue_after_n_sd;
Harald Welte624f9632017-12-16 19:26:04 +01001339} with { extension "internal" };
1340
Harald Welte5b027622019-04-14 23:40:17 +02001341#ifdef RAN_EMULATION_BSSAP
Harald Welte624f9632017-12-16 19:26:04 +01001342/* CreateCallback that can be used as create_cb and will use the expectation table */
1343function ExpectedCreateCallback(BSSAP_N_CONNECT_ind conn_ind, charstring id)
Harald Welte6811d102019-04-14 22:23:14 +02001344runs on RAN_Emulation_CT return RAN_ConnHdlr {
1345 var RAN_ConnHdlr ret := null;
Harald Welte624f9632017-12-16 19:26:04 +01001346 var octetstring l3_info;
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001347 var boolean n_connect := false;
1348 var integer n_connectPointCode;
Harald Welte624f9632017-12-16 19:26:04 +01001349 var integer i;
1350
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001351 if (ischosen(conn_ind.userData.pdu.bssmap.completeLayer3Information)) {
1352 l3_info := conn_ind.userData.pdu.bssmap.completeLayer3Information.layer3Information.layer3info;
1353 log("ExpectedCreateCallback completeLayer3Information");
1354 } else if (ischosen(conn_ind.userData.pdu.bssmap.handoverRequest)) {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001355 n_connect := true;
1356 n_connectPointCode := bit2int(conn_ind.calledAddress.signPointCode);
1357 log("ExpectedCreateCallback handoverRequest ", n_connectPointCode);
Andreas Eversbergd9a348c2023-07-27 16:08:23 +02001358 } else if (ischosen(conn_ind.userData.pdu.bssmap.vGCS_VBSSetup)) {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001359 n_connect := true;
1360 n_connectPointCode := bit2int(conn_ind.calledAddress.signPointCode);
1361 log("ExpectedCreateCallback VGCS/VBS Setup ", n_connectPointCode);
Andreas Eversbergd9a348c2023-07-27 16:08:23 +02001362 } else if (ischosen(conn_ind.userData.pdu.bssmap.vGCS_VBSAssignmentRequest)) {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001363 n_connect := true;
1364 n_connectPointCode := bit2int(conn_ind.calledAddress.signPointCode);
1365 log("ExpectedCreateCallback VGCS/VBS Assignment ", n_connectPointCode);
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001366 } else {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001367 setverdict(fail, "N-CONNECT.ind with L3 != COMPLETE L3 nor a new BSS connection");
Daniel Willmanne4ff5372018-07-05 17:35:03 +02001368 mtc.stop;
Harald Welte624f9632017-12-16 19:26:04 +01001369 }
Harald Welte624f9632017-12-16 19:26:04 +01001370
1371 for (i := 0; i < sizeof(ExpectTable); i:= i+1) {
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001372 if (n_connect) {
1373 log("ExpectTable[", i, "].n_connectPointCode = ", ExpectTable[i].n_connectPointCode,
1374 " ==? ", n_connectPointCode);
1375 if (ExpectTable[i].n_connectPointCode == n_connectPointCode) {
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001376 ret := ExpectTable[i].vc_conn;
Andreas Eversbergd9a348c2023-07-27 16:08:23 +02001377 /* release this entry to be used again */
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001378 ExpectTable[i].n_connectPointCode := omit;
Andreas Eversbergd9a348c2023-07-27 16:08:23 +02001379 ExpectTable[i].vc_conn := null;
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001380 log("Found Expect[", i, "] for N-CONNECT handled at ", ret);
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001381 return ret;
1382 } else {
1383 continue;
1384 }
1385 }
Harald Welte624f9632017-12-16 19:26:04 +01001386 if (not ispresent(ExpectTable[i].l3_payload)) {
1387 continue;
1388 }
1389 if (l3_info == ExpectTable[i].l3_payload) {
1390 ret := ExpectTable[i].vc_conn;
1391 /* release this entry to be used again */
1392 ExpectTable[i].l3_payload := omit;
1393 ExpectTable[i].vc_conn := null;
1394 log("Found Expect[", i, "] for ", l3_info, " handled at ", ret);
1395 /* return the component reference */
1396 return ret;
1397 }
1398 }
1399 setverdict(fail, "Couldn't find Expect for incoming connection ", conn_ind);
Daniel Willmanne4ff5372018-07-05 17:35:03 +02001400 mtc.stop;
Harald Welte624f9632017-12-16 19:26:04 +01001401}
Harald Welte5b027622019-04-14 23:40:17 +02001402#endif
1403
1404#ifdef RAN_EMULATION_RANAP
1405/* CreateCallback that can be used as create_cb and will use the expectation table */
1406function RanapExpectedCreateCallback(RANAP_N_CONNECT_ind conn_ind, charstring id)
1407runs on RAN_Emulation_CT return RAN_ConnHdlr {
1408 var RAN_ConnHdlr ret := null;
1409 var template (omit) octetstring l3_info;
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001410 var boolean rx_sccp_cr_without_payload;
Harald Welte5b027622019-04-14 23:40:17 +02001411 var integer i;
1412
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001413 if (ispresent(conn_ind.userData)) {
1414 l3_info := f_ranap_extract_l3(conn_ind.userData);
1415 rx_sccp_cr_without_payload := false;
1416 if (istemplatekind(l3_info, "omit") and not rx_sccp_cr_without_payload) {
1417 setverdict(fail, "N-CONNECT.ind without NAS payload");
1418 mtc.stop;
1419 return ret;
1420 }
1421 } else {
1422 l3_info := omit;
1423 rx_sccp_cr_without_payload := true;
Harald Welte5b027622019-04-14 23:40:17 +02001424 }
1425
1426 for (i := 0; i < sizeof(ExpectTable); i:= i+1) {
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001427 if ((rx_sccp_cr_without_payload and ExpectTable[i].sccp_cr_without_payload)
1428 or (ispresent(ExpectTable[i].l3_payload) and valueof(l3_info) == ExpectTable[i].l3_payload)) {
Harald Welte5b027622019-04-14 23:40:17 +02001429 ret := ExpectTable[i].vc_conn;
1430 /* release this entry to be used again */
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001431 ExpectTable[i].sccp_cr_without_payload := false;
Harald Welte5b027622019-04-14 23:40:17 +02001432 ExpectTable[i].l3_payload := omit;
1433 ExpectTable[i].vc_conn := null;
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001434 log("Found Expect[", i, "] for l3=", l3_info, " handled at ", ret);
Harald Welte5b027622019-04-14 23:40:17 +02001435 /* return the component reference */
1436 return ret;
1437 }
1438 }
1439 setverdict(fail, "Couldn't find Expect for incoming connection ", conn_ind);
1440 mtc.stop;
1441 return ret;
1442}
1443#endif
Harald Welte624f9632017-12-16 19:26:04 +01001444
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001445private function f_create_expect(template octetstring l3, RAN_ConnHdlr hdlr,
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001446 template integer n_connectPointCode := omit)
Harald Welte6811d102019-04-14 22:23:14 +02001447runs on RAN_Emulation_CT {
Harald Welte624f9632017-12-16 19:26:04 +01001448 var integer i;
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001449 log("f_create_expect(l3 := ", l3, ", n_connectPointCode := ", n_connectPointCode);
Harald Welte624f9632017-12-16 19:26:04 +01001450 for (i := 0; i < sizeof(ExpectTable); i := i+1) {
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001451 if (not ispresent(ExpectTable[i].l3_payload)
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001452 and not ExpectTable[i].sccp_cr_without_payload
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001453 and not ispresent(ExpectTable[i].n_connectPointCode)) {
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001454 if (ispresent(l3)) {
1455 ExpectTable[i].l3_payload := valueof(l3);
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001456 } else {
1457 ExpectTable[i].sccp_cr_without_payload := true;
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001458 }
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001459 if (ispresent(n_connectPointCode)) {
1460 ExpectTable[i].n_connectPointCode := valueof(n_connectPointCode);
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001461 }
Harald Welte624f9632017-12-16 19:26:04 +01001462 ExpectTable[i].vc_conn := hdlr;
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001463 if (ispresent(n_connectPointCode)) {
1464 log("Created Expect[", i, "] for N-CONNECT to be handled at ", hdlr);
Neels Hofmeyr0ac63152019-05-07 01:20:17 +02001465 } else {
1466 log("Created Expect[", i, "] for ", l3, " to be handled at ", hdlr);
1467 }
Harald Welte624f9632017-12-16 19:26:04 +01001468 return;
1469 }
1470 }
Oliver Smith07ebf962023-07-07 12:11:58 +02001471 setverdict(fail, "No space left in ExpectTable");
1472 mtc.stop;
Harald Welte624f9632017-12-16 19:26:04 +01001473}
1474
Harald Welte6811d102019-04-14 22:23:14 +02001475private function f_create_imsi(hexstring imsi, OCT4 tmsi, RAN_ConnHdlr hdlr)
1476runs on RAN_Emulation_CT {
Harald Welte17d21152018-01-27 00:47:11 +01001477 for (var integer i := 0; i < sizeof(ImsiTable); i := i+1) {
1478 if (not ispresent(ImsiTable[i].imsi)) {
1479 ImsiTable[i].imsi := imsi;
1480 ImsiTable[i].tmsi := tmsi;
1481 ImsiTable[i].comp_ref := hdlr;
1482 log("Created IMSI[", i, "] for ", imsi, tmsi, " to be handled at ", hdlr);
1483 return;
1484 }
1485 }
Oliver Smith07ebf962023-07-07 12:11:58 +02001486 setverdict(fail, "No space left in ImsiTable");
1487 mtc.stop;
Harald Welte17d21152018-01-27 00:47:11 +01001488}
1489
Harald Welteee4d70c2022-05-16 21:29:19 +02001490private function f_destroy_imsi(hexstring imsi, RAN_ConnHdlr hdlr)
1491runs on RAN_Emulation_CT {
1492 for (var integer i := 0; i < sizeof(ImsiTable); i := i+1) {
1493 if (ImsiTable[i].imsi == imsi and ImsiTable[i].comp_ref == hdlr) {
1494 ImsiTable[i].comp_ref := null;
1495 ImsiTable[i].imsi := omit;
1496 ImsiTable[i].tmsi := 'FFFFFFFF'O;
1497 log("Removed IMSI[", i, "] for ", imsi, " to be handled at ", hdlr);
1498 return;
1499 }
1500 }
Oliver Smith07ebf962023-07-07 12:11:58 +02001501 setverdict(fail, "Unable to find to-be-destroyed IMSI in ImsiTable");
1502 mtc.stop;
Harald Welteee4d70c2022-05-16 21:29:19 +02001503}
Harald Welte17d21152018-01-27 00:47:11 +01001504
Daniel Willmannd47106b2018-01-17 12:20:56 +01001505private function f_expect_table_init()
Harald Welte6811d102019-04-14 22:23:14 +02001506runs on RAN_Emulation_CT {
Daniel Willmannd47106b2018-01-17 12:20:56 +01001507 for (var integer i := 0; i < sizeof(ExpectTable); i := i+1) {
1508 ExpectTable[i].l3_payload := omit;
Andreas Eversberge5a6ef12023-07-28 10:45:20 +02001509 ExpectTable[i].n_connectPointCode := omit;
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001510 ExpectTable[i].sccp_cr_without_payload := false;
Daniel Willmannd47106b2018-01-17 12:20:56 +01001511 }
1512}
Harald Welte624f9632017-12-16 19:26:04 +01001513
Harald Welte17d21152018-01-27 00:47:11 +01001514/* helper function for clients to register their IMSI/TMSI */
Vadim Yanitskiyae747742020-01-10 00:23:10 +01001515function f_ran_register_imsi(hexstring imsi, template (omit) OCT4 tmsi_or_omit)
Harald Welte6811d102019-04-14 22:23:14 +02001516runs on RAN_ConnHdlr {
Vadim Yanitskiyae747742020-01-10 00:23:10 +01001517 var OCT4 tmsi;
1518
1519 /* Resolve omit to a special reserved value */
1520 if (istemplatekind(tmsi_or_omit, "omit")) {
1521 tmsi := 'FFFFFFFF'O;
1522 } else {
1523 tmsi := valueof(tmsi_or_omit);
1524 }
1525
Harald Welte6811d102019-04-14 22:23:14 +02001526 BSSAP_PROC.call(RAN_register_imsi:{imsi, tmsi, self}) {
1527 [] BSSAP_PROC.getreply(RAN_register_imsi:{?,?,?}) {};
Harald Welte17d21152018-01-27 00:47:11 +01001528 }
1529}
1530
Harald Welteee4d70c2022-05-16 21:29:19 +02001531/* helper function for clients to register their IMSI/TMSI */
1532function f_ran_unregister_imsi(hexstring imsi)
1533runs on RAN_ConnHdlr {
1534
1535 BSSAP_PROC.call(RAN_unregister_imsi:{imsi, self}) {
1536 [] BSSAP_PROC.getreply(RAN_unregister_imsi:{?,?}) {};
1537 }
1538}
1539
Harald Welte1e3bbbe2022-01-11 23:04:33 +01001540/* register an expect with the BSSMAP core */
1541function f_ran_register_exp(octetstring l3_enc) runs on RAN_ConnHdlr {
1542 BSSAP_PROC.call(RAN_register:{l3_enc, self}) {
1543 [] BSSAP_PROC.getreply(RAN_register:{?, ?}) {};
1544 }
1545}
1546
Neels Hofmeyrf0b9ed12022-06-07 17:46:32 +02001547function f_ran_register_sccp_cr_without_payload() runs on RAN_ConnHdlr {
1548 BSSAP_PROC.call(RAN_register_sccp_cr_without_payload:{self}) {
1549 [] BSSAP_PROC.getreply(RAN_register_sccp_cr_without_payload:{?}) {};
1550 }
1551}
1552
Harald Welte475a2c12019-05-02 19:05:48 +02001553#ifdef RAN_EMULATION_RANAP
1554/* expect a IuReleaseCommand; Confirm that; expect SCCP-level N-DISCONNET.ind */
1555altstep as_iu_release_compl_disc(float t := 5.0) runs on RAN_ConnHdlr {
1556 var RANAP_PDU ranap;
1557 [] BSSAP.receive(tr_RANAP_IuReleaseCommand(?)) {
1558 BSSAP.send(ts_RANAP_IuReleaseComplete);
1559 alt {
1560 [] BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
1561 setverdict(pass);
1562 }
1563 [] BSSAP.receive {
1564 setverdict(fail, "Unexpected RANAP while waiting for SCCP Release ");
1565 mtc.stop;
1566 }
1567 }
1568 }
1569 [] BSSAP.receive(RANAP_PDU:?) -> value ranap{
1570 setverdict(fail, "Unexpected RANAP while waiting for IuReleaseCommand", ranap);
1571 mtc.stop;
1572 }
1573}
1574#endif
1575
Harald Welte17d21152018-01-27 00:47:11 +01001576
Harald Welte365f4ed2017-11-23 00:00:43 +01001577}