blob: 61ebe95b94ea210d38be820344d8b8db46586c9c [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 {
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,
Harald Weltebe7afce2021-01-17 22:04:36 +0100155 charstring remote_ip,
156 uint8_t data_weight,
157 uint8_t signalling_weight
Harald Welte90f19742020-11-06 19:34:40 +0100158 };
159 type record NSVCConfigurationFR {
160 charstring netdev, /* HDLC net-device for AF_PACKET socket */
161 integer dlci
162 };
163 type union NSVCConfigurationP {
164 NSVCConfigurationIP ip,
165 NSVCConfigurationFR fr
166 };
167 type record NSVCConfiguration {
168 NSVCConfigurationP provider,
169 Nsvci nsvci
170 };
171 type record of NSVCConfiguration NSVCConfigurations;
172 type record NSConfiguration {
173 Nsvci nsei,
174 boolean role_sgsn,
175 boolean handle_sns,
176 NSVCConfigurations nsvc
177 }
178
179 /***********************************************************************
180 * per NS-VCG component. Exists once per [peer of] NSE
181 ***********************************************************************/
182
Harald Welte6fff3642017-07-22 21:36:13 +0200183 type component NS_CT {
Harald Welte90f19742020-11-06 19:34:40 +0100184 /* NS-User SAP towards the user */
185 port NS_SP_PT NS_SP;
186
187 /* port towards the per-NSVC components */
Harald Welte1308dbb2021-01-18 18:19:38 +0100188 port NSint_PT NSVC;
Harald Welte90f19742020-11-06 19:34:40 +0100189
190 /* all of the NS configuration a user passes to us */
191 var NSConfiguration g_config;
192 var charstring g_id;
193
194 /* references to the per-NSVC components */
195 var NsvcTable g_nsvcs := {};
Harald Weltec4505522020-11-11 18:55:09 +0100196 /* list of indexes to g_nsvcs[] of currently unblocked NSVCs */
Harald Weltebe7afce2021-01-17 22:04:36 +0100197 var ro_integer g_unblocked_nsvcs_sig := {};
198 var ro_integer g_unblocked_nsvcs_data := {};
Harald Welte90f19742020-11-06 19:34:40 +0100199 };
200 type record NsvcTableEntry {
Harald Weltebe7afce2021-01-17 22:04:36 +0100201 NSVCConfiguration cfg,
Harald Welte90f19742020-11-06 19:34:40 +0100202 NSVC_CT vc_conn,
203 NsvcState state
204 };
205 type record of NsvcTableEntry NsvcTable;
Harald Weltec4505522020-11-11 18:55:09 +0100206 type record of integer ro_integer;
Harald Welte90f19742020-11-06 19:34:40 +0100207
Harald Welte1308dbb2021-01-18 18:19:38 +0100208 /* internal port from the NS-VC point of view */
209 type port NSint_SP_PT message {
210 in NsUnitdataRequest,
211 SnsRequest,
212 NsCtrlRequest;
213 out NsUnitdataIndication,
214 SnsIndication,
215 NsStatusIndication;
216 } with { extension "internal" };
217
218 /* internal port from the NS-VCG point of view */
219 type port NSint_PT message {
220 in ASP_Event,
221 NsStatusIndication,
222 SnsIndication,
223 NsUnitdataIndication;
224 out NsUnitdataRequest,
225 SnsRequest,
226 NsCtrlRequest;
227 } with { extension "internal" };
228
229 /* Used by NS-VC to report reception of a SNS PDU to NS-VCG */
230 type record SnsIndication {
231 Nsvci nsvci,
232 PDU_NS ns
233 };
234
235 /* Used by NS-VCG to request transmission of a SNS PDU via a NS-VC */
236 type record SnsRequest {
237 Nsvci nsvci,
238 PDU_NS ns
239 };
240
241 type enumerated NsCtrlRequest {
242 StartAliveProcedure (0)
243 };
244
Harald Welte90f19742020-11-06 19:34:40 +0100245 /* add one NSVC (component and table entry */
246 function f_nsvc_add(NSVCConfiguration nsvc_cfg) runs on NS_CT {
247 var charstring nsvc_id := g_id & "-NSVCI" & int2str(nsvc_cfg.nsvci);
248 var NsvcTableEntry te;
249
Harald Weltebe7afce2021-01-17 22:04:36 +0100250 te.cfg := nsvc_cfg;
Harald Welte90f19742020-11-06 19:34:40 +0100251 te.vc_conn := NSVC_CT.create(nsvc_id);
252 te.state := NSVC_S_DEAD_BLOCKED;
253
254 connect(self:NSVC, te.vc_conn:NS_SP);
255 te.vc_conn.start(NSVCStart(nsvc_cfg, g_config, nsvc_id));
256
257 g_nsvcs := g_nsvcs & { te };
Harald Weltec4505522020-11-11 18:55:09 +0100258 /* no need to add to g_unblocked_nsvcs, as state is always DEAD_BLOCKED above */
Harald Welte90f19742020-11-06 19:34:40 +0100259 }
260
261 function f_nsvc_find_idx(Nsvci nsvci) runs on NS_CT return integer {
262 var integer i;
263 for (i := 0; i < lengthof(g_nsvcs); i := i+1) {
Harald Weltebe7afce2021-01-17 22:04:36 +0100264 if (g_nsvcs[i].cfg.nsvci == nsvci) {
Harald Welte90f19742020-11-06 19:34:40 +0100265 return i;
266 }
267 }
268 return -1;
269 }
270
271 function f_nsvc_find(Nsvci nsvci) runs on NS_CT return NSVC_CT {
272 var integer i := f_nsvc_find_idx(nsvci);
273 if (i < 0) {
274 return null;
275 } else {
276 return g_nsvcs[i].vc_conn;
277 }
278 }
279
280 function f_nsvc_update_state(Nsvci nsvci, NsvcState state) runs on NS_CT {
281 var integer i := f_nsvc_find_idx(nsvci);
282 if (i < 0) {
283 return;
284 }
Harald Weltec4505522020-11-11 18:55:09 +0100285 if (g_nsvcs[i].state != NSVC_S_ALIVE_UNBLOCKED and state == NSVC_S_ALIVE_UNBLOCKED) {
286 /* add index to list of unblocked NSVCs */
Harald Weltebe7afce2021-01-17 22:04:36 +0100287 if (not ischosen(g_nsvcs[i].cfg.provider.ip) or
288 g_nsvcs[i].cfg.provider.ip.signalling_weight > 0) {
289 g_unblocked_nsvcs_sig := g_unblocked_nsvcs_sig & {i};
290 }
291 if (not ischosen(g_nsvcs[i].cfg.provider.ip) or
292 g_nsvcs[i].cfg.provider.ip.data_weight > 0) {
293 g_unblocked_nsvcs_data := g_unblocked_nsvcs_data & {i};
294 }
Harald Weltec4505522020-11-11 18:55:09 +0100295 } else if (g_nsvcs[i].state == NSVC_S_ALIVE_UNBLOCKED and state != NSVC_S_ALIVE_UNBLOCKED) {
296 /* remove index to list of unblocked NSVCs */
Harald Weltebe7afce2021-01-17 22:04:36 +0100297 var ro_integer new_unblocked_nsvcs_sig := {};
298 for (var integer j := 0; j < lengthof(g_unblocked_nsvcs_sig); j := j+1) {
299 if (g_unblocked_nsvcs_sig[j] != i) {
300 new_unblocked_nsvcs_sig := new_unblocked_nsvcs_sig & {j};
Harald Weltec4505522020-11-11 18:55:09 +0100301 }
302 }
Harald Weltebe7afce2021-01-17 22:04:36 +0100303 g_unblocked_nsvcs_sig := new_unblocked_nsvcs_sig;
304
305 var ro_integer new_unblocked_nsvcs_data := {};
306 for (var integer j := 0; j < lengthof(g_unblocked_nsvcs_data); j := j+1) {
307 if (g_unblocked_nsvcs_data[j] != i) {
308 new_unblocked_nsvcs_data := new_unblocked_nsvcs_data & {j};
309 }
310 }
311 g_unblocked_nsvcs_data := new_unblocked_nsvcs_data;
312
Harald Weltec4505522020-11-11 18:55:09 +0100313 }
Harald Welte90f19742020-11-06 19:34:40 +0100314 g_nsvcs[i].state := state;
315 }
316
317 function NSStart(NSConfiguration init_config, charstring id := testcasename()) runs on NS_CT {
318 g_config := init_config;
319 g_id := id;
320
321 /* iterate over list of NS-VCs and start per-NSVC components */
322 for (var integer i := 0; i < lengthof(g_config.nsvc); i := i+1) {
323 var NSVCConfiguration nsvc_cfg := g_config.nsvc[i];
324 f_nsvc_add(nsvc_cfg);
325 }
326
327 while (true) {
328 alt {
329 [] as_ns_common() {}
330 }
331 }
332 }
333
Harald Weltedc0a0902020-11-10 21:03:29 +0100334 function f_count_nsvcs_in_state(template NsvcState state := ?) runs on NS_CT return integer {
335 var integer i;
336 var integer res := 0;
337 for (i := 0; i < lengthof(g_nsvcs); i := i+1) {
338 if (match(g_nsvcs[i].state, state)) {
339 res := res + 1;
340 }
341 }
342 return res;
343 }
344
Harald Welte90f19742020-11-06 19:34:40 +0100345 private altstep as_ns_common() runs on NS_CT {
346 var NsStatusIndication rx_nssi;
347 var NsUnitdataIndication rx_nsudi;
348 var NsUnitdataRequest rx_nsudr;
349 /* pass from NS-VCs up to user */
Harald Weltedc0a0902020-11-10 21:03:29 +0100350 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, NSVC_S_ALIVE_UNBLOCKED)) -> value rx_nssi {
351 /* check if this one is the first to be unblocked */
352 var integer num_nsvc_unblocked := f_count_nsvcs_in_state(NSVC_S_ALIVE_UNBLOCKED);
353 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
354 if (num_nsvc_unblocked == 0) {
355 rx_nssi.first_or_last := true;
356 }
357 NS_SP.send(rx_nssi);
358 }
359 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, NSVC_S_DEAD_BLOCKED)) -> value rx_nssi {
360 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
361 /* check if this one is the last to be blocked */
362 var integer num_nsvc_unblocked := f_count_nsvcs_in_state(NSVC_S_ALIVE_UNBLOCKED);
363 if (num_nsvc_unblocked == 0) {
364 rx_nssi.first_or_last := true;
365 }
366 NS_SP.send(rx_nssi);
367 }
368 [] NSVC.receive(tr_NsStsInd(g_config.nsei, ?, ?, ?)) -> value rx_nssi {
Harald Welte90f19742020-11-06 19:34:40 +0100369 f_nsvc_update_state(rx_nssi.nsvci, rx_nssi.new_state);
370 NS_SP.send(rx_nssi);
371 }
372 [] NSVC.receive(tr_NsStsInd) -> value rx_nssi {
373 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
374 log2str("Received NsStatusInd for invalid NSEI: ", rx_nssi));
375 }
376 [] NSVC.receive(tr_NsUdInd(g_config.nsei, ?, ?)) -> value rx_nsudi {
377 NS_SP.send(rx_nsudi);
378 }
Harald Welte1308dbb2021-01-18 18:19:38 +0100379
380 [g_config.handle_sns and g_config.role_sgsn] as_vcg_sns_sgsn();
381
Harald Welte90f19742020-11-06 19:34:40 +0100382 [] NSVC.receive(tr_NsUdInd(?, ?, ?)) -> value rx_nsudi {
383 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
384 log2str("Received UnitDataInd for invalid NSEI: ", rx_nsudi));
385 }
386 /* from user down to NS-VC */
Harald Weltebe7afce2021-01-17 22:04:36 +0100387 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, 0, ?, ?, *)) -> value rx_nsudr {
Harald Weltec4505522020-11-11 18:55:09 +0100388 /* load distribution function */
Harald Weltebe7afce2021-01-17 22:04:36 +0100389 var integer nsvc_idx := g_unblocked_nsvcs_sig[rx_nsudr.lsp mod lengthof(g_unblocked_nsvcs_sig)];
Harald Weltec4505522020-11-11 18:55:09 +0100390 NSVC.send(rx_nsudr) to g_nsvcs[nsvc_idx].vc_conn;
Harald Welte90f19742020-11-06 19:34:40 +0100391 }
Harald Weltebe7afce2021-01-17 22:04:36 +0100392 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, ?, *)) -> value rx_nsudr {
393 /* load distribution function */
394 var integer nsvc_idx := g_unblocked_nsvcs_data[rx_nsudr.lsp mod lengthof(g_unblocked_nsvcs_data)];
395 NSVC.send(rx_nsudr) to g_nsvcs[nsvc_idx].vc_conn;
396 }
397
Harald Weltec4505522020-11-11 18:55:09 +0100398 [] NS_SP.receive(tr_NsUdReq(?, ?, ?, ?, *)) -> value rx_nsudr {
Harald Welte90f19742020-11-06 19:34:40 +0100399 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
400 log2str("Received NsUnitdataReq for invalid NSEI: ", rx_nsudr));
401 }
402 }
403
Harald Welte1308dbb2021-01-18 18:19:38 +0100404 /* generate a list of v4 + v6 endpoints based on the NSVConfigurations. This is not strictly
405 * accurate, as we should create a list of _endpoints_, while we actually create a list of
406 * NSVCs. Those are only identical as long as our peer only implements one endpoint */
407 private function gen_sns_ip_elems(out template (omit) IP4_Elements v4_out,
408 out template (omit) IP6_Elements v6_out) runs on NS_CT {
409 var integer i;
410 var IP4_Elements v4 := {};
411 var IP6_Elements v6 := {};
412
413 for (i := 0; i < lengthof(g_config.nsvc); i := i + 1) {
414 var NSVCConfiguration nsvc_cfg := g_config.nsvc[i];
415 if (not ischosen(nsvc_cfg.provider.ip)) {
416 continue;
417 }
418 if (nsvc_cfg.provider.ip.address_family == AF_INET) {
419 v4 := v4 & { valueof(ts_SNS_IPv4(nsvc_cfg.provider.ip.local_ip,
Harald Weltebe7afce2021-01-17 22:04:36 +0100420 nsvc_cfg.provider.ip.local_udp_port,
421 nsvc_cfg.provider.ip.signalling_weight,
422 nsvc_cfg.provider.ip.data_weight)) };
Harald Welte1308dbb2021-01-18 18:19:38 +0100423 } else if (nsvc_cfg.provider.ip.address_family == AF_INET6) {
424 v6 := v6 & { valueof(ts_SNS_IPv6(nsvc_cfg.provider.ip.local_ip,
Harald Weltebe7afce2021-01-17 22:04:36 +0100425 nsvc_cfg.provider.ip.local_udp_port,
426 nsvc_cfg.provider.ip.signalling_weight,
427 nsvc_cfg.provider.ip.data_weight)) };
Harald Welte1308dbb2021-01-18 18:19:38 +0100428 }
429 }
430
431 /* we must not return empty lists, but 'omit' as otherwise we get wrong SNS IEs */
432 if (lengthof(v4) == 0) {
433 v4_out := omit;
434 } else {
435 v4_out := v4;
436 }
437 if (lengthof(v6) == 0) {
438 v6_out := omit;
439 } else {
440 v6_out := v6;
441 }
442 }
443
444 /* simple IP Sub-Network Service responder for the SGSN side. This is not a full implementation
445 * of the protocol, merely sufficient to make the PCU/BSS side happy to proceed */
446 private altstep as_vcg_sns_sgsn() runs on NS_CT {
447 var SnsIndication sind;
448 var NSVC_CT vc;
449 [] NSVC.receive(SnsIndication:{?, tr_SNS_SIZE(g_config.nsei)}) -> value sind sender vc {
450 /* blindly acknowledge whatever the PCU sends */
451 NSVC.send(SnsRequest:{sind.nsvci, ts_SNS_SIZE_ACK(g_config.nsei, omit)}) to vc;
452 }
453 /* FIXME: We assume our peer has only one endpoint */
454 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(g_config.nsei, true,
455 {tr_SNS_IPv4(g_config.nsvc[0].provider.ip.remote_ip,
456 g_config.nsvc[0].provider.ip.remote_udp_port)})})
457 -> value sind sender vc {
458 /* blindly acknowledge whatever the PCU sends */
459 NSVC.send(SnsRequest:{sind.nsvci, ts_SNS_CONFIG_ACK(g_config.nsei, omit)}) to vc;
460 /* send a SNS-CONFIG in response and expect a SNS-CONFIG-ACK */
461 var template (omit) IP4_Elements v4;
462 var template (omit) IP6_Elements v6;
463 gen_sns_ip_elems(v4, v6);
464 NSVC.send(SnsRequest:{sind.nsvci,
465 ts_SNS_CONFIG(g_config.nsei, true, v4, v6)}) to vc;
466 alt {
467 [] NSVC.receive(SnsIndication:{sind.nsvci,
468 tr_SNS_CONFIG_ACK(g_config.nsei, omit)}) from vc {
469 /* success */
470 log("SNS Config succeeded. Sending Alive");
471 /* inform all NS-VC that they are now considered alive */
472 for (var integer i := 0; i < lengthof(g_nsvcs); i := i+1) {
473 NSVC.send(NsCtrlRequest:StartAliveProcedure) to g_nsvcs[i].vc_conn;
474 }
475 }
476 [] NSVC.receive(SnsIndication:{sind.nsvci,
477 tr_SNS_CONFIG_ACK(g_config.nsei, ?)}) from vc {
478 setverdict(fail, "Unexpected SNS-CONFIG-NACK");
479 self.stop;
480 }
481 }
482 }
483 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(g_config.nsei, false, ?)}) { /* ignore */}
484 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(g_config.nsei, true, ?)}) {
485 setverdict(fail, "Unexpected SNS-CONFIG content");
486 self.stop;
487 }
488 [] NSVC.receive(SnsIndication:{?, tr_SNS_CONFIG(?, ?, ?)}) {
489 setverdict(fail, "SNS-CONFIG from unexpected NSEI");
490 self.stop;
491 }
492 }
493
Harald Welte90f19742020-11-06 19:34:40 +0100494 /***********************************************************************
495 per-NSVC component. Exists once for each NS-VC in the NS-VCG
496 ***********************************************************************/
497
498 type component NSVC_CT {
Harald Welte6fff3642017-07-22 21:36:13 +0200499 /* UDP port towards the bottom (IUT) */
Harald Welte013d65a2020-09-13 14:41:31 +0200500 port NS_PROVIDER_PT NSCP;
501 var NS_Provider_IPL4_CT vc_NSP_IP;
Harald Welte867243a2020-09-13 18:32:32 +0200502#ifdef NS_EMULATION_FR
503 var NS_Provider_FR_CT vc_NSP_FR;
504#endif
Harald Welte013d65a2020-09-13 14:41:31 +0200505
Harald Welte90f19742020-11-06 19:34:40 +0100506 /* port towards the NS_CT */
Harald Welte1308dbb2021-01-18 18:19:38 +0100507 port NSint_SP_PT NS_SP;
Harald Welte6fff3642017-07-22 21:36:13 +0200508
Harald Welte90f19742020-11-06 19:34:40 +0100509 /* configuration passed by the user */
510 var NSVCConfiguration g_nsvc_config;
511 /* we cannot access the NS_CT.config and hence need to copy those */
512 var NSConfiguration g_config;
Alexander Couzens2c12b242018-07-31 00:30:11 +0200513
Harald Welte90f19742020-11-06 19:34:40 +0100514 var NsvcState vc_state := NSVC_S_DEAD_BLOCKED;
Harald Welte6e594f22017-07-23 16:19:35 +0200515
516 timer Tns_alive := 3.0;
517 timer Tns_test := 10.0;
518 timer Tns_block := 10.0;
Harald Welte3dd83552020-09-14 11:38:01 +0200519 timer Tns_reset := 10.0;
Harald Welte6fff3642017-07-22 21:36:13 +0200520 }
521
Harald Welte90f19742020-11-06 19:34:40 +0100522 function NSVCStart(NSVCConfiguration init_config, NSConfiguration init_g_config, charstring id := testcasename()) runs on NSVC_CT {
523 g_nsvc_config := init_config;
524 g_config := init_g_config;
525 f_init(id & "-NSVCemu" & int2str(g_nsvc_config.nsvci));
526 f_ScanEvents();
Alexander Couzens2c12b242018-07-31 00:30:11 +0200527 }
Harald Welte6fff3642017-07-22 21:36:13 +0200528
Harald Welte90f19742020-11-06 19:34:40 +0100529 private function f_init(charstring id) runs on NSVC_CT {
Harald Welte90f19742020-11-06 19:34:40 +0100530 if (ischosen(g_nsvc_config.provider.ip)) {
531 /* Connect the UDP socket */
532 vc_NSP_IP := NS_Provider_IPL4_CT.create(id & "-provIP");
533 connect(self:NSCP, vc_NSP_IP:NSE);
534 vc_NSP_IP.start(NS_Provider_IPL4.main(g_nsvc_config, g_config, id));
535#ifdef NS_EMULATION_FR
536 } else if (ischosen(g_nsvc_config.provider.fr)) {
537 vc_NSP_FR := NS_Provider_FR_CT.create(id & "-provFR");
538 connect(self:NSCP, vc_NSP_FR:NSE);
539 vc_NSP_FR.start(NS_Provider_FR.main(g_nsvc_config, g_config, id));
540#endif
Harald Weltee15299a2020-11-17 17:30:09 +0100541 } else {
542 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unsupported NS provider");
Harald Welte90f19742020-11-06 19:34:40 +0100543 }
544
545 f_change_state(NSVC_S_DEAD_BLOCKED);
Harald Welte6fff3642017-07-22 21:36:13 +0200546 }
547
Harald Welte90f19742020-11-06 19:34:40 +0100548 private function f_change_state(NsvcState new_state) runs on NSVC_CT {
549 var NsvcState old_state := vc_state;
550 vc_state := new_state;
551 log("NSVC ", g_nsvc_config.nsvci, " State Transition: ", old_state, " -> ", new_state);
552 NS_SP.send(ts_NsStsInd(g_config.nsei, g_nsvc_config.nsvci, old_state, new_state));
553 }
554
555 private function f_sendReset() runs on NSVC_CT {
556 NSCP.send(ts_NS_RESET(NS_CAUSE_OM_INTERVENTION, g_nsvc_config.nsvci, g_config.nsei));
Harald Welte3dd83552020-09-14 11:38:01 +0200557 Tns_reset.start;
Harald Welte90f19742020-11-06 19:34:40 +0100558 vc_state := NSVC_S_WAIT_RESET;
Harald Welte6fff3642017-07-22 21:36:13 +0200559 }
560
Harald Welte90f19742020-11-06 19:34:40 +0100561 private function f_sendAlive() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200562 NSCP.send(t_NS_ALIVE);
Harald Welte6e594f22017-07-23 16:19:35 +0200563 Tns_alive.start;
564 }
565
Harald Welte90f19742020-11-06 19:34:40 +0100566 private function f_sendUnblock() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200567 NSCP.send(t_NS_UNBLOCK);
Harald Welte6e594f22017-07-23 16:19:35 +0200568 Tns_block.start;
569 }
570
Harald Welte90f19742020-11-06 19:34:40 +0100571 private function f_sendBlock(NsCause cause) runs on NSVC_CT {
572 NSCP.send(ts_NS_BLOCK(cause, g_nsvc_config.nsvci));
Harald Welte6e594f22017-07-23 16:19:35 +0200573 Tns_block.start;
574 }
575
Harald Welte90f19742020-11-06 19:34:40 +0100576 private altstep as_allstate() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200577 var PDU_NS rf;
Harald Welte6e594f22017-07-23 16:19:35 +0200578 var ASP_Event evt;
579
580 /* transition to DEAD if t_alive times out */
Harald Welte9a7c5122020-09-14 11:35:57 +0200581 [] Tns_alive.timeout {
582 log("Tns-alive expired: changing to DEAD_BLOCKED + starting Tns-test");
Harald Welte90f19742020-11-06 19:34:40 +0100583 f_change_state(NSVC_S_DEAD_BLOCKED);
Harald Welte6e594f22017-07-23 16:19:35 +0200584 Tns_test.start;
Harald Welte6fff3642017-07-22 21:36:13 +0200585 }
Harald Welte6fff3642017-07-22 21:36:13 +0200586
Harald Welte9a7c5122020-09-14 11:35:57 +0200587 [] Tns_test.timeout {
Harald Welte6e594f22017-07-23 16:19:35 +0200588 log("Tns-test expired: sending NS-ALIVE");
589 f_sendAlive();
Harald Welte6fff3642017-07-22 21:36:13 +0200590 }
Harald Welte6fff3642017-07-22 21:36:13 +0200591
Harald Welte6e594f22017-07-23 16:19:35 +0200592 /* Stop t_alive when receiving ALIVE-ACK */
Harald Welte9a7c5122020-09-14 11:35:57 +0200593 [Tns_alive.running] NSCP.receive(t_NS_ALIVE_ACK) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200594 log("Rx NS-ALIVE-ACK: stopping Tns-alive; starting Tns-test");
Harald Welte6e594f22017-07-23 16:19:35 +0200595 Tns_alive.stop;
596 Tns_test.start;
597 }
Harald Welte6fff3642017-07-22 21:36:13 +0200598
Harald Welte6e594f22017-07-23 16:19:35 +0200599 /* respond to NS-ALIVE with NS-ALIVE-ACK */
Harald Welte013d65a2020-09-13 14:41:31 +0200600 [] NSCP.receive(t_NS_ALIVE) {
601 NSCP.send(t_NS_ALIVE_ACK);
Harald Welte6e594f22017-07-23 16:19:35 +0200602 }
603
604 /* Respond to BLOCK for wrong NSVCI */
Harald Welte013d65a2020-09-13 14:41:31 +0200605 [] NSCP.receive(tr_NS_BLOCK(?, ?)) -> value rf {
Harald Welte6e594f22017-07-23 16:19:35 +0200606 log("Rx NS-BLOCK for unknown NSVCI");
607 /* FIXME */
608 }
609
Harald Welte90f19742020-11-06 19:34:40 +0100610 [not g_config.handle_sns] as_handle_reset();
Harald Welte6e594f22017-07-23 16:19:35 +0200611
Harald Welte1308dbb2021-01-18 18:19:38 +0100612 [g_config.handle_sns and ischosen(g_nsvc_config.provider.ip)] as_nsvc_sns();
Harald Welte5e514fa2018-07-05 00:01:45 +0200613
Harald Welte6e594f22017-07-23 16:19:35 +0200614 /* default case of handling unknown PDUs */
Harald Welte013d65a2020-09-13 14:41:31 +0200615 [] NSCP.receive(PDU_NS: ?) -> value rf {
Harald Welte90f19742020-11-06 19:34:40 +0100616 log("Rx Unexpected NS PDU ", rf," in state ", vc_state);
Harald Welte013d65a2020-09-13 14:41:31 +0200617 NSCP.send(ts_NS_STATUS(NS_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE, rf));
Harald Welte6e594f22017-07-23 16:19:35 +0200618 }
Harald Welte6fff3642017-07-22 21:36:13 +0200619 }
620
Harald Welte90f19742020-11-06 19:34:40 +0100621 private altstep as_handle_reset() runs on NSVC_CT {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200622 var PDU_NS rf;
623
Harald Welte90f19742020-11-06 19:34:40 +0100624 [g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200625 log("Provider Link came up: waiting for NS-RESET");
626 }
627
Harald Welte90f19742020-11-06 19:34:40 +0100628 [not g_config.role_sgsn] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
Daniel Willmann654f85e2020-10-12 18:10:06 +0200629 log("Provider Link came up: sending NS-RESET");
630 f_sendReset();
631 }
632
633 /* Respond to RESET with correct NSEI/NSVCI */
Harald Welte90f19742020-11-06 19:34:40 +0100634 [] NSCP.receive(tr_NS_RESET(?, g_nsvc_config.nsvci, g_config.nsei)) -> value rf {
635 f_change_state(NSVC_S_ALIVE_BLOCKED);
636 NSCP.send(ts_NS_RESET_ACK(g_nsvc_config.nsvci, g_config.nsei));
Daniel Willmann654f85e2020-10-12 18:10:06 +0200637 log("Rx NS-RESET: Sending NS-ALIVE");
638 f_sendAlive();
639 Tns_test.start;
640 }
641
642 /* Respond to RESET with wrong NSEI/NSVCI */
643 [] NSCP.receive(tr_NS_RESET(?, ?, ?)) -> value rf {
644 log("Rx NS-RESET for unknown NSEI/NSVCI");
645 /* FIXME */
646 }
647 }
648
Harald Welte1308dbb2021-01-18 18:19:38 +0100649 private altstep as_nsvc_sns() runs on NSVC_CT {
Harald Welte013d65a2020-09-13 14:41:31 +0200650 var PDU_NS rf;
Harald Welte1308dbb2021-01-18 18:19:38 +0100651 var SnsRequest sreq;
Alexander Couzensd5338902020-12-21 18:41:21 +0100652 [] NSCP.receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP}) {
653 log("Provider Link came up. Waiting for SNS Size");
Harald Welte1308dbb2021-01-18 18:19:38 +0100654 }
Daniel Willmann654f85e2020-10-12 18:10:06 +0200655
Harald Welte1308dbb2021-01-18 18:19:38 +0100656 /* pass up to NS-VCG */
657 [] NSCP.receive(tr_SNS(g_config.nsei)) -> value rf {
658 NS_SP.send(SnsIndication:{g_nsvc_config.nsvci, rf});
Harald Welte5e514fa2018-07-05 00:01:45 +0200659 }
Harald Welte1308dbb2021-01-18 18:19:38 +0100660 [] NSCP.receive(tr_SNS(?)) -> value rf {
661 setverdict(fail, "SNS from unexpected NSEI: ", rf);
Harald Welte5e514fa2018-07-05 00:01:45 +0200662 self.stop;
663 }
Harald Welte1308dbb2021-01-18 18:19:38 +0100664 [] NS_SP.receive(SnsRequest:{g_nsvc_config.nsvci, ?}) -> value sreq {
665 NSCP.send(sreq.ns);
Harald Welte5e514fa2018-07-05 00:01:45 +0200666 }
Harald Welte1308dbb2021-01-18 18:19:38 +0100667 [] NS_SP.receive(SnsRequest:?) -> value sreq {
668 setverdict(fail, "Unexpected SNS from NSVC: ", sreq);
Harald Welte5e514fa2018-07-05 00:01:45 +0200669 self.stop;
670 }
Harald Welte1308dbb2021-01-18 18:19:38 +0100671 [] NS_SP.receive(NsCtrlRequest:StartAliveProcedure) {
672 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
673 f_sendAlive();
674 Tns_test.start;
Harald Welte5e514fa2018-07-05 00:01:45 +0200675 }
676 }
677
Harald Welte90f19742020-11-06 19:34:40 +0100678 private altstep as_alive_blocked() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200679 var PDU_NS rf;
680 /* bogus block, just respond with ACK */
Harald Welte90f19742020-11-06 19:34:40 +0100681 [] NSCP.receive(tr_NS_BLOCK(?, g_nsvc_config.nsvci)) -> value rf {
682 NSCP.send(ts_NS_BLOCK_ACK(g_nsvc_config.nsvci));
Harald Welte4a6a6632020-09-14 09:58:53 +0200683 }
684 /* Respond to UNBLOCK with UNBLOCK-ACK + change state */
685 [] NSCP.receive(t_NS_UNBLOCK) -> value rf {
686 NSCP.send(t_NS_UNBLOCK_ACK);
687 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100688 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200689 }
690 [] NSCP.receive(t_NS_UNBLOCK_ACK) -> value rf {
691 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100692 f_change_state(NSVC_S_ALIVE_UNBLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200693 }
Harald Welteda9d9382020-12-07 15:53:57 +0100694 /* tolerate a late NS-BLOCK-ACK from peer */
695 [] NSCP.receive(tr_NS_BLOCK_ACK(g_nsvc_config.nsvci)) -> value rf {
696 }
Harald Welte4a6a6632020-09-14 09:58:53 +0200697 [] Tns_block.timeout {
698 /* repeat unblock transmission */
699 f_sendUnblock();
700 }
701 }
702
Harald Welte90f19742020-11-06 19:34:40 +0100703 private altstep as_alive_unblocked() runs on NSVC_CT {
Harald Welte6fff3642017-07-22 21:36:13 +0200704 var NsUnitdataRequest ud_req;
Harald Welte013d65a2020-09-13 14:41:31 +0200705 var PDU_NS rf;
Harald Welte4a6a6632020-09-14 09:58:53 +0200706 /* bogus unblock, just respond with ACK */
707 [] NSCP.receive(t_NS_UNBLOCK) -> value rf {
708 NSCP.send(t_NS_UNBLOCK_ACK);
709 }
710 /* Respond to BLOCK with BLOCK-ACK + change state */
Harald Welte90f19742020-11-06 19:34:40 +0100711 [] NSCP.receive(tr_NS_BLOCK(?, g_nsvc_config.nsvci)) -> value rf {
712 NSCP.send(ts_NS_BLOCK_ACK(g_nsvc_config.nsvci));
Harald Welte4a6a6632020-09-14 09:58:53 +0200713 Tns_block.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100714 f_change_state(NSVC_S_ALIVE_BLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200715 }
Harald Welte90f19742020-11-06 19:34:40 +0100716 [] NSCP.receive(tr_NS_BLOCK_ACK(g_nsvc_config.nsvci)) -> value rf {
Harald Welte4a6a6632020-09-14 09:58:53 +0200717 Tns_block.stop;
718 }
Harald Welteda9d9382020-12-07 15:53:57 +0100719 /* tolerate a late NS-UNBLOCK-ACK from peer */
720 [] NSCP.receive(t_NS_UNBLOCK_ACK) -> value rf {
721 }
Harald Weltebe7afce2021-01-17 22:04:36 +0100722
723 [not ischosen(g_nsvc_config.provider.ip) or
724 g_nsvc_config.provider.ip.data_weight > 0] as_alive_unblocked_data();
725
726 [not ischosen(g_nsvc_config.provider.ip) or
727 g_nsvc_config.provider.ip.signalling_weight > 0] as_alive_unblocked_sig();
728
729 /* catch any violations of above rule */
730 [ischosen(g_nsvc_config.provider.ip)] NSCP.receive(tr_NS_UNITDATA(?, ?, ?)) -> value rf {
731 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
732 log2str("Unexpected Rx NS-UNITDATA on NSVC with data_weight=",
733 g_nsvc_config.provider.ip.data_weight, ", sig_weight=",
734 g_nsvc_config.provider.ip.signalling_weight, ": ", rf));
735 }
736 [ischosen(g_nsvc_config.provider.ip)] NS_SP.receive(tr_NsUdReq(g_config.nsei, ?, ?, *, *)) -> value ud_req {
737 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
738 log2str("Unexpected Rx TX-UNITDATA on NSVC with data_weight=",
739 g_nsvc_config.provider.ip.data_weight, ", sig_weight=",
740 g_nsvc_config.provider.ip.signalling_weight, ": ", ud_req));
741 }
742 }
743
744 /* user data transfer; only permitted for some NS-VC */
745 private altstep as_alive_unblocked_data() runs on NSVC_CT {
746 var NsUnitdataRequest ud_req;
747 var PDU_NS rf;
Harald Welte4a6a6632020-09-14 09:58:53 +0200748 /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */
Harald Weltebe7afce2021-01-17 22:04:36 +0100749 [] NSCP.receive(tr_NS_UNITDATA_User(?, ?)) -> value rf {
Harald Welte80a249a2020-11-17 19:57:40 +0100750 NS_SP.send(ts_NsUdInd(g_config.nsei, g_nsvc_config.nsvci,
Harald Welte4a6a6632020-09-14 09:58:53 +0200751 oct2int(rf.pDU_NS_Unitdata.bVCI),
752 rf.pDU_NS_Unitdata.nS_SDU));
753 }
754 /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */
Harald Weltebe7afce2021-01-17 22:04:36 +0100755 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, t_BssgpBvciUser, ?, ?, omit)) -> value ud_req {
Harald Welte4a6a6632020-09-14 09:58:53 +0200756 /* using raw octetstring PDU */
757 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu));
758 }
Harald Weltebe7afce2021-01-17 22:04:36 +0100759 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, t_BssgpBvciUser, ?, omit, ?)) -> value ud_req {
760 /* using decoded BSSGP PDU that we need to encode first */
761 var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp);
762 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc));
763 }
764 }
765
766 /* signalling (BVCI=0) transfer; only permitted for some NS-VC */
767 private altstep as_alive_unblocked_sig() runs on NSVC_CT {
768 var NsUnitdataRequest ud_req;
769 var PDU_NS rf;
770 /* NS-UNITDATA PDU from network to NS-UNITDATA.ind to user */
771 [] NSCP.receive(tr_NS_UNITDATA(?, 0, ?)) -> value rf {
772 NS_SP.send(ts_NsUdInd(g_config.nsei, g_nsvc_config.nsvci,
773 oct2int(rf.pDU_NS_Unitdata.bVCI),
774 rf.pDU_NS_Unitdata.nS_SDU));
775 }
776 /* NS-UNITDATA.req from user to NS-UNITDATA PDU on network */
777 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, 0, ?, ?, omit)) -> value ud_req {
778 /* using raw octetstring PDU */
779 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, ud_req.sdu));
780 }
781 [] NS_SP.receive(tr_NsUdReq(g_config.nsei, 0, ?, omit, ?)) -> value ud_req {
Harald Welte4a6a6632020-09-14 09:58:53 +0200782 /* using decoded BSSGP PDU that we need to encode first */
783 var octetstring enc := enc_PDU_BSSGP(ud_req.bssgp);
784 NSCP.send(ts_NS_UNITDATA(t_SduCtrlB, ud_req.bvci, enc));
785 }
786 }
Harald Welte6e594f22017-07-23 16:19:35 +0200787
Harald Welte90f19742020-11-06 19:34:40 +0100788 private altstep as_wait_reset() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200789 var PDU_NS rf;
Harald Welte3dd83552020-09-14 11:38:01 +0200790 [] Tns_reset.timeout {
791 /* If the sending entity of an NS-RESET PDU receives no NS-RESET-ACK PDU before timer
792 * Tns-reset expires the corresponding NS-VCs shall remain blocked and dead and the
793 * entire reset procedure shall be repeated */
794 f_sendReset();
795 }
Harald Welte90f19742020-11-06 19:34:40 +0100796 [] NSCP.receive(tr_NS_RESET_ACK(g_nsvc_config.nsvci, g_config.nsei)) -> value rf {
Harald Welte3dd83552020-09-14 11:38:01 +0200797 Tns_reset.stop;
Harald Welte90f19742020-11-06 19:34:40 +0100798 f_change_state(NSVC_S_ALIVE_BLOCKED);
Harald Welte4a6a6632020-09-14 09:58:53 +0200799 f_sendAlive();
800 f_sendUnblock();
801 }
802 }
Harald Welte6fff3642017-07-22 21:36:13 +0200803
Harald Welte90f19742020-11-06 19:34:40 +0100804 private function f_ScanEvents() runs on NSVC_CT {
Harald Welte4a6a6632020-09-14 09:58:53 +0200805 var PDU_NS rf;
Harald Welte6fff3642017-07-22 21:36:13 +0200806 while (true) {
Harald Welte6fff3642017-07-22 21:36:13 +0200807 alt {
Harald Welte90f19742020-11-06 19:34:40 +0100808 [vc_state == NSVC_S_WAIT_RESET] as_wait_reset();
809 [vc_state == NSVC_S_ALIVE_BLOCKED] as_alive_blocked();
810 [vc_state == NSVC_S_ALIVE_UNBLOCKED] as_alive_unblocked();
Harald Welte4a6a6632020-09-14 09:58:53 +0200811 [] as_allstate();
Harald Welte6fff3642017-07-22 21:36:13 +0200812 }
813 }
Harald Welte6fff3642017-07-22 21:36:13 +0200814 }
815}