blob: 0ed022aeb96df95437dcc3e32a7c37f148219d52 [file] [log] [blame]
Harald Welte34b5a952019-05-27 11:54:11 +02001/* GPRS-NS Emulation in TTCN-3
Harald Weltebe7afce2021-01-17 22:04:36 +01002 * (C) 2018-2021 Harald Welte <laforge@gnumonks.org>
Harald Welte34b5a952019-05-27 11:54:11 +02003 * contributions by sysmocom - s.f.m.c. GmbH
4 * All rights reserved.
5 *
6 * Released under the terms of GNU General Public License, Version 2 or
7 * (at your option) any later version.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
Harald Welte6fff3642017-07-22 21:36:13 +020012module NS_Emulation {
Harald Welte90f19742020-11-06 19:34:40 +010013 import from Misc_Helpers all;
Harald Welte6fff3642017-07-22 21:36:13 +020014 import from NS_Types all;
15 import from BSSGP_Types all;
Harald Welte867243a2020-09-13 18:32:32 +020016 import from Osmocom_Types all;
Harald Weltee0abc472018-02-05 09:13:31 +010017 import from Osmocom_Gb_Types all;
Harald Welte013d65a2020-09-13 14:41:31 +020018 import from NS_Provider_IPL4 all;
Harald Welte867243a2020-09-13 18:32:32 +020019#ifdef NS_EMULATION_FR
20 import from NS_Provider_FR all;
21#endif
Harald Welte6fff3642017-07-22 21:36:13 +020022 import from IPL4asp_Types all;
23
24 type record NsUnitdataRequest {
25 BssgpBvci bvci,
26 Nsei nsei,
Harald Weltec4505522020-11-11 18:55:09 +010027 integer lsp,
Harald Welte6e594f22017-07-23 16:19:35 +020028 octetstring sdu optional,
Harald Weltee0abc472018-02-05 09:13:31 +010029 PDU_BSSGP bssgp optional
Harald Welte6e594f22017-07-23 16:19:35 +020030 }
31
Harald Weltec4505522020-11-11 18:55:09 +010032 template NsUnitdataRequest tr_NsUdReq(template Nsei nsei, template BssgpBvci bvci, template integer lsp,
33 template octetstring sdu, template PDU_BSSGP bssgp) := {
Harald Welte90f19742020-11-06 19:34:40 +010034 bvci := bvci,
35 nsei := nsei,
Harald Weltec4505522020-11-11 18:55:09 +010036 lsp := lsp,
Harald Welte90f19742020-11-06 19:34:40 +010037 sdu := sdu,
38 bssgp := bssgp
39 }
40
41 template (value) NsUnitdataRequest ts_NsUdReq(template (value) Nsei nsei,
42 template (value) BssgpBvci bvci,
Harald Weltec4505522020-11-11 18:55:09 +010043 template (value) integer lsp,
Harald Welte90f19742020-11-06 19:34:40 +010044 template (omit) octetstring sdu,
45 template (omit) PDU_BSSGP bssgp) := {
Harald Welte6e594f22017-07-23 16:19:35 +020046 bvci := bvci,
47 nsei := nsei,
Harald Weltec4505522020-11-11 18:55:09 +010048 lsp := lsp,
Harald Welte6e594f22017-07-23 16:19:35 +020049 sdu := sdu,
50 bssgp := bssgp
Harald Welte6fff3642017-07-22 21:36:13 +020051 }
52
53 type record NsUnitdataIndication {
54 BssgpBvci bvci,
55 Nsei nsei,
Harald Welte80a249a2020-11-17 19:57:40 +010056 Nsvci nsvci,
Harald Welte6e594f22017-07-23 16:19:35 +020057 octetstring sdu optional,
Harald Weltee0abc472018-02-05 09:13:31 +010058 PDU_BSSGP bssgp optional
Harald Welte6e594f22017-07-23 16:19:35 +020059 }
60
Harald Welte90f19742020-11-06 19:34:40 +010061 template (present) NsUnitdataIndication tr_NsUdInd(template (present) Nsei nsei,
62 template (present) BssgpBvci bvci,
63 template octetstring sdu) := {
64 bvci := bvci,
65 nsei := nsei,
Harald Welte80a249a2020-11-17 19:57:40 +010066 nsvci := ?,
Harald Welte90f19742020-11-06 19:34:40 +010067 sdu := sdu,
68 bssgp := ?
69 }
70
Harald Welte80a249a2020-11-17 19:57:40 +010071 template (value) NsUnitdataIndication ts_NsUdInd(Nsei nsei, Nsvci nsvci, BssgpBvci bvci, octetstring sdu) := {
Harald Welte6e594f22017-07-23 16:19:35 +020072 bvci := bvci,
73 nsei := nsei,
Harald Welte80a249a2020-11-17 19:57:40 +010074 nsvci := nsvci,
Harald Welte6e594f22017-07-23 16:19:35 +020075 sdu := sdu,
Harald Weltee0abc472018-02-05 09:13:31 +010076 bssgp := dec_PDU_BSSGP(sdu)
Harald Welte6e594f22017-07-23 16:19:35 +020077 }
78
79 type record NsStatusIndication {
80 Nsei nsei,
81 Nsvci nsvci,
Harald Welte90f19742020-11-06 19:34:40 +010082 NsvcState old_state,
Harald Weltedc0a0902020-11-10 21:03:29 +010083 NsvcState new_state,
84 boolean first_or_last
Harald Welte6e594f22017-07-23 16:19:35 +020085 }
86
Harald Welte90f19742020-11-06 19:34:40 +010087 template (present) NsStatusIndication tr_NsStsInd(template (present) Nsei nsei := ?,
88 template (present) Nsvci nsvci := ?,
89 template (present) NsvcState old_state := ?,
Harald Weltedc0a0902020-11-10 21:03:29 +010090 template (present) NsvcState state := ?,
91 template (present) boolean first_or_last := ?) := {
Harald Welte6e594f22017-07-23 16:19:35 +020092 nsei := nsei,
93 nsvci := nsvci,
94 old_state := old_state,
Harald Weltedc0a0902020-11-10 21:03:29 +010095 new_state := state,
96 first_or_last := first_or_last
Harald Welte6fff3642017-07-22 21:36:13 +020097 }
98
Harald Welte90f19742020-11-06 19:34:40 +010099
Harald Weltedc0a0902020-11-10 21:03:29 +0100100 template (value) NsStatusIndication ts_NsStsInd(Nsei nsei, Nsvci nsvci, NsvcState old_state, NsvcState state,
101 boolean first_or_last := false) := {
Harald Welte90f19742020-11-06 19:34:40 +0100102 nsei := nsei,
103 nsvci := nsvci,
104 old_state := old_state,
Harald Weltedc0a0902020-11-10 21:03:29 +0100105 new_state := state,
106 first_or_last := first_or_last
Harald Welte90f19742020-11-06 19:34:40 +0100107 }
108
109 type enumerated NsvcState {
Harald Welte3f820892021-01-19 18:19:23 +0100110 NSVC_S_DISABLED, /* administratively disabled */
Harald Welte90f19742020-11-06 19:34:40 +0100111 NSVC_S_DEAD_BLOCKED,
112 NSVC_S_WAIT_RESET,
113 NSVC_S_ALIVE_BLOCKED,
114 NSVC_S_ALIVE_UNBLOCKED
Harald Welte6e594f22017-07-23 16:19:35 +0200115 }
Harald Welte6fff3642017-07-22 21:36:13 +0200116
117 /* port from our (internal) point of view */
118 type port NS_SP_PT message {
119 in NsUnitdataRequest;
120 out NsUnitdataIndication,
Harald Welte013d65a2020-09-13 14:41:31 +0200121 NsStatusIndication;
Harald Welte6fff3642017-07-22 21:36:13 +0200122 } with { extension "internal" };
123
124 /* port from the user point of view */
125 type port NS_PT message {
126 in ASP_Event,
Harald Welte6e594f22017-07-23 16:19:35 +0200127 NsStatusIndication,
Harald Welte6fff3642017-07-22 21:36:13 +0200128 NsUnitdataIndication;
129 out NsUnitdataRequest;
130 } with { extension "internal" };
131
Harald Welte3f820892021-01-19 18:19:23 +0100132 /* port from our (internal) point of view */
133 type port NS_CTRL_SP_PT message {
134 in NsDisableVcRequest,
135 NsEnableVcRequest;
136 } with { extension "internal" };
137
138 /* port from the user point of view */
139 type port NS_CTRL_PT message {
140 out NsEnableVcRequest,
141 NsDisableVcRequest;
142 } with { extension "internal" };
143
144 type record NsDisableVcRequest {
145 Nsvci nsvci
146 };
147 type record NsEnableVcRequest {
148 Nsvci nsvci
149 };
150
Harald Welte013d65a2020-09-13 14:41:31 +0200151 type component NS_Provider_CT {
152 /* upper port, facing to NS_Emulation:NSCP */
153 port NS_PROVIDER_PT NSE;
154 /* lower layer ports (UDP/IP, Frame Relay) are added in derived components */
155 };
156
Harald Weltebd612cd2020-09-14 09:42:28 +0200157 type enumerated NS_Provider_LinkStatus {
158 NS_PROV_LINK_STATUS_UP,
159 NS_PROV_LINK_STATUS_DOWN
160 };
161 type union NS_Provider_Evt {
162 NS_Provider_LinkStatus link_status
163 };
164
Harald Welte013d65a2020-09-13 14:41:31 +0200165 /* port between NS_Provider and NS_CT */
166 type port NS_PROVIDER_PT message {
Harald Weltebd612cd2020-09-14 09:42:28 +0200167 inout PDU_NS, NS_Provider_Evt;
Harald Welte013d65a2020-09-13 14:41:31 +0200168 } with { extension "internal" };
169
Harald Welte90f19742020-11-06 19:34:40 +0100170 type record NSVCConfigurationIP {
171 AddressFamily address_family,
172 PortNumber local_udp_port,
173 charstring local_ip,
174 PortNumber remote_udp_port,
Harald Weltebe7afce2021-01-17 22:04:36 +0100175 charstring remote_ip,
176 uint8_t data_weight,
177 uint8_t signalling_weight
Harald Welte90f19742020-11-06 19:34:40 +0100178 };
179 type record NSVCConfigurationFR {
180 charstring netdev, /* HDLC net-device for AF_PACKET socket */
181 integer dlci
182 };
183 type union NSVCConfigurationP {
184 NSVCConfigurationIP ip,
185 NSVCConfigurationFR fr
186 };
187 type record NSVCConfiguration {
188 NSVCConfigurationP provider,
189 Nsvci nsvci
190 };
191 type record of NSVCConfiguration NSVCConfigurations;
192 type record NSConfiguration {
193 Nsvci nsei,
194 boolean role_sgsn,
195 boolean handle_sns,
196 NSVCConfigurations nsvc
197 }
198
199 /***********************************************************************
200 * per NS-VCG component. Exists once per [peer of] NSE
201 ***********************************************************************/
202
Harald Welte6fff3642017-07-22 21:36:13 +0200203 type component NS_CT {
Harald Welte90f19742020-11-06 19:34:40 +0100204 /* NS-User SAP towards the user */
205 port NS_SP_PT NS_SP;
206
207 /* port towards the per-NSVC components */
Harald Welte1308dbb2021-01-18 18:19:38 +0100208 port NSint_PT NSVC;
Harald Welte90f19742020-11-06 19:34:40 +0100209
Harald Welte3f820892021-01-19 18:19:23 +0100210 /* control port, used to manipulate at runtime */
211 port NS_CTRL_SP_PT NS_CTRL;
212
Harald Welte90f19742020-11-06 19:34:40 +0100213 /* all of the NS configuration a user passes to us */
214 var NSConfiguration g_config;
215 var charstring g_id;
216
Harald Weltead320712021-03-29 21:56:48 +0200217 /* references to the endpoint provider components */
218 var IpEndpointTable g_ip_endpoints := {};
219 /* control port for NS-IP provider */
220 port NSPIP_PROC_PT NSPIP_PROC;
221
Harald Welte90f19742020-11-06 19:34:40 +0100222 /* references to the per-NSVC components */
223 var NsvcTable g_nsvcs := {};
Harald Weltec4505522020-11-11 18:55:09 +0100224 /* list of indexes to g_nsvcs[] of currently unblocked NSVCs */
Harald Welteaaa0dfd2021-02-04 16:58:53 +0100225 var Osmocom_Types.ro_integer g_unblocked_nsvcs_sig := {};
226 var Osmocom_Types.ro_integer g_unblocked_nsvcs_data := {};
Harald Welte90f19742020-11-06 19:34:40 +0100227 };
228 type record NsvcTableEntry {
Harald Weltebe7afce2021-01-17 22:04:36 +0100229 NSVCConfiguration cfg,
Harald Welte90f19742020-11-06 19:34:40 +0100230 NSVC_CT vc_conn,
231 NsvcState state
232 };
233 type record of NsvcTableEntry NsvcTable;
Harald Weltead320712021-03-29 21:56:48 +0200234 type record IpEndpointTableEntry {
235 /* configuration */
236 AddressFamily address_family,
237 PortNumber local_udp_port,
238 charstring local_ip,
239 uint8_t data_weight,
240 uint8_t signalling_weight,
241 /* state */
242 NS_Provider_IPL4_CT provider_ct
243 };
244 type record of IpEndpointTableEntry IpEndpointTable;
Harald Welte90f19742020-11-06 19:34:40 +0100245
Harald Welte1308dbb2021-01-18 18:19:38 +0100246 /* internal port from the NS-VC point of view */
247 type port NSint_SP_PT message {
248 in NsUnitdataRequest,
249 SnsRequest,
250 NsCtrlRequest;
251 out NsUnitdataIndication,
252 SnsIndication,
253 NsStatusIndication;
254 } with { extension "internal" };
255
256 /* internal port from the NS-VCG point of view */
257 type port NSint_PT message {
258 in ASP_Event,
259 NsStatusIndication,
260 SnsIndication,
261 NsUnitdataIndication;
262 out NsUnitdataRequest,
263 SnsRequest,
264 NsCtrlRequest;
265 } with { extension "internal" };
266
267 /* Used by NS-VC to report reception of a SNS PDU to NS-VCG */
268 type record SnsIndication {
269 Nsvci nsvci,
270 PDU_NS ns
271 };
272
273 /* Used by NS-VCG to request transmission of a SNS PDU via a NS-VC */
274 type record SnsRequest {
275 Nsvci nsvci,
276 PDU_NS ns
277 };
278
279 type enumerated NsCtrlRequest {
Harald Welte3f820892021-01-19 18:19:23 +0100280 StartAliveProcedure (0),
281 DisableReq (1), /* administratively disable NS-VC */
Harald Weltec5680002021-02-13 16:45:30 +0100282 EnableReq (2), /* administratively enable NS-VC */
283 ForceAliveState (3)
Harald Welte1308dbb2021-01-18 18:19:38 +0100284 };
285
Harald Weltead320712021-03-29 21:56:48 +0200286 function f_ipep_find(AddressFamily af, PortNumber local_udp_port, charstring local_ip,
287 out IpEndpointTableEntry ret)
288 runs on NS_CT return boolean {
289 var integer i;
290 for (i := 0; i < lengthof(g_ip_endpoints); i := i+1) {
291 var IpEndpointTableEntry ipep := g_ip_endpoints[i];
292 if (ipep.address_family == af and ipep.local_udp_port == local_udp_port and
293 ipep.local_ip == local_ip) {
294 ret := ipep;
295 return true;
296 }
297 }
298 return false
299 }
300
301 /* find or create IP endpoint component for [local part of] nsvc_cfg */
302 function f_ipep_find_or_create(NSVCConfiguration nsvc_cfg)
303 runs on NS_CT return NS_Provider_IPL4_CT {
304 var IpEndpointTableEntry ipep;
305 if (f_ipep_find(nsvc_cfg.provider.ip.address_family,
306 nsvc_cfg.provider.ip.local_udp_port,
307 nsvc_cfg.provider.ip.local_ip, ipep)) {
308 return ipep.provider_ct;
309 } else {
310 var charstring nsvc_id := g_id & "-NSVCI" & int2str(nsvc_cfg.nsvci);
311 ipep := {
312 address_family := nsvc_cfg.provider.ip.address_family,
313 local_udp_port := nsvc_cfg.provider.ip.local_udp_port,
314 local_ip := nsvc_cfg.provider.ip.local_ip,
315 data_weight := nsvc_cfg.provider.ip.data_weight,
316 signalling_weight := nsvc_cfg.provider.ip.signalling_weight,
317 provider_ct := -
318 };
319 /* Create ipep and add it to the list */
320 log("Creating NSIP provider for ", ipep.local_ip, ":",
321 ipep.local_udp_port);
Daniel Willmann09ed9942023-12-05 15:04:50 +0100322 ipep.provider_ct := NS_Provider_IPL4_CT.create(nsvc_id & "-provIP") alive;
Harald Weltead320712021-03-29 21:56:48 +0200323 connect(self:NSPIP_PROC, ipep.provider_ct:PROC);
324 ipep.provider_ct.start(NS_Provider_IPL4.main(nsvc_cfg, g_config, nsvc_id));
325 g_ip_endpoints := g_ip_endpoints & { ipep };
326 return ipep.provider_ct;
327 }
328 }
329
Harald Welte90f19742020-11-06 19:34:40 +0100330 /* add one NSVC (component and table entry */
331 function f_nsvc_add(NSVCConfiguration nsvc_cfg) runs on NS_CT {
332 var charstring nsvc_id := g_id & "-NSVCI" & int2str(nsvc_cfg.nsvci);
333 var NsvcTableEntry te;
Harald Weltead320712021-03-29 21:56:48 +0200334 var NS_Provider_IPL4_CT vc_ipep := null;
335
336 /* For the IP provider, we have one provider component per local endpoint,
337 * which we must create before adding the NSVcs (for each remote endpoint)
338 * to it */
339 if (ischosen(nsvc_cfg.provider.ip)) {
340 vc_ipep := f_ipep_find_or_create(nsvc_cfg);
341 }
342
343 /* Start the actual NSVC component */
Harald Welte90f19742020-11-06 19:34:40 +0100344
Harald Weltebe7afce2021-01-17 22:04:36 +0100345 te.cfg := nsvc_cfg;
Daniel Willmann09ed9942023-12-05 15:04:50 +0100346 te.vc_conn := NSVC_CT.create(nsvc_id) alive;
Harald Welte90f19742020-11-06 19:34:40 +0100347 te.state := NSVC_S_DEAD_BLOCKED;
348
349 connect(self:NSVC, te.vc_conn:NS_SP);
Harald Weltead320712021-03-29 21:56:48 +0200350 log("Starting NSVC component for ", nsvc_cfg);
351 te.vc_conn.start(NSVCStart(nsvc_cfg, g_config, nsvc_id, vc_ipep));
Harald Welte90f19742020-11-06 19:34:40 +0100352
353 g_nsvcs := g_nsvcs & { te };
Harald Weltec4505522020-11-11 18:55:09 +0100354 /* no need to add to g_unblocked_nsvcs, as state is always DEAD_BLOCKED above */
Harald Weltead320712021-03-29 21:56:48 +0200355
356 /* For the IP provider, we must explicitly associate each NSVC with it */
357 if (ischosen(nsvc_cfg.provider.ip)) {
358 /* this causes NS_Provider_IPL4.f_nsvc_add() to be executed */
359 f_nspip_add_nsvc(vc_ipep, nsvc_cfg.provider.ip.remote_ip,
360 nsvc_cfg.provider.ip.remote_udp_port, te.vc_conn);
361 }
Harald Welte90f19742020-11-06 19:34:40 +0100362 }
363
364 function f_nsvc_find_idx(Nsvci nsvci) runs on NS_CT return integer {
365 var integer i;
366 for (i := 0; i < lengthof(g_nsvcs); i := i+1) {
Harald Weltebe7afce2021-01-17 22:04:36 +0100367 if (g_nsvcs[i].cfg.nsvci == nsvci) {
Harald Welte90f19742020-11-06 19:34:40 +0100368 return i;
369 }
370 }
371 return -1;
372 }
373
374 function f_nsvc_find(Nsvci nsvci) runs on NS_CT return NSVC_CT {
375 var integer i := f_nsvc_find_idx(nsvci);
376 if (i < 0) {
377 return null;
378 } else {
379 return g_nsvcs[i].vc_conn;
380 }
381 }
382
383 function f_nsvc_update_state(Nsvci nsvci, NsvcState state) runs on NS_CT {
384 var integer i := f_nsvc_find_idx(nsvci);
385 if (i < 0) {
386 return;
387 }
Harald Weltec4505522020-11-11 18:55:09 +0100388 if (g_nsvcs[i].state != NSVC_S_ALIVE_UNBLOCKED and state == NSVC_S_ALIVE_UNBLOCKED) {
389 /* add index to list of unblocked NSVCs */
Harald Weltebe7afce2021-01-17 22:04:36 +0100390 if (not ischosen(g_nsvcs[i].cfg.provider.ip) or
391 g_nsvcs[i].cfg.provider.ip.signalling_weight > 0) {
Harald Weltedaf89682021-02-04 17:06:20 +0100392 ro_integer_add_unique(g_unblocked_nsvcs_sig, i);
Harald Weltebe7afce2021-01-17 22:04:36 +0100393 }
394 if (not ischosen(g_nsvcs[i].cfg.provider.ip) or
395 g_nsvcs[i].cfg.provider.ip.data_weight > 0) {
Harald Weltedaf89682021-02-04 17:06:20 +0100396 ro_integer_add_unique(g_unblocked_nsvcs_data, i);
Harald Weltebe7afce2021-01-17 22:04:36 +0100397 }
Harald Weltec4505522020-11-11 18:55:09 +0100398 } else if (g_nsvcs[i].state == NSVC_S_ALIVE_UNBLOCKED and state != NSVC_S_ALIVE_UNBLOCKED) {
399 /* remove index to list of unblocked NSVCs */
Harald Weltedaf89682021-02-04 17:06:20 +0100400 ro_integer_del(g_unblocked_nsvcs_sig, i);
401 ro_integer_del(g_unblocked_nsvcs_data, i);
Harald Weltec4505522020-11-11 18:55:09 +0100402 }
Harald Welte90f19742020-11-06 19:34:40 +0100403 g_nsvcs[i].state := state;
404 }
405
406 function NSStart(NSConfiguration init_config, charstring id := testcasename()) runs on NS_CT {
407 g_config := init_config;
408 g_id := id;
409
410 /* iterate over list of NS-VCs and start per-NSVC components */
411 for (var integer i := 0; i < lengthof(g_config.nsvc); i := i+1) {
412 var NSVCConfiguration nsvc_cfg := g_config.nsvc[i];
413 f_nsvc_add(nsvc_cfg);
414 }
415
Harald Weltea4abe202021-04-01 19:12:41 +0200416 if (g_config.handle_sns and not g_config.role_sgsn) {
417 f_sns_outbound_size_config();
418 }
Harald Welte90f19742020-11-06 19:34:40 +0100419 while (true) {
420 alt {
421 [] as_ns_common() {}
422 }
423 }
424 }
425
Harald Weltedc0a0902020-11-10 21:03:29 +0100426 function f_count_nsvcs_in_state(template NsvcState state := ?) runs on NS_CT return integer {
427 var integer i;
428 var integer res := 0;
429 for (i := 0; i < lengthof(g_nsvcs); i := i+1) {
430 if (match(g_nsvcs[i].state, state)) {
431 res := res + 1;
432 }
433 }
434 return res;
435 }
436
Harald Welte516c5c72021-02-13 16:43:58 +0100437 private altstep as_ns_common_status() runs on NS_CT {
Harald Welte90f19742020-11-06 19:34:40 +0100438 var NsStatusIndication rx_nssi;
Harald Weltedc0a0902020-11-10 21:03:29 +0100439 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, NSVC_S_ALIVE_UNBLOCKED)) -> value rx_nssi {
440 /* check if this one is the first to be unblocked */
441 var integer num_nsvc_unblocked := f_count_nsvcs_in_state(NSVC_S_ALIVE_UNBLOCKED);
442 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
443 if (num_nsvc_unblocked == 0) {
444 rx_nssi.first_or_last := true;
445 }
446 NS_SP.send(rx_nssi);
447 }
448 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, NSVC_S_DEAD_BLOCKED)) -> value rx_nssi {
449 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
450 /* check if this one is the last to be blocked */
451 var integer num_nsvc_unblocked := f_count_nsvcs_in_state(NSVC_S_ALIVE_UNBLOCKED);
452 if (num_nsvc_unblocked == 0) {
453 rx_nssi.first_or_last := true;
454 }
455 NS_SP.send(rx_nssi);
456 }
457 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, ?)) -> value rx_nssi {
Harald Welte90f19742020-11-06 19:34:40 +0100458 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
459 NS_SP.send(rx_nssi);
460 }
461 [] NSVC.receive(tr_NsStsInd) -> value rx_nssi {
462 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
463 log2str("Received NsStatusInd for invalid NSEI: ", rx_nssi));
464 }
Harald Welte516c5c72021-02-13 16:43:58 +0100465 }
466
467 private altstep as_ns_common() runs on NS_CT {
468 var NsUnitdataIndication rx_nsudi;
469 var NsUnitdataRequest rx_nsudr;
470 var NsDisableVcRequest rx_disar;
471 var NsEnableVcRequest rx_enar;
472 /* pass from NS-VCs up to user */
473 [] as_ns_common_status();
Harald Welte90f19742020-11-06 19:34:40 +0100474 [] NSVC.receive(tr_NsUdInd(g_config.nsei, ?, ?)) -> value rx_nsudi {
475 NS_SP.send(rx_nsudi);
476 }
Harald Welte1308dbb2021-01-18 18:19:38 +0100477
478 [g_config.handle_sns and g_config.role_sgsn] as_vcg_sns_sgsn();
Harald Weltea4abe202021-04-01 19:12:41 +0200479 [g_config.handle_sns and not g_config.role_sgsn] as_vcg_sns_pcu();
Harald Welte1308dbb2021-01-18 18:19:38 +0100480
Harald Welte90f19742020-11-06 19:34:40 +0100481 [] NSVC.receive(tr_NsUdInd(?, ?, ?)) -> value rx_nsudi {
482 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
483 log2str("Received UnitDataInd for invalid NSEI: ", rx_nsudi));
484 }
485 /* from user down to NS-VC */
Harald Welte3f820892021-01-19 18:19:23 +0100486 [] NS_CTRL.receive(NsDisableVcRequest:?) -> value rx_disar {
487 var integer nsvc_idx := f_nsvc_find_idx(rx_disar.nsvci);
488 NSVC.send(NsCtrlRequest:DisableReq) to g_nsvcs[nsvc_idx].vc_conn;
489 }
490 [] NS_CTRL.receive(NsEnableVcRequest:?) -> value rx_enar {
491 var integer nsvc_idx := f_nsvc_find_idx(rx_enar.nsvci);
492 NSVC.send(NsCtrlRequest:EnableReq) to g_nsvcs[nsvc_idx].vc_conn;
493 }
Harald Weltebe7afce2021-01-17 22:04:36 +0100494 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, 0, ?, ?, *)) -> value rx_nsudr {
Harald Weltec4505522020-11-11 18:55:09 +0100495 /* load distribution function */
Harald Weltebe7afce2021-01-17 22:04:36 +0100496 var integer nsvc_idx := g_unblocked_nsvcs_sig[rx_nsudr.lsp mod lengthof(g_unblocked_nsvcs_sig)];
Harald Weltec4505522020-11-11 18:55:09 +0100497 NSVC.send(rx_nsudr) to g_nsvcs[nsvc_idx].vc_conn;
Harald Welte90f19742020-11-06 19:34:40 +0100498 }
Harald Weltebe7afce2021-01-17 22:04:36 +0100499 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, ?, *)) -> value rx_nsudr {
500 /* load distribution function */
501 var integer nsvc_idx := g_unblocked_nsvcs_data[rx_nsudr.lsp mod lengthof(g_unblocked_nsvcs_data)];
502 NSVC.send(rx_nsudr) to g_nsvcs[nsvc_idx].vc_conn;
503 }
504
Harald Weltec4505522020-11-11 18:55:09 +0100505 [] NS_SP.receive(tr_NsUdReq(?, ?, ?, ?, *)) -> value rx_nsudr {
Harald Welte90f19742020-11-06 19:34:40 +0100506 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
507 log2str("Received NsUnitdataReq for invalid NSEI: ", rx_nsudr));
508 }
509 }
510
Harald Weltec771bfb2021-03-29 22:11:58 +0200511 /* generate a list of v4 + v6 endpoints based on the IpEndpointTable */
Harald Welte1308dbb2021-01-18 18:19:38 +0100512 private function gen_sns_ip_elems(out template (omit) IP4_Elements v4_out,
513 out template (omit) IP6_Elements v6_out) runs on NS_CT {
514 var integer i;
515 var IP4_Elements v4 := {};
516 var IP6_Elements v6 := {};
517
Harald Weltec771bfb2021-03-29 22:11:58 +0200518 for (i := 0; i < lengthof(g_ip_endpoints); i := i + 1) {
519 var IpEndpointTableEntry ipep := g_ip_endpoints[i];
520 if (ipep.address_family == AF_INET) {
521 v4 := v4 & { valueof(ts_SNS_IPv4(ipep.local_ip,
522 ipep.local_udp_port,
523 ipep.signalling_weight,
524 ipep.data_weight)) };
525 } else if (ipep.address_family == AF_INET6) {
526 v6 := v6 & { valueof(ts_SNS_IPv6(ipep.local_ip,
527 ipep.local_udp_port,
528 ipep.signalling_weight,
529 ipep.data_weight)) };
Harald Welte1308dbb2021-01-18 18:19:38 +0100530 }
531 }
532
533 /* we must not return empty lists, but 'omit' as otherwise we get wrong SNS IEs */
534 if (lengthof(v4) == 0) {
535 v4_out := omit;
536 } else {
537 v4_out := v4;
538 }
539 if (lengthof(v6) == 0) {
540 v6_out := omit;
541 } else {
542 v6_out := v6;
543 }
544 }
545
Harald Welte3bd182f2021-02-13 16:43:22 +0100546 private function f_broadcast_ns_ctrl(template (value) NsCtrlRequest req) runs on NS_CT {
547 for (var integer i := 0; i < lengthof(g_nsvcs); i := i+1) {
548 NSVC.send(req) to g_nsvcs[i].vc_conn;
549 }
550 }
551
Harald Weltea4abe202021-04-01 19:12:41 +0200552 /* perform an outbound SNS-SIZE + SNS-CONFIG */
553 private function f_sns_outbound_size_config(integer idx := 0) runs on NS_CT {
554 var NSVCConfiguration nsvc_cfg := g_config.nsvc[idx];
555 var NSVC_CT vc;
556
557 if (nsvc_cfg.provider.ip.address_family == AF_INET) {
558 NSVC.send(SnsRequest:{nsvc_cfg.nsvci, ts_SNS_SIZE(g_config.nsei, rst_flag := true,
559 max_nsvcs := 1,
560 num_v4 := 1, num_v6 := omit)});
561 } else {
562 NSVC.send(SnsRequest:{nsvc_cfg.nsvci, ts_SNS_SIZE(g_config.nsei, rst_flag := true,
563 max_nsvcs := 1,
564 num_v4 := omit, num_v6 := 1)});
565 }
566 /* expect SIZE-ACK */
567 alt {
568 [] NSVC.receive(SnsIndication:{?, tr_SNS_SIZE_ACK(g_config.nsei, omit)}) -> sender vc;
569 [] NSVC.receive(NsStatusIndication:?) { repeat; }
570 }
571 /* send a SNS-CONFIG in response and expect a SNS-CONFIG-ACK */
572 var template (omit) IP4_Elements v4;
573 var template (omit) IP6_Elements v6;
574 gen_sns_ip_elems(v4, v6);
575 NSVC.send(SnsRequest:{nsvc_cfg.nsvci,
576 ts_SNS_CONFIG(g_config.nsei, true, v4, v6)}) to vc;
577 alt {
578 [] as_ns_common_status() {
579 repeat;
580 }
581 [] NSVC.receive(SnsIndication:{?,
582 tr_SNS_CONFIG_ACK(g_config.nsei, omit)}) from vc {
583 /* success */
584 log("Outbound SNS Config succeeded.");
585 }
586 [] NSVC.receive(SnsIndication:{?,
587 tr_SNS_CONFIG_ACK(g_config.nsei, ?)}) from vc {
588 setverdict(fail, "Unexpected SNS-CONFIG-NACK");
589 self.stop;
590 }
591 }
592 }
593
594 /* simple IP Sub-Network Service responder for the PCU/BSS side. This is not a full implementation
595 * of the protocol, merely sufficient to make the SGSN side happy to proceed */
596 private altstep as_vcg_sns_pcu() runs on NS_CT {
597 var SnsIndication sind;
598 var NSVC_CT vc;
599
600 /* FIXME: We assume our peer has only one endpoint */
601 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(g_config.nsei, true,
602 {tr_SNS_IPv4(g_config.nsvc[0].provider.ip.remote_ip,
603 g_config.nsvc[0].provider.ip.remote_udp_port)})})
604 -> value sind sender vc {
605 /* blindly acknowledge whatever the SGSN sends */
606 NSVC.send(SnsRequest:{sind.nsvci, ts_SNS_CONFIG_ACK(g_config.nsei, omit)}) to vc;
607 log("Inbound SNS Config succeeded.");
608 /* switch to "alive" state already before sending the SNS-CONFIG, as otherwise
609 * there would be a race condition between internally performing the state change
610 * of all related NS-VCs and the first incoming NS-PDU after SNS-CONFIG-ACK */
611 f_broadcast_ns_ctrl(NsCtrlRequest:ForceAliveState);
612 /* inform all NS-VC that they are now considered alive */
613 f_broadcast_ns_ctrl(NsCtrlRequest:StartAliveProcedure);
614 }
615 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(g_config.nsei, false, ?)}) { /* ignore */}
616 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(g_config.nsei, true, ?)}) {
617 setverdict(fail, "Unexpected SNS-CONFIG content");
618 self.stop;
619 }
620 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(?, ?, ?)}) {
621 setverdict(fail, "SNS-CONFIG from unexpected NSEI");
622 self.stop;
623 }
624
625 }
626
Harald Welte1308dbb2021-01-18 18:19:38 +0100627 /* simple IP Sub-Network Service responder for the SGSN side. This is not a full implementation
628 * of the protocol, merely sufficient to make the PCU/BSS side happy to proceed */
629 private altstep as_vcg_sns_sgsn() runs on NS_CT {
630 var SnsIndication sind;
631 var NSVC_CT vc;
632 [] NSVC.receive(SnsIndication:{?, tr_SNS_SIZE(g_config.nsei)}) -> value sind sender vc {
633 /* blindly acknowledge whatever the PCU sends */
634 NSVC.send(SnsRequest:{sind.nsvci, ts_SNS_SIZE_ACK(g_config.nsei, omit)}) to vc;
635 }
636 /* FIXME: We assume our peer has only one endpoint */
637 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(g_config.nsei, true,
638 {tr_SNS_IPv4(g_config.nsvc[0].provider.ip.remote_ip,
639 g_config.nsvc[0].provider.ip.remote_udp_port)})})
640 -> value sind sender vc {
641 /* blindly acknowledge whatever the PCU sends */
642 NSVC.send(SnsRequest:{sind.nsvci, ts_SNS_CONFIG_ACK(g_config.nsei, omit)}) to vc;
Harald Weltec5680002021-02-13 16:45:30 +0100643 /* switch to "alive" state already before sending the SNS-CONFIG, as otherwise
644 * there would be a race condition between internally performing the state change
645 * of all related NS-VCs and the first incoming NS-PDU after SNS-CONFIG-ACK */
646 f_broadcast_ns_ctrl(NsCtrlRequest:ForceAliveState);
Harald Welte1308dbb2021-01-18 18:19:38 +0100647 /* send a SNS-CONFIG in response and expect a SNS-CONFIG-ACK */
648 var template (omit) IP4_Elements v4;
649 var template (omit) IP6_Elements v6;
650 gen_sns_ip_elems(v4, v6);
651 NSVC.send(SnsRequest:{sind.nsvci,
652 ts_SNS_CONFIG(g_config.nsei, true, v4, v6)}) to vc;
653 alt {
Harald Weltec5680002021-02-13 16:45:30 +0100654 [] as_ns_common_status() {
655 repeat;
656 }
Harald Welte1308dbb2021-01-18 18:19:38 +0100657 [] NSVC.receive(SnsIndication:{sind.nsvci,
658 tr_SNS_CONFIG_ACK(g_config.nsei, omit)}) from vc {
659 /* success */
660 log("SNS Config succeeded. Sending Alive");
661 /* inform all NS-VC that they are now considered alive */
Harald Welte3bd182f2021-02-13 16:43:22 +0100662 f_broadcast_ns_ctrl(NsCtrlRequest:StartAliveProcedure);
Harald Welte1308dbb2021-01-18 18:19:38 +0100663 }
664 [] NSVC.receive(SnsIndication:{sind.nsvci,
665 tr_SNS_CONFIG_ACK(g_config.nsei, ?)}) from vc {
666 setverdict(fail, "Unexpected SNS-CONFIG-NACK");
667 self.stop;
668 }
669 }
670 }
671 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(g_config.nsei, false, ?)}) { /* ignore */}
672 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(g_config.nsei, true, ?)}) {
673 setverdict(fail, "Unexpected SNS-CONFIG content");
674 self.stop;
675 }
676 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(?, ?, ?)}) {
677 setverdict(fail, "SNS-CONFIG from unexpected NSEI");
678 self.stop;
679 }
680 }
681
Harald Welte90f19742020-11-06 19:34:40 +0100682 /***********************************************************************
683 per-NSVC component. Exists once for each NS-VC in the NS-VCG
684 ***********************************************************************/
685
686 type component NSVC_CT {
Harald Welte6fff3642017-07-22 21:36:13 +0200687 /* UDP port towards the bottom (IUT) */
Harald Welte013d65a2020-09-13 14:41:31 +0200688 port NS_PROVIDER_PT NSCP;
689 var NS_Provider_IPL4_CT vc_NSP_IP;
Harald Welte867243a2020-09-13 18:32:32 +0200690#ifdef NS_EMULATION_FR
691 var NS_Provider_FR_CT vc_NSP_FR;
692#endif
Harald Welte013d65a2020-09-13 14:41:31 +0200693
Harald Welte90f19742020-11-06 19:34:40 +0100694 /* port towards the NS_CT */
Harald Welte1308dbb2021-01-18 18:19:38 +0100695 port NSint_SP_PT NS_SP;
Harald Welte6fff3642017-07-22 21:36:13 +0200696
Harald Welte90f19742020-11-06 19:34:40 +0100697 /* configuration passed by the user */
698 var NSVCConfiguration g_nsvc_config;
699 /* we cannot access the NS_CT.config and hence need to copy those */
700 var NSConfiguration g_config;
Alexander Couzens2c12b242018-07-31 00:30:11 +0200701
Harald Welte90f19742020-11-06 19:34:40 +0100702 var NsvcState vc_state := NSVC_S_DEAD_BLOCKED;
Harald Welte6e594f22017-07-23 16:19:35 +0200703
704 timer Tns_alive := 3.0;
705 timer Tns_test := 10.0;
706 timer Tns_block := 10.0;
Harald Welte3dd83552020-09-14 11:38:01 +0200707 timer Tns_reset := 10.0;
Harald Welte6fff3642017-07-22 21:36:13 +0200708 }
709
Harald Weltead320712021-03-29 21:56:48 +0200710 function NSVCStart(NSVCConfiguration init_config, NSConfiguration init_g_config, charstring id :=
711testcasename(), NS_Provider_IPL4_CT nsp_ip := null) runs on NSVC_CT {
Harald Welte90f19742020-11-06 19:34:40 +0100712 g_nsvc_config := init_config;
713 g_config := init_g_config;
Harald Weltead320712021-03-29 21:56:48 +0200714 f_init(id & "-NSVCemu" & int2str(g_nsvc_config.nsvci), nsp_ip);
Harald Welte90f19742020-11-06 19:34:40 +0100715 f_ScanEvents();
Alexander Couzens2c12b242018-07-31 00:30:11 +0200716 }
Harald Welte6fff3642017-07-22 21:36:13 +0200717
Harald Weltead320712021-03-29 21:56:48 +0200718 private function f_init(charstring id, NS_Provider_IPL4_CT nsp_ip) runs on NSVC_CT {
Harald Welte90f19742020-11-06 19:34:40 +0100719 if (ischosen(g_nsvc_config.provider.ip)) {
Harald Weltead320712021-03-29 21:56:48 +0200720 /* the provider already exists; we just associate with it */
721 vc_NSP_IP := nsp_ip
Harald Welte90f19742020-11-06 19:34:40 +0100722#ifdef NS_EMULATION_FR
723 } else if (ischosen(g_nsvc_config.provider.fr)) {
Daniel Willmann09ed9942023-12-05 15:04:50 +0100724 vc_NSP_FR := NS_Provider_FR_CT.create(id & "-provFR") alive;
Harald Welte90f19742020-11-06 19:34:40 +0100725 connect(self:NSCP, vc_NSP_FR:NSE);
726 vc_NSP_FR.start(NS_Provider_FR.main(g_nsvc_config, g_config, id));
727#endif
Harald Weltee15299a2020-11-17 17:30:09 +0100728 } else {
729 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unsupported NS provider");
Harald Welte90f19742020-11-06 19:34:40 +0100730 }
731
732 f_change_state(NSVC_S_DEAD_BLOCKED);
Harald Welte6fff3642017-07-22 21:36:13 +0200733 }
734
Harald Welte90f19742020-11-06 19:34:40 +0100735 private function f_change_state(NsvcState new_state) runs on NSVC_CT {
736 var NsvcState old_state := vc_state;
737 vc_state := new_state;
738 log("NSVC ", g_nsvc_config.nsvci, " State Transition: ", old_state, " -> ", new_state);
739 NS_SP.send(ts_NsStsInd(g_config.nsei, g_nsvc_config.nsvci, old_state, new_state));
740 }
741
742 private function f_sendReset() runs on NSVC_CT {
743 NSCP.send(ts_NS_RESET(NS_CAUSE_OM_INTERVENTION, g_nsvc_config.nsvci, g_config.nsei));
Harald Welte3dd83552020-09-14 11:38:01 +0200744 Tns_reset.start;
Harald Welte90f19742020-11-06 19:34:40 +0100745 vc_state := NSVC_S_WAIT_RESET;
Harald Welte6fff3642017-07-22 21:36:13 +0200746 }
747
Harald Welte90f19742020-11-06 19:34:40 +0100748 private function f_sendAlive() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200749 NSCP.send(t_NS_ALIVE);
Harald Welte6e594f22017-07-23 16:19:35 +0200750 Tns_alive.start;
751 }
752
Harald Welte90f19742020-11-06 19:34:40 +0100753 private function f_sendUnblock() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200754 NSCP.send(t_NS_UNBLOCK);
Harald Welte6e594f22017-07-23 16:19:35 +0200755 Tns_block.start;
756 }
757
Harald Welte90f19742020-11-06 19:34:40 +0100758 private function f_sendBlock(NsCause cause) runs on NSVC_CT {
759 NSCP.send(ts_NS_BLOCK(cause, g_nsvc_config.nsvci));
Harald Welte6e594f22017-07-23 16:19:35 +0200760 Tns_block.start;
761 }
762
Harald Welte90f19742020-11-06 19:34:40 +0100763 private altstep as_allstate() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200764 var PDU_NS rf;
Harald Welte6e594f22017-07-23 16:19:35 +0200765 var ASP_Event evt;
766
Harald Weltec0c67ff2021-02-03 19:26:30 +0100767 [] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_DOWN}) {
768 log("Provider Link went down");
769 Tns_test.stop;
770 Tns_alive.stop;
771 f_change_state(NSVC_S_DEAD_BLOCKED);
772 }
773
Harald Welte3f820892021-01-19 18:19:23 +0100774 [] NS_SP.receive(NsCtrlRequest:DisableReq) {
775 /* To make NS-VCG remove us from list of active NS-VC */
776 f_change_state(NSVC_S_DEAD_BLOCKED);
777 log("Disabling NSVC on user request");
778 f_change_state(NSVC_S_DISABLED);
779 Tns_test.stop;
780 Tns_alive.stop;
781 }
782
Harald Welte6e594f22017-07-23 16:19:35 +0200783 /* transition to DEAD if t_alive times out */
Pau Espin Pedrol1cbbf9e2024-01-30 11:15:48 +0100784 [Tns_alive.running] Tns_alive.timeout {
Harald Welte9a7c5122020-09-14 11:35:57 +0200785 log("Tns-alive expired: changing to DEAD_BLOCKED + starting Tns-test");
Harald Welte90f19742020-11-06 19:34:40 +0100786 f_change_state(NSVC_S_DEAD_BLOCKED);
Harald Welte6e594f22017-07-23 16:19:35 +0200787 Tns_test.start;
Harald Welte6fff3642017-07-22 21:36:13 +0200788 }
Harald Welte6fff3642017-07-22 21:36:13 +0200789
Pau Espin Pedrol1cbbf9e2024-01-30 11:15:48 +0100790 [Tns_test.running] Tns_test.timeout {
Harald Welte6e594f22017-07-23 16:19:35 +0200791 log("Tns-test expired: sending NS-ALIVE");
792 f_sendAlive();
Harald Welte6fff3642017-07-22 21:36:13 +0200793 }
Harald Welte6fff3642017-07-22 21:36:13 +0200794
Harald Welte6e594f22017-07-23 16:19:35 +0200795 /* Stop t_alive when receiving ALIVE-ACK */
Harald Welte9a7c5122020-09-14 11:35:57 +0200796 [Tns_alive.running] NSCP.receive(t_NS_ALIVE_ACK) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200797 log("Rx NS-ALIVE-ACK: stopping Tns-alive; starting Tns-test");
Harald Welte6e594f22017-07-23 16:19:35 +0200798 Tns_alive.stop;
799 Tns_test.start;
800 }
Harald Welte6fff3642017-07-22 21:36:13 +0200801
Harald Welte6e594f22017-07-23 16:19:35 +0200802 /* respond to NS-ALIVE with NS-ALIVE-ACK */
Harald Welte013d65a2020-09-13 14:41:31 +0200803 [] NSCP.receive(t_NS_ALIVE) {
804 NSCP.send(t_NS_ALIVE_ACK);
Harald Welte6e594f22017-07-23 16:19:35 +0200805 }
806
807 /* Respond to BLOCK for wrong NSVCI */
Harald Welte013d65a2020-09-13 14:41:31 +0200808 [] NSCP.receive(tr_NS_BLOCK(?, ?)) -> value rf {
Harald Welte6e594f22017-07-23 16:19:35 +0200809 log("Rx NS-BLOCK for unknown NSVCI");
810 /* FIXME */
811 }
812
Harald Welte90f19742020-11-06 19:34:40 +0100813 [not g_config.handle_sns] as_handle_reset();
Harald Welte6e594f22017-07-23 16:19:35 +0200814
Harald Welte1308dbb2021-01-18 18:19:38 +0100815 [g_config.handle_sns and ischosen(g_nsvc_config.provider.ip)] as_nsvc_sns();
Harald Welte5e514fa2018-07-05 00:01:45 +0200816
Harald Welte4998a092021-02-04 14:30:47 +0100817 /* log + ignore NS-STATUS; must not create another NS-STATUS in response */
818 [] NSCP.receive(tr_NS_STATUS(?)) -> value rf {
819 log("Rx NS-STATUS ", rf," in state ", vc_state);
820 }
Harald Welte6e594f22017-07-23 16:19:35 +0200821 /* default case of handling unknown PDUs */
Harald Welte013d65a2020-09-13 14:41:31 +0200822 [] NSCP.receive(PDU_NS: ?) -> value rf {
Harald Welte90f19742020-11-06 19:34:40 +0100823 log("Rx Unexpected NS PDU ", rf," in state ", vc_state);
Harald Welte013d65a2020-09-13 14:41:31 +0200824 NSCP.send(ts_NS_STATUS(NS_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, rf));
Harald Welte6e594f22017-07-23 16:19:35 +0200825 }
Harald Welte6fff3642017-07-22 21:36:13 +0200826 }
827
Harald Welte3f820892021-01-19 18:19:23 +0100828 private altstep as_disabled() runs on NSVC_CT {
829 [g_config.handle_sns == true] NS_SP.receive(NsCtrlRequest:EnableReq) {
830 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
831 f_sendAlive();
832 Tns_test.start;
833 }
834 [g_config.handle_sns == false] NS_SP.receive(NsCtrlRequest:EnableReq) {
835 f_change_state(NSVC_S_DEAD_BLOCKED);
836 Tns_test.start;
837 }
838 /* drop any received messages while in this state */
839 [] NSCP.receive {
840 log("Dropping inbound NS mesage as NS-VC is disabled");
841 }
842 [] NS_SP.receive {
843 log("Dropping user primitive as NS-VC is disabled");
844 }
845 }
846
Harald Welte90f19742020-11-06 19:34:40 +0100847 private altstep as_handle_reset() runs on NSVC_CT {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200848 var PDU_NS rf;
849
Harald Welte90f19742020-11-06 19:34:40 +0100850 [g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200851 log("Provider Link came up: waiting for NS-RESET");
852 }
853
Harald Welte90f19742020-11-06 19:34:40 +0100854 [not g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200855 log("Provider Link came up: sending NS-RESET");
856 f_sendReset();
857 }
858
859 /* Respond to RESET with correct NSEI/NSVCI */
Harald Welte90f19742020-11-06 19:34:40 +0100860 [] NSCP.receive(tr_NS_RESET(?, g_nsvc_config.nsvci, g_config.nsei)) -> value rf {
861 f_change_state(NSVC_S_ALIVE_BLOCKED);
862 NSCP.send(ts_NS_RESET_ACK(g_nsvc_config.nsvci, g_config.nsei));
Daniel Willmann654f85e2020-10-12 18:10:06 +0200863 log("Rx NS-RESET: Sending NS-ALIVE");
864 f_sendAlive();
865 Tns_test.start;
866 }
867
868 /* Respond to RESET with wrong NSEI/NSVCI */
869 [] NSCP.receive(tr_NS_RESET(?, ?, ?)) -> value rf {
870 log("Rx NS-RESET for unknown NSEI/NSVCI");
871 /* FIXME */
872 }
873 }
874
Harald Welte1308dbb2021-01-18 18:19:38 +0100875 private altstep as_nsvc_sns() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200876 var PDU_NS rf;
Harald Welte1308dbb2021-01-18 18:19:38 +0100877 var SnsRequest sreq;
Alexander Couzensd5338902020-12-21 18:41:21 +0100878 [] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
879 log("Provider Link came up. Waiting for SNS Size");
Harald Welte1308dbb2021-01-18 18:19:38 +0100880 }
Daniel Willmann654f85e2020-10-12 18:10:06 +0200881
Harald Welte1308dbb2021-01-18 18:19:38 +0100882 /* pass up to NS-VCG */
883 [] NSCP.receive(tr_SNS(g_config.nsei)) -> value rf {
884 NS_SP.send(SnsIndication:{g_nsvc_config.nsvci, rf});
Harald Welte5e514fa2018-07-05 00:01:45 +0200885 }
Harald Welte1308dbb2021-01-18 18:19:38 +0100886 [] NSCP.receive(tr_SNS(?)) -> value rf {
887 setverdict(fail, "SNS from unexpected NSEI: ", rf);
Harald Welte5e514fa2018-07-05 00:01:45 +0200888 self.stop;
889 }
Harald Welte1308dbb2021-01-18 18:19:38 +0100890 [] NS_SP.receive(SnsRequest:{g_nsvc_config.nsvci, ?}) -> value sreq {
891 NSCP.send(sreq.ns);
Harald Welte5e514fa2018-07-05 00:01:45 +0200892 }
Harald Welte1308dbb2021-01-18 18:19:38 +0100893 [] NS_SP.receive(SnsRequest:?) -> value sreq {
894 setverdict(fail, "Unexpected SNS from NSVC: ", sreq);
Harald Welte5e514fa2018-07-05 00:01:45 +0200895 self.stop;
896 }
Harald Weltec5680002021-02-13 16:45:30 +0100897 [] NS_SP.receive(NsCtrlRequest:ForceAliveState) {
Harald Welte1308dbb2021-01-18 18:19:38 +0100898 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Weltec5680002021-02-13 16:45:30 +0100899 }
900 [] NS_SP.receive(NsCtrlRequest:StartAliveProcedure) {
Harald Welte1308dbb2021-01-18 18:19:38 +0100901 f_sendAlive();
902 Tns_test.start;
Harald Welte5e514fa2018-07-05 00:01:45 +0200903 }
904 }
905
Harald Welte90f19742020-11-06 19:34:40 +0100906 private altstep as_alive_blocked() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200907 var PDU_NS rf;
908 /* bogus block, just respond with ACK */
Harald Welte90f19742020-11-06 19:34:40 +0100909 [] NSCP.receive(tr_NS_BLOCK(?, g_nsvc_config.nsvci)) -> value rf {
910 NSCP.send(ts_NS_BLOCK_ACK(g_nsvc_config.nsvci));
Harald Welte4a6a6632020-09-14 09:58:53 +0200911 }
912 /* Respond to UNBLOCK with UNBLOCK-ACK + change state */
913 [] NSCP.receive(t_NS_UNBLOCK) -> value rf {
914 NSCP.send(t_NS_UNBLOCK_ACK);
915 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100916 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200917 }
918 [] NSCP.receive(t_NS_UNBLOCK_ACK) -> value rf {
919 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100920 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200921 }
Harald Welteda9d9382020-12-07 15:53:57 +0100922 /* tolerate a late NS-BLOCK-ACK from peer */
923 [] NSCP.receive(tr_NS_BLOCK_ACK(g_nsvc_config.nsvci)) -> value rf {
924 }
Harald Welte4a6a6632020-09-14 09:58:53 +0200925 [] Tns_block.timeout {
926 /* repeat unblock transmission */
927 f_sendUnblock();
928 }
929 }
930
Harald Welte90f19742020-11-06 19:34:40 +0100931 private altstep as_alive_unblocked() runs on NSVC_CT {
Harald Welte6fff3642017-07-22 21:36:13 +0200932 var NsUnitdataRequest ud_req;
Harald Welte013d65a2020-09-13 14:41:31 +0200933 var PDU_NS rf;
Harald Welte4a6a6632020-09-14 09:58:53 +0200934 /* bogus unblock, just respond with ACK */
935 [] NSCP.receive(t_NS_UNBLOCK) -> value rf {
936 NSCP.send(t_NS_UNBLOCK_ACK);
937 }
938 /* Respond to BLOCK with BLOCK-ACK + change state */
Harald Welte90f19742020-11-06 19:34:40 +0100939 [] NSCP.receive(tr_NS_BLOCK(?, g_nsvc_config.nsvci)) -> value rf {
940 NSCP.send(ts_NS_BLOCK_ACK(g_nsvc_config.nsvci));
Harald Welte4a6a6632020-09-14 09:58:53 +0200941 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100942 f_change_state(NSVC_S_ALIVE_BLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200943 }
Harald Welte90f19742020-11-06 19:34:40 +0100944 [] NSCP.receive(tr_NS_BLOCK_ACK(g_nsvc_config.nsvci)) -> value rf {
Harald Welte4a6a6632020-09-14 09:58:53 +0200945 Tns_block.stop;
946 }
Harald Welteda9d9382020-12-07 15:53:57 +0100947 /* tolerate a late NS-UNBLOCK-ACK from peer */
948 [] NSCP.receive(t_NS_UNBLOCK_ACK) -> value rf {
949 }
Harald Weltebe7afce2021-01-17 22:04:36 +0100950
951 [not ischosen(g_nsvc_config.provider.ip) or
952 g_nsvc_config.provider.ip.data_weight > 0] as_alive_unblocked_data();
953
954 [not ischosen(g_nsvc_config.provider.ip) or
955 g_nsvc_config.provider.ip.signalling_weight > 0] as_alive_unblocked_sig();
956
957 /* catch any violations of above rule */
958 [ischosen(g_nsvc_config.provider.ip)] NSCP.receive(tr_NS_UNITDATA(?, ?, ?)) -> value rf {
959 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
960 log2str("Unexpected Rx NS-UNITDATA on NSVC with data_weight=",
961 g_nsvc_config.provider.ip.data_weight, ", sig_weight=",
962 g_nsvc_config.provider.ip.signalling_weight, ": ", rf));
963 }
964 [ischosen(g_nsvc_config.provider.ip)] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, *, *)) -> value ud_req {
965 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
966 log2str("Unexpected Rx TX-UNITDATA on NSVC with data_weight=",
967 g_nsvc_config.provider.ip.data_weight, ", sig_weight=",
968 g_nsvc_config.provider.ip.signalling_weight, ": ", ud_req));
969 }
970 }
971
972 /* user data transfer; only permitted for some NS-VC */
973 private altstep as_alive_unblocked_data() runs on NSVC_CT {
974 var NsUnitdataRequest ud_req;
975 var PDU_NS rf;
Harald Welte4a6a6632020-09-14 09:58:53 +0200976 /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */
Harald Weltebe7afce2021-01-17 22:04:36 +0100977 [] NSCP.receive(tr_NS_UNITDATA_User(?, ?)) -> value rf {
Harald Welte80a249a2020-11-17 19:57:40 +0100978 NS_SP.send(ts_NsUdInd(g_config.nsei, g_nsvc_config.nsvci,
Harald Welte4a6a6632020-09-14 09:58:53 +0200979 oct2int(rf.pDU_NS_Unitdata.bVCI),
980 rf.pDU_NS_Unitdata.nS_SDU));
981 }
982 /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */
Harald Weltebe7afce2021-01-17 22:04:36 +0100983 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, t_BssgpBvciUser, ?, ?, omit)) -> value ud_req {
Harald Welte4a6a6632020-09-14 09:58:53 +0200984 /* using raw octetstring PDU */
985 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu));
986 }
Harald Weltebe7afce2021-01-17 22:04:36 +0100987 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, t_BssgpBvciUser, ?, omit, ?)) -> value ud_req {
988 /* using decoded BSSGP PDU that we need to encode first */
989 var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp);
990 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc));
991 }
992 }
993
994 /* signalling (BVCI=0) transfer; only permitted for some NS-VC */
995 private altstep as_alive_unblocked_sig() runs on NSVC_CT {
996 var NsUnitdataRequest ud_req;
997 var PDU_NS rf;
998 /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */
999 [] NSCP.receive(tr_NS_UNITDATA(?, 0, ?)) -> value rf {
1000 NS_SP.send(ts_NsUdInd(g_config.nsei, g_nsvc_config.nsvci,
1001 oct2int(rf.pDU_NS_Unitdata.bVCI),
1002 rf.pDU_NS_Unitdata.nS_SDU));
1003 }
1004 /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */
1005 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, 0, ?, ?, omit)) -> value ud_req {
1006 /* using raw octetstring PDU */
1007 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu));
1008 }
1009 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, 0, ?, omit, ?)) -> value ud_req {
Harald Welte4a6a6632020-09-14 09:58:53 +02001010 /* using decoded BSSGP PDU that we need to encode first */
1011 var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp);
1012 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc));
1013 }
1014 }
Harald Welte6e594f22017-07-23 16:19:35 +02001015
Harald Welte90f19742020-11-06 19:34:40 +01001016 private altstep as_wait_reset() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +02001017 var PDU_NS rf;
Harald Welte3dd83552020-09-14 11:38:01 +02001018 [] Tns_reset.timeout {
1019 /* If the sending entity of an NS-RESET PDU receives no NS-RESET-ACK PDU before timer
1020 * Tns-reset expires the corresponding NS-VCs shall remain blocked and dead and the
1021 * entire reset procedure shall be repeated */
1022 f_sendReset();
1023 }
Harald Welte90f19742020-11-06 19:34:40 +01001024 [] NSCP.receive(tr_NS_RESET_ACK(g_nsvc_config.nsvci, g_config.nsei)) -> value rf {
Harald Welte3dd83552020-09-14 11:38:01 +02001025 Tns_reset.stop;
Harald Welte90f19742020-11-06 19:34:40 +01001026 f_change_state(NSVC_S_ALIVE_BLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +02001027 f_sendAlive();
1028 f_sendUnblock();
1029 }
1030 }
Harald Welte6fff3642017-07-22 21:36:13 +02001031
Harald Welte90f19742020-11-06 19:34:40 +01001032 private function f_ScanEvents() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +02001033 var PDU_NS rf;
Harald Welte6fff3642017-07-22 21:36:13 +02001034 while (true) {
Harald Welte6fff3642017-07-22 21:36:13 +02001035 alt {
Harald Welte90f19742020-11-06 19:34:40 +01001036 [vc_state == NSVC_S_WAIT_RESET] as_wait_reset();
1037 [vc_state == NSVC_S_ALIVE_BLOCKED] as_alive_blocked();
1038 [vc_state == NSVC_S_ALIVE_UNBLOCKED] as_alive_unblocked();
Harald Welte3f820892021-01-19 18:19:23 +01001039 [vc_state == NSVC_S_DISABLED] as_disabled();
1040 [vc_state != NSVC_S_DISABLED] as_allstate();
Harald Welte6fff3642017-07-22 21:36:13 +02001041 }
1042 }
Harald Welte6fff3642017-07-22 21:36:13 +02001043 }
1044}