diff options
Diffstat (limited to 'ns/NS_Tests.ttcn')
-rw-r--r-- | ns/NS_Tests.ttcn | 1105 |
1 files changed, 1105 insertions, 0 deletions
diff --git a/ns/NS_Tests.ttcn b/ns/NS_Tests.ttcn new file mode 100644 index 00000000..722f8ecc --- /dev/null +++ b/ns/NS_Tests.ttcn @@ -0,0 +1,1105 @@ +module NS_Tests { + +/* Osmocom NS test suite for NS over framerelay or udp ip.access style in TTCN-3 + * (C) 2021 sysmocom s.f.m.c. GmbH <info@sysmocom.de> + * Author: Alexander Couzens <lynxis@fe80.eu> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +import from General_Types all; +import from Osmocom_Types all; +import from Osmocom_Gb_Types all; +import from NS_Types all; +import from BSSGP_Types all; +import from UD_Types all; +import from NS_Emulation all; +import from Native_Functions all; +import from IPL4asp_Types all; +import from RAW_NS all; +import from Osmocom_VTY_Functions all; +import from TELNETasp_PortType all; + +type enumerated SnsRole { + SNS_ROLE_BSS ('00'H), + SNS_ROLE_SGSN ('01'H) +}; + +modulepar { + SnsRole mp_sns_role := SNS_ROLE_BSS; + OsmoNsDialect mp_dialect := NS2_DIALECT_IPACCESS; + NSConfiguration mp_nsconfig := { + nsei := 96, + role_sgsn := false, + handle_sns := false, + nsvc := { + { + provider := { + ip := { + address_family := AF_INET, + local_udp_port := 21000, + local_ip := "127.0.0.1", + remote_udp_port := 23000, + remote_ip := "127.0.0.1", + data_weight := 2, + signalling_weight := 2 + } + }, + nsvci := 97 + }, + { + provider := { + ip := { + address_family := AF_INET, + local_udp_port := 21000, + local_ip := "127.0.0.1", + remote_udp_port := 23001, + remote_ip := "127.0.0.1", + data_weight := 1, + signalling_weight := 1 + } + }, + nsvci := 98 + } + } + }; +} + +type component RAW_Test_CT extends RAW_NS_CT { + port TELNETasp_PT NSVTY; +} + +private function f_init_vty() runs on RAW_Test_CT { + map(self:NSVTY, system:NSVTY); + f_vty_set_prompts(NSVTY); + f_vty_transceive(NSVTY, "enable"); + f_vty_config2(NSVTY, {}, "mirror-mode disable"); + f_vty_transceive(NSVTY, "nsvc nsei " & int2str(mp_nsconfig.nsei) & " force-unconfigured"); + if (mp_dialect == NS2_DIALECT_SNS) { + f_vty_config2(NSVTY, {"ns", "nse " & int2str(mp_nsconfig.nsei)}, "ip-sns-bind local"); + f_vty_config2(NSVTY, {"ns", "nse " & int2str(mp_nsconfig.nsei)}, "no ip-sns-bind local2"); + f_vty_config2(NSVTY, {"ns", "bind udp local"}, "ip-sns signalling-weight 1 data-weight 1"); + f_vty_config2(NSVTY, {"ns", "bind udp local2"}, "ip-sns signalling-weight 1 data-weight 1"); + } +} + +/* ensure no matching message is received within 'tout' */ +function f_ensure_no_ns(integer idx := 0, boolean answer_alive := false, float tout := 3.0) +runs on RAW_Test_CT { + var PDU_NS nrf; + + timer T := tout; + var default d := activate(ax_rx_fail_on_any_ns(idx)); + T.start; + alt { + [answer_alive] as_rx_alive_tx_ack(); + [] T.timeout { + setverdict(pass); + } + } + deactivate(d); +} + +function f_fails_except_reset(integer idx := 0, float tout := 15.0) +runs on RAW_Test_CT { + var PDU_NS nrf; + timer T := 15.0; + T.start; + alt { + [] NSCP[idx].receive(tr_NS_RESET(*, *, *)) { + repeat; + } + [] NSCP[idx].receive(PDU_NS: ?) -> value nrf { + setverdict(fail, "Received unexpected NS: ", nrf); + mtc.stop; + } + [] T.timeout { + setverdict(pass); + } + } +} + +testcase TC_tx_reset() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 10.0); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(); + + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +testcase TC_tx_reset_tx_alive() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 10.0); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(); + + /* check outgoing NS procedure */ + f_outgoing_ns_alive(); + + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +testcase TC_tx_reset_rx_alive() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 10.0); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(); + + activate(as_rx_ns_unblock_ack()); + /* check outgoing NS procedure */ + as_rx_alive_tx_ack(oneshot := true); + + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.2.1 transmit a UNIT DATA over a BLOCKED NSVC when ttcn3 blocked it + * + * TTCN -> NS: reset + * TTCN <- NS: reset ack + * TTCN -> NS: unblock + * TTCN <- NS: unblock ack + * TTCN -> NS: block + * TTCN <- NS: block ack + * TTCN -> NS: unitdata + * TTCN <- NS: status (cause blocked) + */ +testcase TC_tx_block_unitdata_over_blocked() runs on RAW_Test_CT { + f_tx_block(); + f_sleep(1.0); + + NSCP[0].send(ts_NS_UNITDATA(t_SduCtrlB, 42, '0011234242230101'O)); + f_ns_exp(tr_NS_STATUS(NS_CAUSE_NSVC_BLOCKED)); + + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.2.1 transmit a UNIT DATA over a BLOCKED NSVC when ns2 blocked it + * + * TTCN -> NS: reset + * TTCN <- NS: reset ack + * TTCN -> NS: unblock + * TTCN <- NS: unblock ack + * TTCN <- NS: block + * TTCN -> NS: block ack + * TTCN -> NS: unitdata + * TTCN <- NS: status (cause blocked) + */ +testcase TC_rx_block_unitdata_over_blocked() runs on RAW_Test_CT { + f_tx_block_by_vty(); + f_sleep(1.0); + + NSCP[0].send(ts_NS_UNITDATA(t_SduCtrlB, 42, '0011234242230101'O)); + f_ns_exp(tr_NS_STATUS(NS_CAUSE_NSVC_BLOCKED)); + + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.2 unblock procedure + * + * TTCN -> NS: reset + * TTCN <- NS: reset ack + * TTCN -> NS: unblock + * TTCN <- NS: unblock ack + */ +function f_tx_unblock() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(); + /* send alive acks */ + activate(as_rx_alive_tx_ack()); + + f_outgoing_ns_unblock(); + setverdict(pass); +} + +testcase TC_tx_unblock() runs on RAW_Test_CT { + f_tx_unblock(); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.2 tx unblock retries + * + * TTCN -> NS: reset + * TTCN <- NS: reset ack + * TTCN -> NS: unblock + * TTCN <- NS: unblock ack + * TTCN -> NS: unblock + * TTCN <- NS: unblock ack + * TTCN -> NS: unblock + * TTCN <- NS: unblock ack + */ +testcase TC_tx_unblock_retries() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(); + /* send alive acks */ + activate(as_rx_alive_tx_ack()); + + f_outgoing_ns_unblock(); + f_outgoing_ns_unblock(); + f_outgoing_ns_unblock(); + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.2 block procedure + * + * TTCN -> NS: reset + * TTCN <- NS: reset ack + * TTCN -> NS: unblock + * TTCN <- NS: unblock ack + * TTCN -> NS: block + * TTCN <- NS: block ack + */ +function f_tx_block(float guard_secs := 30.0) runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := guard_secs); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(); + activate(as_rx_alive_tx_ack()); + + f_outgoing_ns_unblock(); + f_sleep(1.0); + + f_outgoing_ns_block(NS_CAUSE_EQUIPMENT_FAILURE); + setverdict(pass); + f_sleep(1.0); +} + +testcase TC_tx_block() runs on RAW_Test_CT { + f_tx_block() + f_clean_ns_codec(); +} + +/* 48.016 7.2 block procedure by vty + * + * TTCN -> NS: reset + * TTCN <- NS: reset ack + * TTCN -> NS: unblock + * TTCN <- NS: unblock ack + * vty: block nsvc + * TTCN <- NS: block + * TTCN -> NS: block ack + */ +function f_tx_block_by_vty(float guard_secs := 30.0) runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := guard_secs); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(); + activate(as_rx_alive_tx_ack()); + + f_outgoing_ns_unblock(); + f_sleep(1.0); + + f_vty_transceive(NSVTY, "nsvc " & int2str(mp_nsconfig.nsvc[0].nsvci) & " block"); + + alt { + [] as_rx_ns_block_ack(oneshot := true, nsvci := mp_nsconfig.nsvc[0].nsvci); + } + setverdict(pass); +} + +testcase TC_tx_block_by_vty() runs on RAW_Test_CT { + f_tx_block_by_vty(30.0); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.2 block precedure by vty and reset the NSVC. + * The NSVC should be still blocked after the reset. + */ +testcase TC_tx_block_by_vty_reset() runs on RAW_Test_CT { + timer T := 10.0; + + f_tx_block_by_vty(60.0); + f_outgoing_ns_reset(); + + var default d := activate(ax_rx_fail_on_any_ns()); + T.start; + alt { + [] as_rx_alive_tx_ack(); + [] T.timeout { setverdict(pass); } + } + deactivate(d); + f_clean_ns_codec(); +} + +/* 48.016 7.4.1 ignore unexpected NS_ALIVE ACK */ +testcase TC_no_reset_alive_ack() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + NSCP[0].send(t_NS_ALIVE_ACK); + f_fails_except_reset(); + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.3.1 NS_RESET with wrong nsei */ +testcase TC_reset_wrong_nsei() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + NSCP[0].send(ts_NS_RESET(NS_CAUSE_EQUIPMENT_FAILURE, g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei + 20)); + NSCP[0].receive(tr_NS_RESET_ACK(g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei)); + f_fails_except_reset(); + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.3.1 NS_RESET with wrong nsvci */ +testcase TC_reset_wrong_nsvci() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + NSCP[0].send(ts_NS_RESET(NS_CAUSE_EQUIPMENT_FAILURE, g_nsconfig.nsvc[0].nsvci + 20, g_nsconfig.nsei)); + NSCP[0].receive(tr_NS_RESET_ACK(g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei)); + f_fails_except_reset(); + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.3.1 NS_RESET with wrong nsvci + nsei */ +testcase TC_reset_wrong_nsei_nsvci() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + NSCP[0].send(ts_NS_RESET(NS_CAUSE_EQUIPMENT_FAILURE, g_nsconfig.nsvc[0].nsvci + 20, g_nsconfig.nsei + 20)); + NSCP[0].receive(tr_NS_RESET_ACK(g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei)); + f_fails_except_reset(); + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.3.1 NS_RESET_ACK with wrong nsei */ +testcase TC_reset_ack_wrong_nsei() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + NSCP[0].receive(tr_NS_RESET(*, g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei)); + NSCP[0].send(ts_NS_RESET_ACK(g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei + 20)); + f_fails_except_reset(); + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.3.1 NS_RESET_ACK with wrong nsvci */ +testcase TC_reset_ack_wrong_nsvci() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + NSCP[0].receive(tr_NS_RESET(*, g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei)); + NSCP[0].send(ts_NS_RESET_ACK(g_nsconfig.nsvc[0].nsvci + 20, g_nsconfig.nsei)); + f_fails_except_reset(); + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.3.1 NS_RESET_ACK with wrong nsvci + nsei */ +testcase TC_reset_ack_wrong_nsei_nsvci() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + NSCP[0].receive(tr_NS_RESET(*, g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei)); + NSCP[0].send(ts_NS_RESET_ACK(g_nsconfig.nsvc[0].nsvci + 20, g_nsconfig.nsei + 20)); + f_fails_except_reset(); + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.3.1 ignore unexpected NS_RESET_ACK after NS_RESET+ALIVE */ +testcase TC_ignore_reset_ack() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(); + + /* unblock and alive */ + alt { + [] as_rx_ns_unblock_ack(oneshot := true); + [] as_rx_alive_tx_ack(); + } + + NSCP[0].send(ts_NS_RESET_ACK(g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei)); + f_ensure_no_ns(answer_alive := true, tout := 15.0); + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.3 NS_RESET retries */ +testcase TC_reset_retries() runs on RAW_Test_CT { + var integer reset := 0; + + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + alt { + [] NSCP[0].receive(tr_NS_RESET(*, *, *)) { + reset := reset + 1; + if (reset <= 3) { + repeat; + } else { + setverdict(pass); + } + } + } + + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 behave RESET_ACK got dropped + * TTCN -> NS: reset + * TTCN <- NS: reset ack + * TTCN <- NS: unblock + * TTCN -> NS: reset + * TTCN <- NS: reset ack + * TTCN <- NS: unblock + */ +testcase TC_reset_on_block_reset() runs on RAW_Test_CT { + var integer i := 0; + + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + f_outgoing_ns_reset(); + activate(as_rx_alive_tx_ack()); + + alt { + [] NSCP[0].receive(t_NS_UNBLOCK) { + NSCP[0].send(ts_NS_RESET(NS_CAUSE_EQUIPMENT_FAILURE, g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei)); + i := i + 1; + if (i < 3) { + repeat; + } else { + setverdict(pass); + } + } + [] NSCP[0].receive(tr_NS_RESET_ACK(g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei)) { repeat; } + } + + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.4 test procedure for frame relay with a single nsvci */ +function f_alive_retries_single(boolean reset := false) runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 60.0); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(); + + alt { + [] as_rx_ns_unblock_ack(oneshot := true); + [] as_rx_alive_tx_ack(); + } + + /* wait for one alive and answer it */ + as_rx_alive_tx_ack(oneshot := true); + NSCP[0].receive(t_NS_ALIVE); + NSCP[0].receive(t_NS_ALIVE); + NSCP[0].receive(t_NS_ALIVE); + NSCP[0].receive(t_NS_ALIVE); + if (reset) { + NSCP[0].receive(tr_NS_RESET(*, g_nsconfig.nsvc[0].nsvci, g_nsconfig.nsei)); + } else { + f_ensure_no_ns(tout := 10.0); + } + + setverdict(pass); + f_sleep(1.0); +} + +testcase TC_alive_retries_single_reset() runs on RAW_Test_CT { + f_alive_retries_single(reset := true); + f_clean_ns_codec(); +} + +testcase TC_alive_retries_single_no_resp() runs on RAW_Test_CT { + f_alive_retries_single(reset := false); + f_clean_ns_codec(); +} + +/* 48.016 SNS test cases */ + +/* do a succesful SNS configuration */ +testcase TC_sns_bss_config_success() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_incoming_sns_size(); + f_incoming_sns_config(); + f_outgoing_sns_config(); + setverdict(pass); + f_clean_ns_codec(); +} + +testcase TC_sns_bss_change_weight() runs on RAW_Test_CT { + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_incoming_sns_size(); + f_incoming_sns_config(); + f_outgoing_sns_config(); + activate(as_rx_alive_tx_ack()); + f_vty_config2(NSVTY, {"ns", "bind udp local"}, "ip-sns signalling-weight 99 data-weight 99"); + f_incoming_sns_chg_weight(); + setverdict(pass); + f_clean_ns_codec(); +} + +/* receive 3x SNS_CHG_WEIGHT but never answer on it */ +testcase TC_sns_bss_change_weight_timeout() runs on RAW_Test_CT { + var integer i := 0; + var template PDU_NS rx; + var NSVCConfiguration nsvc_cfg; + + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_incoming_sns_size(); + f_incoming_sns_config(); + f_outgoing_sns_config(); + activate(as_rx_alive_tx_ack()); + f_vty_config2(NSVTY, {"ns", "bind udp local"}, "ip-sns signalling-weight 99 data-weight 99"); + + nsvc_cfg := g_nsconfig.nsvc[0]; + if (nsvc_cfg.provider.ip.address_family == AF_INET) { + var template IP4_Elements v4_elem := { tr_SNS_IPv4(nsvc_cfg.provider.ip.remote_ip, + nsvc_cfg.provider.ip.remote_udp_port) }; + + rx := tr_SNS_CHG_WEIGHT(g_nsconfig.nsei, ?, v4 := v4_elem); + } else { + var template IP6_Elements v6_elem := { tr_SNS_IPv6(nsvc_cfg.provider.ip.remote_ip, + nsvc_cfg.provider.ip.remote_udp_port) }; + rx := tr_SNS_CHG_WEIGHT(g_nsconfig.nsei, ?, v4 := omit, v6 := v6_elem); + } + + for (i := 0; i < 3; i := i + 1) { + f_ns_exp(rx); + } + + if (nsvc_cfg.provider.ip.address_family == AF_INET) { + /* expect one single SNS-SIZE with RESET flag; 4x v4 EP; no v6 EP */ + rx := f_ns_exp(tr_SNS_SIZE(g_nsconfig.nsei, rst_flag := true, max_nsvcs := ?, + num_v4 := ?, num_v6 := omit), 0); + } else { + /* expect one single SNS-SIZE with RESET flag; no v4 EP; 4x v6 EP */ + rx := f_ns_exp(tr_SNS_SIZE(g_nsconfig.nsei, rst_flag := true, max_nsvcs := ?, + num_v4 := omit, num_v6 := ?), 0); + } + + setverdict(pass); + f_clean_ns_codec(); +} + +testcase TC_sns_bss_add() runs on RAW_Test_CT { + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_init_ns_codec(mp_nsconfig, 1); + f_incoming_sns_size(); + f_incoming_sns_config(); + f_outgoing_sns_config(); + activate(as_rx_alive_tx_ack()); + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "ip-sns-bind local2"); + f_incoming_sns_add(idx_add := 1); + as_rx_alive_tx_ack(oneshot := true, idx := 1); + setverdict(pass); + f_clean_ns_codec(); +} + +testcase TC_sns_bss_del() runs on RAW_Test_CT { + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_init_ns_codec(mp_nsconfig, 1); + f_incoming_sns_size(); + f_incoming_sns_config(); + f_outgoing_sns_config(); + activate(as_rx_alive_tx_ack()); + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "ip-sns-bind local2"); + f_incoming_sns_add(idx_add := 1); + as_rx_alive_tx_ack(oneshot := true, idx := 1); + + /* delete the endpoint */ + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "no ip-sns-bind local2"); + f_incoming_sns_del(idx_del := 1); + setverdict(pass); + f_clean_ns_codec(); +} + +/* 1. do SNS configuration + * 2. add a bind + * 3. receive the SNS_ADD + * 4. before answering the SNS_ADD, change the weight via vty and remove the bind + */ +testcase TC_sns_bss_add_change_del() runs on RAW_Test_CT { + var PDU_NS rx; + var NSVCConfiguration nsvc_cfg; + + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_init_ns_codec(mp_nsconfig, 1); + f_incoming_sns_size(); + f_incoming_sns_config(); + f_outgoing_sns_config(); + activate(as_rx_alive_tx_ack()); + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "ip-sns-bind local2"); + + /* rx SNS ADD */ + nsvc_cfg := g_nsconfig.nsvc[1]; + if (nsvc_cfg.provider.ip.address_family == AF_INET) { + var template (omit) IP4_Elements v4_elem := { ts_SNS_IPv4(nsvc_cfg.provider.ip.remote_ip, + nsvc_cfg.provider.ip.remote_udp_port, + 1, 1) }; + rx := f_ns_exp(tr_SNS_ADD(g_nsconfig.nsei, ?, v4 := v4_elem), 0); + } else { + var template (omit) IP6_Elements v6_elem := { ts_SNS_IPv6(nsvc_cfg.provider.ip.remote_ip, + nsvc_cfg.provider.ip.remote_udp_port, + 1, 1) }; + rx := f_ns_exp(tr_SNS_ADD(g_nsconfig.nsei, ?, omit, v6_elem), 0); + } + + /* delete the endpoint */ + f_vty_config2(NSVTY, {"ns", "bind udp local2"}, "ip-sns signalling-weight 99 data-weight 99"); + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "no ip-sns-bind local2"); + + /* accept the SNS_ADD */ + NSCP[0].send(ts_SNS_ACK(g_nsconfig.nsei, rx.pDU_SNS_Add.transactionID)); + + f_incoming_sns_chg_weight(idx_chg := 1); + f_incoming_sns_del(idx_del := 1, w_sig := 99, w_user := 99); + setverdict(pass); + f_clean_ns_codec(); +} + +/* Ensure the ns2 code doesn't crash when calling force unconfigured while sending SNS SIZE */ +testcase TC_sns_rx_size_force_unconf() runs on RAW_Test_CT { + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_init_ns_codec(mp_nsconfig, 1); + f_ns_exp(tr_SNS_SIZE(mp_nsconfig.nsei, rst_flag := true, max_nsvcs := ?, + num_v4 := ?, num_v6 := omit)); + f_vty_transceive(NSVTY, "nsvc nsei " & int2str(mp_nsconfig.nsei) & " force-unconfigured"); + f_ns_exp(tr_SNS_SIZE(mp_nsconfig.nsei, rst_flag := true, max_nsvcs := ?, + num_v4 := ?, num_v6 := omit)); + setverdict(pass); + f_clean_ns_codec(); +} + +/* Test if SNS fails when all signalling NSVCs failes + * 3GPP TS 48.016 ยง 7.4b.1.1 + * 1. do success SNS configuration + * 2. change sig weight of the seconds inactive bind + * 3. add second bind to SNS + * 4. stop reacting to NS_ALIVE on first NSVC (only NSVC with sig weight) + * 5. expect SNS SIZE + * + * Broken: the test case tests the wrong side. The signalling + * and data weight are valid for the other side. The correct + * test case needs to add a second bind on the ttcn3 side. + */ +testcase TC_sns_bss_all_signalling_nsvcs_failed() runs on RAW_Test_CT { + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_init_ns_codec(mp_nsconfig, 1); + f_incoming_sns_size(); + f_incoming_sns_config(); + f_outgoing_sns_config(); + var default d := activate(as_rx_alive_tx_ack()); + + f_vty_config2(NSVTY, {"ns", "bind udp local2"}, "ip-sns signalling-weight 0 data-weight 99"); + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "ip-sns-bind local2"); + f_incoming_sns_add(idx_add := 1, w_sig := 0, w_user := 99); + as_rx_alive_tx_ack(oneshot := true, idx := 1); + activate(as_rx_alive_tx_ack(idx := 1)); + /* 2x NSVCs up, stop first NSVC */ + deactivate(d); + /* libosmocore will rotate the SNS binds on failure */ + NSCP[0].receive(t_NS_ALIVE); + NSCP[0].receive(t_NS_ALIVE); + NSCP[0].receive(t_NS_ALIVE); + f_incoming_sns_size(idx := 1); + + setverdict(pass); + f_clean_ns_codec(); +} + +/* Test if SNS fails when removing a bind which has the last valid connection + * + * ns2 has 2 binds, ttcn3 1 bind. + * + * nsvcs: + * ns2 ttcn3 + * 1*-----------*1 + * / + * 2*-broken--/ + * + * remove the 1st ns2 bind. + */ +testcase TC_sns_bss_remove_bind_fail_sns() runs on RAW_Test_CT { + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_init_ns_codec(mp_nsconfig, 1); + f_incoming_sns_size(); + f_incoming_sns_config(); + f_outgoing_sns_config(); + var default d := activate(as_rx_alive_tx_ack()); + + f_vty_config2(NSVTY, {"ns", "bind udp local2"}, "ip-sns signalling-weight 1 data-weight 1"); + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "ip-sns-bind local2"); + f_incoming_sns_add(idx_add := 1, w_sig := 1, w_user := 1); + /* 2nd bind won't have a valid connection to the ttcn3 */ + NSCP[1].receive(t_NS_ALIVE); + NSCP[1].receive(t_NS_ALIVE); + NSCP[1].receive(t_NS_ALIVE); + NSCP[1].receive(t_NS_ALIVE); + NSCP[1].receive(t_NS_ALIVE); + f_sleep(1.0); + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "no ip-sns-bind local"); + setverdict(pass); + f_clean_ns_codec(); +} + +testcase TC_idle() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig, guard_secs := 30.0); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(); + activate(as_rx_alive_tx_ack()); + + f_outgoing_ns_unblock(); + f_sleep(30.0); + + setverdict(pass); + f_sleep(1.0); + f_clean_ns_codec(); +} + +testcase TC_sns_sgsn_config_success() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_outgoing_sns_size(); + f_outgoing_sns_config(); + f_incoming_sns_config(); + setverdict(pass); + f_clean_ns_codec(); +} + +/* Ensure a SIZE after a success full configuration is handled */ +testcase TC_sns_sgsn_size_after_success() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_outgoing_sns_size(); + f_outgoing_sns_config(); + f_incoming_sns_config(); + NSCP[0].receive(t_NS_ALIVE); + + f_outgoing_sns_size(); + f_outgoing_sns_config(); + f_incoming_sns_config(); + setverdict(pass); + f_clean_ns_codec(); +} + +/* Ensure a SNS SIZE ACK is transmitted from the correct port */ +testcase TC_sns_sgsn_size_correct_port() runs on RAW_Test_CT { + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_init_ns_codec(mp_nsconfig, 1); + f_outgoing_sns_size(max_nsvcs := 10); + f_outgoing_sns_config(); + f_incoming_sns_config(); + NSCP[0].receive(t_NS_ALIVE); + f_outgoing_sns_size(max_nsvcs := 10, idx := 1); + setverdict(pass); + f_clean_ns_codec(); +} + +testcase TC_sns_sgsn_add() runs on RAW_Test_CT { + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_init_ns_codec(mp_nsconfig, 1); + f_outgoing_sns_size(max_nsvcs := 4, num_ip := 4); + f_outgoing_sns_config(); + f_incoming_sns_config(); + activate(as_rx_alive_tx_ack()); + + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "ip-sns-bind local2"); + f_incoming_sns_add(idx_add := 1); + as_rx_alive_tx_ack(oneshot := true, idx := 1); + + setverdict(pass); + f_clean_ns_codec(); +} + +testcase TC_sns_sgsn_del() runs on RAW_Test_CT { + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_init_ns_codec(mp_nsconfig, 1); + f_outgoing_sns_size(max_nsvcs := 4, num_ip := 4); + f_outgoing_sns_config(); + f_incoming_sns_config(); + activate(as_rx_alive_tx_ack()); + + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "ip-sns-bind local2"); + f_incoming_sns_add(idx_add := 1); + as_rx_alive_tx_ack(oneshot := true, idx := 1); + + /* delete the endpoint */ + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "no ip-sns-bind local2"); + f_incoming_sns_del(idx_del := 1); + + setverdict(pass); + f_clean_ns_codec(); +} + +/* 1. do SNS configuration + * 2. add a bind + * 3. receive the SNS_ADD + * 4. before answering the SNS_ADD, change the weight via vty and remove the bind + */ +testcase TC_sns_sgsn_add_change_del() runs on RAW_Test_CT { + var PDU_NS rx; + var NSVCConfiguration nsvc_cfg; + + g_handle_rx_alive := true; + f_init_vty(); + f_init_ns_codec(mp_nsconfig); + f_init_ns_codec(mp_nsconfig, 1); + f_outgoing_sns_size(max_nsvcs := 4, num_ip := 4); + f_outgoing_sns_config(); + f_incoming_sns_config(); + activate(as_rx_alive_tx_ack()); + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "ip-sns-bind local2"); + + /* rx SNS ADD */ + nsvc_cfg := g_nsconfig.nsvc[1]; + if (nsvc_cfg.provider.ip.address_family == AF_INET) { + var template (omit) IP4_Elements v4_elem := { ts_SNS_IPv4(nsvc_cfg.provider.ip.remote_ip, + nsvc_cfg.provider.ip.remote_udp_port, + 1, 1) }; + rx := f_ns_exp(tr_SNS_ADD(g_nsconfig.nsei, ?, v4 := v4_elem), 0); + } else { + var template (omit) IP6_Elements v6_elem := { ts_SNS_IPv6(nsvc_cfg.provider.ip.remote_ip, + nsvc_cfg.provider.ip.remote_udp_port, + 1, 1) }; + rx := f_ns_exp(tr_SNS_ADD(g_nsconfig.nsei, ?, omit, v6_elem), 0); + } + + /* delete the endpoint */ + f_vty_config2(NSVTY, {"ns", "bind udp local2"}, "ip-sns signalling-weight 99 data-weight 99"); + f_vty_config2(NSVTY, {"ns", "nse " & int2str(g_nsconfig.nsei)}, "no ip-sns-bind local2"); + + /* accept the SNS_ADD */ + NSCP[0].send(ts_SNS_ACK(g_nsconfig.nsei, rx.pDU_SNS_Add.transactionID)); + + f_incoming_sns_chg_weight(idx_chg := 1); + f_incoming_sns_del(idx_del := 1, w_sig := 99, w_user := 99); + setverdict(pass); + f_clean_ns_codec(); +} + +/* 48.016 7.2 transmit a UNITDATA over an ALIVE connection + * + * TTCN -> NS: reset + * TTCN <- NS: reset ack + * TTCN -> NS: unblock + * TTCN <- NS: unblock ack + * TTCN -> NS: unitdata + * TTCN <- NS: unitdata (mirror) + */ +testcase TC_tx_unitdata() runs on RAW_Test_CT { + f_tx_unblock(); + + f_vty_config2(NSVTY, {}, "mirror-mode enable"); + NSCP[0].send(ts_NS_UNITDATA(t_SduCtrlB, 42, '0011234242230101'O)); + f_ns_exp(tr_NS_UNITDATA(t_SduCtrlB, 42, '0011234242230101'O)); + f_vty_config2(NSVTY, {}, "mirror-mode disable"); + + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.2 ensure tx status (blocked) is correctly parsed + * + * TTCN -> NS: reset + * TTCN <- NS: reset ack + * TTCN -> NS: unblock + * TTCN <- NS: unblock ack + * TTCN -> NS: unitdata + * TTCN <- NS: unitdata (mirror) + * TTCN -> NS: status (blocked) + * TTCN -> NS: unitdata + * TTCN <- NS: status (blocked) + */ +testcase TC_mirror_unitdata_tx_status_blocked() runs on RAW_Test_CT { + f_tx_unblock(); + + f_vty_config2(NSVTY, {}, "mirror-mode enable"); + NSCP[0].send(ts_NS_UNITDATA(t_SduCtrlB, 42, '0011234242230101'O)); + var PDU_NS pdu := f_ns_exp(tr_NS_UNITDATA(t_SduCtrlB, 42, '0011234242230101'O)); + + NSCP[0].send(ts_NS_STATUS(NS_CAUSE_NSVC_BLOCKED, pdu)); + NSCP[0].send(ts_NS_UNITDATA(t_SduCtrlB, 42, '0011234242230101'O)); + f_ns_exp(tr_NS_STATUS(NS_CAUSE_NSVC_BLOCKED)); + + f_vty_config2(NSVTY, {}, "mirror-mode disable"); + f_sleep(1.0); + f_clean_ns_codec(); +} + +/* 48.016 7.2 ensure tx status (blocked) is correctly parsed over a foreign NSVC + * + * 2x initialize NSVC (RESET/UNBLOCK) + * TTCN 0-> NS: block (nsvci 1) + * TTCN <-0 NS: block ack (nsvci 1) + * TTCN 1-> NS: unit data (nsvci 1) + * TTCN <-1 NS: status (blocked) + */ +testcase TC_tx_blocked_foreign_nsvc() runs on RAW_Test_CT { + f_init_vty(); + f_vty_config2(NSVTY, {}, "mirror-mode enable"); + f_init_ns_codec(mp_nsconfig, idx := 0); + f_init_ns_codec(mp_nsconfig, idx := 1); + + /* do a NS Reset procedure */ + f_outgoing_ns_reset(idx := 0); + f_outgoing_ns_reset(idx := 1); + + /* send alive acks */ + activate(as_rx_alive_tx_ack(idx := 0)); + activate(as_rx_alive_tx_ack(idx := 1)); + + f_outgoing_ns_unblock(idx := 0); + f_outgoing_ns_unblock(idx := 1); + + /* both NSVC are alive and unblocked */ + NSCP[0].send(ts_NS_BLOCK(NS_CAUSE_TRANSIT_NETWORK_FAILURE, g_nsconfig.nsvc[1].nsvci)); + f_ns_exp(tr_NS_BLOCK_ACK(g_nsconfig.nsvc[1].nsvci)); + + NSCP[1].send(ts_NS_UNITDATA(t_SduCtrlB, 42, '0011234242230101'O)); + f_ns_exp(tr_NS_STATUS(NS_CAUSE_NSVC_BLOCKED), idx := 1); + + setverdict(pass); + f_clean_ns_codec(); +} + + +control { + if (mp_dialect == NS2_DIALECT_STATIC_RESETBLOCK or mp_dialect == NS2_DIALECT_IPACCESS) { + execute( TC_tx_reset() ); + + /* 48.016 7.2 Block procedure */ + execute( TC_tx_block() ); + execute( TC_tx_block_by_vty() ); + execute( TC_tx_block_by_vty_reset() ); + execute( TC_tx_block_unitdata_over_blocked() ); + execute( TC_rx_block_unitdata_over_blocked() ); + execute( TC_mirror_unitdata_tx_status_blocked() ); + execute( TC_tx_blocked_foreign_nsvc() ); + // execute( TC_block_other_nsvc() ); // reset, unblock, sleep(1), block over another nsvci + /* 48.016 7.2 Unblock procedure */ + execute( TC_tx_unblock() ); + execute( TC_tx_unblock_retries() ); + // execute( TC_rx_unblock_tx_unblock() ); // wait for an rx unblock pdu, send an unblock pdu, expect unblock ack pdu + // execute( TC_unblockable() ); // block a NS-VCI via vty, try block procedure + + /* 48.016 7.2.1 Block Abnormal Condition */ + /* 48.016 7.2.1 Unblock Abnormal Condition */ + /* 48.016 7.3.1 Abnormal Condition */ + execute( TC_reset_wrong_nsei() ); + execute( TC_reset_wrong_nsvci() ); + execute( TC_reset_wrong_nsei_nsvci() ); + execute( TC_reset_ack_wrong_nsei() ); + execute( TC_reset_ack_wrong_nsvci() ); + execute( TC_reset_ack_wrong_nsei_nsvci() ); + execute( TC_reset_retries() ); + execute( TC_reset_on_block_reset() ); + execute( TC_ignore_reset_ack() ); + + /* 48.016 7.4 Test procedure on frame relay */ + execute( TC_tx_reset_tx_alive() ); + execute( TC_tx_reset_rx_alive() ); + + /* 48.016 7.4.1 Abnormal Condition */ + if (mp_dialect == NS2_DIALECT_STATIC_RESETBLOCK) { + // execute( TC_alive_retries_multi() ); // check if alive retries works and block over an alive nsvc + execute( TC_alive_retries_single_reset() ); + } else if (mp_dialect == NS2_DIALECT_IPACCESS) { + execute( TC_alive_retries_single_no_resp() ); + } + + execute( TC_no_reset_alive_ack() ); + execute( TC_tx_unitdata() ); + } + + if (mp_dialect == NS2_DIALECT_SNS) { + if (mp_sns_role == SNS_ROLE_BSS) { + /* BSS test cases */ + execute( TC_sns_bss_config_success() ); + execute( TC_sns_bss_change_weight() ); + execute( TC_sns_bss_change_weight_timeout() ); + execute( TC_sns_bss_add() ); + execute( TC_sns_bss_del() ); + execute( TC_sns_bss_add_change_del() ); + /* execute( TC_sns_bss_all_signalling_nsvcs_failed() ); */ + execute( TC_sns_rx_size_force_unconf() ); + execute( TC_sns_bss_remove_bind_fail_sns() ); + } + + if (mp_sns_role == SNS_ROLE_SGSN) { + execute( TC_sns_sgsn_config_success() ); + execute( TC_sns_sgsn_add() ); + execute( TC_sns_sgsn_del() ); + execute( TC_sns_sgsn_add_change_del() ); + execute( TC_sns_sgsn_size_correct_port() ); + execute( TC_sns_sgsn_size_after_success() ); + } + } +} + +} |