blob: d6c7f6111fc2ed05eb7225e6bc1194952030cae6 [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 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 {
110 NSVC_S_DEAD_BLOCKED,
111 NSVC_S_WAIT_RESET,
112 NSVC_S_ALIVE_BLOCKED,
113 NSVC_S_ALIVE_UNBLOCKED
Harald Welte6e594f22017-07-23 16:19:35 +0200114 }
Harald Welte6fff3642017-07-22 21:36:13 +0200115
116 /* port from our (internal) point of view */
117 type port NS_SP_PT message {
118 in NsUnitdataRequest;
119 out NsUnitdataIndication,
Harald Welte013d65a2020-09-13 14:41:31 +0200120 NsStatusIndication;
Harald Welte6fff3642017-07-22 21:36:13 +0200121 } with { extension "internal" };
122
123 /* port from the user point of view */
124 type port NS_PT message {
125 in ASP_Event,
Harald Welte6e594f22017-07-23 16:19:35 +0200126 NsStatusIndication,
Harald Welte6fff3642017-07-22 21:36:13 +0200127 NsUnitdataIndication;
128 out NsUnitdataRequest;
129 } with { extension "internal" };
130
Harald Welte013d65a2020-09-13 14:41:31 +0200131 type component NS_Provider_CT {
132 /* upper port, facing to NS_Emulation:NSCP */
133 port NS_PROVIDER_PT NSE;
134 /* lower layer ports (UDP/IP, Frame Relay) are added in derived components */
135 };
136
Harald Weltebd612cd2020-09-14 09:42:28 +0200137 type enumerated NS_Provider_LinkStatus {
138 NS_PROV_LINK_STATUS_UP,
139 NS_PROV_LINK_STATUS_DOWN
140 };
141 type union NS_Provider_Evt {
142 NS_Provider_LinkStatus link_status
143 };
144
Harald Welte013d65a2020-09-13 14:41:31 +0200145 /* port between NS_Provider and NS_CT */
146 type port NS_PROVIDER_PT message {
Harald Weltebd612cd2020-09-14 09:42:28 +0200147 inout PDU_NS, NS_Provider_Evt;
Harald Welte013d65a2020-09-13 14:41:31 +0200148 } with { extension "internal" };
149
Harald Welte90f19742020-11-06 19:34:40 +0100150 type record NSVCConfigurationIP {
151 AddressFamily address_family,
152 PortNumber local_udp_port,
153 charstring local_ip,
154 PortNumber remote_udp_port,
155 charstring remote_ip
156 };
157 type record NSVCConfigurationFR {
158 charstring netdev, /* HDLC net-device for AF_PACKET socket */
159 integer dlci
160 };
161 type union NSVCConfigurationP {
162 NSVCConfigurationIP ip,
163 NSVCConfigurationFR fr
164 };
165 type record NSVCConfiguration {
166 NSVCConfigurationP provider,
167 Nsvci nsvci
168 };
169 type record of NSVCConfiguration NSVCConfigurations;
170 type record NSConfiguration {
171 Nsvci nsei,
172 boolean role_sgsn,
173 boolean handle_sns,
174 NSVCConfigurations nsvc
175 }
176
177 /***********************************************************************
178 * per NS-VCG component. Exists once per [peer of] NSE
179 ***********************************************************************/
180
Harald Welte6fff3642017-07-22 21:36:13 +0200181 type component NS_CT {
Harald Welte90f19742020-11-06 19:34:40 +0100182 /* NS-User SAP towards the user */
183 port NS_SP_PT NS_SP;
184
185 /* port towards the per-NSVC components */
186 port NS_PT NSVC;
187
188 /* all of the NS configuration a user passes to us */
189 var NSConfiguration g_config;
190 var charstring g_id;
191
192 /* references to the per-NSVC components */
193 var NsvcTable g_nsvcs := {};
Harald Weltec4505522020-11-11 18:55:09 +0100194 /* list of indexes to g_nsvcs[] of currently unblocked NSVCs */
195 var ro_integer g_unblocked_nsvcs := {};
Harald Welte90f19742020-11-06 19:34:40 +0100196 };
197 type record NsvcTableEntry {
198 Nsvci nsvci,
199 NSVC_CT vc_conn,
200 NsvcState state
201 };
202 type record of NsvcTableEntry NsvcTable;
Harald Weltec4505522020-11-11 18:55:09 +0100203 type record of integer ro_integer;
Harald Welte90f19742020-11-06 19:34:40 +0100204
205 /* add one NSVC (component and table entry */
206 function f_nsvc_add(NSVCConfiguration nsvc_cfg) runs on NS_CT {
207 var charstring nsvc_id := g_id & "-NSVCI" & int2str(nsvc_cfg.nsvci);
208 var NsvcTableEntry te;
209
210 te.nsvci := nsvc_cfg.nsvci;
211 te.vc_conn := NSVC_CT.create(nsvc_id);
212 te.state := NSVC_S_DEAD_BLOCKED;
213
214 connect(self:NSVC, te.vc_conn:NS_SP);
215 te.vc_conn.start(NSVCStart(nsvc_cfg, g_config, nsvc_id));
216
217 g_nsvcs := g_nsvcs & { te };
Harald Weltec4505522020-11-11 18:55:09 +0100218 /* no need to add to g_unblocked_nsvcs, as state is always DEAD_BLOCKED above */
Harald Welte90f19742020-11-06 19:34:40 +0100219 }
220
221 function f_nsvc_find_idx(Nsvci nsvci) runs on NS_CT return integer {
222 var integer i;
223 for (i := 0; i < lengthof(g_nsvcs); i := i+1) {
224 if (g_nsvcs[i].nsvci == nsvci) {
225 return i;
226 }
227 }
228 return -1;
229 }
230
231 function f_nsvc_find(Nsvci nsvci) runs on NS_CT return NSVC_CT {
232 var integer i := f_nsvc_find_idx(nsvci);
233 if (i < 0) {
234 return null;
235 } else {
236 return g_nsvcs[i].vc_conn;
237 }
238 }
239
240 function f_nsvc_update_state(Nsvci nsvci, NsvcState state) runs on NS_CT {
241 var integer i := f_nsvc_find_idx(nsvci);
242 if (i < 0) {
243 return;
244 }
Harald Weltec4505522020-11-11 18:55:09 +0100245 if (g_nsvcs[i].state != NSVC_S_ALIVE_UNBLOCKED and state == NSVC_S_ALIVE_UNBLOCKED) {
246 /* add index to list of unblocked NSVCs */
247 g_unblocked_nsvcs := g_unblocked_nsvcs & {i};
248 } else if (g_nsvcs[i].state == NSVC_S_ALIVE_UNBLOCKED and state != NSVC_S_ALIVE_UNBLOCKED) {
249 /* remove index to list of unblocked NSVCs */
250 var ro_integer new_unblocked_nsvcs := {};
251 for (var integer j := 0; j < lengthof(g_unblocked_nsvcs); j := j+1) {
252 if (g_unblocked_nsvcs[j] != i) {
253 new_unblocked_nsvcs := new_unblocked_nsvcs & {j};
254 }
255 }
256 g_unblocked_nsvcs := new_unblocked_nsvcs;
257 }
Harald Welte90f19742020-11-06 19:34:40 +0100258 g_nsvcs[i].state := state;
259 }
260
261 function NSStart(NSConfiguration init_config, charstring id := testcasename()) runs on NS_CT {
262 g_config := init_config;
263 g_id := id;
264
265 /* iterate over list of NS-VCs and start per-NSVC components */
266 for (var integer i := 0; i < lengthof(g_config.nsvc); i := i+1) {
267 var NSVCConfiguration nsvc_cfg := g_config.nsvc[i];
268 f_nsvc_add(nsvc_cfg);
269 }
270
271 while (true) {
272 alt {
273 [] as_ns_common() {}
274 }
275 }
276 }
277
Harald Weltedc0a0902020-11-10 21:03:29 +0100278 function f_count_nsvcs_in_state(template NsvcState state := ?) runs on NS_CT return integer {
279 var integer i;
280 var integer res := 0;
281 for (i := 0; i < lengthof(g_nsvcs); i := i+1) {
282 if (match(g_nsvcs[i].state, state)) {
283 res := res + 1;
284 }
285 }
286 return res;
287 }
288
Harald Welte90f19742020-11-06 19:34:40 +0100289 private altstep as_ns_common() runs on NS_CT {
290 var NsStatusIndication rx_nssi;
291 var NsUnitdataIndication rx_nsudi;
292 var NsUnitdataRequest rx_nsudr;
293 /* pass from NS-VCs up to user */
Harald Weltedc0a0902020-11-10 21:03:29 +0100294 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, NSVC_S_ALIVE_UNBLOCKED)) -> value rx_nssi {
295 /* check if this one is the first to be unblocked */
296 var integer num_nsvc_unblocked := f_count_nsvcs_in_state(NSVC_S_ALIVE_UNBLOCKED);
297 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
298 if (num_nsvc_unblocked == 0) {
299 rx_nssi.first_or_last := true;
300 }
301 NS_SP.send(rx_nssi);
302 }
303 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, NSVC_S_DEAD_BLOCKED)) -> value rx_nssi {
304 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
305 /* check if this one is the last to be blocked */
306 var integer num_nsvc_unblocked := f_count_nsvcs_in_state(NSVC_S_ALIVE_UNBLOCKED);
307 if (num_nsvc_unblocked == 0) {
308 rx_nssi.first_or_last := true;
309 }
310 NS_SP.send(rx_nssi);
311 }
312 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, ?)) -> value rx_nssi {
Harald Welte90f19742020-11-06 19:34:40 +0100313 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
314 NS_SP.send(rx_nssi);
315 }
316 [] NSVC.receive(tr_NsStsInd) -> value rx_nssi {
317 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
318 log2str("Received NsStatusInd for invalid NSEI: ", rx_nssi));
319 }
320 [] NSVC.receive(tr_NsUdInd(g_config.nsei, ?, ?)) -> value rx_nsudi {
321 NS_SP.send(rx_nsudi);
322 }
323 [] NSVC.receive(tr_NsUdInd(?, ?, ?)) -> value rx_nsudi {
324 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
325 log2str("Received UnitDataInd for invalid NSEI: ", rx_nsudi));
326 }
327 /* from user down to NS-VC */
Harald Weltec4505522020-11-11 18:55:09 +0100328 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, ?, *)) -> value rx_nsudr {
329 /* load distribution function */
330 var integer nsvc_idx := g_unblocked_nsvcs[rx_nsudr.lsp mod lengthof(g_unblocked_nsvcs)];
331 NSVC.send(rx_nsudr) to g_nsvcs[nsvc_idx].vc_conn;
Harald Welte90f19742020-11-06 19:34:40 +0100332 }
Harald Weltec4505522020-11-11 18:55:09 +0100333 [] NS_SP.receive(tr_NsUdReq(?, ?, ?, ?, *)) -> value rx_nsudr {
Harald Welte90f19742020-11-06 19:34:40 +0100334 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
335 log2str("Received NsUnitdataReq for invalid NSEI: ", rx_nsudr));
336 }
337 }
338
339 /***********************************************************************
340 per-NSVC component. Exists once for each NS-VC in the NS-VCG
341 ***********************************************************************/
342
343 type component NSVC_CT {
Harald Welte6fff3642017-07-22 21:36:13 +0200344 /* UDP port towards the bottom (IUT) */
Harald Welte013d65a2020-09-13 14:41:31 +0200345 port NS_PROVIDER_PT NSCP;
346 var NS_Provider_IPL4_CT vc_NSP_IP;
Harald Welte867243a2020-09-13 18:32:32 +0200347#ifdef NS_EMULATION_FR
348 var NS_Provider_FR_CT vc_NSP_FR;
349#endif
Harald Welte013d65a2020-09-13 14:41:31 +0200350
Harald Welte90f19742020-11-06 19:34:40 +0100351 /* port towards the NS_CT */
Harald Welte6fff3642017-07-22 21:36:13 +0200352 port NS_SP_PT NS_SP;
353
Harald Welte90f19742020-11-06 19:34:40 +0100354 /* configuration passed by the user */
355 var NSVCConfiguration g_nsvc_config;
356 /* we cannot access the NS_CT.config and hence need to copy those */
357 var NSConfiguration g_config;
Alexander Couzens2c12b242018-07-31 00:30:11 +0200358
Harald Welte90f19742020-11-06 19:34:40 +0100359 var NsvcState vc_state := NSVC_S_DEAD_BLOCKED;
Harald Welte6e594f22017-07-23 16:19:35 +0200360
361 timer Tns_alive := 3.0;
362 timer Tns_test := 10.0;
363 timer Tns_block := 10.0;
Harald Welte3dd83552020-09-14 11:38:01 +0200364 timer Tns_reset := 10.0;
Harald Welte6fff3642017-07-22 21:36:13 +0200365 }
366
Harald Welte90f19742020-11-06 19:34:40 +0100367 function NSVCStart(NSVCConfiguration init_config, NSConfiguration init_g_config, charstring id := testcasename()) runs on NSVC_CT {
368 g_nsvc_config := init_config;
369 g_config := init_g_config;
370 f_init(id & "-NSVCemu" & int2str(g_nsvc_config.nsvci));
371 f_ScanEvents();
Alexander Couzens2c12b242018-07-31 00:30:11 +0200372 }
Harald Welte6fff3642017-07-22 21:36:13 +0200373
Harald Welte90f19742020-11-06 19:34:40 +0100374 private function f_init(charstring id) runs on NSVC_CT {
Harald Welte90f19742020-11-06 19:34:40 +0100375 if (ischosen(g_nsvc_config.provider.ip)) {
376 /* Connect the UDP socket */
377 vc_NSP_IP := NS_Provider_IPL4_CT.create(id & "-provIP");
378 connect(self:NSCP, vc_NSP_IP:NSE);
379 vc_NSP_IP.start(NS_Provider_IPL4.main(g_nsvc_config, g_config, id));
380#ifdef NS_EMULATION_FR
381 } else if (ischosen(g_nsvc_config.provider.fr)) {
382 vc_NSP_FR := NS_Provider_FR_CT.create(id & "-provFR");
383 connect(self:NSCP, vc_NSP_FR:NSE);
384 vc_NSP_FR.start(NS_Provider_FR.main(g_nsvc_config, g_config, id));
385#endif
Harald Weltee15299a2020-11-17 17:30:09 +0100386 } else {
387 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unsupported NS provider");
Harald Welte90f19742020-11-06 19:34:40 +0100388 }
389
390 f_change_state(NSVC_S_DEAD_BLOCKED);
Harald Welte6fff3642017-07-22 21:36:13 +0200391 }
392
Harald Welte90f19742020-11-06 19:34:40 +0100393 private function f_change_state(NsvcState new_state) runs on NSVC_CT {
394 var NsvcState old_state := vc_state;
395 vc_state := new_state;
396 log("NSVC ", g_nsvc_config.nsvci, " State Transition: ", old_state, " -> ", new_state);
397 NS_SP.send(ts_NsStsInd(g_config.nsei, g_nsvc_config.nsvci, old_state, new_state));
398 }
399
400 private function f_sendReset() runs on NSVC_CT {
401 NSCP.send(ts_NS_RESET(NS_CAUSE_OM_INTERVENTION, g_nsvc_config.nsvci, g_config.nsei));
Harald Welte3dd83552020-09-14 11:38:01 +0200402 Tns_reset.start;
Harald Welte90f19742020-11-06 19:34:40 +0100403 vc_state := NSVC_S_WAIT_RESET;
Harald Welte6fff3642017-07-22 21:36:13 +0200404 }
405
Harald Welte90f19742020-11-06 19:34:40 +0100406 private function f_sendAlive() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200407 NSCP.send(t_NS_ALIVE);
Harald Welte6e594f22017-07-23 16:19:35 +0200408 Tns_alive.start;
409 }
410
Harald Welte90f19742020-11-06 19:34:40 +0100411 private function f_sendUnblock() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200412 NSCP.send(t_NS_UNBLOCK);
Harald Welte6e594f22017-07-23 16:19:35 +0200413 Tns_block.start;
414 }
415
Harald Welte90f19742020-11-06 19:34:40 +0100416 private function f_sendBlock(NsCause cause) runs on NSVC_CT {
417 NSCP.send(ts_NS_BLOCK(cause, g_nsvc_config.nsvci));
Harald Welte6e594f22017-07-23 16:19:35 +0200418 Tns_block.start;
419 }
420
Harald Welte90f19742020-11-06 19:34:40 +0100421 private altstep as_allstate() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200422 var PDU_NS rf;
Harald Welte6e594f22017-07-23 16:19:35 +0200423 var ASP_Event evt;
424
425 /* transition to DEAD if t_alive times out */
Harald Welte9a7c5122020-09-14 11:35:57 +0200426 [] Tns_alive.timeout {
427 log("Tns-alive expired: changing to DEAD_BLOCKED + starting Tns-test");
Harald Welte90f19742020-11-06 19:34:40 +0100428 f_change_state(NSVC_S_DEAD_BLOCKED);
Harald Welte6e594f22017-07-23 16:19:35 +0200429 Tns_test.start;
Harald Welte6fff3642017-07-22 21:36:13 +0200430 }
Harald Welte6fff3642017-07-22 21:36:13 +0200431
Harald Welte9a7c5122020-09-14 11:35:57 +0200432 [] Tns_test.timeout {
Harald Welte6e594f22017-07-23 16:19:35 +0200433 log("Tns-test expired: sending NS-ALIVE");
434 f_sendAlive();
Harald Welte6fff3642017-07-22 21:36:13 +0200435 }
Harald Welte6fff3642017-07-22 21:36:13 +0200436
Harald Welte6e594f22017-07-23 16:19:35 +0200437 /* Stop t_alive when receiving ALIVE-ACK */
Harald Welte9a7c5122020-09-14 11:35:57 +0200438 [Tns_alive.running] NSCP.receive(t_NS_ALIVE_ACK) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200439 log("Rx NS-ALIVE-ACK: stopping Tns-alive; starting Tns-test");
Harald Welte6e594f22017-07-23 16:19:35 +0200440 Tns_alive.stop;
441 Tns_test.start;
442 }
Harald Welte6fff3642017-07-22 21:36:13 +0200443
Harald Welte6e594f22017-07-23 16:19:35 +0200444 /* respond to NS-ALIVE with NS-ALIVE-ACK */
Harald Welte013d65a2020-09-13 14:41:31 +0200445 [] NSCP.receive(t_NS_ALIVE) {
446 NSCP.send(t_NS_ALIVE_ACK);
Harald Welte6e594f22017-07-23 16:19:35 +0200447 }
448
449 /* Respond to BLOCK for wrong NSVCI */
Harald Welte013d65a2020-09-13 14:41:31 +0200450 [] NSCP.receive(tr_NS_BLOCK(?, ?)) -> value rf {
Harald Welte6e594f22017-07-23 16:19:35 +0200451 log("Rx NS-BLOCK for unknown NSVCI");
452 /* FIXME */
453 }
454
Harald Welte90f19742020-11-06 19:34:40 +0100455 [not g_config.handle_sns] as_handle_reset();
Harald Welte6e594f22017-07-23 16:19:35 +0200456
Harald Welte90f19742020-11-06 19:34:40 +0100457 [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 +0200458
Harald Welte6e594f22017-07-23 16:19:35 +0200459 /* default case of handling unknown PDUs */
Harald Welte013d65a2020-09-13 14:41:31 +0200460 [] NSCP.receive(PDU_NS: ?) -> value rf {
Harald Welte90f19742020-11-06 19:34:40 +0100461 log("Rx Unexpected NS PDU ", rf," in state ", vc_state);
Harald Welte013d65a2020-09-13 14:41:31 +0200462 NSCP.send(ts_NS_STATUS(NS_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, rf));
Harald Welte6e594f22017-07-23 16:19:35 +0200463 }
Harald Welte6fff3642017-07-22 21:36:13 +0200464 }
465
Harald Welte90f19742020-11-06 19:34:40 +0100466 private altstep as_handle_reset() runs on NSVC_CT {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200467 var PDU_NS rf;
468
Harald Welte90f19742020-11-06 19:34:40 +0100469 [g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200470 log("Provider Link came up: waiting for NS-RESET");
471 }
472
Harald Welte90f19742020-11-06 19:34:40 +0100473 [not g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200474 log("Provider Link came up: sending NS-RESET");
475 f_sendReset();
476 }
477
478 /* Respond to RESET with correct NSEI/NSVCI */
Harald Welte90f19742020-11-06 19:34:40 +0100479 [] NSCP.receive(tr_NS_RESET(?, g_nsvc_config.nsvci, g_config.nsei)) -> value rf {
480 f_change_state(NSVC_S_ALIVE_BLOCKED);
481 NSCP.send(ts_NS_RESET_ACK(g_nsvc_config.nsvci, g_config.nsei));
Daniel Willmann654f85e2020-10-12 18:10:06 +0200482 log("Rx NS-RESET: Sending NS-ALIVE");
483 f_sendAlive();
484 Tns_test.start;
485 }
486
487 /* Respond to RESET with wrong NSEI/NSVCI */
488 [] NSCP.receive(tr_NS_RESET(?, ?, ?)) -> value rf {
489 log("Rx NS-RESET for unknown NSEI/NSVCI");
490 /* FIXME */
491 }
492 }
493
Harald Welte5e514fa2018-07-05 00:01:45 +0200494 /* simple IP Sub-Network Service responder for the SGSN side. This is not a full implementation
495 * of the protocol, merely sufficient to make the PCU/BSS side happy to proceed */
Harald Welte90f19742020-11-06 19:34:40 +0100496 private altstep as_sns_sgsn() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200497 var PDU_NS rf;
Alexander Couzensd5338902020-12-21 18:41:21 +0100498 [] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
499 log("Provider Link came up. Waiting for SNS Size");
Daniel Willmann654f85e2020-10-12 18:10:06 +0200500 }
501
Harald Welte90f19742020-11-06 19:34:40 +0100502 [] NSCP.receive(tr_SNS_SIZE(g_config.nsei)) -> value rf {
Harald Welte5e514fa2018-07-05 00:01:45 +0200503 /* blindly acknowledge whatever the PCU sends */
Harald Welte90f19742020-11-06 19:34:40 +0100504 NSCP.send(ts_SNS_SIZE_ACK(g_config.nsei, omit));
Harald Welte5e514fa2018-07-05 00:01:45 +0200505 }
Harald Welte013d65a2020-09-13 14:41:31 +0200506 [] NSCP.receive(tr_SNS_SIZE(?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200507 setverdict(fail, "SNS-SIZE from unexpected NSEI");
508 self.stop;
509 }
Harald Welte90f19742020-11-06 19:34:40 +0100510 [] NSCP.receive(tr_SNS_CONFIG(g_config.nsei, true,
511 {tr_SNS_IPv4(g_nsvc_config.provider.ip.remote_ip,
512 g_nsvc_config.provider.ip.remote_udp_port)})) -> value rf {
Harald Welte5e514fa2018-07-05 00:01:45 +0200513 /* blindly acknowledge whatever the PCU sends */
Harald Welte90f19742020-11-06 19:34:40 +0100514 NSCP.send(ts_SNS_CONFIG_ACK(g_config.nsei, omit));
Harald Welte5e514fa2018-07-05 00:01:45 +0200515 /* send a SNS-CONFIG in response and expect a SNS-CONFIG-ACK */
Harald Welte90f19742020-11-06 19:34:40 +0100516 var IP4_Elements v4 := { valueof(ts_SNS_IPv4(g_nsvc_config.provider.ip.local_ip,
517 g_nsvc_config.provider.ip.local_udp_port)) };
518 NSCP.send(ts_SNS_CONFIG(g_config.nsei, true, v4));
Harald Welte5e514fa2018-07-05 00:01:45 +0200519 alt {
Harald Welte90f19742020-11-06 19:34:40 +0100520 [] NSCP.receive(tr_SNS_CONFIG_ACK(g_config.nsei, omit)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200521 /* success */
Alexander Couzensd5338902020-12-21 18:41:21 +0100522 log("SNS Config succeeded. Sending Alive");
523 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
524 f_sendAlive();
525 Tns_test.start;
Harald Welte5e514fa2018-07-05 00:01:45 +0200526 }
Harald Welte90f19742020-11-06 19:34:40 +0100527 [] NSCP.receive(tr_SNS_CONFIG_ACK(g_config.nsei, ?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200528 setverdict(fail, "Unexpected SNS-CONFIG-NACK");
529 self.stop;
530 }
531 }
532 }
Harald Welte90f19742020-11-06 19:34:40 +0100533 [] NSCP.receive(tr_SNS_CONFIG(g_config.nsei, false, ?)) { /* ignore */}
534 [] NSCP.receive(tr_SNS_CONFIG(g_config.nsei, true, ?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200535 setverdict(fail, "Unexpected SNS-CONFIG content");
536 self.stop;
537 }
Harald Welte013d65a2020-09-13 14:41:31 +0200538 [] NSCP.receive(tr_SNS_CONFIG(?, ?, ?)) {
Harald Welte5e514fa2018-07-05 00:01:45 +0200539 setverdict(fail, "SNS-CONFIG from unexpected NSEI");
540 self.stop;
541 }
542 }
543
Harald Welte90f19742020-11-06 19:34:40 +0100544 private altstep as_alive_blocked() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200545 var PDU_NS rf;
546 /* bogus block, just respond with ACK */
Harald Welte90f19742020-11-06 19:34:40 +0100547 [] NSCP.receive(tr_NS_BLOCK(?, g_nsvc_config.nsvci)) -> value rf {
548 NSCP.send(ts_NS_BLOCK_ACK(g_nsvc_config.nsvci));
Harald Welte4a6a6632020-09-14 09:58:53 +0200549 }
550 /* Respond to UNBLOCK with UNBLOCK-ACK + change state */
551 [] NSCP.receive(t_NS_UNBLOCK) -> value rf {
552 NSCP.send(t_NS_UNBLOCK_ACK);
553 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100554 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200555 }
556 [] NSCP.receive(t_NS_UNBLOCK_ACK) -> value rf {
557 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100558 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200559 }
Harald Welteda9d9382020-12-07 15:53:57 +0100560 /* tolerate a late NS-BLOCK-ACK from peer */
561 [] NSCP.receive(tr_NS_BLOCK_ACK(g_nsvc_config.nsvci)) -> value rf {
562 }
Harald Welte4a6a6632020-09-14 09:58:53 +0200563 [] Tns_block.timeout {
564 /* repeat unblock transmission */
565 f_sendUnblock();
566 }
567 }
568
Harald Welte90f19742020-11-06 19:34:40 +0100569 private altstep as_alive_unblocked() runs on NSVC_CT {
Harald Welte6fff3642017-07-22 21:36:13 +0200570 var NsUnitdataRequest ud_req;
Harald Welte013d65a2020-09-13 14:41:31 +0200571 var PDU_NS rf;
Harald Welte4a6a6632020-09-14 09:58:53 +0200572 /* bogus unblock, just respond with ACK */
573 [] NSCP.receive(t_NS_UNBLOCK) -> value rf {
574 NSCP.send(t_NS_UNBLOCK_ACK);
575 }
576 /* Respond to BLOCK with BLOCK-ACK + change state */
Harald Welte90f19742020-11-06 19:34:40 +0100577 [] NSCP.receive(tr_NS_BLOCK(?, g_nsvc_config.nsvci)) -> value rf {
578 NSCP.send(ts_NS_BLOCK_ACK(g_nsvc_config.nsvci));
Harald Welte4a6a6632020-09-14 09:58:53 +0200579 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100580 f_change_state(NSVC_S_ALIVE_BLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200581 }
Harald Welte90f19742020-11-06 19:34:40 +0100582 [] NSCP.receive(tr_NS_BLOCK_ACK(g_nsvc_config.nsvci)) -> value rf {
Harald Welte4a6a6632020-09-14 09:58:53 +0200583 Tns_block.stop;
584 }
Harald Welteda9d9382020-12-07 15:53:57 +0100585 /* tolerate a late NS-UNBLOCK-ACK from peer */
586 [] NSCP.receive(t_NS_UNBLOCK_ACK) -> value rf {
587 }
Harald Welte4a6a6632020-09-14 09:58:53 +0200588 /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */
589 [] NSCP.receive(tr_NS_UNITDATA(?, ?, ?)) -> value rf {
Harald Welte80a249a2020-11-17 19:57:40 +0100590 NS_SP.send(ts_NsUdInd(g_config.nsei, g_nsvc_config.nsvci,
Harald Welte4a6a6632020-09-14 09:58:53 +0200591 oct2int(rf.pDU_NS_Unitdata.bVCI),
592 rf.pDU_NS_Unitdata.nS_SDU));
593 }
594 /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */
Harald Weltec4505522020-11-11 18:55:09 +0100595 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, ?, omit)) -> value ud_req {
Harald Welte4a6a6632020-09-14 09:58:53 +0200596 /* using raw octetstring PDU */
597 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu));
598 }
Harald Weltec4505522020-11-11 18:55:09 +0100599 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, omit, ?)) -> value ud_req {
Harald Welte4a6a6632020-09-14 09:58:53 +0200600 /* using decoded BSSGP PDU that we need to encode first */
601 var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp);
602 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc));
603 }
604 }
Harald Welte6e594f22017-07-23 16:19:35 +0200605
Harald Welte90f19742020-11-06 19:34:40 +0100606 private altstep as_wait_reset() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200607 var PDU_NS rf;
Harald Welte3dd83552020-09-14 11:38:01 +0200608 [] Tns_reset.timeout {
609 /* If the sending entity of an NS-RESET PDU receives no NS-RESET-ACK PDU before timer
610 * Tns-reset expires the corresponding NS-VCs shall remain blocked and dead and the
611 * entire reset procedure shall be repeated */
612 f_sendReset();
613 }
Harald Welte90f19742020-11-06 19:34:40 +0100614 [] NSCP.receive(tr_NS_RESET_ACK(g_nsvc_config.nsvci, g_config.nsei)) -> value rf {
Harald Welte3dd83552020-09-14 11:38:01 +0200615 Tns_reset.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100616 f_change_state(NSVC_S_ALIVE_BLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200617 f_sendAlive();
618 f_sendUnblock();
619 }
620 }
Harald Welte6fff3642017-07-22 21:36:13 +0200621
Harald Welte90f19742020-11-06 19:34:40 +0100622 private function f_ScanEvents() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200623 var PDU_NS rf;
Harald Welte6fff3642017-07-22 21:36:13 +0200624 while (true) {
Harald Welte6fff3642017-07-22 21:36:13 +0200625 alt {
Harald Welte90f19742020-11-06 19:34:40 +0100626 [vc_state == NSVC_S_WAIT_RESET] as_wait_reset();
627 [vc_state == NSVC_S_ALIVE_BLOCKED] as_alive_blocked();
628 [vc_state == NSVC_S_ALIVE_UNBLOCKED] as_alive_unblocked();
Harald Welte4a6a6632020-09-14 09:58:53 +0200629 [] as_allstate();
Harald Welte6fff3642017-07-22 21:36:13 +0200630 }
631 }
Harald Welte6fff3642017-07-22 21:36:13 +0200632 }
633}