| module GBProxy_Tests { |
| |
| /* Osmocom GBProxy test suite in TTCN-3 |
| * (C) 2020-2021 Harald Welte <laforge@osmocom.org> |
| * (C) 2020 sysmocom - s.f.m.c. GmbH |
| * All rights reserved. |
| * |
| * Author: Daniel Willmann <dwillmann@sysmocom.de> |
| |
| * 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 Misc_Helpers all; |
| import from GSM_Types all; |
| import from Native_Functions all; |
| import from NS_Types all; |
| import from NS_Emulation all; |
| import from BSSGP_Types all; |
| import from BSSGP_Emulation all; |
| import from SCCPasp_Types all; |
| import from Osmocom_Gb_Types all; |
| |
| import from MobileL3_CommonIE_Types all; |
| import from MobileL3_GMM_SM_Types all; |
| import from MobileL3_Types all; |
| import from L3_Templates all; |
| import from L3_Common all; |
| |
| import from TELNETasp_PortType all; |
| import from Osmocom_VTY_Functions all; |
| |
| import from LLC_Types all; |
| import from LLC_Templates all; |
| |
| import from GSM_RR_Types all; |
| |
| /* mcc_mnc is 24.008 10.5.5.15 encoded. 262 42 */ |
| const BcdMccMnc c_mcc_mnc := '262F42'H; |
| |
| /* 48.016 section 6.1.4.2: The default maximum information field size of 1600 octets shall be supported on the Gb interface */ |
| const integer max_fr_info_size := 1600; |
| |
| modulepar { |
| /* NRI bit-length. 0 for no pooling */ |
| integer mp_nri_bitlength := 5; |
| roro_integer mp_sgsn_nri := { |
| { 3 }, /* list of NRIs of first SGSN */ |
| { 4 } /* list of NRIs of second SGSN */ |
| }; |
| boolean mp_enable_bss_load_sharing := false; |
| /* SGSN NS configuration */ |
| NSConfigurations mp_nsconfig_sgsn := { |
| { |
| nsei := 101, |
| role_sgsn := true, |
| handle_sns := false, |
| nsvc := { |
| { |
| provider := { |
| ip := { |
| address_family := AF_INET, |
| local_udp_port := 7777, |
| local_ip := "127.0.0.1", |
| remote_udp_port := 23000, |
| remote_ip := "127.0.0.1" |
| } |
| }, |
| nsvci := 101 |
| } |
| } |
| }, { |
| nsei := 102, |
| role_sgsn := true, |
| handle_sns := false, |
| nsvc := { |
| { |
| provider := { |
| ip := { |
| address_family := AF_INET, |
| local_udp_port := 8888, |
| local_ip := "127.0.0.1", |
| remote_udp_port := 23000, |
| remote_ip := "127.0.0.1" |
| } |
| }, |
| nsvci := 102 |
| } |
| } |
| } |
| }; |
| /* BSS NSEI start at 2000 + x |
| * NSVCI start from value of NSEI + 100 |
| * UDP port is NSVCI * 10 */ |
| NSConfigurations mp_nsconfig_pcu := { |
| { |
| nsei := 2001, |
| role_sgsn := false, |
| handle_sns := false, |
| nsvc := { |
| { |
| provider := { |
| ip := { |
| address_family := AF_INET, |
| local_udp_port := 21010, |
| local_ip := "127.0.0.1", |
| remote_udp_port := 23000, |
| remote_ip := "127.0.0.1" |
| } |
| }, |
| nsvci := 2101 |
| } |
| } |
| }, |
| { |
| nsei := 2002, |
| role_sgsn := false, |
| handle_sns := false, |
| nsvc := { |
| { |
| provider := { |
| ip := { |
| address_family := AF_INET, |
| local_udp_port := 21020, |
| local_ip := "127.0.0.1", |
| remote_udp_port := 23000, |
| remote_ip := "127.0.0.1" |
| } |
| }, |
| nsvci := 2102 |
| } |
| } |
| }, |
| { |
| nsei := 2003, |
| role_sgsn := false, |
| handle_sns := false, |
| nsvc := { |
| { |
| provider := { |
| ip := { |
| address_family := AF_INET, |
| local_udp_port := 21030, |
| local_ip := "127.0.0.1", |
| remote_udp_port := 23000, |
| remote_ip := "127.0.0.1" |
| } |
| }, |
| nsvci := 2103 |
| } |
| } |
| } |
| }; |
| /* BVCI are NSEI*10 + x |
| * The first NSE only has one BVC, the second one 2 and so on |
| * The Cell ID is BVCI + 10000 |
| * LAC/RAC are configured in such a way that: |
| * LAC 13135 is present once in NSE(2001), twice in NSE(2002) and once in NSE(2003) |
| * LAC 13300 is present twice in NSE(2003) |
| * RAI 13135-1 is present in NSE(2002) and NSE(2003) |
| * RAI 13300-0 is present twice in NSE(2003) |
| */ |
| BssgpConfigs mp_gbconfigs := { |
| { |
| nsei := 2001, |
| sgsn_role := false, |
| bvc := { |
| { |
| bvci := 20011, |
| cell_id := { |
| ra_id := { |
| lai := { |
| mcc_mnc := c_mcc_mnc, |
| lac := 13135 |
| }, |
| rac := 0 |
| }, |
| cell_id := 30011 |
| }, |
| depth := BSSGP_DECODE_DEPTH_BSSGP, |
| create_cb := refers(BSSGP_Emulation.DefaultCreateCallback) |
| } |
| } |
| }, { |
| nsei := 2002, |
| sgsn_role := false, |
| bvc := { |
| { |
| bvci := 20021, |
| cell_id := { |
| ra_id := { |
| lai := { |
| mcc_mnc := c_mcc_mnc, |
| lac := 13135 |
| }, |
| rac := 1 |
| }, |
| cell_id := 30021 |
| }, |
| depth := BSSGP_DECODE_DEPTH_BSSGP, |
| create_cb := refers(BSSGP_Emulation.DefaultCreateCallback) |
| }, |
| { |
| bvci := 20022, |
| cell_id := { |
| ra_id := { |
| lai := { |
| mcc_mnc := c_mcc_mnc, |
| lac := 13135 |
| }, |
| rac := 2 |
| }, |
| cell_id := 30022 |
| }, |
| depth := BSSGP_DECODE_DEPTH_BSSGP, |
| create_cb := refers(BSSGP_Emulation.DefaultCreateCallback) |
| } |
| } |
| }, { |
| nsei := 2003, |
| sgsn_role := false, |
| bvc := { |
| { |
| bvci := 20031, |
| cell_id := { |
| ra_id := { |
| lai := { |
| mcc_mnc := c_mcc_mnc, |
| lac := 13135 |
| }, |
| rac := 1 |
| }, |
| cell_id := 30031 |
| }, |
| depth := BSSGP_DECODE_DEPTH_BSSGP, |
| create_cb := refers(BSSGP_Emulation.DefaultCreateCallback) |
| }, |
| { |
| bvci := 20032, |
| cell_id := { |
| ra_id := { |
| lai := { |
| mcc_mnc := c_mcc_mnc, |
| lac := 13300 |
| }, |
| rac := 0 |
| }, |
| cell_id := 30032 |
| }, |
| depth := BSSGP_DECODE_DEPTH_BSSGP, |
| create_cb := refers(BSSGP_Emulation.DefaultCreateCallback) |
| }, |
| { |
| bvci := 20033, |
| cell_id := { |
| ra_id := { |
| lai := { |
| mcc_mnc := c_mcc_mnc, |
| lac := 13300 |
| }, |
| rac := 0 |
| }, |
| cell_id := 30033 |
| }, |
| depth := BSSGP_DECODE_DEPTH_BSSGP, |
| create_cb := refers(BSSGP_Emulation.DefaultCreateCallback) |
| } |
| } |
| } |
| } |
| }; |
| |
| type record GbInstance { |
| NS_CT vc_NS, |
| BSSGP_CT vc_BSSGP, |
| BSSGP_BVC_CTs vc_BSSGP_BVC, |
| BssgpConfig cfg |
| }; |
| type record of BSSGP_BVC_CT BSSGP_BVC_CTs |
| |
| const integer NUM_PCU := 3; |
| type record of GbInstance GbInstances; |
| type record of BssgpConfig BssgpConfigs; |
| type record of NSConfiguration NSConfigurations; |
| type record of BssgpCellId BssgpCellIds; |
| |
| const integer NUM_SGSN := 2; |
| |
| type component test_CT { |
| var GbInstances g_pcu; |
| var GbInstances g_sgsn; |
| |
| port BSSGP_CT_PROC_PT PROC; |
| |
| port BSSGP_BVC_MGMT_PT SGSN_MGMT; |
| port BSSGP_BVC_MGMT_PT PCU_MGMT; |
| |
| port TELNETasp_PT GBPVTY; |
| |
| var boolean g_initialized := false; |
| var boolean g_use_echo := false; |
| |
| var ro_integer g_roi := {}; |
| timer g_Tguard; |
| }; |
| |
| type component BSSGP_ConnHdlr { |
| /* array of per-BVC ports on the PCU side */ |
| port BSSGP_PT PCU_PTP[NUM_PCU]; |
| port BSSGP_PT PCU_SIG[NUM_PCU]; |
| port BSSGP_PROC_PT PCU_PROC[NUM_PCU]; |
| /* component reference to the component to which we're currently connected */ |
| var BSSGP_BVC_CT pcu_ct[NUM_PCU]; |
| /* BSSGP BVC configuration of the component to which we're currently connected */ |
| var BssgpBvcConfig pcu_bvc_cfg[NUM_PCU]; |
| |
| /* array of per-BVC ports on the SGSN side */ |
| port BSSGP_PT SGSN_PTP[NUM_SGSN]; |
| port BSSGP_PT SGSN_SIG[NUM_SGSN]; |
| port BSSGP_PROC_PT SGSN_PROC[NUM_SGSN]; |
| /* component reference to the component to which we're currently connected */ |
| var BSSGP_BVC_CT sgsn_ct[NUM_PCU]; |
| |
| var BSSGP_ConnHdlrPars g_pars; |
| timer g_Tguard; |
| var LLC_Entities llc; |
| |
| var ro_integer g_roi := {}; |
| } |
| |
| type record SGSN_ConnHdlrNetworkPars { |
| boolean expect_ptmsi, |
| boolean expect_auth, |
| boolean expect_ciph |
| }; |
| |
| type record BSSGP_ConnHdlrPars { |
| /* IMEI of the simulated ME */ |
| hexstring imei, |
| /* IMSI of the simulated MS */ |
| hexstring imsi, |
| /* MSISDN of the simulated MS (probably unused) */ |
| hexstring msisdn, |
| /* P-TMSI allocated to the simulated MS */ |
| OCT4 p_tmsi optional, |
| OCT3 p_tmsi_sig optional, |
| /* TLLI of the simulated MS */ |
| OCT4 tlli, |
| OCT4 tlli_old optional, |
| RoutingAreaIdentificationV ra optional, |
| GbInstances pcu, |
| GbInstances sgsn, |
| /* The SGSN index to be used within the test */ |
| integer sgsn_idx, |
| float t_guard |
| }; |
| |
| private function f_cellid_to_RAI(in BssgpCellId cell_id) return RoutingAreaIdentificationV { |
| /* mcc_mnc is encoded as of 24.008 10.5.5.15 */ |
| var BcdMccMnc mcc_mnc := cell_id.ra_id.lai.mcc_mnc; |
| |
| var RoutingAreaIdentificationV ret := { |
| mccDigit1 := mcc_mnc[0], |
| mccDigit2 := mcc_mnc[1], |
| mccDigit3 := mcc_mnc[2], |
| mncDigit3 := mcc_mnc[3], |
| mncDigit1 := mcc_mnc[4], |
| mncDigit2 := mcc_mnc[5], |
| lac := int2oct(cell_id.ra_id.lai.lac, 16), |
| rac := int2oct(cell_id.ra_id.rac, 8) |
| } |
| return ret; |
| }; |
| |
| private function f_fix_create_cb(inout BssgpConfig cfg) |
| { |
| for (var integer i := 0; i < lengthof(cfg.bvc); i := i + 1) { |
| if (not isbound(cfg.bvc[i].create_cb)) { |
| cfg.bvc[i].create_cb := refers(BSSGP_Emulation.DefaultCreateCallback) |
| } |
| } |
| } |
| |
| private function f_init_gb_pcu(inout GbInstance gb, charstring id, integer offset) runs on test_CT { |
| var charstring ns_id := id & "-NS(PCU[" & int2str(offset) & "])"; |
| var charstring bssgp_id := id & "-BSSGP(PCU[" & int2str(offset) & "])"; |
| gb.vc_NS := NS_CT.create(ns_id); |
| gb.vc_BSSGP := BSSGP_CT.create(bssgp_id); |
| /* connect lower end of BSSGP emulation with NS upper port */ |
| connect(gb.vc_BSSGP:BSCP, gb.vc_NS:NS_SP); |
| |
| gb.vc_NS.start(NSStart(mp_nsconfig_pcu[offset], ns_id)); |
| gb.vc_BSSGP.start(BssgpStart(gb.cfg, bssgp_id)); |
| |
| for (var integer i := 0; i < lengthof(gb.cfg.bvc); i := i + 1) { |
| /* obtain the component reference of the BSSGP_BVC_CT for each PTP BVC */ |
| connect(self:PROC, gb.vc_BSSGP:PROC); |
| gb.vc_BSSGP_BVC[i] := f_bssgp_get_bvci_ct(gb.cfg.bvc[i].bvci, PROC); |
| disconnect(self:PROC, gb.vc_BSSGP:PROC); |
| /* connect all of the per-BVC MGMT ports to our PCU_MGMT port (1:N) */ |
| connect(self:PCU_MGMT, gb.vc_BSSGP_BVC[i]:MGMT); |
| } |
| /* connect all of the BSSGP/NSE global MGMT port to our PCU_MGMT port (1:N) */ |
| connect(self:PCU_MGMT, gb.vc_BSSGP:MGMT); |
| } |
| |
| private function f_init_gb_sgsn(inout GbInstance gb, charstring id, integer offset) runs on test_CT { |
| var charstring ns_id := id & "-NS(SGSN[" & int2str(offset) & "])"; |
| var charstring bssgp_id := id & "-BSSGP(SGSN[" & int2str(offset) & "])"; |
| gb.vc_NS := NS_CT.create(ns_id); |
| gb.vc_BSSGP := BSSGP_CT.create(bssgp_id); |
| /* connect lower end of BSSGP emulation with NS upper port */ |
| connect(gb.vc_BSSGP:BSCP, gb.vc_NS:NS_SP); |
| |
| gb.vc_NS.start(NSStart(mp_nsconfig_sgsn[offset], ns_id)); |
| gb.vc_BSSGP.start(BssgpStart(gb.cfg, bssgp_id)); |
| |
| for (var integer i := 0; i < lengthof(gb.cfg.bvc); i := i + 1) { |
| /* obtain the component reference of the BSSGP_BVC_CT for each PTP BVC */ |
| connect(self:PROC, gb.vc_BSSGP:PROC); |
| gb.vc_BSSGP_BVC[i] := f_bssgp_get_bvci_ct(gb.cfg.bvc[i].bvci, PROC); |
| disconnect(self:PROC, gb.vc_BSSGP:PROC); |
| /* connect all of the per-BVC MGMT ports to our SGSN_MGMT port (1:N) */ |
| connect(self:SGSN_MGMT, gb.vc_BSSGP_BVC[i]:MGMT); |
| } |
| /* connect all of the BSSGP/NSE global MGMT port to our SGSN_MGMT port (1:N) */ |
| connect(self:SGSN_MGMT, gb.vc_BSSGP:MGMT); |
| } |
| |
| |
| private function f_destroy_gb(inout GbInstance gb) runs on test_CT { |
| gb.vc_NS.stop; |
| gb.vc_BSSGP.stop; |
| |
| for (var integer i := 0; i < lengthof(gb.cfg.bvc); i := i + 1) { |
| gb.vc_BSSGP_BVC[i].stop; |
| } |
| } |
| |
| private function f_init_vty() runs on test_CT { |
| map(self:GBPVTY, system:GBPVTY); |
| f_vty_set_prompts(GBPVTY); |
| f_vty_transceive(GBPVTY, "enable"); |
| } |
| |
| type record of integer ro_integer; |
| |
| private function ro_integer_contains(ro_integer r, integer x) return boolean { |
| for (var integer j := 0; j < lengthof(r); j := j+1) { |
| if (r[j] == x) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private type record of ro_integer roro_integer; |
| |
| /* count the number of unblocked BVCI for each SGSN NSE */ |
| private altstep as_count_unblocked4nse(integer sgsn_idx, inout roro_integer bvci_unblocked) |
| runs on test_CT { |
| var BssgpStatusIndication bsi; |
| [] SGSN_MGMT.receive(BssgpStatusIndication:{g_sgsn[sgsn_idx].cfg.nsei, ?, BVC_S_UNBLOCKED}) -> value bsi { |
| bvci_unblocked[sgsn_idx] := bvci_unblocked[sgsn_idx] & { bsi.bvci }; |
| /* 'repeat' until sufficient number of BVC-rest has been received on all SGSNs */ |
| for (var integer i := 0; i < lengthof(bvci_unblocked); i := i+1) { |
| if (lengthof(bvci_unblocked[i]) < lengthof(g_sgsn[i].cfg.bvc)) { |
| repeat; |
| } |
| } |
| } |
| } |
| |
| function f_init(float t_guard := 30.0) runs on test_CT { |
| var roro_integer bvci_unblocked; |
| var BssgpStatusIndication bsi; |
| var integer i; |
| |
| if (g_initialized == true) { |
| return; |
| } |
| g_initialized := true; |
| |
| g_Tguard.start(t_guard); |
| activate(as_gTguard(g_Tguard)); |
| |
| var BssgpBvcConfigs bvcs := { }; |
| for (i := 0; i < lengthof(mp_gbconfigs); i := i+1) { |
| g_pcu[i].cfg := mp_gbconfigs[i]; |
| /* make sure all have a proper crate_cb, which cannot be specified in config file */ |
| f_fix_create_cb(g_pcu[i].cfg); |
| /* concatenate all the PCU-side BVCs for the SGSN side */ |
| bvcs := bvcs & g_pcu[i].cfg.bvc; |
| } |
| |
| for (i := 0; i < lengthof(mp_nsconfig_sgsn); i := i+1) { |
| g_sgsn[i].cfg := { |
| nsei := mp_nsconfig_sgsn[i].nsei, |
| sgsn_role := true, |
| bvc := bvcs |
| } |
| } |
| |
| f_init_vty(); |
| for (i := 0; i < lengthof(mp_nsconfig_sgsn); i := i+1) { |
| f_vty_transceive(GBPVTY, "nsvc nsei " & int2str(g_sgsn[i].cfg.nsei) & " force-unconfigured"); |
| } |
| for (i := 0; i < lengthof(mp_nsconfig_pcu); i := i+1) { |
| f_vty_transceive(GBPVTY, "nsvc nsei " & int2str(g_pcu[i].cfg.nsei) & " force-unconfigured"); |
| f_vty_transceive(GBPVTY, "delete-gbproxy-peer " & int2str(g_pcu[i].cfg.nsei) & " only-bvc"); |
| } |
| |
| for (i := 0; i < lengthof(mp_nsconfig_sgsn); i := i+1) { |
| f_init_gb_sgsn(g_sgsn[i], "GbProxy_Test", i); |
| } |
| f_sleep(4.0); |
| for (i := 0; i < lengthof(mp_nsconfig_pcu); i := i+1) { |
| f_init_gb_pcu(g_pcu[i], "GbProxy_Test", i); |
| } |
| |
| for (i := 0; i < lengthof(mp_nsconfig_sgsn); i := i+1) { |
| bvci_unblocked[i] := {}; |
| } |
| |
| /* wait until all BVC are unblocked on both sides */ |
| timer T := 15.0; |
| T.start; |
| alt { |
| /* TODO: We need to add more lines if NUM_SGSN increases. Activating default altsteps |
| * unfortunately doesn't work as we want to access the local variable bvci_unblocked. */ |
| [] as_count_unblocked4nse(0, bvci_unblocked); |
| [lengthof(g_sgsn) > 1] as_count_unblocked4nse(1, bvci_unblocked); |
| [] SGSN_MGMT.receive(BssgpStatusIndication:{*, ?, ?}) { |
| repeat; |
| } |
| [] SGSN_MGMT.receive(BssgpResetIndication:?) { |
| repeat; |
| } |
| [] SGSN_MGMT.receive { |
| setverdict(fail, "Received unexpected message on SGSN_MGMT"); |
| mtc.stop; |
| } |
| |
| [] PCU_MGMT.receive(BssgpStatusIndication:{*, ?, BVC_S_UNBLOCKED}) -> value bsi { |
| repeat; |
| } |
| [] PCU_MGMT.receive(BssgpStatusIndication:{*, ?, ?}) { |
| repeat; |
| } |
| [] PCU_MGMT.receive(BssgpResetIndication:{0}) { |
| repeat; |
| } |
| [] PCU_MGMT.receive { |
| setverdict(fail, "Received unexpected message on PCU_MGMT"); |
| mtc.stop; |
| } |
| |
| [] T.timeout { |
| setverdict(fail, "Timeout waiting for unblock of all BVCs on SGSN side; ", |
| "unblocked so far: ", bvci_unblocked); |
| /* don't stop here but print below analysis */ |
| } |
| } |
| |
| for (i := 0; i < lengthof(mp_nsconfig_sgsn); i := i+1) { |
| /* iterate over list and check all BVCI */ |
| for (var integer j := 0; j < lengthof(g_sgsn[i].cfg.bvc); j := j+1) { |
| var BssgpBvci bvci := g_sgsn[i].cfg.bvc[j].bvci; |
| if (not ro_integer_contains(bvci_unblocked[i], bvci)) { |
| setverdict(fail, "SGSN ", i, " BVCI=", bvci, " was not unblocked during start-up"); |
| mtc.stop; |
| } |
| } |
| } |
| |
| /* re-start guard timer after all BVCs are up, so it only counts the actual test case */ |
| g_Tguard.start(t_guard); |
| } |
| |
| function f_cleanup() runs on test_CT { |
| var integer i; |
| |
| /* To avoid a dynamic test case error we need to prevent messages arriving on unconnected |
| * ports. Waiting here ensures that any messages "in flight" will be delivered to the port |
| * before the component is shutdown and disconnected. */ |
| f_sleep(0.2); |
| |
| for (i := 0; i < lengthof(mp_nsconfig_sgsn); i := i+1) { |
| f_destroy_gb(g_sgsn[i]); |
| } |
| for (i := 0; i < lengthof(mp_nsconfig_pcu); i := i+1) { |
| f_destroy_gb(g_pcu[i]); |
| } |
| |
| Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); |
| } |
| |
| type function void_fn(charstring id) runs on BSSGP_ConnHdlr; |
| |
| /* helper function to create, connect and start a BSSGP_ConnHdlr component */ |
| function f_start_handler(void_fn fn, charstring id, integer imsi_suffix, float t_guard := 30.0, |
| integer sgsn_idx := 0, integer nri_idx := 0, boolean have_ptmsi := true) |
| runs on test_CT return BSSGP_ConnHdlr { |
| var BSSGP_ConnHdlr vc_conn; |
| var integer nri := mp_sgsn_nri[sgsn_idx][nri_idx]; |
| var OCT4 p_tmsi := f_gen_tmsi(imsi_suffix, nri_v := nri, nri_bitlen := mp_nri_bitlength); |
| |
| var BSSGP_ConnHdlrPars pars := { |
| imei := f_gen_imei(imsi_suffix), |
| imsi := f_gen_imsi(imsi_suffix), |
| msisdn := f_gen_msisdn(imsi_suffix), |
| p_tmsi := p_tmsi, |
| p_tmsi_sig := omit, |
| tlli := f_gprs_tlli_from_tmsi(p_tmsi, TLLI_LOCAL), |
| tlli_old := omit, |
| ra := omit, |
| pcu := g_pcu, |
| sgsn := g_sgsn, |
| sgsn_idx := sgsn_idx, |
| t_guard := t_guard |
| }; |
| if (not have_ptmsi) { |
| pars.p_tmsi := omit; |
| } |
| |
| vc_conn := BSSGP_ConnHdlr.create(id); |
| |
| vc_conn.start(f_handler_init(fn, id, pars)); |
| return vc_conn; |
| } |
| |
| function f_start_handlers(void_fn fn, charstring id, integer imsi_suffix, float t_guard := 30.0, |
| boolean have_ptmsi := true) |
| runs on test_CT |
| { |
| var integer sgsn_idx, nri_idx; |
| for (sgsn_idx := 0; sgsn_idx < NUM_SGSN; sgsn_idx:=sgsn_idx+1) { |
| for (nri_idx := 0; nri_idx < lengthof(mp_sgsn_nri[sgsn_idx]); nri_idx:=nri_idx+1) { |
| var integer extd_imsi_suffix := 1000*sgsn_idx + 100*nri_idx; |
| var BSSGP_ConnHdlr vc_conn; |
| vc_conn := f_start_handler(fn, id, extd_imsi_suffix, t_guard, sgsn_idx, nri_idx, |
| have_ptmsi); |
| /* Idea: we could also run them in parallel ? */ |
| vc_conn.done; |
| } |
| } |
| } |
| |
| /* Connect the PCU-side per-BVC ports (PCU/PCU_SIG/PCU_PROC) array slot 'port_idx' to specified per-BVC component */ |
| private function f_connect_to_pcu_bvc(integer port_idx, integer nse_idx, integer bvc_idx) |
| runs on BSSGP_ConnHdlr { |
| var BSSGP_BVC_CT bvc_ct := g_pars.pcu[nse_idx].vc_BSSGP_BVC[bvc_idx] |
| if (PCU_PTP[port_idx].checkstate("Connected")) { |
| /* unregister + disconnect from old BVC */ |
| f_client_unregister(g_pars.imsi, PCU_PROC[port_idx]); |
| disconnect(self:PCU_PTP[port_idx], pcu_ct[port_idx]:BSSGP_SP); |
| disconnect(self:PCU_SIG[port_idx], pcu_ct[port_idx]:BSSGP_SP_SIG); |
| disconnect(self:PCU_PROC[port_idx], pcu_ct[port_idx]:BSSGP_PROC); |
| } |
| /* connect to new BVC and register us */ |
| connect(self:PCU_PTP[port_idx], bvc_ct:BSSGP_SP); |
| connect(self:PCU_SIG[port_idx], bvc_ct:BSSGP_SP_SIG); |
| connect(self:PCU_PROC[port_idx], bvc_ct:BSSGP_PROC); |
| f_client_register(g_pars.imsi, g_pars.tlli, PCU_PROC[port_idx]); |
| pcu_ct[port_idx] := bvc_ct; |
| pcu_bvc_cfg[port_idx] := g_pars.pcu[nse_idx].cfg.bvc[bvc_idx]; |
| } |
| |
| /* Connect the SGSN-side per-BVC ports (SGSN/SGSN_SIG/SGSN_PROC) array slot 'port_idx' to specified per-BVC component */ |
| private function f_connect_to_sgsn_bvc(integer port_idx, BSSGP_BVC_CT bvc_ct) runs on BSSGP_ConnHdlr { |
| if (SGSN_PTP[port_idx].checkstate("Connected")) { |
| /* unregister + disconnect from old BVC */ |
| f_client_unregister(g_pars.imsi, SGSN_PROC[port_idx]); |
| disconnect(self:SGSN_PTP[port_idx], sgsn_ct[port_idx]:BSSGP_SP); |
| disconnect(self:SGSN_SIG[port_idx], sgsn_ct[port_idx]:BSSGP_SP_SIG); |
| disconnect(self:SGSN_PROC[port_idx], sgsn_ct[port_idx]:BSSGP_PROC); |
| } |
| /* connect to new BVC and register us */ |
| connect(self:SGSN_PTP[port_idx], bvc_ct:BSSGP_SP); |
| connect(self:SGSN_SIG[port_idx], bvc_ct:BSSGP_SP_SIG); |
| connect(self:SGSN_PROC[port_idx], bvc_ct:BSSGP_PROC); |
| f_client_register(g_pars.imsi, g_pars.tlli, SGSN_PROC[port_idx]); |
| sgsn_ct[port_idx] := bvc_ct; |
| } |
| |
| private altstep as_gTguard(timer Tguard) { |
| [] Tguard.timeout { |
| setverdict(fail, "Tguard timeout"); |
| mtc.stop; |
| } |
| } |
| |
| /* first function called in every ConnHdlr */ |
| private function f_handler_init(void_fn fn, charstring id, BSSGP_ConnHdlrPars pars) |
| runs on BSSGP_ConnHdlr { |
| var integer i; |
| /* do some common stuff like setting up g_pars */ |
| g_pars := pars; |
| |
| llc := f_llc_create(false); |
| |
| /* default connections on PCU side: First BVC of each NSE/PCU */ |
| for (i := 0; i < lengthof(g_pars.pcu); i := i+1) { |
| f_connect_to_pcu_bvc(port_idx := i, nse_idx := i, bvc_idx := 0); |
| } |
| |
| /* default connections on SGSN side: First BVC of each NSE/SGSN */ |
| for (i := 0; i < lengthof(g_pars.sgsn); i := i+1) { |
| f_connect_to_sgsn_bvc(i, g_pars.sgsn[i].vc_BSSGP_BVC[0]); |
| } |
| |
| g_Tguard.start(pars.t_guard); |
| activate(as_gTguard(g_Tguard)); |
| |
| /* call the user-supplied test case function */ |
| fn.apply(id); |
| |
| for (i := 0; i < NUM_SGSN; i := i+1) { |
| if (SGSN_PROC[i].checkstate("Connected")) { |
| f_client_unregister(g_pars.imsi, SGSN_PROC[i]) |
| } |
| } |
| |
| for (i := 0; i < NUM_PCU; i := i+1) { |
| if (PCU_PROC[i].checkstate("Connected")) { |
| f_client_unregister(g_pars.imsi, PCU_PROC[i]) |
| } |
| } |
| } |
| |
| private function f_client_register(hexstring imsi, OCT4 tlli, BSSGP_PROC_PT PT) |
| runs on BSSGP_ConnHdlr { |
| PT.call(BSSGP_register_client:{imsi, tlli}) { |
| [] PT.getreply(BSSGP_register_client:{imsi, tlli}) {}; |
| } |
| } |
| |
| private function f_client_unregister(hexstring imsi, BSSGP_PROC_PT PT) |
| runs on BSSGP_ConnHdlr { |
| PT.call(BSSGP_unregister_client:{imsi}) { |
| [] PT.getreply(BSSGP_unregister_client:{imsi}) {}; |
| } |
| } |
| |
| /* Send 'tx' on PTP-BVCI from PCU; expect 'rx' on SGSN */ |
| friend function f_pcu2sgsn(template (value) PDU_BSSGP tx, template (present) PDU_BSSGP exp_rx, |
| integer pcu_idx := 0, boolean use_sig := false) runs on BSSGP_ConnHdlr { |
| var integer sgsn_idx := g_pars.sgsn_idx; |
| var PDU_BSSGP rx; |
| timer T := 1.0; |
| |
| if (use_sig) { |
| PCU_SIG[pcu_idx].send(tx); |
| } else { |
| PCU_PTP[pcu_idx].send(tx); |
| } |
| |
| T.start; |
| alt { |
| [use_sig] SGSN_SIG[sgsn_idx].receive(exp_rx) { |
| setverdict(pass); |
| } |
| [not use_sig] SGSN_PTP[sgsn_idx].receive(exp_rx) { |
| setverdict(pass); |
| } |
| [] SGSN_PTP[sgsn_idx].receive(PDU_BSSGP:?) -> value rx { |
| setverdict(fail, "Unexpected BSSGP on SGSN[", sgsn_idx, "] side: ", rx); |
| mtc.stop; |
| } |
| [] SGSN_SIG[sgsn_idx].receive(PDU_BSSGP:?) -> value rx { |
| setverdict(fail, "Unexpected SIG BSSGP on SGSN[", sgsn_idx, "] side: ", rx); |
| mtc.stop; |
| } |
| [] T.timeout { |
| setverdict(fail, "Timeout waiting for BSSGP on SGSN[", sgsn_idx, "] side: ", exp_rx); |
| mtc.stop; |
| } |
| } |
| } |
| |
| /* Send 'tx' on PTP-BVCI from SGSN; expect 'rx' on PCU */ |
| friend function f_sgsn2pcu(template (value) PDU_BSSGP tx, template (present) PDU_BSSGP exp_rx, |
| integer pcu_idx := 0, boolean use_sig := false) runs on BSSGP_ConnHdlr { |
| var integer sgsn_idx := g_pars.sgsn_idx; |
| var PDU_BSSGP rx; |
| timer T := 1.0; |
| |
| if (use_sig) { |
| SGSN_SIG[sgsn_idx].send(tx); |
| } else { |
| SGSN_PTP[sgsn_idx].send(tx); |
| } |
| |
| T.start; |
| alt { |
| [use_sig] PCU_SIG[pcu_idx].receive(exp_rx) { |
| setverdict(pass); |
| } |
| [not use_sig] PCU_PTP[pcu_idx].receive(exp_rx) { |
| setverdict(pass); |
| } |
| [] PCU_PTP[pcu_idx].receive(PDU_BSSGP:?) -> value rx { |
| setverdict(fail, "Unexpected BSSGP on PCU side: ", rx); |
| mtc.stop; |
| } |
| [] PCU_SIG[pcu_idx].receive(PDU_BSSGP:?) -> value rx { |
| setverdict(fail, "Unexpected SIG BSSGP on PCU side: ", rx); |
| mtc.stop; |
| } |
| [] T.timeout { |
| setverdict(fail, "Timeout waiting for BSSGP on PCU side: ", exp_rx); |
| mtc.stop; |
| } |
| } |
| } |
| |
| /*********************************************************************** |
| * GlobaLTest_CT: Using the per-NSE GLOBAL ports on PCU + SGSN side |
| ***********************************************************************/ |
| |
| type component GlobalTest_CT extends test_CT { |
| port BSSGP_PT G_PCU[NUM_PCU]; |
| port BSSGP_PT G_SGSN[NUM_SGSN]; |
| }; |
| |
| /* connect the signaling BVC of each NSE to the G_PCU / G_SGSN ports */ |
| private function f_global_init() runs on GlobalTest_CT { |
| var integer i; |
| for (i := 0; i < lengthof(g_sgsn); i := i+1) { |
| connect(self:G_SGSN[i], g_sgsn[i].vc_BSSGP:GLOBAL); |
| } |
| for (i := 0; i < lengthof(g_pcu); i := i+1) { |
| connect(self:G_PCU[i], g_pcu[i].vc_BSSGP:GLOBAL); |
| } |
| } |
| |
| /* connect the first PTP BVC of each NSE to the G_PCU / G_SGSN ports */ |
| private function f_global_init_ptp() runs on GlobalTest_CT { |
| var integer i; |
| for (i := 0; i < lengthof(g_sgsn); i := i+1) { |
| connect(self:G_SGSN[i], g_sgsn[i].vc_BSSGP_BVC[0]:GLOBAL); |
| } |
| for (i := 0; i < lengthof(g_pcu); i := i+1) { |
| connect(self:G_PCU[i], g_pcu[i].vc_BSSGP_BVC[0]:GLOBAL); |
| } |
| } |
| |
| /* Send 'tx' on PTP-BVCI from PCU; expect 'rx' on SGSN */ |
| friend function f_global_pcu2sgsn(template (value) PDU_BSSGP tx, template (present) PDU_BSSGP exp_rx, |
| integer pcu_idx := 0, integer sgsn_idx := 0) runs on GlobalTest_CT { |
| var PDU_BSSGP rx; |
| timer T := 1.0; |
| |
| G_PCU[pcu_idx].send(tx); |
| T.start; |
| alt { |
| [] G_SGSN[sgsn_idx].receive(exp_rx) { |
| setverdict(pass); |
| } |
| [] G_SGSN[sgsn_idx].receive(PDU_BSSGP:?) -> value rx { |
| setverdict(fail, "Unexpected BSSGP on SGSN side: ", rx); |
| mtc.stop; |
| } |
| [] T.timeout { |
| setverdict(fail, "Timeout waiting for BSSGP on SGSN side: ", exp_rx); |
| mtc.stop; |
| } |
| } |
| } |
| |
| /* Send 'tx' on PTP-BVCI from SGSN; expect 'rx' on PCU */ |
| friend function f_global_sgsn2pcu(template (value) PDU_BSSGP tx, template (present) PDU_BSSGP exp_rx, |
| integer sgsn_idx := 0, integer pcu_idx := 0) runs on GlobalTest_CT { |
| var PDU_BSSGP rx; |
| timer T := 1.0; |
| |
| G_SGSN[sgsn_idx].send(tx); |
| T.start; |
| alt { |
| [] G_PCU[pcu_idx].receive(exp_rx) { |
| setverdict(pass); |
| } |
| [] G_PCU[pcu_idx].receive(PDU_BSSGP:?) -> value rx { |
| setverdict(fail, "Unexpected BSSGP on PCU side: ", rx); |
| mtc.stop; |
| } |
| [] T.timeout { |
| setverdict(fail, "Timeout waiting for BSSGP on PCU side: ", exp_rx); |
| mtc.stop; |
| } |
| } |
| } |
| |
| |
| /* TODO: |
| * Detach without Attach |
| * SM procedures without attach / RAU |
| * ATTACH / RAU |
| ** with / without authentication |
| ** with / without P-TMSI allocation |
| * re-transmissions of LLC frames |
| * PDP Context activation |
| ** with different GGSN config in SGSN VTY |
| ** with different PDP context type (v4/v6/v46) |
| ** timeout from GGSN |
| ** multiple / secondary PDP context |
| */ |
| |
| private function f_TC_BVC_bringup(charstring id) runs on BSSGP_ConnHdlr { |
| f_sleep(5.0); |
| setverdict(pass); |
| } |
| |
| testcase TC_BVC_bringup() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_BVC_bringup), testcasename(), 51); |
| f_cleanup(); |
| } |
| |
| friend function f_bssgp_suspend(integer ran_idx := 0) runs on BSSGP_ConnHdlr return OCT1 { |
| var BssgpBvcConfig bvcc := g_pars.pcu[ran_idx].cfg.bvc[0]; |
| timer T := 5.0; |
| var PDU_BSSGP rx_pdu; |
| PCU_SIG[ran_idx].send(ts_BSSGP_SUSPEND(g_pars.tlli, bvcc.cell_id.ra_id)); |
| T.start; |
| alt { |
| [] PCU_SIG[ran_idx].receive(tr_BSSGP_SUSPEND_ACK(g_pars.tlli, bvcc.cell_id.ra_id, ?)) -> value rx_pdu { |
| return rx_pdu.pDU_BSSGP_SUSPEND_ACK.suspend_Reference_Number.suspend_Reference_Number_value; |
| } |
| [] PCU_SIG[ran_idx].receive(tr_BSSGP_SUSPEND_NACK(g_pars.tlli, bvcc.cell_id.ra_id, ?)) -> value rx_pdu { |
| setverdict(fail, "SUSPEND-NACK in response to SUSPEND for TLLI ", g_pars.tlli); |
| mtc.stop; |
| } |
| [] T.timeout { |
| setverdict(fail, "No SUSPEND-ACK in response to SUSPEND for TLLI ", g_pars.tlli); |
| mtc.stop; |
| } |
| } |
| return '00'O; |
| } |
| |
| friend function f_bssgp_resume(OCT1 susp_ref, integer ran_idx := 0) runs on BSSGP_ConnHdlr { |
| var BssgpBvcConfig bvcc := g_pars.pcu[ran_idx].cfg.bvc[0]; |
| timer T := 5.0; |
| PCU_SIG[ran_idx].send(ts_BSSGP_RESUME(g_pars.tlli, bvcc.cell_id.ra_id, susp_ref)); |
| T.start; |
| alt { |
| [] PCU_SIG[ran_idx].receive(tr_BSSGP_RESUME_ACK(g_pars.tlli, bvcc.cell_id.ra_id)); |
| [] PCU_SIG[ran_idx].receive(tr_BSSGP_RESUME_NACK(g_pars.tlli, bvcc.cell_id.ra_id, ?)) { |
| setverdict(fail, "RESUME-NACK in response to RESUME for TLLI ", g_pars.tlli); |
| mtc.stop; |
| } |
| [] T.timeout { |
| setverdict(fail, "No RESUME-ACK in response to SUSPEND for TLLI ", g_pars.tlli); |
| mtc.stop; |
| } |
| } |
| } |
| |
| |
| /* send uplink-unitdata of a variety of different sizes; expect it to show up on SGSN */ |
| private function f_TC_ul_unitdata(charstring id) runs on BSSGP_ConnHdlr { |
| var integer ran_idx := 0; |
| var BssgpBvcConfig bvcc := g_pars.pcu[ran_idx].cfg.bvc[0]; |
| var integer i; |
| |
| for (i := 0; i < max_fr_info_size-4; i := i+4) { |
| var octetstring payload := f_rnd_octstring(i); |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_UL_UD(g_pars.tlli, bvcc.cell_id, payload); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_UL_UD(g_pars.tlli, bvcc.cell_id, payload); |
| |
| log("UL-UNITDATA(payload_size=", i); |
| f_pcu2sgsn(pdu_tx, pdu_rx); |
| } |
| setverdict(pass); |
| } |
| |
| testcase TC_ul_unitdata() runs on test_CT |
| { |
| f_init(); |
| f_start_handlers(refers(f_TC_ul_unitdata), testcasename(), 1); |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| f_cleanup(); |
| } |
| |
| /* send downlink-unitdata of a variety of different sizes; expect it to show up on PCU */ |
| private function f_TC_dl_unitdata(charstring id) runs on BSSGP_ConnHdlr { |
| var integer i; |
| |
| for (i := 0; i < max_fr_info_size-4; i := i+4) { |
| var octetstring payload := f_rnd_octstring(i); |
| var template (value) PDU_BSSGP pdu_tx := |
| ts_BSSGP_DL_UD(g_pars.tlli, payload, omit, ts_BSSGP_IMSI(g_pars.imsi)); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := |
| tr_BSSGP_DL_UD(g_pars.tlli, payload, tr_BSSGP_IMSI(g_pars.imsi)); |
| |
| log("DL-UNITDATA(payload_size=", i); |
| f_sgsn2pcu(pdu_tx, pdu_rx); |
| } |
| setverdict(pass); |
| } |
| |
| testcase TC_dl_unitdata() runs on test_CT |
| { |
| f_init(); |
| f_start_handlers(refers(f_TC_dl_unitdata), testcasename(), 2); |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| f_cleanup(); |
| } |
| |
| private function f_TC_ra_capability(charstring id) runs on BSSGP_ConnHdlr { |
| var integer i; |
| |
| for (i := 0; i < 10; i := i+1) { |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_RA_CAP(g_pars.tlli, { ts_RaCapRec_BSSGP }); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_RA_CAP(g_pars.tlli, { tr_RaCapRec_BSSGP }) |
| |
| f_sgsn2pcu(pdu_tx, pdu_rx); |
| } |
| setverdict(pass); |
| } |
| testcase TC_ra_capability() runs on test_CT |
| { |
| f_init(); |
| f_start_handlers(refers(f_TC_ra_capability), testcasename(), 3); |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| f_cleanup(); |
| } |
| |
| private function f_TC_ra_capability_upd(charstring id) runs on BSSGP_ConnHdlr { |
| var integer i; |
| var OCT1 tag; |
| for (i := 0; i < 10; i := i+1) { |
| tag := int2oct(23 + i, 1); |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_RA_CAP_UPD(g_pars.tlli, tag); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_RA_CAP_UPD(g_pars.tlli, tag) |
| |
| f_pcu2sgsn(pdu_tx, pdu_rx); |
| |
| pdu_tx := ts_BSSGP_RA_CAP_UPD_ACK(g_pars.tlli, tag, '42'O); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| pdu_rx := tr_BSSGP_RA_CAP_UPD_ACK(g_pars.tlli, tag, '42'O) |
| |
| f_sgsn2pcu(pdu_tx, pdu_rx); |
| } |
| setverdict(pass); |
| } |
| testcase TC_ra_capability_upd() runs on test_CT |
| { |
| f_init(); |
| f_start_handlers(refers(f_TC_ra_capability_upd), testcasename(), 4); |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| f_cleanup(); |
| } |
| |
| private function f_TC_radio_status(charstring id) runs on BSSGP_ConnHdlr { |
| var integer i; |
| var BssgpRadioCause cause := BSSGP_RADIO_CAUSE_CONTACT_LOST; |
| for (i := 0; i < 10; i := i+1) { |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_RADIO_STATUS(g_pars.tlli, cause); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_RADIO_STATUS(g_pars.tlli, cause) |
| |
| f_pcu2sgsn(pdu_tx, pdu_rx); |
| } |
| setverdict(pass); |
| } |
| testcase TC_radio_status() runs on test_CT |
| { |
| f_init(); |
| f_start_handlers(refers(f_TC_radio_status), testcasename(), 5); |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| f_cleanup(); |
| } |
| |
| private function f_suspend_one(integer sgsn_idx, integer nri_idx, integer pcu_idx, integer bvc_idx, |
| integer suffix) |
| runs on GlobalTest_CT |
| { |
| var RoutingAreaIdentification ra_id := g_pcu[pcu_idx].cfg.bvc[bvc_idx].cell_id.ra_id; |
| var OCT4 p_tmsi := f_gen_tmsi(suffix, nri_v := mp_sgsn_nri[sgsn_idx][nri_idx], |
| nri_bitlen := mp_nri_bitlength); |
| var OCT4 tlli := f_gprs_tlli_from_tmsi(p_tmsi, TLLI_LOCAL); |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_SUSPEND(tlli, ra_id); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_SUSPEND(tlli, ra_id); |
| f_global_pcu2sgsn(pdu_tx, pdu_rx, pcu_idx, sgsn_idx); |
| |
| pdu_tx := ts_BSSGP_SUSPEND_ACK(tlli, ra_id, int2oct(suffix, 1)); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| pdu_rx := tr_BSSGP_SUSPEND_ACK(tlli, ra_id, int2oct(suffix, 1)); |
| f_global_sgsn2pcu(pdu_tx, pdu_rx, sgsn_idx, pcu_idx); |
| |
| pdu_tx := ts_BSSGP_SUSPEND(tlli, ra_id); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| pdu_rx := tr_BSSGP_SUSPEND(tlli, ra_id); |
| f_global_pcu2sgsn(pdu_tx, pdu_rx, pcu_idx, sgsn_idx); |
| |
| /* These messages are simple passed through so just also test sending NACK */ |
| pdu_tx := ts_BSSGP_SUSPEND_NACK(tlli, ra_id, BSSGP_CAUSE_UNKNOWN_MS); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| pdu_rx := tr_BSSGP_SUSPEND_NACK(tlli, ra_id, BSSGP_CAUSE_UNKNOWN_MS); |
| f_global_sgsn2pcu(pdu_tx, pdu_rx, sgsn_idx, pcu_idx); |
| } |
| |
| private function f_TC_suspend(integer sgsn_idx, integer nri_idx, integer pcu_idx, integer bvc_idx) |
| runs on GlobalTest_CT { |
| var integer i; |
| |
| for (i := 0; i < 10; i := i+1) { |
| f_suspend_one(sgsn_idx, nri_idx, pcu_idx, bvc_idx, suffix := i); |
| } |
| setverdict(pass); |
| } |
| testcase TC_suspend() runs on GlobalTest_CT |
| { |
| var integer sgsn_idx, nri_idx; |
| f_init(); |
| f_global_init(); |
| for (sgsn_idx := 0; sgsn_idx < NUM_SGSN; sgsn_idx := sgsn_idx+1) { |
| for (nri_idx := 0; nri_idx < lengthof(mp_sgsn_nri[sgsn_idx]); nri_idx := nri_idx+1) { |
| f_TC_suspend(sgsn_idx, nri_idx, pcu_idx:=0, bvc_idx:=0); |
| } |
| } |
| f_cleanup(); |
| } |
| |
| private function f_resume_one(integer sgsn_idx, integer nri_idx, integer pcu_idx, integer bvc_idx, |
| integer suffix) |
| runs on GlobalTest_CT |
| { |
| var RoutingAreaIdentification ra_id := g_pcu[pcu_idx].cfg.bvc[bvc_idx].cell_id.ra_id; |
| var OCT4 p_tmsi := f_gen_tmsi(suffix, nri_v := mp_sgsn_nri[sgsn_idx][nri_idx], |
| nri_bitlen := mp_nri_bitlength); |
| var OCT4 tlli := f_gprs_tlli_from_tmsi(p_tmsi, TLLI_LOCAL); |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_RESUME(tlli, ra_id, int2oct(suffix, 1)); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_RESUME(tlli, ra_id, int2oct(suffix, 1)); |
| f_global_pcu2sgsn(pdu_tx, pdu_rx, pcu_idx, sgsn_idx); |
| |
| pdu_tx := ts_BSSGP_RESUME_ACK(tlli, ra_id); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| pdu_rx := tr_BSSGP_RESUME_ACK(tlli, ra_id); |
| f_global_sgsn2pcu(pdu_tx, pdu_rx, sgsn_idx, pcu_idx); |
| |
| pdu_tx := ts_BSSGP_RESUME(tlli, ra_id, int2oct(suffix, 1)); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| pdu_rx := tr_BSSGP_RESUME(tlli, ra_id, int2oct(suffix, 1)); |
| f_global_pcu2sgsn(pdu_tx, pdu_rx, pcu_idx, sgsn_idx); |
| |
| /* These messages are simple passed through so just also test sending NACK */ |
| pdu_tx := ts_BSSGP_RESUME_NACK(tlli, ra_id, BSSGP_CAUSE_UNKNOWN_MS); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| pdu_rx := tr_BSSGP_RESUME_NACK(tlli, ra_id, BSSGP_CAUSE_UNKNOWN_MS); |
| f_global_sgsn2pcu(pdu_tx, pdu_rx, sgsn_idx, pcu_idx); |
| } |
| |
| private function f_TC_resume(integer sgsn_idx, integer nri_idx, integer pcu_idx, integer bvc_idx) |
| runs on GlobalTest_CT { |
| var integer i; |
| |
| for (i := 0; i < 10; i := i+1) { |
| f_resume_one(sgsn_idx, nri_idx, pcu_idx, bvc_idx, suffix := i); |
| } |
| setverdict(pass); |
| } |
| testcase TC_resume() runs on GlobalTest_CT |
| { |
| var integer sgsn_idx, nri_idx; |
| f_init(); |
| f_global_init(); |
| for (sgsn_idx := 0; sgsn_idx < NUM_SGSN; sgsn_idx := sgsn_idx+1) { |
| for (nri_idx := 0; nri_idx < lengthof(mp_sgsn_nri[sgsn_idx]); nri_idx := nri_idx+1) { |
| f_TC_resume(sgsn_idx, nri_idx, pcu_idx:=0, bvc_idx:=0); |
| } |
| } |
| f_cleanup(); |
| } |
| |
| /* test the load-sharing between multiple NS-VC on the BSS side */ |
| private function f_TC_dl_ud_unidir(charstring id) runs on BSSGP_ConnHdlr { |
| var integer i; |
| |
| for (i := 0; i < 10; i := i+1) { |
| var octetstring payload := f_rnd_octstring(i); |
| var template (value) PDU_BSSGP pdu_tx := |
| ts_BSSGP_DL_UD(g_pars.tlli, payload, omit, ts_BSSGP_IMSI(g_pars.imsi)); |
| SGSN_PTP[g_pars.sgsn_idx].send(pdu_tx); |
| } |
| setverdict(pass); |
| } |
| |
| private function f_TC_load_sharing_dl(integer sgsn_idx) runs on test_CT_NS |
| { |
| const integer num_ue := 10; |
| var BSSGP_ConnHdlr vc_conn[num_ue]; |
| /* all BVC are now fully brought up. We disconnect BSSGP from NS on the BSS |
| * side so we get the raw NsUnitdataIndication and hence observe different |
| * NSVCI */ |
| disconnect(g_pcu[0].vc_NS:NS_SP, g_pcu[0].vc_BSSGP:BSCP); |
| connect(g_pcu[0].vc_NS:NS_SP, self:NS); |
| |
| /* there may still be some NS-VCs coming up? After all, the BVC-RESET succeeds after the first |
| * of the NS-VC is ALIVE/UNBLOCKED */ |
| f_sleep(3.0); |
| |
| /* start parallel components generating DL-UNITDATA from the SGSN side */ |
| for (var integer i:= 0; i < num_ue; i := i+1) { |
| vc_conn[i] := f_start_handler(refers(f_TC_dl_ud_unidir), testcasename(), |
| 5+i, 30.0, sgsn_idx); |
| } |
| |
| /* now start counting all the messages that were queued before */ |
| /* TODO: We have a hard-coded assumption of 4 NS-VC in one NSE/NS-VCG here! */ |
| var ro_integer rx_count := { 0, 0, 0, 0 }; |
| timer T := 2.0; |
| T.start; |
| alt { |
| [] as_NsUdiCount(0, rx_count); |
| [] as_NsUdiCount(1, rx_count); |
| [] as_NsUdiCount(2, rx_count); |
| [] as_NsUdiCount(3, rx_count); |
| [] NS.receive(NsUnitdataIndication:{0,?,?,*,*}) { repeat; } /* signaling BVC */ |
| [] NS.receive(NsStatusIndication:?) { repeat; } |
| [] NS.receive { |
| setverdict(fail, "Rx unexpected NS"); |
| mtc.stop; |
| } |
| [] T.timeout { |
| } |
| } |
| for (var integer i := 0; i < lengthof(rx_count); i := i+1) { |
| log("Rx on NSVCI ", mp_nsconfig_pcu[0].nsvc[i].nsvci, ": ", rx_count[i]); |
| if (rx_count[i] == 0) { |
| setverdict(fail, "Data not shared over all NSVC"); |
| } |
| } |
| } |
| |
| testcase TC_load_sharing_dl() runs on test_CT_NS |
| { |
| var integer sgsn_idx, nri_idx; |
| f_init(); |
| for (sgsn_idx:=0; sgsn_idx < NUM_SGSN; sgsn_idx:=sgsn_idx+1) { |
| f_TC_load_sharing_dl(sgsn_idx); |
| } |
| setverdict(pass); |
| } |
| private altstep as_NsUdiCount(integer nsvc_idx, inout ro_integer roi) runs on test_CT_NS { |
| var NsUnitdataIndication udi; |
| var BssgpBvcConfig bvcc := g_pcu[0].cfg.bvc[0]; |
| [] NS.receive(NsUnitdataIndication:{bvcc.bvci, g_pcu[0].cfg.nsei, mp_nsconfig_pcu[0].nsvc[nsvc_idx].nsvci, *, *}) -> value udi { |
| roi[nsvc_idx] := roi[nsvc_idx] + 1; |
| repeat; |
| } |
| } |
| type component test_CT_NS extends test_CT { |
| port NS_PT NS; |
| }; |
| |
| |
| /*********************************************************************** |
| * PAGING PS procedure |
| ***********************************************************************/ |
| |
| private function f_send_paging_ps(template (value) Paging_Field4 p4, integer sgsn_idx := 0, |
| boolean use_sig := false) |
| runs on BSSGP_ConnHdlr return template (present) PDU_BSSGP { |
| var template (value) PDU_BSSGP pdu_tx; |
| var template (present) PDU_BSSGP pdu_rx; |
| /* we always specify '0' as BVCI in the templates below, as we override it with |
| * 'p4' later anyway */ |
| pdu_rx := tr_BSSGP_PS_PAGING(0); |
| pdu_rx.pDU_BSSGP_PAGING_PS.iMSI := tr_BSSGP_IMSI(g_pars.imsi); |
| if (ispresent(g_pars.p_tmsi)) { |
| pdu_tx := ts_BSSGP_PS_PAGING_PTMSI(0, g_pars.imsi, oct2int(g_pars.p_tmsi)); |
| pdu_rx.pDU_BSSGP_PAGING_PS.pTMSI := tr_BSSGP_TMSI(oct2int(g_pars.p_tmsi)); |
| } else { |
| pdu_tx := ts_BSSGP_PS_PAGING_IMSI(0, g_pars.imsi); |
| pdu_rx.pDU_BSSGP_PAGING_PS.pTMSI := omit; |
| } |
| pdu_tx.pDU_BSSGP_PAGING_PS.paging_Field4 := p4; |
| pdu_rx.pDU_BSSGP_PAGING_PS.paging_Field4 := p4; |
| if (use_sig == false) { |
| SGSN_PTP[sgsn_idx].send(pdu_tx); |
| } else { |
| SGSN_SIG[sgsn_idx].send(pdu_tx); |
| } |
| return pdu_rx; |
| } |
| |
| /* send paging defined by 'p4' on given SGSN-side index (ptp or signaling) and expect one paging to arrive on |
| * specified PCU index */ |
| private function f_send_paging_ps_exp_one_bss(template (value) Paging_Field4 p4, integer sgsn_idx := 0, |
| boolean use_sig := false,integer pcu_idx := 0) |
| runs on BSSGP_ConnHdlr { |
| var template (present) PDU_BSSGP exp_rx; |
| var boolean test_done := false; |
| /* doesn't really make sense: Sending to a single BVCI means the message ends up |
| * at that BVC (cell) only, and paging all over the BSS area is not possible */ |
| exp_rx := f_send_paging_ps(p4, sgsn_idx, use_sig); |
| /* Expect paging to propagate to the one BSS addressed by the BVCI only */ |
| timer T := 2.0; |
| T.start; |
| alt { |
| [not use_sig and not test_done] PCU_PTP[pcu_idx].receive(exp_rx) { |
| setverdict(pass); |
| test_done := true; |
| repeat; |
| } |
| [not use_sig] PCU_SIG[pcu_idx].receive(exp_rx) { |
| setverdict(fail, "Received paging on SIGNALING BVC, expected PTP BVC"); |
| } |
| [use_sig and not test_done] PCU_SIG[pcu_idx].receive(exp_rx) { |
| setverdict(pass); |
| test_done := true; |
| repeat; |
| } |
| [use_sig] PCU_PTP[pcu_idx].receive(exp_rx) { |
| setverdict(fail, "Received paging on PTP BVC, expected SIGNALING BVC"); |
| } |
| [] any from PCU_PTP.receive(exp_rx) { |
| setverdict(fail, "Paging received on unexpected BVC"); |
| } |
| [] any from PCU_SIG.receive(exp_rx) { |
| setverdict(fail, "Paging received on unexpected BVC"); |
| } |
| [] any from PCU_PTP.receive(PDU_BSSGP:{pDU_BSSGP_PAGING_PS:=?}) { |
| setverdict(fail, "Different Paging than expected received PTP BVC"); |
| } |
| [] any from PCU_SIG.receive(PDU_BSSGP:{pDU_BSSGP_PAGING_PS:=?}) { |
| setverdict(fail, "Different Paging than expected on SIGNALING BVC"); |
| } |
| [not test_done] T.timeout { |
| setverdict(fail, "Timeout waiting for paging"); |
| } |
| [test_done] T.timeout; |
| } |
| } |
| |
| /* send a PS-PAGING but don't expect it to show up on any PTP or SIG BVC */ |
| private function f_send_paging_ps_exp_no_bss(template (value) Paging_Field4 p4, integer sgsn_idx := 0, |
| boolean use_sig := false) |
| runs on BSSGP_ConnHdlr { |
| var template (present) PDU_BSSGP exp_rx; |
| exp_rx := f_send_paging_ps(p4, sgsn_idx, use_sig); |
| /* Expect paging to propagate to no BSS */ |
| timer T := 2.0; |
| T.start; |
| alt { |
| [] any from PCU_PTP.receive(exp_rx) { |
| setverdict(fail, "Paging received on unexpected BVC"); |
| } |
| [] any from PCU_SIG.receive(exp_rx) { |
| setverdict(fail, "Paging received on unexpected BVC"); |
| } |
| [] any from PCU_PTP.receive(PDU_BSSGP:{pDU_BSSGP_PAGING_PS:=?}) { |
| setverdict(fail, "Different Paging received on PTP BVC"); |
| } |
| [] any from PCU_SIG.receive(PDU_BSSGP:{pDU_BSSGP_PAGING_PS:=?}) { |
| setverdict(fail, "Different Paging received on SIGNALING BVC"); |
| } |
| [] T.timeout { |
| setverdict(pass); |
| } |
| } |
| } |
| |
| private function f_TC_paging_ps_ptp_bss(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* doesn't really make sense: Sending to a single BVCI means the message ends up |
| * at that BVC (cell) only, and paging all over the BSS area is not possible */ |
| f_send_paging_ps_exp_one_bss(ts_BssgpP4BssArea, 0, false, 0); |
| } |
| testcase TC_paging_ps_ptp_bss() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_ptp_bss), testcasename(), 9); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on PTP-BVC for Location Area */ |
| private function f_TC_paging_ps_ptp_lac(charstring id) runs on BSSGP_ConnHdlr |
| { |
| var template (present) PDU_BSSGP exp_rx; |
| /* doesn't really make sense: Sending to a single BVCI means the message ends up |
| * at that BVC (cell) only, and paging all over the BSS area is not possible */ |
| f_send_paging_ps_exp_one_bss(ts_BssgpP4LAC(pcu_bvc_cfg[0].cell_id.ra_id.lai), 0, false, 0); |
| } |
| testcase TC_paging_ps_ptp_lac() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_ptp_lac), testcasename(), 10); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on PTP-BVC for unknown Location Area */ |
| private function f_TC_paging_ps_ptp_lac_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| var GSM_Types.LocationAreaIdentification unknown_la := { |
| mcc_mnc := '567F99'H, |
| lac := 33333 |
| }; |
| /* as it's sent on the PTP BVC, we expect it to pass even for unknown LAC */ |
| f_send_paging_ps_exp_one_bss(ts_BssgpP4LAC(unknown_la), 0, false, 0); |
| } |
| testcase TC_paging_ps_ptp_lac_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_ptp_lac_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on PTP-BVC for Routeing Area */ |
| private function f_TC_paging_ps_ptp_rac(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* doesn't really make sense: Sending to a single BVCI means the message ends up |
| * at that BVC (cell) only, and paging all over the BSS area is not possible */ |
| f_send_paging_ps_exp_one_bss(ts_BssgpP4RAC(pcu_bvc_cfg[0].cell_id.ra_id), 0, false, 0); |
| } |
| testcase TC_paging_ps_ptp_rac() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_ptp_rac), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on PTP-BVC for unknown Routeing Area */ |
| private function f_TC_paging_ps_ptp_rac_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| var RoutingAreaIdentification unknown_ra := { |
| lai := { |
| mcc_mnc := '567F99'H, |
| lac := 33333 |
| }, |
| rac := 254 |
| }; |
| /* as it's sent on the PTP BVC, we expect it to pass even for unknown RAC */ |
| f_send_paging_ps_exp_one_bss(ts_BssgpP4RAC(unknown_ra), 0, false, 0); |
| } |
| testcase TC_paging_ps_ptp_rac_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_ptp_rac_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on PTP-BVC for BVCI (one cell) */ |
| private function f_TC_paging_ps_ptp_bvci(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* this should be the normal case for MS in READY MM state after a lower layer failure */ |
| f_send_paging_ps_exp_one_bss(ts_BssgpP4Bvci(pcu_bvc_cfg[0].bvci), 0, false, 0); |
| } |
| testcase TC_paging_ps_ptp_bvci() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_ptp_bvci), testcasename(), 12); |
| f_cleanup(); |
| } |
| |
| |
| /* PS-PAGING on PTP-BVC for BVCI (one cell) using IMSI only (no P-TMSI allocated) */ |
| testcase TC_paging_ps_ptp_bvci_imsi() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_ptp_bvci), testcasename(), 12, have_ptmsi:=false); |
| f_cleanup(); |
| } |
| |
| /* Rejected PS-PAGING on PTP-BVC for BVCI (one cell) */ |
| testcase TC_paging_ps_reject_ptp_bvci() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_reject_ptp_bvci), testcasename(), 16); |
| f_cleanup(); |
| } |
| |
| /* Rejected PS-PAGING on PTP-BVC for BVCI (one cell) using IMSI only (no P-TMSI allocated) */ |
| private function f_TC_paging_ps_reject_ptp_bvci(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* first send the PS-PAGING from SGSN -> PCU */ |
| f_send_paging_ps_exp_one_bss(ts_BssgpP4Bvci(pcu_bvc_cfg[0].bvci), 0, false, 0); |
| /* then simulate the PS-PAGING-REJECT from the PCU */ |
| f_send_paging_ps_rej(use_sig:=false); |
| } |
| testcase TC_paging_ps_reject_ptp_bvci_imsi() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_reject_ptp_bvci), testcasename(), 16, have_ptmsi:=false); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on PTP-BVC for unknown BVCI */ |
| private function f_TC_paging_ps_ptp_bvci_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* as it's sent on the PTP BVC, we expect it to pass even for unknown BVCI */ |
| f_send_paging_ps_exp_one_bss(ts_BssgpP4Bvci(33333), 0, false, 0); |
| } |
| testcase TC_paging_ps_ptp_bvci_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_ptp_bvci_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* altstep for expecting BSSGP PDU on signaling BVC of given pcu_idx + storing in 'roi' */ |
| private altstep as_paging_sig_pcu(integer pcu_idx, template (present) PDU_BSSGP exp_rx, inout ro_integer roi) |
| runs on BSSGP_ConnHdlr { |
| [] PCU_SIG[pcu_idx].receive(exp_rx) { |
| if (ro_integer_contains(roi, pcu_idx)) { |
| setverdict(fail, "Received multiple paging on same SIG BVC"); |
| } |
| roi := roi & { pcu_idx }; |
| repeat; |
| } |
| [] PCU_PTP[pcu_idx].receive(exp_rx) { |
| setverdict(fail, "Received paging on PTP BVC, expected SIGNALING BVC"); |
| } |
| [] PCU_SIG[pcu_idx].receive(PDU_BSSGP:{pDU_BSSGP_PAGING_PS:=?}) { |
| setverdict(fail, "Different Paging than expected received SIGNALING BVC"); |
| } |
| [] PCU_PTP[pcu_idx].receive(PDU_BSSGP:{pDU_BSSGP_PAGING_PS:=?}) { |
| setverdict(fail, "Different Paging than expected received PTP BVC"); |
| } |
| } |
| |
| type record of default ro_default; |
| |
| /* send PS-PAGING on SIG BVC, expect it to arrive on given list of PCU indexes */ |
| private function f_send_paging_ps_exp_multi(template (value) Paging_Field4 p4, integer sgsn_idx := 0, |
| ro_integer exp_on_pcu_idx) runs on BSSGP_ConnHdlr |
| { |
| var template (present) PDU_BSSGP exp_rx; |
| exp_rx := f_send_paging_ps(p4, 0, true); |
| |
| /* FIXME: make sure the relevant BVCs/BSS are connected to the ports! */ |
| var ro_default defaults := {}; |
| for (var integer i := 0; i < lengthof(mp_nsconfig_pcu); i := i+1) { |
| var default d := activate(as_paging_sig_pcu(i, exp_rx, g_roi)); |
| defaults := defaults & { d }; |
| } |
| f_sleep(2.0); |
| for (var integer i := 0; i < lengthof(defaults); i := i+1) { |
| deactivate(defaults[i]); |
| } |
| log("Paging received on PCU ", g_roi); |
| |
| for (var integer i := 0; i < lengthof(mp_nsconfig_pcu); i := i+1) { |
| var boolean rx_on_i := ro_integer_contains(g_roi, i); |
| var boolean exp_on_i := ro_integer_contains(exp_on_pcu_idx, i); |
| if (exp_on_i and not rx_on_i) { |
| setverdict(fail, "PS-PAGING not received on ", mp_nsconfig_pcu[i].nsei); |
| } |
| if (not exp_on_i and rx_on_i) { |
| setverdict(fail, "PS-PAGING not expected but received on ", mp_nsconfig_pcu[i].nsei); |
| } |
| } |
| setverdict(pass); |
| } |
| |
| /* Send PAGING-PS-REJECT on SIG BVC, expect it to arrive on the "right" SGSN */ |
| private function f_send_paging_ps_rej(boolean use_sig := true, integer pcu_idx := 0) runs on BSSGP_ConnHdlr |
| { |
| var template (value) PDU_BSSGP pdu_tx; |
| var template (present) PDU_BSSGP exp_rx; |
| var PDU_BSSGP pdu_rx; |
| timer T := 5.0; |
| var template (omit) GsmTmsi tmsi_int := omit; |
| |
| if (ispresent(g_pars.p_tmsi)) { |
| tmsi_int := oct2int(g_pars.p_tmsi); |
| } |
| |
| pdu_tx := ts_BSSGP_PAGING_PS_REJ(g_pars.imsi, 23, 42, tmsi_int); |
| exp_rx := tr_BSSGP_PAGING_PS_REJ(g_pars.imsi, 23, 42, tmsi_int); |
| |
| if (use_sig) { |
| PCU_SIG[pcu_idx].send(pdu_tx); |
| } else { |
| PCU_PTP[pcu_idx].send(pdu_tx); |
| } |
| T.start; |
| alt { |
| [use_sig] SGSN_SIG[g_pars.sgsn_idx].receive(exp_rx) -> value pdu_rx { |
| setverdict(pass); |
| } |
| [use_sig] SGSN_SIG[g_pars.sgsn_idx].receive { |
| setverdict(fail, "Unexpected PDU on SGSN"); |
| } |
| [use_sig] any from SGSN_SIG.receive(exp_rx) -> value pdu_rx { |
| setverdict(fail, "PAGING-PS-REJECT arrived on wrong SGSN"); |
| } |
| [not use_sig] SGSN_PTP[g_pars.sgsn_idx].receive(exp_rx) -> value pdu_rx { |
| setverdict(pass); |
| } |
| [not use_sig] SGSN_PTP[g_pars.sgsn_idx].receive { |
| setverdict(fail, "Unexpected PDU on SGSN"); |
| } |
| [not use_sig] any from SGSN_PTP.receive(exp_rx) -> value pdu_rx { |
| setverdict(fail, "PAGING-PS-REJECT arrived on wrong SGSN"); |
| } |
| [] T.timeout { |
| setverdict(fail, "Timeout waiting for PAGING-PS-REJECT"); |
| } |
| } |
| } |
| |
| /* PS-PAGING on SIG-BVC for BSS Area */ |
| private function f_TC_paging_ps_sig_bss(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* we expect the paging to arrive on all three NSE */ |
| f_send_paging_ps_exp_multi(ts_BssgpP4BssArea, 0, {0, 1, 2}); |
| } |
| testcase TC_paging_ps_sig_bss() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_sig_bss), testcasename(), 13); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on SIG-BVC for Location Area */ |
| private function f_TC_paging_ps_sig_lac(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* The first LAC (13135) is shared by all three NSEs */ |
| f_send_paging_ps_exp_multi(ts_BssgpP4LAC(pcu_bvc_cfg[0].cell_id.ra_id.lai), 0, {0, 1, 2}); |
| /* Reset state */ |
| g_roi := {}; |
| /* Make LAC (13300) available on pcu index 2 */ |
| f_connect_to_pcu_bvc(port_idx := 2, nse_idx := 2, bvc_idx := 1); |
| f_send_paging_ps_exp_multi(ts_BssgpP4LAC(pcu_bvc_cfg[2].cell_id.ra_id.lai), 0, {2}); |
| } |
| testcase TC_paging_ps_sig_lac() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_sig_lac), testcasename(), 14); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on SIG-BVC for unknown Location Area */ |
| private function f_TC_paging_ps_sig_lac_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| var GSM_Types.LocationAreaIdentification unknown_la := { |
| mcc_mnc := '567F99'H, |
| lac := 33333 |
| }; |
| f_send_paging_ps_exp_no_bss(ts_BssgpP4LAC(unknown_la), 0, true); |
| } |
| testcase TC_paging_ps_sig_lac_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_sig_lac_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on SIG-BVC for Routeing Area */ |
| private function f_TC_paging_ps_sig_rac(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* Only PCU index 0 has a matching BVC with the RA ID */ |
| f_send_paging_ps_exp_multi(ts_BssgpP4RAC(pcu_bvc_cfg[0].cell_id.ra_id), 0, {0}); |
| g_roi := {}; |
| /* PCU index 1 and 2 have a matching BVC with the RA ID */ |
| f_send_paging_ps_exp_multi(ts_BssgpP4RAC(pcu_bvc_cfg[2].cell_id.ra_id), 0, {1, 2}); |
| g_roi := {}; |
| /* PCU index 2 has two matching BVCs with the RA ID */ |
| f_connect_to_pcu_bvc(port_idx := 2, nse_idx := 2, bvc_idx := 1); |
| f_send_paging_ps_exp_multi(ts_BssgpP4RAC(pcu_bvc_cfg[2].cell_id.ra_id), 0, {2}); |
| } |
| testcase TC_paging_ps_sig_rac() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_sig_rac), testcasename(), 15); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on SIG-BVC for unknown Routeing Area */ |
| private function f_TC_paging_ps_sig_rac_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| var RoutingAreaIdentification unknown_ra := { |
| lai := { |
| mcc_mnc := '567F99'H, |
| lac := 33333 |
| }, |
| rac := 254 |
| }; |
| f_send_paging_ps_exp_no_bss(ts_BssgpP4RAC(unknown_ra), 0, true); |
| } |
| testcase TC_paging_ps_sig_rac_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_sig_rac_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on SIG-BVC for BVCI (one cell) */ |
| private function f_TC_paging_ps_sig_bvci(charstring id) runs on BSSGP_ConnHdlr |
| { |
| f_send_paging_ps_exp_multi(ts_BssgpP4Bvci(pcu_bvc_cfg[0].bvci), 0, {0}); |
| } |
| testcase TC_paging_ps_sig_bvci() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_sig_bvci), testcasename(), 16); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on SIG-BVC for BVCI (one cell) using IMSI only (no P-TMSI allocated) */ |
| testcase TC_paging_ps_sig_bvci_imsi() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_sig_bvci), testcasename(), 16, have_ptmsi:=false); |
| f_cleanup(); |
| } |
| |
| /* Rejected PS-PAGING on SIG-BVC for BVCI (one cell) */ |
| private function f_TC_paging_ps_reject_sig_bvci(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* first send the PS-PAGING from SGSN -> PCU */ |
| f_send_paging_ps_exp_multi(ts_BssgpP4Bvci(pcu_bvc_cfg[0].bvci), 0, {0}); |
| /* then simulate the PS-PAGING-REJECT from the PCU */ |
| f_send_paging_ps_rej(use_sig:=true); |
| |
| } |
| testcase TC_paging_ps_reject_sig_bvci() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_reject_sig_bvci), testcasename(), 16); |
| f_cleanup(); |
| } |
| |
| /* Rejected PS-PAGING on SIG-BVC for BVCI (one cell) using IMSI only (no P-TMSI allocated) */ |
| testcase TC_paging_ps_reject_sig_bvci_imsi() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_reject_sig_bvci), testcasename(), 16, have_ptmsi:=false); |
| f_cleanup(); |
| } |
| |
| /* PS-PAGING on SIG-BVC for unknown BVCI */ |
| private function f_TC_paging_ps_sig_bvci_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| f_send_paging_ps_exp_no_bss(ts_BssgpP4Bvci(33333), 0, true); |
| } |
| testcase TC_paging_ps_sig_bvci_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_ps_sig_bvci_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| |
| |
| /*********************************************************************** |
| * PAGING CS procedure |
| ***********************************************************************/ |
| |
| private function f_send_paging_cs(template (value) Paging_Field4 p4, integer sgsn_idx := 0, |
| boolean use_sig := false) |
| runs on BSSGP_ConnHdlr return template (present) PDU_BSSGP { |
| var template (value) PDU_BSSGP pdu_tx; |
| var template (present) PDU_BSSGP pdu_rx; |
| /* we always specify '0' as BVCI in the templates below, as we override it with |
| * 'p4' later anyway */ |
| pdu_rx := tr_BSSGP_CS_PAGING(0); |
| pdu_rx.pDU_BSSGP_PAGING_CS.iMSI := tr_BSSGP_IMSI(g_pars.imsi); |
| if (ispresent(g_pars.p_tmsi)) { |
| pdu_tx := ts_BSSGP_CS_PAGING_PTMSI(0, g_pars.imsi, oct2int(g_pars.p_tmsi)); |
| pdu_rx.pDU_BSSGP_PAGING_CS.tMSI := tr_BSSGP_TMSI(oct2int(g_pars.p_tmsi)); |
| } else { |
| pdu_tx := ts_BSSGP_CS_PAGING_IMSI(0, g_pars.imsi); |
| pdu_rx.pDU_BSSGP_PAGING_CS.tMSI := omit; |
| } |
| pdu_tx.pDU_BSSGP_PAGING_CS.paging_Field4 := p4; |
| pdu_rx.pDU_BSSGP_PAGING_CS.paging_Field4 := p4; |
| if (use_sig == false) { |
| SGSN_PTP[sgsn_idx].send(pdu_tx); |
| } else { |
| SGSN_SIG[sgsn_idx].send(pdu_tx); |
| } |
| return pdu_rx; |
| } |
| |
| /* send paging defined by 'p4' on given SGSN-side index (ptp or signaling) and expect one paging to arrive on |
| * specified PCU index */ |
| private function f_send_paging_cs_exp_one_bss(template (value) Paging_Field4 p4, integer sgsn_idx := 0, |
| boolean use_sig := false,integer pcu_idx := 0) |
| runs on BSSGP_ConnHdlr { |
| var template (present) PDU_BSSGP exp_rx; |
| var boolean test_done := false; |
| /* doesn't really make sense: Sending to a single BVCI means the message ends up |
| * at that BVC (cell) only, and paging all over the BSS area is not possible */ |
| exp_rx := f_send_paging_cs(p4, sgsn_idx, use_sig); |
| /* Expect paging to propagate to the one BSS addressed by the BVCI only */ |
| timer T := 2.0; |
| T.start; |
| alt { |
| [not use_sig and not test_done] PCU_PTP[pcu_idx].receive(exp_rx) { |
| setverdict(pass); |
| test_done := true; |
| repeat; |
| } |
| [not use_sig] PCU_SIG[pcu_idx].receive(exp_rx) { |
| setverdict(fail, "Received paging on SIGNALING BVC, expected PTP BVC"); |
| } |
| [use_sig and not test_done] PCU_SIG[pcu_idx].receive(exp_rx) { |
| setverdict(pass); |
| test_done := true; |
| repeat; |
| } |
| [use_sig] PCU_PTP[pcu_idx].receive(exp_rx) { |
| setverdict(fail, "Received paging on PTP BVC, expected SIGNALING BVC"); |
| } |
| [] any from PCU_PTP.receive(exp_rx) { |
| setverdict(fail, "Paging received on unexpected BVC"); |
| } |
| [] any from PCU_SIG.receive(exp_rx) { |
| setverdict(fail, "Paging received on unexpected BVC"); |
| } |
| [] any from PCU_PTP.receive(PDU_BSSGP:{pDU_BSSGP_PAGING_CS:=?}) { |
| setverdict(fail, "Different Paging than expected received PTP BVC"); |
| } |
| [] any from PCU_SIG.receive(PDU_BSSGP:{pDU_BSSGP_PAGING_CS:=?}) { |
| setverdict(fail, "Different Paging than expected on SIGNALING BVC"); |
| } |
| [not test_done] T.timeout { |
| setverdict(fail, "Timeout while waiting for paging") |
| } |
| [test_done] T.timeout; |
| } |
| } |
| |
| /* send a CS-PAGING but don't expect it to show up on any PTP or SIG BVC */ |
| private function f_send_paging_cs_exp_no_bss(template (value) Paging_Field4 p4, integer sgsn_idx := 0, |
| boolean use_sig := false) |
| runs on BSSGP_ConnHdlr { |
| var template (present) PDU_BSSGP exp_rx; |
| exp_rx := f_send_paging_cs(p4, sgsn_idx, use_sig); |
| /* Expect paging to propagate to no BSS */ |
| timer T := 2.0; |
| T.start; |
| alt { |
| [] any from PCU_PTP.receive(exp_rx) { |
| setverdict(fail, "Paging received on unexpected BVC"); |
| } |
| [] any from PCU_SIG.receive(exp_rx) { |
| setverdict(fail, "Paging received on unexpected BVC"); |
| } |
| [] any from PCU_PTP.receive(PDU_BSSGP:{pDU_BSSGP_PAGING_CS:=?}) { |
| setverdict(fail, "Different Paging received on PTP BVC"); |
| } |
| [] any from PCU_SIG.receive(PDU_BSSGP:{pDU_BSSGP_PAGING_CS:=?}) { |
| setverdict(fail, "Different Paging received on SIGNALING BVC"); |
| } |
| [] T.timeout { |
| setverdict(pass); |
| } |
| } |
| } |
| |
| private function f_TC_paging_cs_ptp_bss(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* doesn't really make sense: Sending to a single BVCI means the message ends up |
| * at that BVC (cell) only, and paging all over the BSS area is not possible */ |
| f_send_paging_cs_exp_one_bss(ts_BssgpP4BssArea, 0, false, 0); |
| } |
| testcase TC_paging_cs_ptp_bss() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_ptp_bss), testcasename(), 17); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on PTP-BVC for Location Area */ |
| private function f_TC_paging_cs_ptp_lac(charstring id) runs on BSSGP_ConnHdlr |
| { |
| var template (present) PDU_BSSGP exp_rx; |
| /* doesn't really make sense: Sending to a single BVCI means the message ends up |
| * at that BVC (cell) only, and paging all over the BSS area is not possible */ |
| f_send_paging_cs_exp_one_bss(ts_BssgpP4LAC(pcu_bvc_cfg[0].cell_id.ra_id.lai), 0, false, 0); |
| } |
| testcase TC_paging_cs_ptp_lac() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_ptp_lac), testcasename(), 18); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on PTP-BVC for unknown Location Area */ |
| private function f_TC_paging_cs_ptp_lac_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| var GSM_Types.LocationAreaIdentification unknown_la := { |
| mcc_mnc := '567F99'H, |
| lac := 33333 |
| }; |
| /* as it's sent on the PTP BVC, we expect it to pass even for unknown LAC */ |
| f_send_paging_cs_exp_one_bss(ts_BssgpP4LAC(unknown_la), 0, false, 0); |
| } |
| testcase TC_paging_cs_ptp_lac_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_ptp_lac_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on PTP-BVC for Routeing Area */ |
| private function f_TC_paging_cs_ptp_rac(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* doesn't really make sense: Sending to a single BVCI means the message ends up |
| * at that BVC (cell) only, and paging all over the BSS area is not possible */ |
| f_send_paging_cs_exp_one_bss(ts_BssgpP4RAC(pcu_bvc_cfg[0].cell_id.ra_id), 0, false, 0); |
| } |
| testcase TC_paging_cs_ptp_rac() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_ptp_rac), testcasename(), 19); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on PTP-BVC for unknown Routeing Area */ |
| private function f_TC_paging_cs_ptp_rac_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| var RoutingAreaIdentification unknown_ra := { |
| lai := { |
| mcc_mnc := '567F99'H, |
| lac := 33333 |
| }, |
| rac := 254 |
| }; |
| /* as it's sent on the PTP BVC, we expect it to pass even for unknown RAC */ |
| f_send_paging_cs_exp_one_bss(ts_BssgpP4RAC(unknown_ra), 0, false, 0); |
| } |
| testcase TC_paging_cs_ptp_rac_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_ptp_rac_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on PTP-BVC for BVCI (one cell) */ |
| private function f_TC_paging_cs_ptp_bvci(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* this should be the normal case for MS in READY MM state after a lower layer failure */ |
| f_send_paging_cs_exp_one_bss(ts_BssgpP4Bvci(pcu_bvc_cfg[0].bvci), 0, false, 0); |
| } |
| testcase TC_paging_cs_ptp_bvci() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_ptp_bvci), testcasename(), 20); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on PTP-BVC for unknown BVCI */ |
| private function f_TC_paging_cs_ptp_bvci_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* as it's sent on the PTP BVC, we expect it to pass even for unknown BVCI */ |
| f_send_paging_cs_exp_one_bss(ts_BssgpP4Bvci(33333), 0, false, 0); |
| } |
| testcase TC_paging_cs_ptp_bvci_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_ptp_bvci_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* send CS-PAGING on SIG BVC, expect it to arrive on given list of PCU indexes */ |
| private function f_send_paging_cs_exp_multi(template (value) Paging_Field4 p4, integer sgsn_idx := 0, |
| ro_integer exp_on_pcu_idx) runs on BSSGP_ConnHdlr |
| { |
| var template (present) PDU_BSSGP exp_rx; |
| exp_rx := f_send_paging_cs(p4, 0, true); |
| |
| /* FIXME: make sure the relevant BVCs/BSS are connected to the ports! */ |
| var ro_default defaults := {}; |
| for (var integer i := 0; i < lengthof(mp_nsconfig_pcu); i := i+1) { |
| var default d := activate(as_paging_sig_pcu(i, exp_rx, g_roi)); |
| defaults := defaults & { d }; |
| } |
| f_sleep(2.0); |
| for (var integer i := 0; i < lengthof(defaults); i := i+1) { |
| deactivate(defaults[i]); |
| } |
| log("Paging received on PCU ", g_roi); |
| |
| for (var integer i := 0; i < lengthof(mp_nsconfig_pcu); i := i+1) { |
| var boolean rx_on_i := ro_integer_contains(g_roi, i); |
| var boolean exp_on_i := ro_integer_contains(exp_on_pcu_idx, i); |
| if (exp_on_i and not rx_on_i) { |
| setverdict(fail, "PS-PAGING not received on ", mp_nsconfig_pcu[i].nsei); |
| } |
| if (not exp_on_i and rx_on_i) { |
| setverdict(fail, "PS-PAGING not expected but received on ", mp_nsconfig_pcu[i].nsei); |
| } |
| } |
| setverdict(pass); |
| } |
| |
| /* CS-PAGING on SIG-BVC for BSS Area */ |
| private function f_TC_paging_cs_sig_bss(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* we expect the paging to arrive on all three NSE */ |
| f_send_paging_cs_exp_multi(ts_BssgpP4BssArea, 0, {0, 1, 2}); |
| } |
| testcase TC_paging_cs_sig_bss() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_sig_bss), testcasename(), 13); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on SIG-BVC for Location Area */ |
| private function f_TC_paging_cs_sig_lac(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* The first LAC (13135) is shared by all three NSEs */ |
| f_send_paging_cs_exp_multi(ts_BssgpP4LAC(pcu_bvc_cfg[0].cell_id.ra_id.lai), 0, {0, 1, 2}); |
| /* Reset state */ |
| g_roi := {}; |
| /* Make LAC (13300) available on pcu index 2 */ |
| f_connect_to_pcu_bvc(port_idx := 2, nse_idx := 2, bvc_idx := 1); |
| f_send_paging_cs_exp_multi(ts_BssgpP4LAC(pcu_bvc_cfg[2].cell_id.ra_id.lai), 0, {2}); |
| } |
| testcase TC_paging_cs_sig_lac() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_sig_lac), testcasename(), 14); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on SIG-BVC for unknown Location Area */ |
| private function f_TC_paging_cs_sig_lac_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| var GSM_Types.LocationAreaIdentification unknown_la := { |
| mcc_mnc := '567F99'H, |
| lac := 33333 |
| }; |
| f_send_paging_cs_exp_no_bss(ts_BssgpP4LAC(unknown_la), 0, true); |
| } |
| testcase TC_paging_cs_sig_lac_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_sig_lac_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on SIG-BVC for Routeing Area */ |
| private function f_TC_paging_cs_sig_rac(charstring id) runs on BSSGP_ConnHdlr |
| { |
| /* Only PCU index 0 has a matching BVC with the RA ID */ |
| f_send_paging_cs_exp_multi(ts_BssgpP4RAC(pcu_bvc_cfg[0].cell_id.ra_id), 0, {0}); |
| g_roi := {}; |
| /* PCU index 1 and 2 have a matching BVC with the RA ID */ |
| f_send_paging_cs_exp_multi(ts_BssgpP4RAC(pcu_bvc_cfg[2].cell_id.ra_id), 0, {1, 2}); |
| g_roi := {}; |
| /* PCU index 2 has two matching BVCs with the RA ID */ |
| f_connect_to_pcu_bvc(port_idx := 2, nse_idx := 2, bvc_idx := 1); |
| f_send_paging_cs_exp_multi(ts_BssgpP4RAC(pcu_bvc_cfg[2].cell_id.ra_id), 0, {2}); |
| } |
| testcase TC_paging_cs_sig_rac() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_sig_rac), testcasename(), 15); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on SIG-BVC for unknown Routeing Area */ |
| private function f_TC_paging_cs_sig_rac_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| var RoutingAreaIdentification unknown_ra := { |
| lai := { |
| mcc_mnc := '567F99'H, |
| lac := 33333 |
| }, |
| rac := 254 |
| }; |
| f_send_paging_cs_exp_no_bss(ts_BssgpP4RAC(unknown_ra), 0, true); |
| } |
| testcase TC_paging_cs_sig_rac_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_sig_rac_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on SIG-BVC for BVCI (one cell) */ |
| private function f_TC_paging_cs_sig_bvci(charstring id) runs on BSSGP_ConnHdlr |
| { |
| f_send_paging_cs_exp_multi(ts_BssgpP4Bvci(pcu_bvc_cfg[0].bvci), 0, {0}); |
| } |
| testcase TC_paging_cs_sig_bvci() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_sig_bvci), testcasename(), 16); |
| f_cleanup(); |
| } |
| |
| /* CS-PAGING on SIG-BVC for unknown BVCI */ |
| private function f_TC_paging_cs_sig_bvci_unknown(charstring id) runs on BSSGP_ConnHdlr |
| { |
| f_send_paging_cs_exp_no_bss(ts_BssgpP4Bvci(33333), 0, true); |
| } |
| testcase TC_paging_cs_sig_bvci_unknown() runs on test_CT { |
| f_init(); |
| f_start_handlers(refers(f_TC_paging_cs_sig_bvci_unknown), testcasename(), 11); |
| f_cleanup(); |
| } |
| |
| /*********************************************************************** |
| * FLUSH-LL procedure |
| ***********************************************************************/ |
| |
| private function f_TC_flush_ll(charstring id) runs on BSSGP_ConnHdlr { |
| var BssgpBvci bvci := g_pars.pcu[0].cfg.bvc[0].bvci; |
| var integer i; |
| for (i := 0; i < 10; i := i+1) { |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_FLUSH_LL(g_pars.tlli, bvci, bvci_new := bvci); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_FLUSH_LL(g_pars.tlli, bvci, bvci_new := bvci); |
| |
| f_sgsn2pcu(pdu_tx, pdu_rx, use_sig := true); |
| |
| pdu_tx := ts_BSSGP_FLUSH_LL_ACK(g_pars.tlli, int2oct(0, 1), 23, bvci_new := bvci); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| pdu_rx := tr_BSSGP_FLUSH_LL_ACK(g_pars.tlli, int2oct(0, 1), 23, bvci_new := bvci); |
| |
| f_pcu2sgsn(pdu_tx, pdu_rx, use_sig := true); |
| } |
| setverdict(pass); |
| } |
| testcase TC_flush_ll() runs on test_CT |
| { |
| f_init(); |
| f_start_handlers(refers(f_TC_flush_ll), testcasename(), 6); |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| f_cleanup(); |
| } |
| |
| /*********************************************************************** |
| * SGSN-INVOKE-TRACE procedure |
| ***********************************************************************/ |
| |
| private altstep as_bssgp_g_pcu_count(integer pcu_idx, template (present) PDU_BSSGP exp_rx, inout ro_integer roi) |
| runs on GlobalTest_CT { |
| [] G_PCU[pcu_idx].receive(exp_rx) from g_pcu[pcu_idx].vc_BSSGP { |
| if (ro_integer_contains(roi, pcu_idx)) { |
| setverdict(fail, "Received multiple on same SIG BVC"); |
| } |
| roi := roi & { pcu_idx }; |
| repeat; |
| } |
| } |
| /* send a INVOKE-TRACE from SGSN and expect to receive a copy on each NSE */ |
| testcase TC_trace() runs on GlobalTest_CT |
| { |
| var BSSGP_ConnHdlr vc_conn; |
| f_init(); |
| f_global_init(); |
| |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_INVOKE_TRACE('23'O, '4321'O); |
| var template (present) PDU_BSSGP exp_rx := ts_BSSGP_INVOKE_TRACE('23'O, '4321'O); |
| |
| var ro_default defaults := {}; |
| for (var integer i := 0; i < lengthof(g_pcu); i := i+1) { |
| activate(as_bssgp_g_pcu_count(i, exp_rx, g_roi)); |
| } |
| G_SGSN[0].send(pdu_tx); |
| f_sleep(2.0); |
| for (var integer i := 0; i < lengthof(defaults); i := i+1) { |
| deactivate(defaults[i]); |
| } |
| |
| for (var integer i := 0; i < lengthof(g_pcu); i := i+1) { |
| if (not ro_integer_contains(g_roi, i)) { |
| setverdict(fail, "Failed to receive TRACE on PCU index ", i); |
| } |
| } |
| setverdict(pass); |
| |
| f_cleanup(); |
| } |
| |
| /*********************************************************************** |
| * LLC-DISCARDED procedure |
| ***********************************************************************/ |
| |
| private function f_TC_llc_discarded(charstring id) runs on BSSGP_ConnHdlr { |
| var BssgpBvci bvci := g_pars.pcu[0].cfg.bvc[0].bvci; |
| |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_LLC_DISCARDED(g_pars.tlli, 23, bvci, 2342); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_LLC_DISCARDED(g_pars.tlli, 23, bvci, 2342); |
| |
| f_pcu2sgsn(pdu_tx, pdu_rx, use_sig := true); |
| |
| setverdict(pass); |
| } |
| /* Send a LLC-DISCARDED from BSS side and expect it to show up on SGSN (SIG BVC) */ |
| testcase TC_llc_discarded() runs on test_CT |
| { |
| f_init(); |
| f_start_handlers(refers(f_TC_llc_discarded), testcasename(), 6); |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| f_cleanup(); |
| } |
| |
| /*********************************************************************** |
| * OVERLOAD procedure |
| ***********************************************************************/ |
| |
| /* Send an OVERLOAD from SGSN side and expect it to show up on each PCU (SIG BVC) */ |
| testcase TC_overload() runs on GlobalTest_CT |
| { |
| f_init(); |
| f_global_init(); |
| |
| var template (value) PDU_BSSGP pdu_tx := ts_OVERLOAD('1'B); |
| var template (present) PDU_BSSGP exp_rx := tr_OVERLOAD('1'B); |
| |
| var ro_default defaults := {}; |
| for (var integer i := 0; i < lengthof(g_pcu); i := i+1) { |
| activate(as_bssgp_g_pcu_count(i, exp_rx, g_roi)); |
| } |
| G_SGSN[0].send(pdu_tx); |
| f_sleep(2.0); |
| for (var integer i := 0; i < lengthof(defaults); i := i+1) { |
| deactivate(defaults[i]); |
| } |
| |
| for (var integer i := 0; i < lengthof(g_pcu); i := i+1) { |
| if (not ro_integer_contains(g_roi, i)) { |
| setverdict(fail, "Failed to receive OVERLOAD on PCU index ", i); |
| } |
| } |
| setverdict(pass); |
| |
| f_cleanup(); |
| } |
| |
| /*********************************************************************** |
| * BVC-BLOCK / BVC-UNBLOCK procedure |
| ***********************************************************************/ |
| |
| private function f_block_ptp_bvc_from_pcu(integer pcu_idx, integer bvc_idx) runs on test_CT |
| { |
| var BSSGP_BVC_CT bvc_ct := g_pcu[pcu_idx].vc_BSSGP_BVC[bvc_idx]; |
| var BssgpBvcConfig bvc_cfg := g_pcu[pcu_idx].cfg.bvc[bvc_idx]; |
| var Nsei nsei_pcu := g_pcu[pcu_idx].cfg.nsei; |
| |
| SGSN_MGMT.clear; |
| PCU_MGMT.clear; |
| |
| /* block the PTP BVC from the PCU side */ |
| PCU_MGMT.send(BssgpBlockRequest:{cause:=BSSGP_CAUSE_OM_INTERVENTION}) to bvc_ct; |
| /* expect state on both PCU and SGSN side to change */ |
| interleave { |
| [] PCU_MGMT.receive(tr_BssgpStsInd(nsei_pcu, bvc_cfg.bvci, BVC_S_BLOCKED)) from bvc_ct; |
| [] SGSN_MGMT.receive(tr_BssgpStsInd(*, bvc_cfg.bvci, BVC_S_BLOCKED)); |
| } |
| setverdict(pass); |
| } |
| testcase TC_bvc_block_ptp() runs on test_CT |
| { |
| f_init(); |
| f_sleep(1.0); |
| f_block_ptp_bvc_from_pcu(0, 0); |
| f_cleanup(); |
| } |
| |
| private function f_unblock_ptp_bvc_from_pcu(integer pcu_idx, integer bvc_idx) runs on test_CT |
| { |
| var BSSGP_BVC_CT bvc_ct := g_pcu[pcu_idx].vc_BSSGP_BVC[bvc_idx]; |
| var BssgpBvcConfig bvc_cfg := g_pcu[pcu_idx].cfg.bvc[bvc_idx]; |
| var Nsei nsei_pcu := g_pcu[pcu_idx].cfg.nsei; |
| |
| SGSN_MGMT.clear; |
| PCU_MGMT.clear; |
| |
| /* block the PTP BVC from the PCU side */ |
| PCU_MGMT.send(BssgpUnblockRequest:{}) to bvc_ct; |
| /* expect state on both PCU and SGSN side to change */ |
| interleave { |
| [] PCU_MGMT.receive(tr_BssgpStsInd(nsei_pcu, bvc_cfg.bvci, BVC_S_UNBLOCKED)) from bvc_ct; |
| [] SGSN_MGMT.receive(tr_BssgpStsInd(*, bvc_cfg.bvci, BVC_S_UNBLOCKED)); |
| } |
| setverdict(pass); |
| } |
| testcase TC_bvc_unblock_ptp() runs on test_CT |
| { |
| f_init(); |
| f_sleep(1.0); |
| f_block_ptp_bvc_from_pcu(0, 0); |
| f_sleep(1.0); |
| f_unblock_ptp_bvc_from_pcu(0, 0); |
| f_cleanup(); |
| } |
| |
| /*********************************************************************** |
| * BVC-RESET procedure |
| ***********************************************************************/ |
| |
| private altstep as_ignore_status(BSSGP_BVC_MGMT_PT pt) { |
| [] pt.receive(BssgpStatusIndication:?) { repeat; } |
| } |
| private function f_get_sgsn_bvc_ct(integer sgsn_idx, BssgpBvci bvci) runs on test_CT return BSSGP_BVC_CT { |
| for (var integer i := 0; i < lengthof(g_sgsn[sgsn_idx].cfg.bvc); i := i+1) { |
| if (g_sgsn[sgsn_idx].cfg.bvc[i].bvci == bvci) { |
| return g_sgsn[sgsn_idx].vc_BSSGP_BVC[i]; |
| } |
| } |
| return null; |
| } |
| private function f_reset_ptp_bvc_from_pcu(integer pcu_idx, integer bvc_idx) runs on test_CT |
| { |
| var BSSGP_BVC_CT pcu_bvc_ct := g_pcu[pcu_idx].vc_BSSGP_BVC[bvc_idx]; |
| var BssgpBvcConfig bvc_cfg := g_pcu[pcu_idx].cfg.bvc[bvc_idx]; |
| var Nsei nsei_pcu := g_pcu[pcu_idx].cfg.nsei; |
| var BSSGP_BVC_CT sgsn_bvc_ct := f_get_sgsn_bvc_ct(0, bvc_cfg.bvci); |
| var default d; |
| |
| SGSN_MGMT.clear; |
| PCU_MGMT.clear; |
| |
| /* block the PTP BVC from the PCU side */ |
| PCU_MGMT.send(BssgpResetRequest:{cause:=BSSGP_CAUSE_OM_INTERVENTION}) to pcu_bvc_ct; |
| /* expect state on both PCU and SGSN side to change */ |
| d := activate(as_ignore_status(SGSN_MGMT)); |
| interleave { |
| [] PCU_MGMT.receive(tr_BssgpStsInd(nsei_pcu, bvc_cfg.bvci, BVC_S_BLOCKED)) from pcu_bvc_ct; |
| [] SGSN_MGMT.receive(BssgpResetIndication:{bvc_cfg.bvci}) from sgsn_bvc_ct; |
| } |
| deactivate(d); |
| setverdict(pass); |
| } |
| /* Send a BVC-RESET for a PTP BVC from the BSS side: expect it to propagate */ |
| testcase TC_bvc_reset_ptp_from_bss() runs on test_CT |
| { |
| f_init(); |
| f_sleep(3.0); |
| f_reset_ptp_bvc_from_pcu(0, 0); |
| f_cleanup(); |
| } |
| |
| private altstep as_count_bvc_block(integer sgsn_idx, BssgpBvci bvci, inout ro_integer roi) |
| runs on test_CT { |
| var BSSGP_BVC_CT sgsn_bvc_ct := f_get_sgsn_bvc_ct(sgsn_idx, bvci); |
| [] SGSN_MGMT.receive(tr_BssgpStsInd(?, bvci, BVC_S_BLOCKED)) from sgsn_bvc_ct { |
| roi := roi & { bvci }; |
| repeat; |
| } |
| } |
| /* reset the signaling BVC from one BSS; expect no signaling BVC reset on SGSN; but BVC-BLOCK for PTP */ |
| testcase TC_bvc_reset_sig_from_bss() runs on test_CT { |
| |
| f_init(); |
| f_sleep(3.0); |
| |
| /* Start BVC-RESET procedure for BVCI=0 */ |
| PCU_MGMT.send(BssgpResetRequest:{cause:=BSSGP_CAUSE_OM_INTERVENTION}) to g_pcu[0].vc_BSSGP; |
| |
| /* Activate altsteps: One for each PTP BVC within that PCUs NSE */ |
| var ro_default defaults := {}; |
| for (var integer i := 0; i < lengthof(g_pcu[0].cfg.bvc); i := i+1) { |
| var BssgpBvcConfig bvcc := g_pcu[0].cfg.bvc[i]; |
| var default d := activate(as_count_bvc_block(0, bvcc.bvci, g_roi)); |
| defaults := defaults & { d }; |
| } |
| |
| timer T := 3.0; |
| T.start; |
| alt { |
| [] SGSN_MGMT.receive(BssgpResetIndication:{0}) { |
| setverdict(fail, "BSS-side Reset of BVCI=0 should not propagate"); |
| } |
| [] T.timeout; |
| } |
| |
| for (var integer i := 0; i < lengthof(defaults); i := i+1) { |
| deactivate(defaults[i]); |
| } |
| |
| /* check if BVC-block was received on all expected BVC */ |
| for (var integer i := 0; i < lengthof(g_pcu[0].cfg.bvc); i := i+1) { |
| var BssgpBvcConfig bvcc := g_pcu[0].cfg.bvc[i]; |
| if (not ro_integer_contains(g_roi, bvcc.bvci)) { |
| setverdict(fail, "Missing SGSN-side BVC-BLOCK of BVCI=", bvcc.bvci); |
| } |
| } |
| |
| /* check if BVC-block was not received on any unexpected BVC is not required as |
| * such a message would basically run into 'no matching clause' */ |
| setverdict(pass); |
| f_cleanup(); |
| } |
| |
| private function f_reset_ptp_bvc_from_sgsn(integer pcu_idx, integer bvc_idx) runs on test_CT |
| { |
| var BSSGP_BVC_CT pcu_bvc_ct := g_pcu[pcu_idx].vc_BSSGP_BVC[bvc_idx]; |
| var BssgpBvcConfig bvc_cfg := g_pcu[pcu_idx].cfg.bvc[bvc_idx]; |
| var Nsei nsei_pcu := g_pcu[pcu_idx].cfg.nsei; |
| var BSSGP_BVC_CT sgsn_bvc_ct := f_get_sgsn_bvc_ct(0, bvc_cfg.bvci); |
| var default d; |
| |
| SGSN_MGMT.clear; |
| PCU_MGMT.clear; |
| |
| /* block the PTP BVC from the PCU side */ |
| SGSN_MGMT.send(BssgpResetRequest:{cause:=BSSGP_CAUSE_OM_INTERVENTION}) to sgsn_bvc_ct; |
| /* expect state on both PCU and SGSN side to change */ |
| d := activate(as_ignore_status(PCU_MGMT)); |
| interleave { |
| [] SGSN_MGMT.receive(tr_BssgpStsInd(?, bvc_cfg.bvci, BVC_S_BLOCKED)) from sgsn_bvc_ct; |
| [] PCU_MGMT.receive(BssgpResetIndication:{bvc_cfg.bvci}) from pcu_bvc_ct; |
| } |
| deactivate(d); |
| setverdict(pass); |
| } |
| /* Send a BVC-RESET for a PTP BVC from the SGSN side: expect it to propagate */ |
| testcase TC_bvc_reset_ptp_from_sgsn() runs on test_CT |
| { |
| f_init(); |
| f_sleep(3.0); |
| f_reset_ptp_bvc_from_sgsn(0, 0); |
| f_cleanup(); |
| } |
| |
| private altstep as_ignore_mgmt(BSSGP_BVC_MGMT_PT pt) { |
| [] pt.receive {repeat; } |
| } |
| |
| private altstep as_count_bvc0_block(integer pcu_idx, Nsei nsei, inout ro_integer roi) |
| runs on test_CT { |
| var BSSGP_CT pcu_ct := g_pcu[pcu_idx].vc_BSSGP; |
| [] PCU_MGMT.receive(BssgpResetIndication:{0}) from pcu_ct { |
| roi := roi & { nsei }; |
| repeat; |
| } |
| } |
| |
| /* reset the signaling BVC from the SGSN; expect all signaling BVC on all BSS to be reset */ |
| testcase TC_bvc_reset_sig_from_sgsn() runs on test_CT { |
| |
| f_init(); |
| f_sleep(3.0); |
| |
| SGSN_MGMT.clear; |
| PCU_MGMT.clear; |
| |
| /* Start BVC-RESET procedure for BVCI=0 */ |
| SGSN_MGMT.send(BssgpResetRequest:{cause:=BSSGP_CAUSE_OM_INTERVENTION}) to g_sgsn[0].vc_BSSGP; |
| |
| /* Defaults match in reverse activation order, this one is a catch-all for Status indications |
| * and reset indications sent from other components (like the ptp_bvcs). If we don't drain |
| * the port and a different message sits at the front we wait forever and fail the test. |
| */ |
| var ro_default defaults := { activate(as_ignore_mgmt(PCU_MGMT)) }; |
| |
| /* Activate altsteps: One for each PCU NSE */ |
| for (var integer i := 0; i < lengthof(g_pcu); i := i+1) { |
| var NSConfiguration nscfg := mp_nsconfig_pcu[i]; |
| var default d := activate(as_count_bvc0_block(i, nscfg.nsei, g_roi)); |
| defaults := defaults & { d }; |
| } |
| |
| f_sleep(3.0); |
| |
| for (var integer i := 0; i < lengthof(defaults); i := i+1) { |
| deactivate(defaults[i]); |
| } |
| |
| /* check if BVC-block was received on all expected BVC */ |
| for (var integer i := 0; i < lengthof(g_pcu); i := i+1) { |
| var NSConfiguration nscfg := mp_nsconfig_pcu[i]; |
| if (not ro_integer_contains(g_roi, nscfg.nsei)) { |
| setverdict(fail, "Missing PCU-side BVC-RESET of BVCI=0 on PCU index ", i); |
| } |
| } |
| |
| /* check if BVC-block was not received on any unexpected BVC is not required as |
| * such a message would basically run into 'no matching clause' */ |
| |
| f_cleanup(); |
| } |
| |
| /*********************************************************************** |
| * FLOW-CONTROL-BVC procedure |
| ***********************************************************************/ |
| |
| private altstep as_g_count_sgsn(integer sgsn_idx, inout ro_integer roi, |
| template PDU_BSSGP exp_rx, template (omit) PDU_BSSGP tx_reply) |
| runs on GlobalTest_CT { |
| [] G_SGSN[sgsn_idx].receive(exp_rx) { |
| roi := roi & { sgsn_idx }; |
| if (ispresent(tx_reply)) { |
| G_SGSN[sgsn_idx].send(tx_reply); |
| } |
| repeat; |
| } |
| } |
| /* Send FC-BVC from simulated PCU; expect each SGSN to receive it; expect PCU to receive ACK */ |
| testcase TC_fc_bvc() runs on GlobalTest_CT |
| { |
| f_init(); |
| f_global_init_ptp(); |
| |
| var template (value) PDU_BSSGP pdu_tx := t_BVC_FC_BVC(10240, 2000, 1024, 1000, '01'O); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BVC_FC_BVC(10240, 2000, 1024, 1000, '01'O); |
| var template (omit) PDU_BSSGP ack_tx := |
| t_BVC_FC_BVC_ACK(pdu_tx.pDU_BSSGP_FLOW_CONTROL_BVC.tag.unstructured_Value); |
| |
| /* Send a FC-BVC from BSS to gbproxy, expect an ACK in response */ |
| G_PCU[0].send(pdu_tx); |
| |
| /* Activate altsteps: One for each SGSN-side PTP BVC port */ |
| var ro_default defaults := {}; |
| for (var integer i := 0; i < lengthof(g_sgsn); i := i+1) { |
| var default d := activate(as_g_count_sgsn(i, g_roi, pdu_rx, ack_tx)); |
| defaults := defaults & { d }; |
| } |
| |
| f_sleep(3.0); |
| |
| for (var integer i := 0; i < lengthof(defaults); i := i+1) { |
| deactivate(defaults[i]); |
| } |
| |
| /* check if BVC-block was received on all expected BVC */ |
| for (var integer i := 0; i < lengthof(g_sgsn); i := i+1) { |
| if (not ro_integer_contains(g_roi, i)) { |
| setverdict(fail, "Missing BVC-FLOW-CONTROL on SGSN index ", i); |
| } |
| } |
| |
| /* Expect ACK on PCU side */ |
| G_PCU[0].receive(ack_tx); |
| |
| setverdict(pass); |
| |
| f_cleanup(); |
| } |
| |
| /*********************************************************************** |
| * FLOW-CONTROL-MS procedure |
| ***********************************************************************/ |
| |
| private function f_TC_fc_ms(charstring id) runs on BSSGP_ConnHdlr { |
| var BssgpBvci bvci := g_pars.pcu[0].cfg.bvc[0].bvci; |
| |
| var template (value) PDU_BSSGP fc_tx := ts_BVC_FC_MS(g_pars.tlli, 100, 200, '12'O); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP fc_rx := tr_BVC_FC_MS(g_pars.tlli, 100, 200, '12'O); |
| var template (value) PDU_BSSGP ack_tx := ts_BVC_FC_MS_ACK(g_pars.tlli, '12'O); |
| |
| f_pcu2sgsn(fc_tx, fc_rx, use_sig := false); |
| f_sgsn2pcu(ack_tx, ack_tx, use_sig := false); |
| |
| setverdict(pass); |
| } |
| /* Send a FLOW-CONTROL-MS from BSS side and expect it to show up on SGSN (PTP BVC) */ |
| testcase TC_fc_ms() runs on test_CT |
| { |
| f_init(); |
| f_start_handlers(refers(f_TC_fc_ms), testcasename(), 21); |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| f_cleanup(); |
| } |
| |
| |
| |
| control { |
| execute( TC_BVC_bringup() ); |
| execute( TC_ul_unitdata() ); |
| execute( TC_dl_unitdata() ); |
| execute( TC_ra_capability() ); |
| execute( TC_ra_capability_upd() ); |
| execute( TC_radio_status() ); |
| execute( TC_suspend() ); |
| execute( TC_resume() ); |
| execute( TC_trace() ); |
| execute( TC_llc_discarded() ); |
| execute( TC_overload() ); |
| execute( TC_bvc_block_ptp() ); |
| execute( TC_bvc_unblock_ptp() ); |
| execute( TC_bvc_reset_ptp_from_bss() ); |
| execute( TC_bvc_reset_sig_from_bss() ); |
| execute( TC_bvc_reset_ptp_from_sgsn() ); |
| execute( TC_bvc_reset_sig_from_sgsn() ); |
| if (mp_enable_bss_load_sharing) { |
| /* don't enable this by default, as we don't yet have any automatic test setup for FR with 4 NS-VC */ |
| execute( TC_load_sharing_dl() ); |
| } |
| |
| /* PAGING-PS over PTP BVC */ |
| execute( TC_paging_ps_ptp_bss() ); |
| execute( TC_paging_ps_ptp_lac() ); |
| execute( TC_paging_ps_ptp_lac_unknown() ); |
| execute( TC_paging_ps_ptp_rac() ); |
| execute( TC_paging_ps_ptp_rac_unknown() ); |
| execute( TC_paging_ps_ptp_bvci() ); |
| execute( TC_paging_ps_ptp_bvci_imsi() ); |
| execute( TC_paging_ps_ptp_bvci_unknown() ); |
| execute( TC_paging_ps_reject_ptp_bvci() ); |
| execute( TC_paging_ps_reject_ptp_bvci_imsi() ); |
| |
| /* PAGING-PS over SIG BVC */ |
| execute( TC_paging_ps_sig_bss() ); |
| execute( TC_paging_ps_sig_lac() ); |
| execute( TC_paging_ps_sig_lac_unknown() ); |
| execute( TC_paging_ps_sig_rac() ); |
| execute( TC_paging_ps_sig_rac_unknown() ); |
| execute( TC_paging_ps_sig_bvci() ); |
| execute( TC_paging_ps_sig_bvci_imsi() ); |
| execute( TC_paging_ps_sig_bvci_unknown() ); |
| execute( TC_paging_ps_reject_sig_bvci() ); |
| execute( TC_paging_ps_reject_sig_bvci_imsi() ); |
| |
| /* PAGING-CS over PTP BVC */ |
| execute( TC_paging_cs_ptp_bss() ); |
| execute( TC_paging_cs_ptp_lac() ); |
| execute( TC_paging_cs_ptp_lac_unknown() ); |
| execute( TC_paging_cs_ptp_rac() ); |
| execute( TC_paging_cs_ptp_rac_unknown() ); |
| execute( TC_paging_cs_ptp_bvci() ); |
| execute( TC_paging_cs_ptp_bvci_unknown() ); |
| |
| /* PAGING-CS over SIG BVC */ |
| execute( TC_paging_cs_sig_bss() ); |
| execute( TC_paging_cs_sig_lac() ); |
| execute( TC_paging_cs_sig_lac_unknown() ); |
| execute( TC_paging_cs_sig_rac() ); |
| execute( TC_paging_cs_sig_rac_unknown() ); |
| execute( TC_paging_cs_sig_bvci() ); |
| execute( TC_paging_cs_sig_bvci_unknown() ); |
| |
| |
| execute( TC_flush_ll() ); |
| execute( TC_fc_bvc() ); |
| execute( TC_fc_ms() ); |
| } |
| |
| |
| } |