module PCU_Tests_SNS { /* Osmocom PCU test suite for IP Sub-Network-Service (SNS) in TTCN-3 * (C) 2018-2019 Harald Welte * 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 Osmocom_Types all; import from Osmocom_VTY_Functions all; import from PCU_Tests_NS all; import from SGSN_Components all; import from Osmocom_Gb_Types all; import from NS_Emulation all; import from NS_Types all; import from RAW_NS all; import from BSSGP_Types all; /********************************************************************************** * Modern Gb/IP bring-up test cases using IP Sub-Network Service (SNS) **********************************************************************************/ /* PCU-originated SNS-SIZE: successful case */ testcase TC_sns_po_size_success() runs on RAW_Test_CT { f_init_ns_codec(mp_nsconfig); f_init_pcuif(); f_incoming_sns_size(); f_sleep(1.0); setverdict(pass); f_clean_ns_codec(); } /* PCU-originated SNS-SIZE: NACK from our side */ testcase TC_sns_po_size_nack() runs on RAW_Test_CT { f_init_ns_codec(mp_nsconfig); f_init_pcuif(); f_incoming_sns_size(NS_CAUSE_PROTOCOL_ERROR_UNSPECIFIED); /* FIXME: ensure we don't get a SNS-CONFIG */ /* FIXME: ensure we get re-transmitted SNS-SIZE attempts */ f_sleep(10.0); setverdict(pass); f_clean_ns_codec(); } /* PCU-originated SNS-CONFIG: successful case */ testcase TC_sns_po_config_success() runs on RAW_Test_CT { f_init_ns_codec(mp_nsconfig); f_init_pcuif(); f_incoming_sns_size(); f_incoming_sns_config(); f_sleep(1.0); setverdict(pass); f_clean_ns_codec(); } /* PCU-originated SNS-CONFIG: successful case */ testcase TC_sns_po_config_nack() runs on RAW_Test_CT { f_init_ns_codec(mp_nsconfig); f_init_pcuif(); f_incoming_sns_size(); f_incoming_sns_config(NS_CAUSE_PROTOCOL_ERROR_UNSPECIFIED); /* FIXME: ensure we get re-transmitted SNS-CONFIG attempts */ f_sleep(10.0); setverdict(pass); f_clean_ns_codec(); } /* SGSN-originated SNS-SIZE: successful case */ testcase TC_sns_so_config_success() runs on RAW_Test_CT { f_init_ns_codec(mp_nsconfig); f_init_pcuif(); f_incoming_sns_size(); f_incoming_sns_config(); f_outgoing_sns_config(); /* wait for one ALIVE cycle, then ACK any further ALIVE in the background */ as_rx_alive_tx_ack(oneshot := true); activate(as_rx_alive_tx_ack()); f_outgoing_ns_alive(); /* Expect BVC-RESET for signaling (0) and ptp BVCI */ as_rx_bvc_reset_tx_ack(0, omit, omit, oneshot := true); as_rx_bvc_reset_tx_ack(mp_gb_cfg.bvc[0].bvci, mp_gb_cfg.bvc[0].cell_id, omit, oneshot := true); as_rx_bvc_unblock_tx_ack(mp_gb_cfg.bvc[0].bvci, oneshot := true); /* wait for one FLOW-CONTROL BVC and then ACK any further in the future */ as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvc[0].bvci, oneshot := true); activate(as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvc[0].bvci)); setverdict(pass); f_clean_ns_codec(); } private function f_sns_bringup_1c1u(boolean sgsn_originated_reset := false) runs on RAW_Test_CT { /* Activate two NS codec ports */ f_init_ns_codec(mp_nsconfig); f_init_ns_codec(mp_nsconfig, 1); f_init_pcuif(); /* Perform Size + BSS-originated config */ f_incoming_sns_size(); f_incoming_sns_config(); /* perform SGSN-originated config using idx==0 for signalling and idx==1 for user traffic */ f_outgoing_sns_config_1c1u(); /* wait for one ALIVE cycle, then ACK any further ALIVE in the background * for both NS-VCs */ as_rx_alive_tx_ack(oneshot := true, idx := 0); activate(as_rx_alive_tx_ack(idx := 0)); as_rx_alive_tx_ack(oneshot := true, idx := 1); activate(as_rx_alive_tx_ack(idx := 1)); /* perform outgoing ALIVE procedure for both NS-VCs */ f_outgoing_ns_alive(0); f_outgoing_ns_alive(1); if (sgsn_originated_reset) { /* Expect BVC-RESET, but ignore it to prevent a race condition of BVC RESETs */ var template PDU_NS pdu := tr_NS_UNITDATA(t_SduCtrlB, 0, decmatch tr_BVC_RESET(?, 0, omit)); f_ns_exp(pdu); /* SGSN originated BVC-RESET on an uninitialized signalling BVC */ f_tx_bvc_reset_rx_ack(0, omit, omit); /* Expect BVC-RESET PTP BVC, but ignore it to prevent a race condition of BVC RESETs */ pdu := tr_NS_UNITDATA(t_SduCtrlB, 0, decmatch tr_BVC_RESET(?, mp_gb_cfg.bvc[0].bvci, mp_gb_cfg.bvc[0].cell_id)); f_ns_exp(pdu); /* SGSN originated BVC-RESET on an uninitialized PTP BVC */ f_tx_bvc_reset_rx_ack(mp_gb_cfg.bvc[0].bvci, omit, mp_gb_cfg.bvc[0].cell_id); } else { /* Expect BVC-RESET for signaling BVCI=0 */ as_rx_bvc_reset_tx_ack(0, omit, omit, oneshot := true); /* Expect BVC-RESET from the PCU on PTP BVC */ as_rx_bvc_reset_tx_ack(mp_gb_cfg.bvc[0].bvci, mp_gb_cfg.bvc[0].cell_id, omit, oneshot := true); } /* Expect UNBLOCK for ptp BVCI on signaling NS-VC (idx==0) */ as_rx_bvc_unblock_tx_ack(mp_gb_cfg.bvc[0].bvci, oneshot := true); /* wait for one FLOW-CONTROL BVC and then ACK any further in the future. Flow * control happens on the p-t-p BVCI and hence on index 1 */ as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvc[0].bvci, oneshot := true, idx := 1); activate(as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvc[0].bvci, idx := 1)); } /* Test full IP-SNS bring-up with two NS-VCs, one sig-only and one user-only */ testcase TC_sns_1c1u() runs on RAW_Test_CT { f_sns_bringup_1c1u(); setverdict(pass); f_clean_ns_codec(); } private function f_sns_bringup_1c1u_separate(boolean sgsn_originated_reset := false) runs on RAW_Test_CT { /* Activate two NS codec ports */ f_init_ns_codec(mp_nsconfig); f_init_ns_codec(mp_nsconfig, 1); f_init_ns_codec(mp_nsconfig, 2); f_init_pcuif(); /* Perform Size + BSS-originated config */ f_incoming_sns_size(); f_incoming_sns_config(); /* perform SGSN-originated config using idx==0 for signalling and idx==1 for user traffic */ f_outgoing_sns_config_1c1u_separate(); /* wait for one ALIVE cycle, then ACK any further ALIVE in the background * for both NS-VCs */ as_rx_alive_tx_ack(oneshot := true, idx := 1); activate(as_rx_alive_tx_ack(idx := 1)); as_rx_alive_tx_ack(oneshot := true, idx := 2); activate(as_rx_alive_tx_ack(idx := 2)); /* ensure there's no NS-ALIVE received on idx==0 */ f_ensure_no_ns(t_NS_ALIVE, idx := 0); /* perform outgoing ALIVE procedure for both NS-VCs */ f_outgoing_ns_alive(1); f_outgoing_ns_alive(2); /* ensure there's no response to NS-ALIVE sent on idx==0 */ f_outgoing_ns_alive_no_ack(idx := 0); if (sgsn_originated_reset) { /* Expect BVC-RESET, but ignore it to prevent a race condition of BVC RESETs */ var template PDU_NS pdu := tr_NS_UNITDATA(t_SduCtrlB, 0, decmatch tr_BVC_RESET(?, 0, omit)); f_ns_exp(pdu, idx := 1); /* SGSN originated BVC-RESET on an uninitialized sign BVC */ f_tx_bvc_reset_rx_ack(0, omit, omit, idx := 1); /* Expect BVC-RESET PTP BVC, but ignore it to prevent a race condition of BVC RESETs */ pdu := tr_NS_UNITDATA(t_SduCtrlB, 0, decmatch tr_BVC_RESET(?, mp_gb_cfg.bvc[0].bvci, mp_gb_cfg.bvc[0].cell_id)); f_ns_exp(pdu, idx := 1); f_tx_bvc_reset_rx_ack(mp_gb_cfg.bvc[0].bvci, omit, mp_gb_cfg.bvc[0].cell_id, idx := 1); } else { /* Expect BVC-RESET for signaling BVCI=0 */ as_rx_bvc_reset_tx_ack(0, omit, omit, oneshot := true, idx := 1); /* Expect BVC-RESET from the PCU on PTP BVC */ as_rx_bvc_reset_tx_ack(mp_gb_cfg.bvc[0].bvci, mp_gb_cfg.bvc[0].cell_id, omit, oneshot := true, idx := 1); } /* Expect UNBLOCK for ptp BVCI on signaling NS-VC (idx==1) */ as_rx_bvc_unblock_tx_ack(mp_gb_cfg.bvc[0].bvci, oneshot := true, idx := 1); /* wait for one FLOW-CONTROL BVC and then ACK any further in the future. Flow * control happens on the p-t-p BVCI and hence on index 1 */ as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvc[0].bvci, oneshot := true, idx := 2); activate(as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvc[0].bvci, idx := 2)); } /* Test full IP-SNS bring-up with two NS-VCs, one sig-only and one user-only - and where * the initial IP/port for the SNS procedure is *not* part of the NS-VCs later */ testcase TC_sns_1c1u_separate() runs on RAW_Test_CT { f_sns_bringup_1c1u_separate(); setverdict(pass); f_clean_ns_codec(); } /* Test full IP-SNS bring-up with two NS-VCs, one sig-only and one user-only and use * SGSN-originated BVC-RESET rather than BSS-originated */ testcase TC_sns_1c1u_so_bvc_reset() runs on RAW_Test_CT { f_sns_bringup_1c1u_separate(sgsn_originated_reset := true); setverdict(pass); f_clean_ns_codec(); } /* Test full IP_SNS bring-up over an initial NS-VC with two NS-VCs */ testcase TC_sns_1c1u_unconfigured_nsvc() runs on RAW_Test_CT { f_init_vty(testcasename()); f_sns_bringup_1c1u_separate(); f_vty_transceive_not_match(PCUVTY, "show ns entities", pattern "*UNCONFIGURED*"); setverdict(pass); f_clean_ns_codec(); } /* Transmit BVC-RESET before NS-ALIVE of PCU was ACKed: expect no response */ testcase TC_sns_1c1u_so_bvc_reset_too_early() runs on RAW_Test_CT { /* Activate two NS codec ports */ f_init_ns_codec(mp_nsconfig); f_init_ns_codec(mp_nsconfig, 1); f_init_ns_codec(mp_nsconfig, 2); f_init_pcuif(); /* Perform Size + BSS-originated config */ f_incoming_sns_size(); f_incoming_sns_config(); /* perform SGSN-originated config using idx==0 for signalling and idx==1 for user traffic */ f_outgoing_sns_config_1c1u_separate(); /* DON'T ACK ANY INBOUND NS-ALIVE HERE! */ /* perform outgoing ALIVE procedure for both NS-VCs */ f_outgoing_ns_alive(1); f_outgoing_ns_alive(2); /* ensure there's no response to NS-ALIVE sent on idx==0 */ f_outgoing_ns_alive_no_ack(idx := 0); /* Transmit BVC-RESET and expect no ACK*/ f_tx_bvc_reset_rx_ack(0, omit, omit, idx := 1, exp_ack := false); f_tx_bvc_reset_rx_ack(mp_gb_cfg.bvc[0].bvci, omit, mp_gb_cfg.bvc[0].cell_id, idx := 1, exp_ack := false); f_clean_ns_codec(); } /* Do an SGSN originated BSSGP-Reset of a not-configured BVCI. * * PCU -X SGSN: BVCI 0 BSSGP-RESET (ignores reset) * PCU <- SGSN: BVCI 0 BSSGP-RESET * PCU -> SGSN: BVCI 0 BSSGP-RESET-ACK (with cell information) * PCU -X SGSN: BVCI 23 BSSGP-RESET (ignores reset, 23 is configured on PCU, 24 is not configured) * PCU <- SGSN: BVCI 24 BSSGP-RESET (unconfigured BVCI) * PCU -> SGSN: BVCI 24 BSSGP-STATUS Unknown BVCI */ testcase TC_sns_so_bvc_reset_unknown_bvci() runs on RAW_Test_CT { g_handle_rx_alive := true; f_init_ns_codec(mp_nsconfig); f_init_pcuif(); f_incoming_sns_size(); f_incoming_sns_config(); f_outgoing_sns_config(); /* Expect BVC-RESET, but ignore it to prevent a race condition of BVC RESETs */ var template PDU_NS pdu := tr_NS_UNITDATA(t_SduCtrlB, 0, decmatch tr_BVC_RESET(?, 0, omit)); f_ns_exp(pdu, idx := 0); /* SGSN originated BVC-RESET on an uninitialized sign BVC */ f_tx_bvc_reset_rx_ack(0, omit, omit, idx := 0); /* Expect BVC-RESET PTP BVC, but ignore it to prevent a race condition of BVC RESETs */ pdu := tr_NS_UNITDATA(t_SduCtrlB, 0, decmatch tr_BVC_RESET(?, mp_gb_cfg.bvc[0].bvci, mp_gb_cfg.bvc[0].cell_id)); f_ns_exp(pdu); /* Send a BVC-RESET on the wrong BVC */ var BssgpCellId cell_id := mp_gb_cfg.bvc[0].cell_id; cell_id.cell_id := cell_id.cell_id + 1; var PDU_BSSGP bssgp_tx := valueof(ts_BVC_RESET(BSSGP_CAUSE_NET_SV_CAP_MOD_GT_ZERO_KBPS, mp_gb_cfg.bvc[0].bvci + 1, cell_id)); NSCP[0].send(ts_NS_UNITDATA(t_SduCtrlB, 0, enc_PDU_BSSGP(bssgp_tx))); NSCP[0].receive(tr_NS_UNITDATA(t_SduCtrlB, 0, decmatch tr_BSSGP_STATUS(mp_gb_cfg.bvc[0].bvci + 1, BSSGP_CAUSE_BVCI_UNKNOWN, *))); setverdict(pass); f_clean_ns_codec(); } /* Test adding new IP endpoints at runtime */ testcase TC_sns_add() runs on RAW_Test_CT { f_sns_bringup_1c1u(); /* create another NS codec port on the tester side */ f_init_ns_codec(mp_nsconfig, 2); g_handle_rx_alive := true; f_outgoing_sns_add(idx_add := 2, w_sig := 0, w_user := 1, idx := 0); g_handle_rx_alive := false; /* wait for one ALIVE cycle, then ACK any further ALIVE in the background */ as_rx_alive_tx_ack(oneshot := true, idx := 2); activate(as_rx_alive_tx_ack(idx := 2)); f_outgoing_ns_alive(2); setverdict(pass); f_clean_ns_codec(); } /* Test adding an already present IP endpoint at runtime */ testcase TC_sns_add_nack() runs on RAW_Test_CT { g_handle_rx_alive := true; f_sns_bringup_1c1u(); f_outgoing_sns_add(idx_add := 0, w_sig := 0, w_user := 1, idx := 0, cause := NS_CAUSE_PROTOCOL_ERROR_UNSPECIFIED); setverdict(pass); f_clean_ns_codec(); } /* Test deleting IP endpoints at runtime */ testcase TC_sns_del() runs on RAW_Test_CT { f_sns_bringup_1c1u(); g_handle_rx_alive := true; f_outgoing_sns_del(idx_del := 1, w_sig := 0, w_user := 1, idx := 0); /* FIXME: ensure we don't receive anything on just-deleted NS-VC anymore */ setverdict(pass); f_clean_ns_codec(); } /* Test changing weights at runtime */ testcase TC_sns_chg_weight() runs on RAW_Test_CT { f_sns_bringup_1c1u(); g_handle_rx_alive := true; /* change w_user from 1 to 200 */ f_outgoing_sns_chg_weight(idx_chg := 1, w_sig := 0, w_user := 200, idx := 0); setverdict(pass); f_clean_ns_codec(); } import from PCUIF_Types all; import from PCUIF_CodecPort all; altstep as_pcu_activate() runs on RAW_PCU_CT { var PCUIF_send_data sd; [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_ACT_REQ(?, ?, ?))) -> value sd { repeat; } } testcase TC_pcuif_rach() runs on RAW_Test_CT { f_sns_bringup_1c1u(); activate(as_pcu_activate()); f_pcuif_tx(ts_PCUIF_RACH_IND(bts_nr:=0, trx_nr:=0, ts_nr:=0, ra:=23, is_11bit:=0, burst_type:=BURST_TYPE_0, fn:=42, arfcn:=871, qta:=0)); PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_DATA_REQ(bts_nr:=0, trx_nr:=0, ts_nr:=0, block_nr:=?, fn:=?, sapi:=PCU_IF_SAPI_AGCH_2, data:=?))); setverdict(pass); f_clean_ns_codec(); } control { execute( TC_sns_po_size_success() ); execute( TC_sns_po_size_nack() ); execute( TC_sns_po_config_success() ); execute( TC_sns_po_config_nack() ); execute( TC_sns_so_config_success() ); execute( TC_sns_1c1u() ); execute( TC_sns_1c1u_separate() ); execute( TC_sns_1c1u_so_bvc_reset() ); execute( TC_sns_1c1u_so_bvc_reset_too_early() ); execute( TC_sns_1c1u_unconfigured_nsvc() ); execute( TC_sns_so_bvc_reset_unknown_bvci() ); execute( TC_sns_add() ); execute( TC_sns_add_nack() ); execute( TC_sns_del() ); execute( TC_sns_chg_weight() ); execute( TC_pcuif_rach() ); } }