blob: c1d297d45c9b32adb3dfdee424d4170eedb77e8d [file] [log] [blame]
Harald Welte1733a382017-07-23 17:26:17 +02001module BSSGP_Emulation {
Harald Welte1733a382017-07-23 17:26:17 +02002
Harald Welte34b5a952019-05-27 11:54:11 +02003/* BSSGP Emulation in TTCN-3
4 * (C) 2018-2019 Harald Welte <laforge@gnumonks.org>
5 * All rights reserved.
6 *
7 * Released under the terms of GNU General Public License, Version 2 or
8 * (at your option) any later version.
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
Harald Welte5ac31492018-02-15 20:39:13 +010013import from General_Types all;
14import from Osmocom_Types all;
Harald Welte853c0ad2018-02-15 17:45:29 +010015import from NS_Types all;
16import from NS_Emulation all;
17import from BSSGP_Types all;
18import from Osmocom_Gb_Types all;
19import from IPL4asp_Types all;
Harald Welte1733a382017-07-23 17:26:17 +020020
Harald Welte93331e72020-09-12 20:51:05 +020021#ifdef BSSGP_EM_L3
Harald Welte5ac31492018-02-15 20:39:13 +010022import from MobileL3_GMM_SM_Types all;
23import from MobileL3_Types all;
Harald Welte93331e72020-09-12 20:51:05 +020024#endif
Harald Welte5ac31492018-02-15 20:39:13 +010025
26import from LLC_Types all;
27import from LLC_Templates all;
28
Harald Weltea2526a82018-02-18 19:03:36 +010029import from SNDCP_Types all;
30
Harald Welte12d19b82020-10-09 11:41:06 +020031
32modulepar {
33 /* tolerate CellID absence/presence in BVC-RESET in violation to spec */
34 boolean mp_tolerate_bvc_reset_cellid := false;
35}
36
Harald Welte5ac31492018-02-15 20:39:13 +010037/***********************************************************************
38 * Communication between Client Components and Main Component
39 ***********************************************************************/
40
Harald Welte853c0ad2018-02-15 17:45:29 +010041type record BssgpStatusIndication {
42 Nsei nsei,
43 BssgpBvci bvci,
44 BvcState state
45}
46
47template BssgpStatusIndication t_BssgpStsInd(template Nsei nsei, template BssgpBvci bvci, template BvcState state) := {
48 nsei := nsei,
49 bvci := bvci,
50 state := state
51}
52
53type enumerated BvcState {
54 BVC_S_BLOCKED,
55 BVC_S_UNBLOCKED
56};
57
58/* port from our (internal) point of view */
59type port BSSGP_SP_PT message {
Harald Welte5ac31492018-02-15 20:39:13 +010060 in PDU_BSSGP,
Harald Welte93331e72020-09-12 20:51:05 +020061 PDU_LLC
62#ifdef BSSGP_EM_L3
63 ,
Harald Welte5ac31492018-02-15 20:39:13 +010064 PDU_L3_MS_SGSN,
Harald Welte93331e72020-09-12 20:51:05 +020065 PDU_L3_SGSN_MS
66#endif
67 ;
Harald Welte955aa942019-05-03 01:29:29 +020068 out PDU_BSSGP,
69 PDU_LLC,
70 PDU_SN,
Harald Welte853c0ad2018-02-15 17:45:29 +010071 NsStatusIndication,
72 BssgpStatusIndication,
Harald Welte93331e72020-09-12 20:51:05 +020073 ASP_Event
74#ifdef BSSGP_EM_L3
75 ,
Harald Welte5ac31492018-02-15 20:39:13 +010076 PDU_L3_MS_SGSN,
Harald Welte93331e72020-09-12 20:51:05 +020077 PDU_L3_SGSN_MS
78#endif
79 ;
Harald Welte853c0ad2018-02-15 17:45:29 +010080} with { extension "internal" };
81
82/* port from the user point of view */
83type port BSSGP_PT message {
84 in ASP_Event,
85 NsStatusIndication,
86 BssgpStatusIndication,
Harald Welte955aa942019-05-03 01:29:29 +020087 PDU_BSSGP,
88 PDU_LLC,
Harald Welte93331e72020-09-12 20:51:05 +020089 PDU_SN
90#ifdef BSSGP_EM_L3
91 ,
Harald Welte5ac31492018-02-15 20:39:13 +010092 PDU_L3_MS_SGSN,
Harald Welte93331e72020-09-12 20:51:05 +020093 PDU_L3_SGSN_MS
94#endif
95 ;
Harald Welte5ac31492018-02-15 20:39:13 +010096 out PDU_BSSGP,
Harald Welte93331e72020-09-12 20:51:05 +020097 PDU_LLC
98#ifdef BSSGP_EM_L3
99 ,
Harald Welte5ac31492018-02-15 20:39:13 +0100100 PDU_L3_SGSN_MS,
Harald Welte93331e72020-09-12 20:51:05 +0200101 PDU_L3_MS_SGSN
102#endif
103 ;
Harald Welte853c0ad2018-02-15 17:45:29 +0100104} with { extension "internal" };
105
Harald Welte5ac31492018-02-15 20:39:13 +0100106signature BSSGP_register_client(hexstring imsi, OCT4 tlli, BssgpCellId cell_id);
107signature BSSGP_unregister_client(hexstring imsi);
Harald Weltef70997d2018-02-17 10:11:19 +0100108signature BSSGP_llgmm_assign(OCT4 tlli_old, OCT4 tlli);
Harald Welte5ac31492018-02-15 20:39:13 +0100109
110type port BSSGP_PROC_PT procedure {
Harald Weltef70997d2018-02-17 10:11:19 +0100111 inout BSSGP_register_client, BSSGP_unregister_client, BSSGP_llgmm_assign;
Harald Welte5ac31492018-02-15 20:39:13 +0100112} with { extension "internal" };
113
114
115/***********************************************************************
116 * Client Component for a single MS/TLLI
117 ***********************************************************************/
118
119type component BSSGP_Client_CT {
Alexander Couzens0e510e62018-07-28 23:06:00 +0200120 port BSSGP_PT BSSGP[3];
121 port BSSGP_PT BSSGP_SIG[3];
122 port BSSGP_PROC_PT BSSGP_PROC[3];
Harald Welte5ac31492018-02-15 20:39:13 +0100123};
124
125/***********************************************************************
126 * Main Component
127 ***********************************************************************/
128
129function BssgpStart(BssgpConfig cfg) runs on BSSGP_CT {
130 g_cfg := cfg;
Harald Welte853c0ad2018-02-15 17:45:29 +0100131 f_init();
132 f_ScanEvents();
133}
134
135private function f_init() runs on BSSGP_CT {
136 /* Connect the UDP socket */
137 f_change_state(BVC_S_BLOCKED);
138}
139
140type component BSSGP_CT {
Stefan Sperlingf82bbb62018-05-03 19:14:28 +0200141 /* UDP ports towards the bottom (IUT) */
Harald Welte853c0ad2018-02-15 17:45:29 +0100142 port NS_PT BSCP;
143 /* NS-User SAP towards the user */
144 port BSSGP_SP_PT BSSGP_SP;
Stefan Sperlingf82bbb62018-05-03 19:14:28 +0200145 port BSSGP_SP_PT BSSGP_SP_SIG;
Harald Welte5ac31492018-02-15 20:39:13 +0100146 port BSSGP_PROC_PT BSSGP_PROC;
Harald Welte853c0ad2018-02-15 17:45:29 +0100147
Harald Welte5ac31492018-02-15 20:39:13 +0100148 var BssgpConfig g_cfg;
149
Harald Welte853c0ad2018-02-15 17:45:29 +0100150 var BvcState g_ptp_bvc_state := BVC_S_BLOCKED;
151 timer g_T1 := 15.0;
152 timer g_T2 := 60.0;
Harald Welte5ac31492018-02-15 20:39:13 +0100153
154 var ClientEntity ClientTable[16];
Harald Welte853c0ad2018-02-15 17:45:29 +0100155}
156
Alexander Couzens6b449fb2018-07-31 14:19:36 +0200157type record length(16) of LLC_Entity LLC_Entities;
158
Harald Welte5ac31492018-02-15 20:39:13 +0100159type record ClientEntity {
160 OCT4 tlli,
161 OCT4 tlli_old optional,
162 hexstring imsi,
163 BssgpCellId cell_id,
164 BSSGP_Client_CT comp_ref,
165 /* LLC entities, one for each SAPI */
166 LLC_Entity llc[16]
Harald Welte853c0ad2018-02-15 17:45:29 +0100167};
168
Harald Welte5ac31492018-02-15 20:39:13 +0100169type record LLC_Entity {
170 boolean sgsn_role,
171 /* N(U) on transmit side for next PDU */
172 uint9_t n_u_tx_next,
173 /* N(U) on receive side, last PDU */
174 uint9_t n_u_rx_last optional
175};
176
Alexander Couzenscdfb7512018-07-31 15:37:14 +0200177function f_llc_create(boolean sgsn_role := false) return LLC_Entities {
178 var LLC_Entities llc;
179 for (var integer i := 0; i < 16; i := i+1) {
180 llc[i] := valueof(t_LLC_init(sgsn_role));
181 }
182 return llc;
183}
184
Harald Welte5ac31492018-02-15 20:39:13 +0100185private template LLC_Entity t_LLC_init(boolean sgsn_role := false) := {
186 sgsn_role := sgsn_role,
187 n_u_tx_next := 0,
188 n_u_rx_last := -
189}
190
Oliver Smithaac9b9c2019-09-02 08:36:36 +0200191type enumerated BssgpDecodeDepth {
192 BSSGP_DECODE_DEPTH_BSSGP,
193 BSSGP_DECODE_DEPTH_LLC,
Harald Welte93331e72020-09-12 20:51:05 +0200194 BSSGP_DECODE_DEPTH_SNDCP
195#ifdef BSSGP_EM_L3
196 ,
Oliver Smithaac9b9c2019-09-02 08:36:36 +0200197 BSSGP_DECODE_DEPTH_L3
Harald Welte93331e72020-09-12 20:51:05 +0200198#endif
Oliver Smithaac9b9c2019-09-02 08:36:36 +0200199};
200
Harald Welte5ac31492018-02-15 20:39:13 +0100201type record BssgpConfig {
202 Nsvci nsei,
203 Nsvci bvci,
204 BssgpCellId cell_id,
Oliver Smithaac9b9c2019-09-02 08:36:36 +0200205 boolean sgsn_role,
206 BssgpDecodeDepth depth
Harald Welte5ac31492018-02-15 20:39:13 +0100207};
208
209function f_BnsUdReq(template PDU_BSSGP pdu, BssgpBvci bvci)
210runs on BSSGP_CT return NsUnitdataRequest {
Harald Welte853c0ad2018-02-15 17:45:29 +0100211 var NsUnitdataRequest udr := {
Harald Welte1733a382017-07-23 17:26:17 +0200212 bvci := bvci,
Harald Welte5ac31492018-02-15 20:39:13 +0100213 nsei := g_cfg.nsei,
Harald Welte853c0ad2018-02-15 17:45:29 +0100214 /* for some weird reason we get "Dynamic test case error: Text encoder: Encoding an
215 * unbound integer value." when trying to send the reocrd rather than the octetstring */
216 //sdu := omit,
217 //bssgp := valueof(pdu)
218 sdu := enc_PDU_BSSGP(valueof(pdu)),
219 bssgp := omit
220 }
221 return udr;
222}
223
Harald Welte5ac31492018-02-15 20:39:13 +0100224function f_BnsUdInd(template PDU_BSSGP pdu, template BssgpBvci bvci)
225runs on BSSGP_CT return template NsUnitdataIndication {
Harald Welte853c0ad2018-02-15 17:45:29 +0100226 var template NsUnitdataIndication udi := {
227 bvci := bvci,
Harald Welte5ac31492018-02-15 20:39:13 +0100228 nsei := g_cfg.nsei,
Harald Welte853c0ad2018-02-15 17:45:29 +0100229 sdu := *,
230 bssgp := pdu
231 }
232 return udi;
233}
234
235private function f_change_state(BvcState new_state) runs on BSSGP_CT {
236 log("BSSGP State Transition: ", g_ptp_bvc_state, " -> ", new_state);
237 g_ptp_bvc_state := new_state;
Harald Welte5ac31492018-02-15 20:39:13 +0100238 for (var integer i := 0; i < sizeof(ClientTable); i := i+1) {
239 if (isbound(ClientTable[i].comp_ref)) {
240 BSSGP_SP.send(t_BssgpStsInd(g_cfg.nsei, g_cfg.bvci, g_ptp_bvc_state)) to ClientTable[i].comp_ref;
241 }
242 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100243}
244
Harald Weltec967d0e2020-09-14 16:07:26 +0200245private function f_sendReset(BssgpBvci bvci) runs on BSSGP_CT {
246 var PDU_BSSGP pdu;
247
248 /* The Cell Identifier IE is mandatory in the BVC-RESET PDU sent from BSS to
249 * SGSN in order to reset a BVC corresponding to a PTP functional entity. The
250 * Cell Identifier IE shall not be used in any other BVC-RESET PDU. */
251 if (g_cfg.sgsn_role) {
252 pdu := valueof(ts_BVC_RESET(BSSGP_CAUSE_OM_INTERVENTION, bvci, omit));
253 } else {
254 pdu := valueof(ts_BVC_RESET(BSSGP_CAUSE_OM_INTERVENTION, bvci, g_cfg.cell_id));
255 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100256 log("PDU: ", pdu);
257 log("ENC: ", enc_PDU_BSSGP(pdu));
258
259 /* BVC-RESET is always sent via the SIGNALLING BVCI, see Table 5.4.1 */
260 BSCP.send(f_BnsUdReq(pdu, 0));
261 g_T2.start;
262 //f_change_state(BVC_S_WAIT_RESET);
263}
264
265private function f_sendUnblock() runs on BSSGP_CT {
Harald Welte5ac31492018-02-15 20:39:13 +0100266 BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK(g_cfg.bvci), 0));
Harald Welte853c0ad2018-02-15 17:45:29 +0100267 g_T1.start;
268}
269
270private function f_sendBlock(BssgpCause cause) runs on BSSGP_CT {
Harald Welte5ac31492018-02-15 20:39:13 +0100271 BSCP.send(f_BnsUdReq(t_BVC_BLOCK(g_cfg.bvci, cause), 0));
Harald Welte853c0ad2018-02-15 17:45:29 +0100272 g_T1.start;
273}
274
275private function f_sendStatus(BssgpCause cause, PDU_BSSGP pdu) runs on BSSGP_CT {
276 /* FIXME: Make sure correct Signaling or PTP BVCI is used! */
Harald Welte5ac31492018-02-15 20:39:13 +0100277 BSCP.send(f_BnsUdReq(ts_BSSGP_STATUS(g_cfg.bvci, cause, pdu), g_cfg.bvci));
278}
279
280/* attempt to extract the TLLI from a BSSGP PDU */
281function f_bssgp_get_tlli(PDU_BSSGP bssgp) return template OCT4 {
282 if (ischosen(bssgp.pDU_BSSGP_DL_UNITDATA)) {
283 return bssgp.pDU_BSSGP_DL_UNITDATA.tLLI_current;
284 } else if (ischosen(bssgp.pDU_BSSGP_UL_UNITDATA)) {
285 return bssgp.pDU_BSSGP_UL_UNITDATA.tLLI;
286 } else if (ischosen(bssgp.pDU_BSSGP_RA_CAPABILITY)) {
287 return bssgp.pDU_BSSGP_RA_CAPABILITY.tLLI.tLLI_Value;
288 } else if (ischosen(bssgp.pDU_BSSGP_RA_CAPABILITY_UPDATE)) {
289 return bssgp.pDU_BSSGP_RA_CAPABILITY_UPDATE.tLLI.tLLI_Value;
290 } else if (ischosen(bssgp.pDU_BSSGP_RA_CAPABILITY_UPDATE_ACK)) {
291 return bssgp.pDU_BSSGP_RA_CAPABILITY_UPDATE_ACK.tLLI.tLLI_Value;
292 } else if (ischosen(bssgp.pDU_BSSGP_RADIO_STATUS)) {
293 return bssgp.pDU_BSSGP_RADIO_STATUS.tLLI.tLLI_Value;
294 } else if (ischosen(bssgp.pDU_BSSGP_SUSPEND)) {
295 return bssgp.pDU_BSSGP_SUSPEND.tLLI.tLLI_Value;
296 } else if (ischosen(bssgp.pDU_BSSGP_SUSPEND_ACK)) {
297 return bssgp.pDU_BSSGP_SUSPEND_ACK.tLLI.tLLI_Value;
298 } else if (ischosen(bssgp.pDU_BSSGP_SUSPEND_NACK)) {
299 return bssgp.pDU_BSSGP_SUSPEND_NACK.tLLI.tLLI_Value;
300 } else if (ischosen(bssgp.pDU_BSSGP_RESUME)) {
301 return bssgp.pDU_BSSGP_RESUME.tLLI.tLLI_Value;
302 } else if (ischosen(bssgp.pDU_BSSGP_RESUME_ACK)) {
303 return bssgp.pDU_BSSGP_RESUME_ACK.tLLI.tLLI_Value;
304 } else if (ischosen(bssgp.pDU_BSSGP_RESUME_NACK)) {
305 return bssgp.pDU_BSSGP_RESUME_NACK.tLLI.tLLI_Value;
306 } else if (ischosen(bssgp.pDU_BSSGP_FLUSH_LL)) {
307 return bssgp.pDU_BSSGP_FLUSH_LL.tLLI.tLLI_Value;
308 } else if (ischosen(bssgp.pDU_BSSGP_FLUSH_LL_ACK)) {
309 return bssgp.pDU_BSSGP_FLUSH_LL_ACK.tLLI.tLLI_Value;
310 } else if (ischosen(bssgp.pDU_BSSGP_LLC_DISCARDED)) {
311 return bssgp.pDU_BSSGP_LLC_DISCARDED.tLLI.tLLI_Value;
312 } else if (ischosen(bssgp.pDU_BSSGP_LLC_DISCARDED)) {
313 return bssgp.pDU_BSSGP_LLC_DISCARDED.tLLI.tLLI_Value;
314 } else if (ischosen(bssgp.pDU_BSSGP_PAGING_CS) and
315 isvalue(bssgp.pDU_BSSGP_PAGING_CS.tLLI)) {
316 return bssgp.pDU_BSSGP_PAGING_CS.tLLI.tLLI_Value;
317 } else if (ischosen(bssgp.pDU_BSSGP_FLOW_CONTROL_MS)) {
318 return bssgp.pDU_BSSGP_FLOW_CONTROL_MS.tLLI.tLLI_Value;
319 } else if (ischosen(bssgp.pDU_BSSGP_FLOW_CONTROL_MS_ACK)) {
320 return bssgp.pDU_BSSGP_FLOW_CONTROL_MS_ACK.tLLI.tLLI_Value;
321 }
322 /* TODO: Handover, PFC, LCS */
323 return omit;
324}
325
326/*
327private function f_tbl_init() runs on BSSGP_CT {
328 var integer i;
329 for (i := 0; i < sizeof(ImsiTable); i := i+1) {
330 ImsiTable[i] := -;
331 }
332
333 for (i := 0; i < sizeof(TlliTable); i := i+1) {
334 TlliTable[i] := -;
335 }
336}
337*/
338
339private function f_tbl_client_add(hexstring imsi, OCT4 tlli, BssgpCellId cell_id, BSSGP_Client_CT vc_conn)
340runs on BSSGP_CT {
341 var integer i;
342 for (i := 0; i < sizeof(ClientTable); i := i+1) {
Harald Weltec7872fa2018-02-18 14:06:12 +0100343 if (not isvalue(ClientTable[i].comp_ref)) {
344 log("Adding Client=", vc_conn, ", IMSI=", imsi, ", TLLI=", tlli, ", index=", i);
Harald Welte5ac31492018-02-15 20:39:13 +0100345 ClientTable[i] := {
346 tlli := tlli,
347 tlli_old := omit,
348 imsi := imsi,
349 cell_id := cell_id,
350 comp_ref := vc_conn,
351 llc := -
352 };
353 for (var integer j := 0; j < sizeof(ClientTable[i].llc); j := j+1) {
354 ClientTable[i].llc[j] := valueof(t_LLC_init(g_cfg.sgsn_role));
355 }
356 return;
357 }
358 }
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200359 testcase.stop("Client Table full");
Harald Welte5ac31492018-02-15 20:39:13 +0100360}
361
362private function f_tbl_client_del(hexstring imsi, BSSGP_Client_CT vc_conn) runs on BSSGP_CT {
363 var integer i;
364 for (i := 0; i < sizeof(ClientTable); i := i+1) {
Harald Weltec7872fa2018-02-18 14:06:12 +0100365 if (isvalue(ClientTable[i].imsi) and ClientTable[i].imsi == imsi) {
Harald Welte5ac31492018-02-15 20:39:13 +0100366 if (ClientTable[i].comp_ref != vc_conn) {
Alexander Couzens2c153422018-06-12 18:10:30 +0200367 setverdict(fail, "Cannot unregister index=", i, " IMSI ", imsi, " registred to ",
Harald Welte5ac31492018-02-15 20:39:13 +0100368 ClientTable[i].comp_ref, " from ", vc_conn);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200369 mtc.stop;
Harald Welte5ac31492018-02-15 20:39:13 +0100370 }
371 log("Removing Client IMSI=", imsi, ", index=", i);
Alexander Couzens2c153422018-06-12 18:10:30 +0200372 ClientTable[i] := {
373 tlli := -,
374 tlli_old := omit,
375 imsi := ''H,
376 cell_id := -,
377 comp_ref := null,
378 llc := - };
Harald Welte5ac31492018-02-15 20:39:13 +0100379 return;
380 }
381 }
Alexander Couzens56101c92018-07-31 15:55:34 +0200382 log("Warning: Could not find client for IMSI ", imsi);
383 return;
Harald Welte5ac31492018-02-15 20:39:13 +0100384}
385
Harald Weltef70997d2018-02-17 10:11:19 +0100386/* TS 44.064 7.2.1.1 LLGMM-ASSIGN */
387private function f_tbl_client_llgmm_assign(OCT4 tlli_old, OCT4 tlli_new, BSSGP_Client_CT vc_conn)
388runs on BSSGP_CT {
389 var integer i := f_tbl_idx_by_comp(vc_conn);
390
391 if (tlli_old == 'FFFFFFFF'O and tlli_new != 'FFFFFFFF'O) {
392 /* TLLI assignment */
393 ClientTable[i].tlli := tlli_new;
394 ClientTable[i].tlli_old := omit;
395 } else if (tlli_old != 'FFFFFFFF'O and tlli_new != 'FFFFFFFF'O) {
396 /* TLLI change: both active */
397 ClientTable[i].tlli := tlli_new;
398 ClientTable[i].tlli_old := tlli_old;
399 } else if (tlli_old != 'FFFFFFFF'O and tlli_new == 'FFFFFFFF'O) {
400 /* TLLI unassignment: old shall be unassigned; new stays */
401 ClientTable[i].tlli_old := omit;
402 }
403}
404
Harald Welte5ac31492018-02-15 20:39:13 +0100405private function f_tbl_comp_by_imsi(hexstring imsi) runs on BSSGP_CT return BSSGP_Client_CT {
406 var integer i;
407 for (i := 0; i < sizeof(ClientTable); i := i+1) {
Harald Weltec7872fa2018-02-18 14:06:12 +0100408 if (isvalue(ClientTable[i].imsi) and isvalue(ClientTable[i].comp_ref)
Harald Welte5ac31492018-02-15 20:39:13 +0100409 and ClientTable[i].imsi == imsi) {
410 return ClientTable[i].comp_ref;
411 }
412 }
413 setverdict(fail, "Couldn't find Component for IMSI ", imsi);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200414 mtc.stop;
Harald Welte5ac31492018-02-15 20:39:13 +0100415}
416
417private function f_tbl_comp_by_tlli(OCT4 tlli) runs on BSSGP_CT return BSSGP_Client_CT {
418 var integer i;
419 for (i := 0; i < sizeof(ClientTable); i := i+1) {
Harald Weltec7872fa2018-02-18 14:06:12 +0100420 if (isvalue(ClientTable[i].comp_ref) and
421 (isvalue(ClientTable[i].tlli) and (ClientTable[i].tlli == tlli or
422 isvalue(ClientTable[i].tlli_old) and ClientTable[i].tlli_old == tlli) )) {
Harald Welte5ac31492018-02-15 20:39:13 +0100423 return ClientTable[i].comp_ref;
424 }
425 }
426 setverdict(fail, "Couldn't find Component for TLLI ", tlli);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200427 mtc.stop;
Harald Welte5ac31492018-02-15 20:39:13 +0100428}
429
430private function f_tbl_idx_by_comp(BSSGP_Client_CT comp_ref) runs on BSSGP_CT return integer {
431 var integer i;
432 for (i := 0; i < sizeof(ClientTable); i := i+1) {
Harald Weltec7872fa2018-02-18 14:06:12 +0100433 if (isvalue(ClientTable[i].comp_ref) and ClientTable[i].comp_ref == comp_ref) {
Harald Welte5ac31492018-02-15 20:39:13 +0100434 return i;
435 }
436 }
437 setverdict(fail, "Couldn't find Client for Component ", comp_ref);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200438 mtc.stop;
Harald Welte5ac31492018-02-15 20:39:13 +0100439}
440
441private function f_tbl_tlli_by_comp(BSSGP_Client_CT comp_ref) runs on BSSGP_CT return OCT4 {
442 var integer i;
443 for (i := 0; i < sizeof(ClientTable); i := i+1) {
Harald Weltec7872fa2018-02-18 14:06:12 +0100444 if (isvalue(ClientTable[i].tlli) and isvalue(ClientTable[i].comp_ref)
Harald Welte5ac31492018-02-15 20:39:13 +0100445 and ClientTable[i].comp_ref == comp_ref) {
446 return ClientTable[i].tlli;
447 }
448 }
449 setverdict(fail, "Couldn't find TLLI for Component ", comp_ref);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200450 mtc.stop;
Harald Welte853c0ad2018-02-15 17:45:29 +0100451}
452
Harald Weltec967d0e2020-09-14 16:07:26 +0200453private function f_send_bvc_reset_ack(BssgpBvci bvci) runs on BSSGP_CT {
454 /* The Cell Identifier IE is mandatory in the BVC-RESET-ACK PDU sent from BSS to
455 * SGSN in response to reset a BVC corresponding to a PTP functional entity. The Cell
456 * Identifier IE shall not be used in any other BVC-RESET-ACK PDU */
457 if (g_cfg.sgsn_role) {
458 BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(bvci, omit), 0));
459 } else {
460 BSCP.send(f_BnsUdReq(ts_BVC_RESET_ACK(bvci, g_cfg.cell_id), 0));
461 }
462}
463
Harald Welte853c0ad2018-02-15 17:45:29 +0100464altstep as_allstate() runs on BSSGP_CT {
Harald Welte5ac31492018-02-15 20:39:13 +0100465 var BSSGP_Client_CT vc_conn;
Harald Welte853c0ad2018-02-15 17:45:29 +0100466 var NsUnitdataIndication udi;
467 var NsStatusIndication nsi;
468 var ASP_Event evt;
Harald Welte5ac31492018-02-15 20:39:13 +0100469 var hexstring imsi;
Harald Weltef70997d2018-02-17 10:11:19 +0100470 var OCT4 tlli, tlli_old;
Harald Welte5ac31492018-02-15 20:39:13 +0100471 var BssgpCellId cell_id;
Harald Welte853c0ad2018-02-15 17:45:29 +0100472
473 /* Respond to BLOCK for wrong NSVCI */
474 [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(?, ?), 0)) -> value udi {
475 log("Rx BVC-BLOCK for unknown BVCI");
476 f_sendStatus(BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp);
Harald Welte1733a382017-07-23 17:26:17 +0200477 }
478
Harald Welte853c0ad2018-02-15 17:45:29 +0100479 /* Respond to RESET with correct BVCI/CellID */
Harald Welte5ac31492018-02-15 20:39:13 +0100480 [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, g_cfg.bvci, g_cfg.cell_id), 0)) -> value udi {
481 log("Rx BVC-RESET for Our BVCI=", g_cfg.bvci);
Harald Weltec967d0e2020-09-14 16:07:26 +0200482 f_send_bvc_reset_ack(g_cfg.bvci);
Harald Welte853c0ad2018-02-15 17:45:29 +0100483 f_change_state(BVC_S_UNBLOCKED);
Harald Welte1733a382017-07-23 17:26:17 +0200484 }
485
Harald Welte853c0ad2018-02-15 17:45:29 +0100486 /* Respond to RESET for signalling BVCI 0 */
Harald Welte12d19b82020-10-09 11:41:06 +0200487 [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, 0, omit), 0)) -> value udi {
488 log("Rx BVC-RESET for Signaling BVCI=0");
489 f_send_bvc_reset_ack(0);
490 }
491
492 /* work-around for old, buggy libosmogb before Change-Id Ie87820537d6d616da4fd4bbf73eab06e28fda5e1 */
493 [mp_tolerate_bvc_reset_cellid] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, 0, g_cfg.cell_id), 0)) -> value udi {
Harald Welte853c0ad2018-02-15 17:45:29 +0100494 log("Rx BVC-RESET for Signaling BVCI=0");
Harald Weltec967d0e2020-09-14 16:07:26 +0200495 f_send_bvc_reset_ack(0);
Harald Welte1733a382017-07-23 17:26:17 +0200496 }
497
Harald Welte853c0ad2018-02-15 17:45:29 +0100498 /* Respond to RESET with wrong NSEI/NSVCI */
499 [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET(?, ?, ?), 0)) -> value udi {
500 log("Rx BVC-RESET for unknown BVCI");
501 f_sendStatus(BSSGP_CAUSE_BVCI_UNKNOWN, udi.bssgp);
Harald Welte1733a382017-07-23 17:26:17 +0200502 }
503
Harald Welte853c0ad2018-02-15 17:45:29 +0100504 /* default case of handling unknown PDUs */
505 [] BSCP.receive(f_BnsUdInd(?, ?)) -> value udi {
506 log("Rx Unexpected BSSGP PDU ", udi.bssgp," in state ", g_ptp_bvc_state);
507 f_sendStatus(BSSGP_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, udi.bssgp);
Harald Welte1733a382017-07-23 17:26:17 +0200508 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100509 /* Forwarding of ASP_Event and NsStatusIndication to user */
Harald Welte5ac31492018-02-15 20:39:13 +0100510 [] BSCP.receive(ASP_Event:?) -> value evt {
511 for (var integer i := 0; i < sizeof(ClientTable); i := i+1) {
512 if (isbound(ClientTable[i].comp_ref)) {
513 BSSGP_SP.send(evt) to ClientTable[i].comp_ref;
514 }
515 }
516 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100517 [] BSCP.receive(NsStatusIndication:?) -> value nsi {
518 /* if we just became NS-unblocked, send a BCC-RESET */
519 if (nsi.old_state != NSE_S_ALIVE_UNBLOCKED and nsi.new_state == NSE_S_ALIVE_UNBLOCKED) {
Harald Welte5ac31492018-02-15 20:39:13 +0100520 if (g_cfg.sgsn_role == false) {
Harald Weltec967d0e2020-09-14 16:07:26 +0200521 f_sendReset(g_cfg.bvci);
Harald Welte1733a382017-07-23 17:26:17 +0200522 }
Harald Welte5ac31492018-02-15 20:39:13 +0100523 /* Idea: We could send BVC-UNBLOCK here like some SGSN do */
Harald Welte1733a382017-07-23 17:26:17 +0200524 }
Harald Welte5ac31492018-02-15 20:39:13 +0100525 for (var integer i := 0; i < sizeof(ClientTable); i := i+1) {
526 if (isbound(ClientTable[i].comp_ref)) {
527 BSSGP_SP.send(nsi) to ClientTable[i].comp_ref;
528 }
529 }
530 }
531
532 [] BSSGP_PROC.getcall(BSSGP_register_client:{?,?,?}) -> param(imsi, tlli, cell_id) sender vc_conn {
533 f_tbl_client_add(imsi, tlli, cell_id, vc_conn);
Harald Weltee32ad992018-05-31 22:17:46 +0200534 BSSGP_PROC.reply(BSSGP_register_client:{imsi, tlli, cell_id}) to vc_conn;
Harald Welte5ac31492018-02-15 20:39:13 +0100535 }
536 [] BSSGP_PROC.getcall(BSSGP_unregister_client:{?}) -> param(imsi) sender vc_conn {
537 f_tbl_client_del(imsi, vc_conn);
Harald Weltee32ad992018-05-31 22:17:46 +0200538 BSSGP_PROC.reply(BSSGP_unregister_client:{imsi}) to vc_conn;
Harald Welte5ac31492018-02-15 20:39:13 +0100539 }
Harald Weltef70997d2018-02-17 10:11:19 +0100540 [] BSSGP_PROC.getcall(BSSGP_llgmm_assign:{?,?}) -> param(tlli_old, tlli) sender vc_conn {
541 f_tbl_client_llgmm_assign(tlli_old, tlli, vc_conn);
Harald Weltee32ad992018-05-31 22:17:46 +0200542 BSSGP_PROC.reply(BSSGP_llgmm_assign:{tlli_old, tlli}) to vc_conn;
Harald Weltef70997d2018-02-17 10:11:19 +0100543 }
544
Harald Welte5ac31492018-02-15 20:39:13 +0100545}
546
547altstep as_blocked() runs on BSSGP_CT {
Harald Weltec27f6842018-03-02 21:40:03 +0100548 [g_T1.running] g_T1.timeout {
Harald Welte5ac31492018-02-15 20:39:13 +0100549 f_sendUnblock();
550 }
551 [] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK_ACK(g_cfg.bvci), 0)) {
552 g_T1.stop;
553 f_change_state(BVC_S_UNBLOCKED);
554 }
555 [not g_cfg.sgsn_role] BSCP.receive(f_BnsUdInd(tr_BVC_RESET_ACK(g_cfg.bvci, omit), 0)) {
556 f_sendUnblock();
Harald Welte1733a382017-07-23 17:26:17 +0200557 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100558}
Harald Welte1733a382017-07-23 17:26:17 +0200559
Harald Welte955aa942019-05-03 01:29:29 +0200560private function f_send_bssgp_dec(BssgpDecoded dec, BSSGP_Client_CT vc_conn, BSSGP_SP_PT pt := BSSGP_SP) runs on BSSGP_CT {
Harald Welte07cb87a2020-09-13 18:38:02 +0200561#ifdef BSSGP_EM_L3
Harald Welte955aa942019-05-03 01:29:29 +0200562 if (ispresent(dec.l3_mt)) {
563 pt.send(dec.l3_mt) to vc_conn;
564 } else if (ispresent(dec.l3_mo)) {
565 pt.send(dec.l3_mo) to vc_conn;
Harald Welte07cb87a2020-09-13 18:38:02 +0200566 } else
567#endif
568 if (ispresent(dec.sndcp)) {
Harald Welte955aa942019-05-03 01:29:29 +0200569 pt.send(dec.sndcp) to vc_conn;
570 } else if (ispresent(dec.llc)) {
571 pt.send(dec.llc) to vc_conn;
572 } else {
573 pt.send(dec.bssgp) to vc_conn;
574 }
575}
576
577
Harald Welte5ac31492018-02-15 20:39:13 +0100578altstep as_unblocked() runs on BSSGP_CT {
579 var BSSGP_Client_CT vc_conn;
Harald Welte853c0ad2018-02-15 17:45:29 +0100580 var NsUnitdataIndication udi;
581 var PDU_BSSGP bs_pdu;
Harald Welte752abba2018-02-18 19:42:17 +0100582 var PDU_LLC llc;
Harald Welte93331e72020-09-12 20:51:05 +0200583#ifdef BSSGP_EM_L3
Harald Welte5ac31492018-02-15 20:39:13 +0100584 var PDU_L3_MS_SGSN l3_mo;
585 var PDU_L3_SGSN_MS l3_mt;
Harald Welte93331e72020-09-12 20:51:05 +0200586#endif
Harald Welte1733a382017-07-23 17:26:17 +0200587
Harald Welte5ac31492018-02-15 20:39:13 +0100588 /* bogus unblock, just respond with ACK */
589 [] BSCP.receive(f_BnsUdInd(t_BVC_UNBLOCK(g_cfg.bvci), 0)) -> value udi {
590 BSCP.send(f_BnsUdReq(t_BVC_UNBLOCK_ACK(g_cfg.bvci), 0));
591 }
592 /* Respond to BLOCK with BLOCK-ACK + change state */
593 [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK(g_cfg.bvci, ?), 0)) -> value udi {
594 BSCP.send(f_BnsUdReq(t_BVC_BLOCK_ACK(g_cfg.bvci), 0));
595 g_T1.stop;
596 f_change_state(BVC_S_BLOCKED);
597 }
Harald Weltec27f6842018-03-02 21:40:03 +0100598 [g_T1.running] g_T1.timeout {
Harald Welte5ac31492018-02-15 20:39:13 +0100599 f_sendBlock(BSSGP_CAUSE_OM_INTERVENTION);
600 }
601 [] BSCP.receive(f_BnsUdInd(t_BVC_BLOCK_ACK(g_cfg.bvci), 0)) -> value udi {
602 g_T1.stop;
603 f_change_state(BVC_S_BLOCKED);
604 }
605 [] BSCP.receive(f_BnsUdInd(tr_BVC_RESET_ACK(g_cfg.bvci, g_cfg.cell_id), 0)) -> value udi {
606 g_T2.stop;
607 f_change_state(BVC_S_UNBLOCKED);
608 }
Harald Welte13d391e2017-07-23 19:52:33 +0200609
Harald Welte5ac31492018-02-15 20:39:13 +0100610 /* simply acknowledge all Flow Control Messages */
Harald Welteedcdd902018-03-02 22:04:54 +0100611 [g_cfg.sgsn_role] BSCP.receive(f_BnsUdInd(tr_BVC_FC_BVC, g_cfg.bvci)) -> value udi {
612 var OCT1 tag := udi.bssgp.pDU_BSSGP_FLOW_CONTROL_BVC.tag.unstructured_Value;
613 BSCP.send(f_BnsUdReq(t_BVC_FC_BVC_ACK(tag), g_cfg.bvci));
Harald Welte5ac31492018-02-15 20:39:13 +0100614 }
Harald Welteedcdd902018-03-02 22:04:54 +0100615/*
616 [g_cfg.sgsn_role] BSCP.receive(f_BnsUdInd(t_BVC_FC_MS, g_cfg.bvci)) {
617 BSCP.send(f_BnsUdReq(t_BVC_FC_MS_ACK, g_cfg.bvci));
Harald Welte5ac31492018-02-15 20:39:13 +0100618 }
Harald Weltee0abc472018-02-05 09:13:31 +0100619*/
Harald Welte13d391e2017-07-23 19:52:33 +0200620
Harald Welte5ac31492018-02-15 20:39:13 +0100621 /* FIXME: CS PAGING: dispatch by IMSI */
Harald Welte1733a382017-07-23 17:26:17 +0200622
Harald Welte5ac31492018-02-15 20:39:13 +0100623 /* PS PAGING: dispatch by IMSI */
624 [] BSCP.receive(f_BnsUdInd(tr_BSSGP_PS_PAGING(g_cfg.bvci), g_cfg.bvci)) -> value udi {
625 var hexstring imsi := udi.bssgp.pDU_BSSGP_PAGING_PS.iMSI.digits
626 vc_conn := f_tbl_comp_by_imsi(imsi);
Harald Welte955aa942019-05-03 01:29:29 +0200627 f_send_bssgp_dec(f_dec_bssgp(udi.bssgp), vc_conn);
Harald Welte5ac31492018-02-15 20:39:13 +0100628 }
629
Harald Welte001b0da2019-03-21 21:30:47 +0100630 /* Any other PTP BSSGP message: If it has TLLi, route to component; otherwise broadcast */
Harald Welte5ac31492018-02-15 20:39:13 +0100631 [] BSCP.receive(f_BnsUdInd(?, g_cfg.bvci)) -> value udi {
632 var BssgpDecoded dec := f_dec_bssgp(udi.bssgp);
633 var template OCT4 tlli := f_bssgp_get_tlli(udi.bssgp);
634 if (isvalue(tlli)) {
635 vc_conn := f_tbl_comp_by_tlli(valueof(tlli));
Harald Welte955aa942019-05-03 01:29:29 +0200636 f_send_bssgp_dec(dec, vc_conn);
Harald Welte5ac31492018-02-15 20:39:13 +0100637 } else {
638 log("No TLLI: Broadcasting ", dec);
639 /* broadcast this message to all components */
640 // TITAN DOESN'T DO THIS, *SIGH*: "BSSGP_SP.send(dec) to all component;"
641 for (var integer i := 0; i < sizeof(ClientTable); i := i+1) {
642 if (isbound(ClientTable[i].comp_ref)) {
Harald Welte955aa942019-05-03 01:29:29 +0200643 f_send_bssgp_dec(dec, ClientTable[i].comp_ref);
Harald Welte5ac31492018-02-15 20:39:13 +0100644 }
645 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100646 }
Harald Welte1733a382017-07-23 17:26:17 +0200647 }
Harald Welte853c0ad2018-02-15 17:45:29 +0100648
Harald Welte001b0da2019-03-21 21:30:47 +0100649 /* Any other SIG BSSGP message: If it has TLLi, route to component; otherwise broadcast */
650 [] BSCP.receive(f_BnsUdInd(?, 0)) -> value udi {
651 var BssgpDecoded dec := f_dec_bssgp(udi.bssgp);
652 var template OCT4 tlli := f_bssgp_get_tlli(udi.bssgp);
653 if (isvalue(tlli)) {
654 vc_conn := f_tbl_comp_by_tlli(valueof(tlli));
Harald Welte955aa942019-05-03 01:29:29 +0200655 f_send_bssgp_dec(dec, vc_conn, BSSGP_SP_SIG);
Harald Welte001b0da2019-03-21 21:30:47 +0100656 } else {
657 log("No TLLI: Broadcasting ", dec);
658 /* broadcast this message to all components */
659 // TITAN DOESN'T DO THIS, *SIGH*: "BSSGP_SP.send(dec) to all component;"
660 for (var integer i := 0; i < sizeof(ClientTable); i := i+1) {
661 if (isbound(ClientTable[i].comp_ref)) {
Oliver Smitha2cf8bd2019-08-30 11:48:00 +0200662 f_send_bssgp_dec(dec, ClientTable[i].comp_ref, BSSGP_SP_SIG);
Harald Welte001b0da2019-03-21 21:30:47 +0100663 }
664 }
665 }
666 }
667
668
Harald Welte1e5a02d2019-05-03 00:50:48 +0200669 /* ConnHdlr sends BSSGP on BVCI=0 port: forward it to BSSGP Codec Port */
Stefan Sperlingf82bbb62018-05-03 19:14:28 +0200670 [] BSSGP_SP_SIG.receive(PDU_BSSGP:?)-> value bs_pdu sender vc_conn {
671 BSCP.send(f_BnsUdReq(bs_pdu, 0));
672 }
673
Harald Welte1e5a02d2019-05-03 00:50:48 +0200674 /* ConnHdlr sends BSSGP on BVCI=PTP port: forward it to BSSGP Codec Port */
Harald Welte5ac31492018-02-15 20:39:13 +0100675 [] BSSGP_SP.receive(PDU_BSSGP:?) -> value bs_pdu sender vc_conn {
676 BSCP.send(f_BnsUdReq(bs_pdu, g_cfg.bvci));
677 }
678
Harald Welte93331e72020-09-12 20:51:05 +0200679#ifdef BSSGP_EM_L3
Harald Welte1e5a02d2019-05-03 00:50:48 +0200680 /* ConnHdlr sends L3: Encode and send as UL_UD / DL_UD */
Harald Welte5ac31492018-02-15 20:39:13 +0100681 [g_cfg.sgsn_role] BSSGP_SP.receive(PDU_L3_SGSN_MS:?) -> value l3_mt sender vc_conn {
682 var integer idx := f_tbl_idx_by_comp(vc_conn);
683 var octetstring l3_enc := enc_PDU_L3_SGSN_MS(l3_mt);
684 var BIT4 sapi := f_llc_sapi_by_l3_mt(l3_mt);
685 var integer n_u := f_llc_get_n_u_tx(ClientTable[idx].llc[bit2int(sapi)]);
686 var octetstring llc_enc := enc_PDU_LLC(valueof(ts_LLC_UI(l3_enc, sapi, '1'B, n_u)));
Harald Welte8d1d8932019-05-03 00:41:41 +0200687 BSCP.send(f_BnsUdReq(ts_BSSGP_DL_UD(ClientTable[idx].tlli, llc_enc), g_cfg.bvci));
Harald Welte5ac31492018-02-15 20:39:13 +0100688 }
Harald Welte425f7822019-05-03 00:48:46 +0200689 [not g_cfg.sgsn_role] BSSGP_SP.receive(PDU_L3_MS_SGSN:?) -> value l3_mo sender vc_conn {
690 var integer idx := f_tbl_idx_by_comp(vc_conn);
691 var octetstring l3_enc := enc_PDU_L3_MS_SGSN(l3_mo);
692 var BIT4 sapi := f_llc_sapi_by_l3_mo(l3_mo);
693 var integer n_u := f_llc_get_n_u_tx(ClientTable[idx].llc[bit2int(sapi)]);
694 var octetstring llc_enc := enc_PDU_LLC(valueof(ts_LLC_UI(l3_enc, sapi, '1'B, n_u)));
695 BSCP.send(f_BnsUdReq(ts_BSSGP_UL_UD(ClientTable[idx].tlli, ClientTable[idx].cell_id, llc_enc), g_cfg.bvci));
696 }
Harald Welte93331e72020-09-12 20:51:05 +0200697#endif
Harald Welte752abba2018-02-18 19:42:17 +0100698
Harald Welte1b85bf32019-05-03 00:49:25 +0200699 /* ConnHdlr sends raw LLC: Encode and send as UL_UD / DL_UD */
700 [not g_cfg.sgsn_role] BSSGP_SP.receive(PDU_LLC:?) -> value llc sender vc_conn {
Harald Welte752abba2018-02-18 19:42:17 +0100701 var integer idx := f_tbl_idx_by_comp(vc_conn);
702 var octetstring llc_enc := enc_PDU_LLC(llc);
703 BSCP.send(f_BnsUdReq(ts_BSSGP_UL_UD(ClientTable[idx].tlli, ClientTable[idx].cell_id, llc_enc), g_cfg.bvci));
704 }
Harald Welte1b85bf32019-05-03 00:49:25 +0200705 [g_cfg.sgsn_role] BSSGP_SP.receive(PDU_LLC:?) -> value llc sender vc_conn {
706 var integer idx := f_tbl_idx_by_comp(vc_conn);
707 var octetstring llc_enc := enc_PDU_LLC(llc);
708 BSCP.send(f_BnsUdReq(ts_BSSGP_DL_UD(ClientTable[idx].tlli, llc_enc), g_cfg.bvci));
709 }
710
Harald Welte853c0ad2018-02-15 17:45:29 +0100711}
712
Alexander Couzenscdfb7512018-07-31 15:37:14 +0200713function f_llc_get_n_u_tx(inout LLC_Entity llc) return uint9_t {
Harald Welte5ac31492018-02-15 20:39:13 +0100714 var uint9_t ret := llc.n_u_tx_next;
715 llc.n_u_tx_next := llc.n_u_tx_next + 1;
716 return ret;
717}
718
Harald Welte93331e72020-09-12 20:51:05 +0200719#ifdef BSSGP_EM_L3
Alexander Couzenscdfb7512018-07-31 15:37:14 +0200720function f_llc_sapi_by_l3_mo(PDU_L3_MS_SGSN l3_mo) return BIT4 {
Harald Welte5ac31492018-02-15 20:39:13 +0100721 if (ischosen(l3_mo.msgs.gprs_mm)) {
722 return c_LLC_SAPI_LLGMM;
723 } else if (ischosen(l3_mo.msgs.gprs_sm)) {
Harald Welted4719012018-02-17 16:45:06 +0100724 return c_LLC_SAPI_LLGMM;
Harald Welte5ac31492018-02-15 20:39:13 +0100725 } else if (ischosen(l3_mo.msgs.sms)) {
726 return c_LLC_SAPI_LLSMS;
727 }
728 setverdict(fail, "No LLC SAPI for ", l3_mo);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200729 mtc.stop;
Harald Welte5ac31492018-02-15 20:39:13 +0100730}
731
732private function f_llc_sapi_by_l3_mt(PDU_L3_SGSN_MS l3_mt) return BIT4 {
733 if (ischosen(l3_mt.msgs.gprs_mm)) {
734 return c_LLC_SAPI_LLGMM;
735 } else if (ischosen(l3_mt.msgs.gprs_sm)) {
Harald Welted4719012018-02-17 16:45:06 +0100736 return c_LLC_SAPI_LLGMM;
Harald Welte5ac31492018-02-15 20:39:13 +0100737 } else if (ischosen(l3_mt.msgs.sms)) {
738 return c_LLC_SAPI_LLSMS;
739 }
740 setverdict(fail, "No LLC SAPI for ", l3_mt);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200741 mtc.stop;
Harald Welte5ac31492018-02-15 20:39:13 +0100742}
Harald Welte93331e72020-09-12 20:51:05 +0200743#endif
Harald Welte5ac31492018-02-15 20:39:13 +0100744
745
746
747private function f_ScanEvents() runs on BSSGP_CT {
748 log("matching against ", tr_BVC_RESET(?, g_cfg.bvci, g_cfg.cell_id));
749
750 while (true) {
751 alt {
752 [g_ptp_bvc_state == BVC_S_BLOCKED] as_blocked();
753 [g_ptp_bvc_state == BVC_S_UNBLOCKED] as_unblocked();
754 [] as_allstate();
755 }
756 } /* while */
757}
758
759/* PDU_BSSGP enhanced with LLC and possibly L3 decoded payloads */
760type record BssgpDecoded {
761 PDU_BSSGP bssgp,
762 PDU_LLC llc optional,
Harald Welte93331e72020-09-12 20:51:05 +0200763#ifdef BSSGP_EM_L3
Harald Welte5ac31492018-02-15 20:39:13 +0100764 PDU_L3_MS_SGSN l3_mo optional,
Harald Weltea2526a82018-02-18 19:03:36 +0100765 PDU_L3_SGSN_MS l3_mt optional,
Harald Welte93331e72020-09-12 20:51:05 +0200766#endif
Harald Weltea2526a82018-02-18 19:03:36 +0100767 PDU_SN sndcp optional
Harald Welte5ac31492018-02-15 20:39:13 +0100768}
769
770/* Decode a PDU_BSSGP into a BssgpDecoded (i.e. with LLC/L3 decoded, as applicable) */
771private function f_dec_bssgp(PDU_BSSGP bssgp) runs on BSSGP_CT return BssgpDecoded {
772 var BssgpDecoded dec := {
773 bssgp := bssgp,
774 llc := omit,
Harald Welte93331e72020-09-12 20:51:05 +0200775#ifdef BSSGP_EM_L3
Harald Welte5ac31492018-02-15 20:39:13 +0100776 l3_mo := omit,
Harald Weltea2526a82018-02-18 19:03:36 +0100777 l3_mt := omit,
Harald Welte93331e72020-09-12 20:51:05 +0200778#endif
Harald Weltea2526a82018-02-18 19:03:36 +0100779 sndcp := omit
Harald Welte5ac31492018-02-15 20:39:13 +0100780 };
781
782 /* Decode LLC, if it is a PDU that contains LLC */
Oliver Smithaac9b9c2019-09-02 08:36:36 +0200783 if (g_cfg.depth >= BSSGP_DECODE_DEPTH_LLC) {
784 if (ischosen(bssgp.pDU_BSSGP_DL_UNITDATA)) {
785 dec.llc := dec_PDU_LLC(bssgp.pDU_BSSGP_DL_UNITDATA.lLC_PDU.lLC_PDU);
786 } else if (ischosen(bssgp.pDU_BSSGP_UL_UNITDATA)) {
787 dec.llc := dec_PDU_LLC(bssgp.pDU_BSSGP_UL_UNITDATA.lLC_PDU.lLC_PDU);
Harald Welte5ac31492018-02-15 20:39:13 +0100788 }
789 }
Harald Weltea2526a82018-02-18 19:03:36 +0100790
791 /* Decode SNDCP, if it is a LLC PDU containing user plane data */
Oliver Smithaac9b9c2019-09-02 08:36:36 +0200792 if (g_cfg.depth >= BSSGP_DECODE_DEPTH_SNDCP) {
793 if (isvalue(dec.llc) and match(dec.llc, tr_LLC_UI_USER)) {
794 dec.sndcp := dec_PDU_SN(dec.llc.pDU_LLC_UI.information_field_UI);
795 }
Harald Weltea2526a82018-02-18 19:03:36 +0100796 }
Oliver Smithaac9b9c2019-09-02 08:36:36 +0200797
Harald Welte93331e72020-09-12 20:51:05 +0200798#ifdef BSSGP_EM_L3
Oliver Smithaac9b9c2019-09-02 08:36:36 +0200799 /* Decode L3, if it is a LLC PDU containing L3 */
800 if (g_cfg.depth >= BSSGP_DECODE_DEPTH_L3) {
801 if (isvalue(dec.llc) and match(dec.llc, tr_LLC_UI_L3)) {
802 if (g_cfg.sgsn_role) {
803 dec.l3_mo := dec_PDU_L3_MS_SGSN(dec.llc.pDU_LLC_UI.information_field_UI);
804 } else {
805 dec.l3_mt := dec_PDU_L3_SGSN_MS(dec.llc.pDU_LLC_UI.information_field_UI);
806 }
807 }
808 }
Harald Welte93331e72020-09-12 20:51:05 +0200809#endif
Oliver Smithaac9b9c2019-09-02 08:36:36 +0200810
Harald Welte5ac31492018-02-15 20:39:13 +0100811 return dec;
812}
813
Alexander Couzens0e510e62018-07-28 23:06:00 +0200814function f_bssgp_client_register(hexstring imsi, OCT4 tlli, BssgpCellId cell_id, BSSGP_PROC_PT PT := BSSGP_PROC[0])
Harald Welte5ac31492018-02-15 20:39:13 +0100815runs on BSSGP_Client_CT {
816 PT.call(BSSGP_register_client:{imsi, tlli, cell_id}) {
817 [] PT.getreply(BSSGP_register_client:{imsi, tlli, cell_id}) {};
818 }
819}
820
Alexander Couzens0e510e62018-07-28 23:06:00 +0200821function f_bssgp_client_unregister(hexstring imsi, BSSGP_PROC_PT PT := BSSGP_PROC[0])
Harald Welte5ac31492018-02-15 20:39:13 +0100822runs on BSSGP_Client_CT {
823 PT.call(BSSGP_unregister_client:{imsi}) {
824 [] PT.getreply(BSSGP_unregister_client:{imsi}) {};
825 }
826}
827
Harald Weltef70997d2018-02-17 10:11:19 +0100828/* TS 44.064 7.2.1.1 LLGMM-ASSIGN */
Alexander Couzens0e510e62018-07-28 23:06:00 +0200829function f_bssgp_client_llgmm_assign(OCT4 tlli_old, OCT4 tlli_new, BSSGP_PROC_PT PT := BSSGP_PROC[0])
Harald Weltef70997d2018-02-17 10:11:19 +0100830runs on BSSGP_Client_CT {
831 PT.call(BSSGP_llgmm_assign:{tlli_old, tlli_new}) {
832 [] PT.getreply(BSSGP_llgmm_assign:{tlli_old, tlli_new}) {};
833 }
834}
835
Harald Welte5ac31492018-02-15 20:39:13 +0100836
Harald Welte1733a382017-07-23 17:26:17 +0200837}