blob: 2e038802c9bb29c791dd01e4bf0091c1fb17aa4c [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 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 Welte6e594f22017-07-23 16:19:35 +020056 octetstring sdu optional,
Harald Weltee0abc472018-02-05 09:13:31 +010057 PDU_BSSGP bssgp optional
Harald Welte6e594f22017-07-23 16:19:35 +020058 }
59
Harald Welte90f19742020-11-06 19:34:40 +010060 template (present) NsUnitdataIndication tr_NsUdInd(template (present) Nsei nsei,
61 template (present) BssgpBvci bvci,
62 template octetstring sdu) := {
63 bvci := bvci,
64 nsei := nsei,
65 sdu := sdu,
66 bssgp := ?
67 }
68
69 template (value) NsUnitdataIndication ts_NsUdInd(Nsei nsei, BssgpBvci bvci, octetstring sdu) := {
Harald Welte6e594f22017-07-23 16:19:35 +020070 bvci := bvci,
71 nsei := nsei,
72 sdu := sdu,
Harald Weltee0abc472018-02-05 09:13:31 +010073 bssgp := dec_PDU_BSSGP(sdu)
Harald Welte6e594f22017-07-23 16:19:35 +020074 }
75
76 type record NsStatusIndication {
77 Nsei nsei,
78 Nsvci nsvci,
Harald Welte90f19742020-11-06 19:34:40 +010079 NsvcState old_state,
Harald Weltedc0a0902020-11-10 21:03:29 +010080 NsvcState new_state,
81 boolean first_or_last
Harald Welte6e594f22017-07-23 16:19:35 +020082 }
83
Harald Welte90f19742020-11-06 19:34:40 +010084 template (present) NsStatusIndication tr_NsStsInd(template (present) Nsei nsei := ?,
85 template (present) Nsvci nsvci := ?,
86 template (present) NsvcState old_state := ?,
Harald Weltedc0a0902020-11-10 21:03:29 +010087 template (present) NsvcState state := ?,
88 template (present) boolean first_or_last := ?) := {
Harald Welte6e594f22017-07-23 16:19:35 +020089 nsei := nsei,
90 nsvci := nsvci,
91 old_state := old_state,
Harald Weltedc0a0902020-11-10 21:03:29 +010092 new_state := state,
93 first_or_last := first_or_last
Harald Welte6fff3642017-07-22 21:36:13 +020094 }
95
Harald Welte90f19742020-11-06 19:34:40 +010096
Harald Weltedc0a0902020-11-10 21:03:29 +010097 template (value) NsStatusIndication ts_NsStsInd(Nsei nsei, Nsvci nsvci, NsvcState old_state, NsvcState state,
98 boolean first_or_last := false) := {
Harald Welte90f19742020-11-06 19:34:40 +010099 nsei := nsei,
100 nsvci := nsvci,
101 old_state := old_state,
Harald Weltedc0a0902020-11-10 21:03:29 +0100102 new_state := state,
103 first_or_last := first_or_last
Harald Welte90f19742020-11-06 19:34:40 +0100104 }
105
106 type enumerated NsvcState {
107 NSVC_S_DEAD_BLOCKED,
108 NSVC_S_WAIT_RESET,
109 NSVC_S_ALIVE_BLOCKED,
110 NSVC_S_ALIVE_UNBLOCKED
Harald Welte6e594f22017-07-23 16:19:35 +0200111 }
Harald Welte6fff3642017-07-22 21:36:13 +0200112
113 /* port from our (internal) point of view */
114 type port NS_SP_PT message {
115 in NsUnitdataRequest;
116 out NsUnitdataIndication,
Harald Welte013d65a2020-09-13 14:41:31 +0200117 NsStatusIndication;
Harald Welte6fff3642017-07-22 21:36:13 +0200118 } with { extension "internal" };
119
120 /* port from the user point of view */
121 type port NS_PT message {
122 in ASP_Event,
Harald Welte6e594f22017-07-23 16:19:35 +0200123 NsStatusIndication,
Harald Welte6fff3642017-07-22 21:36:13 +0200124 NsUnitdataIndication;
125 out NsUnitdataRequest;
126 } with { extension "internal" };
127
Harald Welte013d65a2020-09-13 14:41:31 +0200128 type component NS_Provider_CT {
129 /* upper port, facing to NS_Emulation:NSCP */
130 port NS_PROVIDER_PT NSE;
131 /* lower layer ports (UDP/IP, Frame Relay) are added in derived components */
132 };
133
Harald Weltebd612cd2020-09-14 09:42:28 +0200134 type enumerated NS_Provider_LinkStatus {
135 NS_PROV_LINK_STATUS_UP,
136 NS_PROV_LINK_STATUS_DOWN
137 };
138 type union NS_Provider_Evt {
139 NS_Provider_LinkStatus link_status
140 };
141
Harald Welte013d65a2020-09-13 14:41:31 +0200142 /* port between NS_Provider and NS_CT */
143 type port NS_PROVIDER_PT message {
Harald Weltebd612cd2020-09-14 09:42:28 +0200144 inout PDU_NS, NS_Provider_Evt;
Harald Welte013d65a2020-09-13 14:41:31 +0200145 } with { extension "internal" };
146
Harald Welte90f19742020-11-06 19:34:40 +0100147 type record NSVCConfigurationIP {
148 AddressFamily address_family,
149 PortNumber local_udp_port,
150 charstring local_ip,
151 PortNumber remote_udp_port,
152 charstring remote_ip
153 };
154 type record NSVCConfigurationFR {
155 charstring netdev, /* HDLC net-device for AF_PACKET socket */
156 integer dlci
157 };
158 type union NSVCConfigurationP {
159 NSVCConfigurationIP ip,
160 NSVCConfigurationFR fr
161 };
162 type record NSVCConfiguration {
163 NSVCConfigurationP provider,
164 Nsvci nsvci
165 };
166 type record of NSVCConfiguration NSVCConfigurations;
167 type record NSConfiguration {
168 Nsvci nsei,
169 boolean role_sgsn,
170 boolean handle_sns,
171 NSVCConfigurations nsvc
172 }
173
174 /***********************************************************************
175 * per NS-VCG component. Exists once per [peer of] NSE
176 ***********************************************************************/
177
Harald Welte6fff3642017-07-22 21:36:13 +0200178 type component NS_CT {
Harald Welte90f19742020-11-06 19:34:40 +0100179 /* NS-User SAP towards the user */
180 port NS_SP_PT NS_SP;
181
182 /* port towards the per-NSVC components */
183 port NS_PT NSVC;
184
185 /* all of the NS configuration a user passes to us */
186 var NSConfiguration g_config;
187 var charstring g_id;
188
189 /* references to the per-NSVC components */
190 var NsvcTable g_nsvcs := {};
Harald Weltec4505522020-11-11 18:55:09 +0100191 /* list of indexes to g_nsvcs[] of currently unblocked NSVCs */
192 var ro_integer g_unblocked_nsvcs := {};
Harald Welte90f19742020-11-06 19:34:40 +0100193 };
194 type record NsvcTableEntry {
195 Nsvci nsvci,
196 NSVC_CT vc_conn,
197 NsvcState state
198 };
199 type record of NsvcTableEntry NsvcTable;
Harald Weltec4505522020-11-11 18:55:09 +0100200 type record of integer ro_integer;
Harald Welte90f19742020-11-06 19:34:40 +0100201
202 /* add one NSVC (component and table entry */
203 function f_nsvc_add(NSVCConfiguration nsvc_cfg) runs on NS_CT {
204 var charstring nsvc_id := g_id & "-NSVCI" & int2str(nsvc_cfg.nsvci);
205 var NsvcTableEntry te;
206
207 te.nsvci := nsvc_cfg.nsvci;
208 te.vc_conn := NSVC_CT.create(nsvc_id);
209 te.state := NSVC_S_DEAD_BLOCKED;
210
211 connect(self:NSVC, te.vc_conn:NS_SP);
212 te.vc_conn.start(NSVCStart(nsvc_cfg, g_config, nsvc_id));
213
214 g_nsvcs := g_nsvcs & { te };
Harald Weltec4505522020-11-11 18:55:09 +0100215 /* no need to add to g_unblocked_nsvcs, as state is always DEAD_BLOCKED above */
Harald Welte90f19742020-11-06 19:34:40 +0100216 }
217
218 function f_nsvc_find_idx(Nsvci nsvci) runs on NS_CT return integer {
219 var integer i;
220 for (i := 0; i < lengthof(g_nsvcs); i := i+1) {
221 if (g_nsvcs[i].nsvci == nsvci) {
222 return i;
223 }
224 }
225 return -1;
226 }
227
228 function f_nsvc_find(Nsvci nsvci) runs on NS_CT return NSVC_CT {
229 var integer i := f_nsvc_find_idx(nsvci);
230 if (i < 0) {
231 return null;
232 } else {
233 return g_nsvcs[i].vc_conn;
234 }
235 }
236
237 function f_nsvc_update_state(Nsvci nsvci, NsvcState state) runs on NS_CT {
238 var integer i := f_nsvc_find_idx(nsvci);
239 if (i < 0) {
240 return;
241 }
Harald Weltec4505522020-11-11 18:55:09 +0100242 if (g_nsvcs[i].state != NSVC_S_ALIVE_UNBLOCKED and state == NSVC_S_ALIVE_UNBLOCKED) {
243 /* add index to list of unblocked NSVCs */
244 g_unblocked_nsvcs := g_unblocked_nsvcs & {i};
245 } else if (g_nsvcs[i].state == NSVC_S_ALIVE_UNBLOCKED and state != NSVC_S_ALIVE_UNBLOCKED) {
246 /* remove index to list of unblocked NSVCs */
247 var ro_integer new_unblocked_nsvcs := {};
248 for (var integer j := 0; j < lengthof(g_unblocked_nsvcs); j := j+1) {
249 if (g_unblocked_nsvcs[j] != i) {
250 new_unblocked_nsvcs := new_unblocked_nsvcs & {j};
251 }
252 }
253 g_unblocked_nsvcs := new_unblocked_nsvcs;
254 }
Harald Welte90f19742020-11-06 19:34:40 +0100255 g_nsvcs[i].state := state;
256 }
257
258 function NSStart(NSConfiguration init_config, charstring id := testcasename()) runs on NS_CT {
259 g_config := init_config;
260 g_id := id;
261
262 /* iterate over list of NS-VCs and start per-NSVC components */
263 for (var integer i := 0; i < lengthof(g_config.nsvc); i := i+1) {
264 var NSVCConfiguration nsvc_cfg := g_config.nsvc[i];
265 f_nsvc_add(nsvc_cfg);
266 }
267
268 while (true) {
269 alt {
270 [] as_ns_common() {}
271 }
272 }
273 }
274
Harald Weltedc0a0902020-11-10 21:03:29 +0100275 function f_count_nsvcs_in_state(template NsvcState state := ?) runs on NS_CT return integer {
276 var integer i;
277 var integer res := 0;
278 for (i := 0; i < lengthof(g_nsvcs); i := i+1) {
279 if (match(g_nsvcs[i].state, state)) {
280 res := res + 1;
281 }
282 }
283 return res;
284 }
285
Harald Welte90f19742020-11-06 19:34:40 +0100286 private altstep as_ns_common() runs on NS_CT {
287 var NsStatusIndication rx_nssi;
288 var NsUnitdataIndication rx_nsudi;
289 var NsUnitdataRequest rx_nsudr;
290 /* pass from NS-VCs up to user */
Harald Weltedc0a0902020-11-10 21:03:29 +0100291 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, NSVC_S_ALIVE_UNBLOCKED)) -> value rx_nssi {
292 /* check if this one is the first to be unblocked */
293 var integer num_nsvc_unblocked := f_count_nsvcs_in_state(NSVC_S_ALIVE_UNBLOCKED);
294 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
295 if (num_nsvc_unblocked == 0) {
296 rx_nssi.first_or_last := true;
297 }
298 NS_SP.send(rx_nssi);
299 }
300 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, NSVC_S_DEAD_BLOCKED)) -> value rx_nssi {
301 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
302 /* check if this one is the last to be blocked */
303 var integer num_nsvc_unblocked := f_count_nsvcs_in_state(NSVC_S_ALIVE_UNBLOCKED);
304 if (num_nsvc_unblocked == 0) {
305 rx_nssi.first_or_last := true;
306 }
307 NS_SP.send(rx_nssi);
308 }
309 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, ?)) -> value rx_nssi {
Harald Welte90f19742020-11-06 19:34:40 +0100310 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
311 NS_SP.send(rx_nssi);
312 }
313 [] NSVC.receive(tr_NsStsInd) -> value rx_nssi {
314 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
315 log2str("Received NsStatusInd for invalid NSEI: ", rx_nssi));
316 }
317 [] NSVC.receive(tr_NsUdInd(g_config.nsei, ?, ?)) -> value rx_nsudi {
318 NS_SP.send(rx_nsudi);
319 }
320 [] NSVC.receive(tr_NsUdInd(?, ?, ?)) -> value rx_nsudi {
321 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
322 log2str("Received UnitDataInd for invalid NSEI: ", rx_nsudi));
323 }
324 /* from user down to NS-VC */
Harald Weltec4505522020-11-11 18:55:09 +0100325 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, ?, *)) -> value rx_nsudr {
326 /* load distribution function */
327 var integer nsvc_idx := g_unblocked_nsvcs[rx_nsudr.lsp mod lengthof(g_unblocked_nsvcs)];
328 NSVC.send(rx_nsudr) to g_nsvcs[nsvc_idx].vc_conn;
Harald Welte90f19742020-11-06 19:34:40 +0100329 }
Harald Weltec4505522020-11-11 18:55:09 +0100330 [] NS_SP.receive(tr_NsUdReq(?, ?, ?, ?, *)) -> value rx_nsudr {
Harald Welte90f19742020-11-06 19:34:40 +0100331 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
332 log2str("Received NsUnitdataReq for invalid NSEI: ", rx_nsudr));
333 }
334 }
335
336 /***********************************************************************
337 per-NSVC component. Exists once for each NS-VC in the NS-VCG
338 ***********************************************************************/
339
340 type component NSVC_CT {
Harald Welte6fff3642017-07-22 21:36:13 +0200341 /* UDP port towards the bottom (IUT) */
Harald Welte013d65a2020-09-13 14:41:31 +0200342 port NS_PROVIDER_PT NSCP;
343 var NS_Provider_IPL4_CT vc_NSP_IP;
Harald Welte867243a2020-09-13 18:32:32 +0200344#ifdef NS_EMULATION_FR
345 var NS_Provider_FR_CT vc_NSP_FR;
346#endif
Harald Welte013d65a2020-09-13 14:41:31 +0200347
Harald Welte90f19742020-11-06 19:34:40 +0100348 /* port towards the NS_CT */
Harald Welte6fff3642017-07-22 21:36:13 +0200349 port NS_SP_PT NS_SP;
350
Harald Welte90f19742020-11-06 19:34:40 +0100351 /* configuration passed by the user */
352 var NSVCConfiguration g_nsvc_config;
353 /* we cannot access the NS_CT.config and hence need to copy those */
354 var NSConfiguration g_config;
Alexander Couzens2c12b242018-07-31 00:30:11 +0200355
Harald Welte90f19742020-11-06 19:34:40 +0100356 var NsvcState vc_state := NSVC_S_DEAD_BLOCKED;
Harald Welte6e594f22017-07-23 16:19:35 +0200357
358 timer Tns_alive := 3.0;
359 timer Tns_test := 10.0;
360 timer Tns_block := 10.0;
Harald Welte3dd83552020-09-14 11:38:01 +0200361 timer Tns_reset := 10.0;
Harald Welte6fff3642017-07-22 21:36:13 +0200362 }
363
Harald Welte90f19742020-11-06 19:34:40 +0100364 function NSVCStart(NSVCConfiguration init_config, NSConfiguration init_g_config, charstring id := testcasename()) runs on NSVC_CT {
365 g_nsvc_config := init_config;
366 g_config := init_g_config;
367 f_init(id & "-NSVCemu" & int2str(g_nsvc_config.nsvci));
368 f_ScanEvents();
Alexander Couzens2c12b242018-07-31 00:30:11 +0200369 }
Harald Welte6fff3642017-07-22 21:36:13 +0200370
Harald Welte90f19742020-11-06 19:34:40 +0100371 private function f_init(charstring id) runs on NSVC_CT {
372 var Result res;
373
374 if (ischosen(g_nsvc_config.provider.ip)) {
375 /* Connect the UDP socket */
376 vc_NSP_IP := NS_Provider_IPL4_CT.create(id & "-provIP");
377 connect(self:NSCP, vc_NSP_IP:NSE);
378 vc_NSP_IP.start(NS_Provider_IPL4.main(g_nsvc_config, g_config, id));
379#ifdef NS_EMULATION_FR
380 } else if (ischosen(g_nsvc_config.provider.fr)) {
381 vc_NSP_FR := NS_Provider_FR_CT.create(id & "-provFR");
382 connect(self:NSCP, vc_NSP_FR:NSE);
383 vc_NSP_FR.start(NS_Provider_FR.main(g_nsvc_config, g_config, id));
384#endif
Harald Weltee15299a2020-11-17 17:30:09 +0100385 } else {
386 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unsupported NS provider");
Harald Welte90f19742020-11-06 19:34:40 +0100387 }
388
389 f_change_state(NSVC_S_DEAD_BLOCKED);
Harald Welte6fff3642017-07-22 21:36:13 +0200390 }
391
Harald Welte90f19742020-11-06 19:34:40 +0100392 private function f_change_state(NsvcState new_state) runs on NSVC_CT {
393 var NsvcState old_state := vc_state;
394 vc_state := new_state;
395 log("NSVC ", g_nsvc_config.nsvci, " State Transition: ", old_state, " -> ", new_state);
396 NS_SP.send(ts_NsStsInd(g_config.nsei, g_nsvc_config.nsvci, old_state, new_state));
397 }
398
399 private function f_sendReset() runs on NSVC_CT {
400 NSCP.send(ts_NS_RESET(NS_CAUSE_OM_INTERVENTION, g_nsvc_config.nsvci, g_config.nsei));
Harald Welte3dd83552020-09-14 11:38:01 +0200401 Tns_reset.start;
Harald Welte90f19742020-11-06 19:34:40 +0100402 vc_state := NSVC_S_WAIT_RESET;
Harald Welte6fff3642017-07-22 21:36:13 +0200403 }
404
Harald Welte90f19742020-11-06 19:34:40 +0100405 private function f_sendAlive() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200406 NSCP.send(t_NS_ALIVE);
Harald Welte6e594f22017-07-23 16:19:35 +0200407 Tns_alive.start;
408 }
409
Harald Welte90f19742020-11-06 19:34:40 +0100410 private function f_sendUnblock() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200411 NSCP.send(t_NS_UNBLOCK);
Harald Welte6e594f22017-07-23 16:19:35 +0200412 Tns_block.start;
413 }
414
Harald Welte90f19742020-11-06 19:34:40 +0100415 private function f_sendBlock(NsCause cause) runs on NSVC_CT {
416 NSCP.send(ts_NS_BLOCK(cause, g_nsvc_config.nsvci));
Harald Welte6e594f22017-07-23 16:19:35 +0200417 Tns_block.start;
418 }
419
Harald Welte90f19742020-11-06 19:34:40 +0100420 private altstep as_allstate() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200421 var PDU_NS rf;
Harald Welte6e594f22017-07-23 16:19:35 +0200422 var ASP_Event evt;
423
424 /* transition to DEAD if t_alive times out */
Harald Welte9a7c5122020-09-14 11:35:57 +0200425 [] Tns_alive.timeout {
426 log("Tns-alive expired: changing to DEAD_BLOCKED + starting Tns-test");
Harald Welte90f19742020-11-06 19:34:40 +0100427 f_change_state(NSVC_S_DEAD_BLOCKED);
Harald Welte6e594f22017-07-23 16:19:35 +0200428 Tns_test.start;
Harald Welte6fff3642017-07-22 21:36:13 +0200429 }
Harald Welte6fff3642017-07-22 21:36:13 +0200430
Harald Welte9a7c5122020-09-14 11:35:57 +0200431 [] Tns_test.timeout {
Harald Welte6e594f22017-07-23 16:19:35 +0200432 log("Tns-test expired: sending NS-ALIVE");
433 f_sendAlive();
Harald Welte6fff3642017-07-22 21:36:13 +0200434 }
Harald Welte6fff3642017-07-22 21:36:13 +0200435
Harald Welte6e594f22017-07-23 16:19:35 +0200436 /* Stop t_alive when receiving ALIVE-ACK */
Harald Welte9a7c5122020-09-14 11:35:57 +0200437 [Tns_alive.running] NSCP.receive(t_NS_ALIVE_ACK) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200438 log("Rx NS-ALIVE-ACK: stopping Tns-alive; starting Tns-test");
Harald Welte6e594f22017-07-23 16:19:35 +0200439 Tns_alive.stop;
440 Tns_test.start;
441 }
Harald Welte6fff3642017-07-22 21:36:13 +0200442
Harald Welte6e594f22017-07-23 16:19:35 +0200443 /* respond to NS-ALIVE with NS-ALIVE-ACK */
Harald Welte013d65a2020-09-13 14:41:31 +0200444 [] NSCP.receive(t_NS_ALIVE) {
445 NSCP.send(t_NS_ALIVE_ACK);
Harald Welte6e594f22017-07-23 16:19:35 +0200446 }
447
448 /* Respond to BLOCK for wrong NSVCI */
Harald Welte013d65a2020-09-13 14:41:31 +0200449 [] NSCP.receive(tr_NS_BLOCK(?, ?)) -> value rf {
Harald Welte6e594f22017-07-23 16:19:35 +0200450 log("Rx NS-BLOCK for unknown NSVCI");
451 /* FIXME */
452 }
453
Harald Welte90f19742020-11-06 19:34:40 +0100454 [not g_config.handle_sns] as_handle_reset();
Harald Welte6e594f22017-07-23 16:19:35 +0200455
Harald Welte90f19742020-11-06 19:34:40 +0100456 [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 +0200457
Harald Welte6e594f22017-07-23 16:19:35 +0200458 /* default case of handling unknown PDUs */
Harald Welte013d65a2020-09-13 14:41:31 +0200459 [] NSCP.receive(PDU_NS: ?) -> value rf {
Harald Welte90f19742020-11-06 19:34:40 +0100460 log("Rx Unexpected NS PDU ", rf," in state ", vc_state);
Harald Welte013d65a2020-09-13 14:41:31 +0200461 NSCP.send(ts_NS_STATUS(NS_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, rf));
Harald Welte6e594f22017-07-23 16:19:35 +0200462 }
Harald Welte6fff3642017-07-22 21:36:13 +0200463 }
464
Harald Welte90f19742020-11-06 19:34:40 +0100465 private altstep as_handle_reset() runs on NSVC_CT {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200466 var PDU_NS rf;
467
Harald Welte90f19742020-11-06 19:34:40 +0100468 [g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200469 log("Provider Link came up: waiting for NS-RESET");
470 }
471
Harald Welte90f19742020-11-06 19:34:40 +0100472 [not g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200473 log("Provider Link came up: sending NS-RESET");
474 f_sendReset();
475 }
476
477 /* Respond to RESET with correct NSEI/NSVCI */
Harald Welte90f19742020-11-06 19:34:40 +0100478 [] NSCP.receive(tr_NS_RESET(?, g_nsvc_config.nsvci, g_config.nsei)) -> value rf {
479 f_change_state(NSVC_S_ALIVE_BLOCKED);
480 NSCP.send(ts_NS_RESET_ACK(g_nsvc_config.nsvci, g_config.nsei));
Daniel Willmann654f85e2020-10-12 18:10:06 +0200481 log("Rx NS-RESET: Sending NS-ALIVE");
482 f_sendAlive();
483 Tns_test.start;
484 }
485
486 /* Respond to RESET with wrong NSEI/NSVCI */
487 [] NSCP.receive(tr_NS_RESET(?, ?, ?)) -> value rf {
488 log("Rx NS-RESET for unknown NSEI/NSVCI");
489 /* FIXME */
490 }
491 }
492
Harald Welte5e514fa2018-07-05 00:01:45 +0200493 /* simple IP Sub-Network Service responder for the SGSN side. This is not a full implementation
494 * of the protocol, merely sufficient to make the PCU/BSS side happy to proceed */
Harald Welte90f19742020-11-06 19:34:40 +0100495 private altstep as_sns_sgsn() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200496 var PDU_NS rf;
Harald Welte90f19742020-11-06 19:34:40 +0100497 [g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200498 log("Provider Link came up: sending NS-ALIVE");
499 f_sendAlive();
500 }
501
Harald Welte90f19742020-11-06 19:34:40 +0100502 [not g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200503 log("Provider Link came up: sending NS-ALIVE");
504 f_sendAlive();
505 }
506
Harald Welte90f19742020-11-06 19:34:40 +0100507 [] NSCP.receive(tr_SNS_SIZE(g_config.nsei)) -> value rf {
Harald Welte5e514fa2018-07-05 00:01:45 +0200508 /* blindly acknowledge whatever the PCU sends */
Harald Welte90f19742020-11-06 19:34:40 +0100509 NSCP.send(ts_SNS_SIZE_ACK(g_config.nsei, omit));
Harald Welte5e514fa2018-07-05 00:01:45 +0200510 }
Harald Welte013d65a2020-09-13 14:41:31 +0200511 [] NSCP.receive(tr_SNS_SIZE(?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200512 setverdict(fail, "SNS-SIZE from unexpected NSEI");
513 self.stop;
514 }
Harald Welte90f19742020-11-06 19:34:40 +0100515 [] NSCP.receive(tr_SNS_CONFIG(g_config.nsei, true,
516 {tr_SNS_IPv4(g_nsvc_config.provider.ip.remote_ip,
517 g_nsvc_config.provider.ip.remote_udp_port)})) -> value rf {
Harald Welte5e514fa2018-07-05 00:01:45 +0200518 /* blindly acknowledge whatever the PCU sends */
Harald Welte90f19742020-11-06 19:34:40 +0100519 NSCP.send(ts_SNS_CONFIG_ACK(g_config.nsei, omit));
Harald Welte5e514fa2018-07-05 00:01:45 +0200520 /* send a SNS-CONFIG in response and expect a SNS-CONFIG-ACK */
Harald Welte90f19742020-11-06 19:34:40 +0100521 var IP4_Elements v4 := { valueof(ts_SNS_IPv4(g_nsvc_config.provider.ip.local_ip,
522 g_nsvc_config.provider.ip.local_udp_port)) };
523 NSCP.send(ts_SNS_CONFIG(g_config.nsei, true, v4));
Harald Welte5e514fa2018-07-05 00:01:45 +0200524 alt {
Harald Welte90f19742020-11-06 19:34:40 +0100525 [] NSCP.receive(tr_SNS_CONFIG_ACK(g_config.nsei, omit)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200526 /* success */
527 }
Harald Welte90f19742020-11-06 19:34:40 +0100528 [] NSCP.receive(tr_SNS_CONFIG_ACK(g_config.nsei, ?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200529 setverdict(fail, "Unexpected SNS-CONFIG-NACK");
530 self.stop;
531 }
532 }
533 }
Harald Welte90f19742020-11-06 19:34:40 +0100534 [] NSCP.receive(tr_SNS_CONFIG(g_config.nsei, false, ?)) { /* ignore */}
535 [] NSCP.receive(tr_SNS_CONFIG(g_config.nsei, true, ?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200536 setverdict(fail, "Unexpected SNS-CONFIG content");
537 self.stop;
538 }
Harald Welte013d65a2020-09-13 14:41:31 +0200539 [] NSCP.receive(tr_SNS_CONFIG(?, ?, ?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200540 setverdict(fail, "SNS-CONFIG from unexpected NSEI");
541 self.stop;
542 }
543 }
544
Harald Welte90f19742020-11-06 19:34:40 +0100545 private altstep as_alive_blocked() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200546 var PDU_NS rf;
547 /* bogus block, just respond with ACK */
Harald Welte90f19742020-11-06 19:34:40 +0100548 [] NSCP.receive(tr_NS_BLOCK(?, g_nsvc_config.nsvci)) -> value rf {
549 NSCP.send(ts_NS_BLOCK_ACK(g_nsvc_config.nsvci));
Harald Welte4a6a6632020-09-14 09:58:53 +0200550 }
551 /* Respond to UNBLOCK with UNBLOCK-ACK + change state */
552 [] NSCP.receive(t_NS_UNBLOCK) -> value rf {
553 NSCP.send(t_NS_UNBLOCK_ACK);
554 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100555 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200556 }
557 [] NSCP.receive(t_NS_UNBLOCK_ACK) -> value rf {
558 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100559 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200560 }
561 [] Tns_block.timeout {
562 /* repeat unblock transmission */
563 f_sendUnblock();
564 }
565 }
566
Harald Welte90f19742020-11-06 19:34:40 +0100567 private altstep as_alive_unblocked() runs on NSVC_CT {
Harald Welte6fff3642017-07-22 21:36:13 +0200568 var NsUnitdataRequest ud_req;
Harald Welte013d65a2020-09-13 14:41:31 +0200569 var PDU_NS rf;
Harald Welte4a6a6632020-09-14 09:58:53 +0200570 /* bogus unblock, just respond with ACK */
571 [] NSCP.receive(t_NS_UNBLOCK) -> value rf {
572 NSCP.send(t_NS_UNBLOCK_ACK);
573 }
574 /* Respond to BLOCK with BLOCK-ACK + change state */
Harald Welte90f19742020-11-06 19:34:40 +0100575 [] NSCP.receive(tr_NS_BLOCK(?, g_nsvc_config.nsvci)) -> value rf {
576 NSCP.send(ts_NS_BLOCK_ACK(g_nsvc_config.nsvci));
Harald Welte4a6a6632020-09-14 09:58:53 +0200577 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100578 f_change_state(NSVC_S_ALIVE_BLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200579 }
Harald Welte90f19742020-11-06 19:34:40 +0100580 [] NSCP.receive(tr_NS_BLOCK_ACK(g_nsvc_config.nsvci)) -> value rf {
Harald Welte4a6a6632020-09-14 09:58:53 +0200581 Tns_block.stop;
582 }
583 /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */
584 [] NSCP.receive(tr_NS_UNITDATA(?, ?, ?)) -> value rf {
Harald Welte90f19742020-11-06 19:34:40 +0100585 NS_SP.send(ts_NsUdInd(g_config.nsei,
Harald Welte4a6a6632020-09-14 09:58:53 +0200586 oct2int(rf.pDU_NS_Unitdata.bVCI),
587 rf.pDU_NS_Unitdata.nS_SDU));
588 }
589 /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */
Harald Weltec4505522020-11-11 18:55:09 +0100590 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, ?, omit)) -> value ud_req {
Harald Welte4a6a6632020-09-14 09:58:53 +0200591 /* using raw octetstring PDU */
592 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu));
593 }
Harald Weltec4505522020-11-11 18:55:09 +0100594 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, omit, ?)) -> value ud_req {
Harald Welte4a6a6632020-09-14 09:58:53 +0200595 /* using decoded BSSGP PDU that we need to encode first */
596 var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp);
597 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc));
598 }
599 }
Harald Welte6e594f22017-07-23 16:19:35 +0200600
Harald Welte90f19742020-11-06 19:34:40 +0100601 private altstep as_wait_reset() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200602 var PDU_NS rf;
Harald Welte3dd83552020-09-14 11:38:01 +0200603 [] Tns_reset.timeout {
604 /* If the sending entity of an NS-RESET PDU receives no NS-RESET-ACK PDU before timer
605 * Tns-reset expires the corresponding NS-VCs shall remain blocked and dead and the
606 * entire reset procedure shall be repeated */
607 f_sendReset();
608 }
Harald Welte90f19742020-11-06 19:34:40 +0100609 [] NSCP.receive(tr_NS_RESET_ACK(g_nsvc_config.nsvci, g_config.nsei)) -> value rf {
Harald Welte3dd83552020-09-14 11:38:01 +0200610 Tns_reset.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100611 f_change_state(NSVC_S_ALIVE_BLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200612 f_sendAlive();
613 f_sendUnblock();
614 }
615 }
Harald Welte6fff3642017-07-22 21:36:13 +0200616
Harald Welte90f19742020-11-06 19:34:40 +0100617 private function f_ScanEvents() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200618 var PDU_NS rf;
Harald Welte6fff3642017-07-22 21:36:13 +0200619 while (true) {
Harald Welte6fff3642017-07-22 21:36:13 +0200620 alt {
Harald Welte90f19742020-11-06 19:34:40 +0100621 [vc_state == NSVC_S_WAIT_RESET] as_wait_reset();
622 [vc_state == NSVC_S_ALIVE_BLOCKED] as_alive_blocked();
623 [vc_state == NSVC_S_ALIVE_UNBLOCKED] as_alive_unblocked();
Harald Welte4a6a6632020-09-14 09:58:53 +0200624 [] as_allstate();
Harald Welte6fff3642017-07-22 21:36:13 +0200625 }
626 }
Harald Welte6fff3642017-07-22 21:36:13 +0200627 }
628}