blob: e28694588021560917adcc736d1d475861d9d66d [file] [log] [blame]
Harald Welte34b5a952019-05-27 11:54:11 +02001/* GPRS-NS Emulation in TTCN-3
Harald Welte013d65a2020-09-13 14:41:31 +02002 * (C) 2018-2020 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 Welte6e594f22017-07-23 16:19:35 +020027 octetstring sdu optional,
Harald Weltee0abc472018-02-05 09:13:31 +010028 PDU_BSSGP bssgp optional
Harald Welte6e594f22017-07-23 16:19:35 +020029 }
30
Harald Welte90f19742020-11-06 19:34:40 +010031 template NsUnitdataRequest tr_NsUdReq(template Nsei nsei, template BssgpBvci bvci, template octetstring sdu,
32 template PDU_BSSGP bssgp) := {
33 bvci := bvci,
34 nsei := nsei,
35 sdu := sdu,
36 bssgp := bssgp
37 }
38
39 template (value) NsUnitdataRequest ts_NsUdReq(template (value) Nsei nsei,
40 template (value) BssgpBvci bvci,
41 template (omit) octetstring sdu,
42 template (omit) PDU_BSSGP bssgp) := {
Harald Welte6e594f22017-07-23 16:19:35 +020043 bvci := bvci,
44 nsei := nsei,
45 sdu := sdu,
46 bssgp := bssgp
Harald Welte6fff3642017-07-22 21:36:13 +020047 }
48
49 type record NsUnitdataIndication {
50 BssgpBvci bvci,
51 Nsei nsei,
Harald Welte6e594f22017-07-23 16:19:35 +020052 octetstring sdu optional,
Harald Weltee0abc472018-02-05 09:13:31 +010053 PDU_BSSGP bssgp optional
Harald Welte6e594f22017-07-23 16:19:35 +020054 }
55
Harald Welte90f19742020-11-06 19:34:40 +010056 template (present) NsUnitdataIndication tr_NsUdInd(template (present) Nsei nsei,
57 template (present) BssgpBvci bvci,
58 template octetstring sdu) := {
59 bvci := bvci,
60 nsei := nsei,
61 sdu := sdu,
62 bssgp := ?
63 }
64
65 template (value) NsUnitdataIndication ts_NsUdInd(Nsei nsei, BssgpBvci bvci, octetstring sdu) := {
Harald Welte6e594f22017-07-23 16:19:35 +020066 bvci := bvci,
67 nsei := nsei,
68 sdu := sdu,
Harald Weltee0abc472018-02-05 09:13:31 +010069 bssgp := dec_PDU_BSSGP(sdu)
Harald Welte6e594f22017-07-23 16:19:35 +020070 }
71
72 type record NsStatusIndication {
73 Nsei nsei,
74 Nsvci nsvci,
Harald Welte90f19742020-11-06 19:34:40 +010075 NsvcState old_state,
76 NsvcState new_state
Harald Welte6e594f22017-07-23 16:19:35 +020077 }
78
Harald Welte90f19742020-11-06 19:34:40 +010079 template (present) NsStatusIndication tr_NsStsInd(template (present) Nsei nsei := ?,
80 template (present) Nsvci nsvci := ?,
81 template (present) NsvcState old_state := ?,
82 template (present) NsvcState state := ?) := {
Harald Welte6e594f22017-07-23 16:19:35 +020083 nsei := nsei,
84 nsvci := nsvci,
85 old_state := old_state,
86 new_state := state
Harald Welte6fff3642017-07-22 21:36:13 +020087 }
88
Harald Welte90f19742020-11-06 19:34:40 +010089
90 template (value) NsStatusIndication ts_NsStsInd(Nsei nsei, Nsvci nsvci, NsvcState old_state, NsvcState state) := {
91 nsei := nsei,
92 nsvci := nsvci,
93 old_state := old_state,
94 new_state := state
95 }
96
97 type enumerated NsvcState {
98 NSVC_S_DEAD_BLOCKED,
99 NSVC_S_WAIT_RESET,
100 NSVC_S_ALIVE_BLOCKED,
101 NSVC_S_ALIVE_UNBLOCKED
Harald Welte6e594f22017-07-23 16:19:35 +0200102 }
Harald Welte6fff3642017-07-22 21:36:13 +0200103
104 /* port from our (internal) point of view */
105 type port NS_SP_PT message {
106 in NsUnitdataRequest;
107 out NsUnitdataIndication,
Harald Welte013d65a2020-09-13 14:41:31 +0200108 NsStatusIndication;
Harald Welte6fff3642017-07-22 21:36:13 +0200109 } with { extension "internal" };
110
111 /* port from the user point of view */
112 type port NS_PT message {
113 in ASP_Event,
Harald Welte6e594f22017-07-23 16:19:35 +0200114 NsStatusIndication,
Harald Welte6fff3642017-07-22 21:36:13 +0200115 NsUnitdataIndication;
116 out NsUnitdataRequest;
117 } with { extension "internal" };
118
Harald Welte013d65a2020-09-13 14:41:31 +0200119 type component NS_Provider_CT {
120 /* upper port, facing to NS_Emulation:NSCP */
121 port NS_PROVIDER_PT NSE;
122 /* lower layer ports (UDP/IP, Frame Relay) are added in derived components */
123 };
124
Harald Weltebd612cd2020-09-14 09:42:28 +0200125 type enumerated NS_Provider_LinkStatus {
126 NS_PROV_LINK_STATUS_UP,
127 NS_PROV_LINK_STATUS_DOWN
128 };
129 type union NS_Provider_Evt {
130 NS_Provider_LinkStatus link_status
131 };
132
Harald Welte013d65a2020-09-13 14:41:31 +0200133 /* port between NS_Provider and NS_CT */
134 type port NS_PROVIDER_PT message {
Harald Weltebd612cd2020-09-14 09:42:28 +0200135 inout PDU_NS, NS_Provider_Evt;
Harald Welte013d65a2020-09-13 14:41:31 +0200136 } with { extension "internal" };
137
Harald Welte90f19742020-11-06 19:34:40 +0100138 type record NSVCConfigurationIP {
139 AddressFamily address_family,
140 PortNumber local_udp_port,
141 charstring local_ip,
142 PortNumber remote_udp_port,
143 charstring remote_ip
144 };
145 type record NSVCConfigurationFR {
146 charstring netdev, /* HDLC net-device for AF_PACKET socket */
147 integer dlci
148 };
149 type union NSVCConfigurationP {
150 NSVCConfigurationIP ip,
151 NSVCConfigurationFR fr
152 };
153 type record NSVCConfiguration {
154 NSVCConfigurationP provider,
155 Nsvci nsvci
156 };
157 type record of NSVCConfiguration NSVCConfigurations;
158 type record NSConfiguration {
159 Nsvci nsei,
160 boolean role_sgsn,
161 boolean handle_sns,
162 NSVCConfigurations nsvc
163 }
164
165 /***********************************************************************
166 * per NS-VCG component. Exists once per [peer of] NSE
167 ***********************************************************************/
168
Harald Welte6fff3642017-07-22 21:36:13 +0200169 type component NS_CT {
Harald Welte90f19742020-11-06 19:34:40 +0100170 /* NS-User SAP towards the user */
171 port NS_SP_PT NS_SP;
172
173 /* port towards the per-NSVC components */
174 port NS_PT NSVC;
175
176 /* all of the NS configuration a user passes to us */
177 var NSConfiguration g_config;
178 var charstring g_id;
179
180 /* references to the per-NSVC components */
181 var NsvcTable g_nsvcs := {};
182
183 };
184 type record NsvcTableEntry {
185 Nsvci nsvci,
186 NSVC_CT vc_conn,
187 NsvcState state
188 };
189 type record of NsvcTableEntry NsvcTable;
190
191 /* add one NSVC (component and table entry */
192 function f_nsvc_add(NSVCConfiguration nsvc_cfg) runs on NS_CT {
193 var charstring nsvc_id := g_id & "-NSVCI" & int2str(nsvc_cfg.nsvci);
194 var NsvcTableEntry te;
195
196 te.nsvci := nsvc_cfg.nsvci;
197 te.vc_conn := NSVC_CT.create(nsvc_id);
198 te.state := NSVC_S_DEAD_BLOCKED;
199
200 connect(self:NSVC, te.vc_conn:NS_SP);
201 te.vc_conn.start(NSVCStart(nsvc_cfg, g_config, nsvc_id));
202
203 g_nsvcs := g_nsvcs & { te };
204 }
205
206 function f_nsvc_find_idx(Nsvci nsvci) runs on NS_CT return integer {
207 var integer i;
208 for (i := 0; i < lengthof(g_nsvcs); i := i+1) {
209 if (g_nsvcs[i].nsvci == nsvci) {
210 return i;
211 }
212 }
213 return -1;
214 }
215
216 function f_nsvc_find(Nsvci nsvci) runs on NS_CT return NSVC_CT {
217 var integer i := f_nsvc_find_idx(nsvci);
218 if (i < 0) {
219 return null;
220 } else {
221 return g_nsvcs[i].vc_conn;
222 }
223 }
224
225 function f_nsvc_update_state(Nsvci nsvci, NsvcState state) runs on NS_CT {
226 var integer i := f_nsvc_find_idx(nsvci);
227 if (i < 0) {
228 return;
229 }
230 g_nsvcs[i].state := state;
231 }
232
233 function NSStart(NSConfiguration init_config, charstring id := testcasename()) runs on NS_CT {
234 g_config := init_config;
235 g_id := id;
236
237 /* iterate over list of NS-VCs and start per-NSVC components */
238 for (var integer i := 0; i < lengthof(g_config.nsvc); i := i+1) {
239 var NSVCConfiguration nsvc_cfg := g_config.nsvc[i];
240 f_nsvc_add(nsvc_cfg);
241 }
242
243 while (true) {
244 alt {
245 [] as_ns_common() {}
246 }
247 }
248 }
249
250 private altstep as_ns_common() runs on NS_CT {
251 var NsStatusIndication rx_nssi;
252 var NsUnitdataIndication rx_nsudi;
253 var NsUnitdataRequest rx_nsudr;
254 /* pass from NS-VCs up to user */
255 [] NSVC.receive(tr_NsStsInd(g_config.nsei)) -> value rx_nssi {
256 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
257 NS_SP.send(rx_nssi);
258 }
259 [] NSVC.receive(tr_NsStsInd) -> value rx_nssi {
260 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
261 log2str("Received NsStatusInd for invalid NSEI: ", rx_nssi));
262 }
263 [] NSVC.receive(tr_NsUdInd(g_config.nsei, ?, ?)) -> value rx_nsudi {
264 NS_SP.send(rx_nsudi);
265 }
266 [] NSVC.receive(tr_NsUdInd(?, ?, ?)) -> value rx_nsudi {
267 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
268 log2str("Received UnitDataInd for invalid NSEI: ", rx_nsudi));
269 }
270 /* from user down to NS-VC */
271 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, *)) -> value rx_nsudr {
272 /* FIXME: load distribution function */
273 NSVC.send(rx_nsudr) to g_nsvcs[0].vc_conn;
274 }
275 [] NS_SP.receive(tr_NsUdReq(?, ?, ?, *)) -> value rx_nsudr {
276 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
277 log2str("Received NsUnitdataReq for invalid NSEI: ", rx_nsudr));
278 }
279 }
280
281 /***********************************************************************
282 per-NSVC component. Exists once for each NS-VC in the NS-VCG
283 ***********************************************************************/
284
285 type component NSVC_CT {
Harald Welte6fff3642017-07-22 21:36:13 +0200286 /* UDP port towards the bottom (IUT) */
Harald Welte013d65a2020-09-13 14:41:31 +0200287 port NS_PROVIDER_PT NSCP;
288 var NS_Provider_IPL4_CT vc_NSP_IP;
Harald Welte867243a2020-09-13 18:32:32 +0200289#ifdef NS_EMULATION_FR
290 var NS_Provider_FR_CT vc_NSP_FR;
291#endif
Harald Welte013d65a2020-09-13 14:41:31 +0200292
Harald Welte90f19742020-11-06 19:34:40 +0100293 /* port towards the NS_CT */
Harald Welte6fff3642017-07-22 21:36:13 +0200294 port NS_SP_PT NS_SP;
295
Harald Welte90f19742020-11-06 19:34:40 +0100296 /* configuration passed by the user */
297 var NSVCConfiguration g_nsvc_config;
298 /* we cannot access the NS_CT.config and hence need to copy those */
299 var NSConfiguration g_config;
Alexander Couzens2c12b242018-07-31 00:30:11 +0200300
Harald Welte90f19742020-11-06 19:34:40 +0100301 var NsvcState vc_state := NSVC_S_DEAD_BLOCKED;
Harald Welte6e594f22017-07-23 16:19:35 +0200302
303 timer Tns_alive := 3.0;
304 timer Tns_test := 10.0;
305 timer Tns_block := 10.0;
Harald Welte3dd83552020-09-14 11:38:01 +0200306 timer Tns_reset := 10.0;
Harald Welte6fff3642017-07-22 21:36:13 +0200307 }
308
Harald Welte90f19742020-11-06 19:34:40 +0100309 function NSVCStart(NSVCConfiguration init_config, NSConfiguration init_g_config, charstring id := testcasename()) runs on NSVC_CT {
310 g_nsvc_config := init_config;
311 g_config := init_g_config;
312 f_init(id & "-NSVCemu" & int2str(g_nsvc_config.nsvci));
313 f_ScanEvents();
Alexander Couzens2c12b242018-07-31 00:30:11 +0200314 }
Harald Welte6fff3642017-07-22 21:36:13 +0200315
Harald Welte90f19742020-11-06 19:34:40 +0100316 private function f_init(charstring id) runs on NSVC_CT {
317 var Result res;
318
319 if (ischosen(g_nsvc_config.provider.ip)) {
320 /* Connect the UDP socket */
321 vc_NSP_IP := NS_Provider_IPL4_CT.create(id & "-provIP");
322 connect(self:NSCP, vc_NSP_IP:NSE);
323 vc_NSP_IP.start(NS_Provider_IPL4.main(g_nsvc_config, g_config, id));
324#ifdef NS_EMULATION_FR
325 } else if (ischosen(g_nsvc_config.provider.fr)) {
326 vc_NSP_FR := NS_Provider_FR_CT.create(id & "-provFR");
327 connect(self:NSCP, vc_NSP_FR:NSE);
328 vc_NSP_FR.start(NS_Provider_FR.main(g_nsvc_config, g_config, id));
329#endif
330 }
331
332 f_change_state(NSVC_S_DEAD_BLOCKED);
Harald Welte6fff3642017-07-22 21:36:13 +0200333 }
334
Harald Welte90f19742020-11-06 19:34:40 +0100335 private function f_change_state(NsvcState new_state) runs on NSVC_CT {
336 var NsvcState old_state := vc_state;
337 vc_state := new_state;
338 log("NSVC ", g_nsvc_config.nsvci, " State Transition: ", old_state, " -> ", new_state);
339 NS_SP.send(ts_NsStsInd(g_config.nsei, g_nsvc_config.nsvci, old_state, new_state));
340 }
341
342 private function f_sendReset() runs on NSVC_CT {
343 NSCP.send(ts_NS_RESET(NS_CAUSE_OM_INTERVENTION, g_nsvc_config.nsvci, g_config.nsei));
Harald Welte3dd83552020-09-14 11:38:01 +0200344 Tns_reset.start;
Harald Welte90f19742020-11-06 19:34:40 +0100345 vc_state := NSVC_S_WAIT_RESET;
Harald Welte6fff3642017-07-22 21:36:13 +0200346 }
347
Harald Welte90f19742020-11-06 19:34:40 +0100348 private function f_sendAlive() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200349 NSCP.send(t_NS_ALIVE);
Harald Welte6e594f22017-07-23 16:19:35 +0200350 Tns_alive.start;
351 }
352
Harald Welte90f19742020-11-06 19:34:40 +0100353 private function f_sendUnblock() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200354 NSCP.send(t_NS_UNBLOCK);
Harald Welte6e594f22017-07-23 16:19:35 +0200355 Tns_block.start;
356 }
357
Harald Welte90f19742020-11-06 19:34:40 +0100358 private function f_sendBlock(NsCause cause) runs on NSVC_CT {
359 NSCP.send(ts_NS_BLOCK(cause, g_nsvc_config.nsvci));
Harald Welte6e594f22017-07-23 16:19:35 +0200360 Tns_block.start;
361 }
362
Harald Welte90f19742020-11-06 19:34:40 +0100363 private altstep as_allstate() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200364 var PDU_NS rf;
Harald Welte6e594f22017-07-23 16:19:35 +0200365 var ASP_Event evt;
366
367 /* transition to DEAD if t_alive times out */
Harald Welte9a7c5122020-09-14 11:35:57 +0200368 [] Tns_alive.timeout {
369 log("Tns-alive expired: changing to DEAD_BLOCKED + starting Tns-test");
Harald Welte90f19742020-11-06 19:34:40 +0100370 f_change_state(NSVC_S_DEAD_BLOCKED);
Harald Welte6e594f22017-07-23 16:19:35 +0200371 Tns_test.start;
Harald Welte6fff3642017-07-22 21:36:13 +0200372 }
Harald Welte6fff3642017-07-22 21:36:13 +0200373
Harald Welte9a7c5122020-09-14 11:35:57 +0200374 [] Tns_test.timeout {
Harald Welte6e594f22017-07-23 16:19:35 +0200375 log("Tns-test expired: sending NS-ALIVE");
376 f_sendAlive();
Harald Welte6fff3642017-07-22 21:36:13 +0200377 }
Harald Welte6fff3642017-07-22 21:36:13 +0200378
Harald Welte6e594f22017-07-23 16:19:35 +0200379 /* Stop t_alive when receiving ALIVE-ACK */
Harald Welte9a7c5122020-09-14 11:35:57 +0200380 [Tns_alive.running] NSCP.receive(t_NS_ALIVE_ACK) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200381 log("Rx NS-ALIVE-ACK: stopping Tns-alive; starting Tns-test");
Harald Welte6e594f22017-07-23 16:19:35 +0200382 Tns_alive.stop;
383 Tns_test.start;
384 }
Harald Welte6fff3642017-07-22 21:36:13 +0200385
Harald Welte6e594f22017-07-23 16:19:35 +0200386 /* respond to NS-ALIVE with NS-ALIVE-ACK */
Harald Welte013d65a2020-09-13 14:41:31 +0200387 [] NSCP.receive(t_NS_ALIVE) {
388 NSCP.send(t_NS_ALIVE_ACK);
Harald Welte6e594f22017-07-23 16:19:35 +0200389 }
390
391 /* Respond to BLOCK for wrong NSVCI */
Harald Welte013d65a2020-09-13 14:41:31 +0200392 [] NSCP.receive(tr_NS_BLOCK(?, ?)) -> value rf {
Harald Welte6e594f22017-07-23 16:19:35 +0200393 log("Rx NS-BLOCK for unknown NSVCI");
394 /* FIXME */
395 }
396
Harald Welte90f19742020-11-06 19:34:40 +0100397 [not g_config.handle_sns] as_handle_reset();
Harald Welte6e594f22017-07-23 16:19:35 +0200398
Harald Welte90f19742020-11-06 19:34:40 +0100399 [g_config.role_sgsn and g_config.handle_sns and ischosen(g_nsvc_config.provider.ip)] as_sns_sgsn();
Harald Welte5e514fa2018-07-05 00:01:45 +0200400
Harald Welte6e594f22017-07-23 16:19:35 +0200401 /* default case of handling unknown PDUs */
Harald Welte013d65a2020-09-13 14:41:31 +0200402 [] NSCP.receive(PDU_NS: ?) -> value rf {
Harald Welte90f19742020-11-06 19:34:40 +0100403 log("Rx Unexpected NS PDU ", rf," in state ", vc_state);
Harald Welte013d65a2020-09-13 14:41:31 +0200404 NSCP.send(ts_NS_STATUS(NS_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, rf));
Harald Welte6e594f22017-07-23 16:19:35 +0200405 }
Harald Welte6fff3642017-07-22 21:36:13 +0200406 }
407
Harald Welte90f19742020-11-06 19:34:40 +0100408 private altstep as_handle_reset() runs on NSVC_CT {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200409 var PDU_NS rf;
410
Harald Welte90f19742020-11-06 19:34:40 +0100411 [g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200412 log("Provider Link came up: waiting for NS-RESET");
413 }
414
Harald Welte90f19742020-11-06 19:34:40 +0100415 [not g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200416 log("Provider Link came up: sending NS-RESET");
417 f_sendReset();
418 }
419
420 /* Respond to RESET with correct NSEI/NSVCI */
Harald Welte90f19742020-11-06 19:34:40 +0100421 [] NSCP.receive(tr_NS_RESET(?, g_nsvc_config.nsvci, g_config.nsei)) -> value rf {
422 f_change_state(NSVC_S_ALIVE_BLOCKED);
423 NSCP.send(ts_NS_RESET_ACK(g_nsvc_config.nsvci, g_config.nsei));
Daniel Willmann654f85e2020-10-12 18:10:06 +0200424 log("Rx NS-RESET: Sending NS-ALIVE");
425 f_sendAlive();
426 Tns_test.start;
427 }
428
429 /* Respond to RESET with wrong NSEI/NSVCI */
430 [] NSCP.receive(tr_NS_RESET(?, ?, ?)) -> value rf {
431 log("Rx NS-RESET for unknown NSEI/NSVCI");
432 /* FIXME */
433 }
434 }
435
Harald Welte5e514fa2018-07-05 00:01:45 +0200436 /* simple IP Sub-Network Service responder for the SGSN side. This is not a full implementation
437 * of the protocol, merely sufficient to make the PCU/BSS side happy to proceed */
Harald Welte90f19742020-11-06 19:34:40 +0100438 private altstep as_sns_sgsn() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200439 var PDU_NS rf;
Harald Welte90f19742020-11-06 19:34:40 +0100440 [g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200441 log("Provider Link came up: sending NS-ALIVE");
442 f_sendAlive();
443 }
444
Harald Welte90f19742020-11-06 19:34:40 +0100445 [not g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200446 log("Provider Link came up: sending NS-ALIVE");
447 f_sendAlive();
448 }
449
Harald Welte90f19742020-11-06 19:34:40 +0100450 [] NSCP.receive(tr_SNS_SIZE(g_config.nsei)) -> value rf {
Harald Welte5e514fa2018-07-05 00:01:45 +0200451 /* blindly acknowledge whatever the PCU sends */
Harald Welte90f19742020-11-06 19:34:40 +0100452 NSCP.send(ts_SNS_SIZE_ACK(g_config.nsei, omit));
Harald Welte5e514fa2018-07-05 00:01:45 +0200453 }
Harald Welte013d65a2020-09-13 14:41:31 +0200454 [] NSCP.receive(tr_SNS_SIZE(?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200455 setverdict(fail, "SNS-SIZE from unexpected NSEI");
456 self.stop;
457 }
Harald Welte90f19742020-11-06 19:34:40 +0100458 [] NSCP.receive(tr_SNS_CONFIG(g_config.nsei, true,
459 {tr_SNS_IPv4(g_nsvc_config.provider.ip.remote_ip,
460 g_nsvc_config.provider.ip.remote_udp_port)})) -> value rf {
Harald Welte5e514fa2018-07-05 00:01:45 +0200461 /* blindly acknowledge whatever the PCU sends */
Harald Welte90f19742020-11-06 19:34:40 +0100462 NSCP.send(ts_SNS_CONFIG_ACK(g_config.nsei, omit));
Harald Welte5e514fa2018-07-05 00:01:45 +0200463 /* send a SNS-CONFIG in response and expect a SNS-CONFIG-ACK */
Harald Welte90f19742020-11-06 19:34:40 +0100464 var IP4_Elements v4 := { valueof(ts_SNS_IPv4(g_nsvc_config.provider.ip.local_ip,
465 g_nsvc_config.provider.ip.local_udp_port)) };
466 NSCP.send(ts_SNS_CONFIG(g_config.nsei, true, v4));
Harald Welte5e514fa2018-07-05 00:01:45 +0200467 alt {
Harald Welte90f19742020-11-06 19:34:40 +0100468 [] NSCP.receive(tr_SNS_CONFIG_ACK(g_config.nsei, omit)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200469 /* success */
470 }
Harald Welte90f19742020-11-06 19:34:40 +0100471 [] NSCP.receive(tr_SNS_CONFIG_ACK(g_config.nsei, ?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200472 setverdict(fail, "Unexpected SNS-CONFIG-NACK");
473 self.stop;
474 }
475 }
476 }
Harald Welte90f19742020-11-06 19:34:40 +0100477 [] NSCP.receive(tr_SNS_CONFIG(g_config.nsei, false, ?)) { /* ignore */}
478 [] NSCP.receive(tr_SNS_CONFIG(g_config.nsei, true, ?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200479 setverdict(fail, "Unexpected SNS-CONFIG content");
480 self.stop;
481 }
Harald Welte013d65a2020-09-13 14:41:31 +0200482 [] NSCP.receive(tr_SNS_CONFIG(?, ?, ?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200483 setverdict(fail, "SNS-CONFIG from unexpected NSEI");
484 self.stop;
485 }
486 }
487
Harald Welte90f19742020-11-06 19:34:40 +0100488 private altstep as_alive_blocked() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200489 var PDU_NS rf;
490 /* bogus block, just respond with ACK */
Harald Welte90f19742020-11-06 19:34:40 +0100491 [] NSCP.receive(tr_NS_BLOCK(?, g_nsvc_config.nsvci)) -> value rf {
492 NSCP.send(ts_NS_BLOCK_ACK(g_nsvc_config.nsvci));
Harald Welte4a6a6632020-09-14 09:58:53 +0200493 }
494 /* Respond to UNBLOCK with UNBLOCK-ACK + change state */
495 [] NSCP.receive(t_NS_UNBLOCK) -> value rf {
496 NSCP.send(t_NS_UNBLOCK_ACK);
497 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100498 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200499 }
500 [] NSCP.receive(t_NS_UNBLOCK_ACK) -> value rf {
501 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100502 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200503 }
504 [] Tns_block.timeout {
505 /* repeat unblock transmission */
506 f_sendUnblock();
507 }
508 }
509
Harald Welte90f19742020-11-06 19:34:40 +0100510 private altstep as_alive_unblocked() runs on NSVC_CT {
Harald Welte6fff3642017-07-22 21:36:13 +0200511 var NsUnitdataRequest ud_req;
Harald Welte013d65a2020-09-13 14:41:31 +0200512 var PDU_NS rf;
Harald Welte4a6a6632020-09-14 09:58:53 +0200513 /* bogus unblock, just respond with ACK */
514 [] NSCP.receive(t_NS_UNBLOCK) -> value rf {
515 NSCP.send(t_NS_UNBLOCK_ACK);
516 }
517 /* Respond to BLOCK with BLOCK-ACK + change state */
Harald Welte90f19742020-11-06 19:34:40 +0100518 [] NSCP.receive(tr_NS_BLOCK(?, g_nsvc_config.nsvci)) -> value rf {
519 NSCP.send(ts_NS_BLOCK_ACK(g_nsvc_config.nsvci));
Harald Welte4a6a6632020-09-14 09:58:53 +0200520 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100521 f_change_state(NSVC_S_ALIVE_BLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200522 }
Harald Welte90f19742020-11-06 19:34:40 +0100523 [] NSCP.receive(tr_NS_BLOCK_ACK(g_nsvc_config.nsvci)) -> value rf {
Harald Welte4a6a6632020-09-14 09:58:53 +0200524 Tns_block.stop;
525 }
526 /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */
527 [] NSCP.receive(tr_NS_UNITDATA(?, ?, ?)) -> value rf {
Harald Welte90f19742020-11-06 19:34:40 +0100528 NS_SP.send(ts_NsUdInd(g_config.nsei,
Harald Welte4a6a6632020-09-14 09:58:53 +0200529 oct2int(rf.pDU_NS_Unitdata.bVCI),
530 rf.pDU_NS_Unitdata.nS_SDU));
531 }
532 /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */
Harald Welte90f19742020-11-06 19:34:40 +0100533 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, omit)) -> value ud_req {
Harald Welte4a6a6632020-09-14 09:58:53 +0200534 /* using raw octetstring PDU */
535 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu));
536 }
Harald Welte90f19742020-11-06 19:34:40 +0100537 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, omit, ?)) -> value ud_req {
Harald Welte4a6a6632020-09-14 09:58:53 +0200538 /* using decoded BSSGP PDU that we need to encode first */
539 var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp);
540 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc));
541 }
542 }
Harald Welte6e594f22017-07-23 16:19:35 +0200543
Harald Welte90f19742020-11-06 19:34:40 +0100544 private altstep as_wait_reset() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200545 var PDU_NS rf;
Harald Welte3dd83552020-09-14 11:38:01 +0200546 [] Tns_reset.timeout {
547 /* If the sending entity of an NS-RESET PDU receives no NS-RESET-ACK PDU before timer
548 * Tns-reset expires the corresponding NS-VCs shall remain blocked and dead and the
549 * entire reset procedure shall be repeated */
550 f_sendReset();
551 }
Harald Welte90f19742020-11-06 19:34:40 +0100552 [] NSCP.receive(tr_NS_RESET_ACK(g_nsvc_config.nsvci, g_config.nsei)) -> value rf {
Harald Welte3dd83552020-09-14 11:38:01 +0200553 Tns_reset.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100554 f_change_state(NSVC_S_ALIVE_BLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200555 f_sendAlive();
556 f_sendUnblock();
557 }
558 }
Harald Welte6fff3642017-07-22 21:36:13 +0200559
Harald Welte90f19742020-11-06 19:34:40 +0100560 private function f_ScanEvents() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200561 var PDU_NS rf;
Harald Welte6fff3642017-07-22 21:36:13 +0200562 while (true) {
Harald Welte6fff3642017-07-22 21:36:13 +0200563 alt {
Harald Welte90f19742020-11-06 19:34:40 +0100564 [vc_state == NSVC_S_WAIT_RESET] as_wait_reset();
565 [vc_state == NSVC_S_ALIVE_BLOCKED] as_alive_blocked();
566 [vc_state == NSVC_S_ALIVE_UNBLOCKED] as_alive_unblocked();
Harald Welte4a6a6632020-09-14 09:58:53 +0200567 [] as_allstate();
Harald Welte6fff3642017-07-22 21:36:13 +0200568 }
569 }
Harald Welte6fff3642017-07-22 21:36:13 +0200570 }
571}