osmo-ttcn3-hacks/gbproxy/GBProxy_Tests.ttcn

2366 lines
72 KiB
Plaintext

module GBProxy_Tests {
/* Osmocom GBProxy test suite in TTCN-3
* (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 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 {
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
}
}
}
};
/* 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 := 1;
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 := {};
};
type component BSSGP_ConnHdlr {
/* array of per-BVC ports on the PCU side */
port BSSGP_PT PCU[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[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,
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) {
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(self:PCU_MGMT, gb.vc_BSSGP_BVC[i]:MGMT);
}
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) {
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(self:SGSN_MGMT, gb.vc_BSSGP_BVC[i]:MGMT);
}
connect(self:SGSN_MGMT, gb.vc_BSSGP:MGMT);
}
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;
}
function f_init() runs on test_CT {
var ro_integer bvci_unblocked := {};
var BssgpStatusIndication bsi;
var integer i;
if (g_initialized == true) {
return;
}
g_initialized := true;
g_sgsn[0].cfg := {
nsei := mp_nsconfig_sgsn[0].nsei,
sgsn_role := true,
bvc := { }
}
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 */
g_sgsn[0].cfg.bvc := g_sgsn[0].cfg.bvc & g_pcu[i].cfg.bvc;
}
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);
}
/* wait until all BVC are unblocked on both sides */
timer T := 15.0;
T.start;
alt {
[] SGSN_MGMT.receive(BssgpStatusIndication:{*, ?, BVC_S_UNBLOCKED}) -> value bsi {
bvci_unblocked := bvci_unblocked & { bsi.bvci };
if (lengthof(bvci_unblocked) != lengthof(g_sgsn[0].cfg.bvc)) {
repeat;
}
}
[] 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");
mtc.stop;
}
}
/* iterate over list and check all BVCI */
for (i := 0; i < lengthof(g_sgsn[0].cfg.bvc); i := i+1) {
var BssgpBvci bvci := g_sgsn[0].cfg.bvc[i].bvci;
if (not ro_integer_contains(bvci_unblocked, bvci)) {
setverdict(fail, "BVCI=", bvci, " was not unblocked during start-up");
mtc.stop;
}
}
}
function f_cleanup() runs on test_CT {
self.stop;
}
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, GbInstances pcu, GbInstances sgsn, integer imsi_suffix,
float t_guard := 30.0)
runs on test_CT return BSSGP_ConnHdlr {
var BSSGP_ConnHdlr vc_conn;
var BSSGP_ConnHdlrPars pars := {
imei := f_gen_imei(imsi_suffix),
imsi := f_gen_imsi(imsi_suffix),
msisdn := f_gen_msisdn(imsi_suffix),
p_tmsi := omit,
p_tmsi_sig := omit,
tlli := f_gprs_tlli_random(),
tlli_old := omit,
ra := omit,
pcu := g_pcu,
sgsn := g_sgsn,
t_guard := t_guard
};
vc_conn := BSSGP_ConnHdlr.create(id);
vc_conn.start(f_handler_init(fn, id, pars));
return vc_conn;
}
/* 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[port_idx].checkstate("Connected")) {
/* unregister + disconnect from old BVC */
f_client_unregister(g_pars.imsi, PCU_PROC[port_idx]);
disconnect(self:PCU[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[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[port_idx].checkstate("Connected")) {
/* unregister + disconnect from old BVC */
f_client_unregister(g_pars.imsi, SGSN_PROC[port_idx]);
disconnect(self:SGSN[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[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_Tguard() runs on BSSGP_ConnHdlr {
[] g_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_Tguard());
/* call the user-supplied test case function */
fn.apply(id);
}
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, integer sgsn_idx := 0, boolean use_sig := false) runs on BSSGP_ConnHdlr {
var PDU_BSSGP rx;
timer T := 1.0;
if (use_sig) {
PCU_SIG[pcu_idx].send(tx);
} else {
PCU[pcu_idx].send(tx);
}
T.start;
alt {
[use_sig] SGSN_SIG[sgsn_idx].receive(exp_rx) {
setverdict(pass);
}
[not use_sig] SGSN[sgsn_idx].receive(exp_rx) {
setverdict(pass);
}
[] SGSN[sgsn_idx].receive(PDU_BSSGP:?) -> value rx {
setverdict(fail, "Unexpected BSSGP on SGSN side: ", rx);
mtc.stop;
}
[] SGSN_SIG[sgsn_idx].receive(PDU_BSSGP:?) -> value rx {
setverdict(fail, "Unexpected SIG 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_sgsn2pcu(template (value) PDU_BSSGP tx, template (present) PDU_BSSGP exp_rx,
integer sgsn_idx:= 0, integer pcu_idx := 0, boolean use_sig := false) runs on BSSGP_ConnHdlr {
var PDU_BSSGP rx;
timer T := 1.0;
if (use_sig) {
SGSN_SIG[sgsn_idx].send(tx);
} else {
SGSN[sgsn_idx].send(tx);
}
T.start;
alt {
[use_sig] PCU_SIG[pcu_idx].receive(exp_rx) {
setverdict(pass);
}
[not use_sig] PCU[pcu_idx].receive(exp_rx) {
setverdict(pass);
}
[] PCU[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];
};
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);
}
}
/* 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: ", 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: ", 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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_BVC_bringup), testcasename(), g_pcu, g_sgsn, 51);
vc_conn.done;
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
{
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_ul_unitdata), testcasename(), g_pcu, g_sgsn, 1);
vc_conn.done;
/* 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
{
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_dl_unitdata), testcasename(), g_pcu, g_sgsn, 2);
vc_conn.done;
/* 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
{
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_ra_capability), testcasename(), g_pcu, g_sgsn, 3);
vc_conn.done;
/* 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
{
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_ra_capability_upd), testcasename(), g_pcu, g_sgsn, 4);
vc_conn.done;
/* 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
{
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_radio_status), testcasename(), g_pcu, g_sgsn, 5);
vc_conn.done;
/* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */
f_cleanup();
}
private function f_TC_suspend() runs on GlobalTest_CT {
var integer i;
/* TODO: Generate RA ID for each ConnHdlr */
var RoutingAreaIdentification ra_id := g_pcu[0].cfg.bvc[0].cell_id.ra_id;
for (i := 0; i < 10; i := i+1) {
var OCT4 tlli := f_gprs_tlli_random();
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);
pdu_tx := ts_BSSGP_SUSPEND_ACK(tlli, ra_id, int2oct(i, 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(i, 1));
f_global_sgsn2pcu(pdu_tx, pdu_rx);
/* 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);
}
setverdict(pass);
}
testcase TC_suspend() runs on GlobalTest_CT
{
f_init();
f_global_init();
f_TC_suspend();
f_cleanup();
}
private function f_TC_resume() runs on GlobalTest_CT {
var integer i;
/* TODO: Generate RA ID for each ConnHdlr */
var RoutingAreaIdentification ra_id := g_pcu[0].cfg.bvc[0].cell_id.ra_id;
for (i := 0; i < 10; i := i+1) {
var OCT4 tlli := f_gprs_tlli_random();
var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_RESUME(tlli, ra_id, int2oct(i, 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(i, 1));
f_global_pcu2sgsn(pdu_tx, pdu_rx);
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);
/* 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);
}
setverdict(pass);
}
testcase TC_resume() runs on GlobalTest_CT
{
f_init();
f_global_init();
f_TC_resume();
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[0].send(pdu_tx);
}
setverdict(pass);
}
testcase TC_load_sharing_dl() runs on test_CT_NS
{
const integer num_ue := 10;
var BSSGP_ConnHdlr vc_conn[num_ue];
f_init();
/* 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(), g_pcu, g_sgsn, 5+i);
}
/* 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");
}
}
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[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[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[pcu_idx].receive(exp_rx) {
setverdict(fail, "Received paging on PTP BVC, expected SIGNALING BVC");
}
[] any from PCU.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.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.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.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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_ptp_bss), testcasename(), g_pcu, g_sgsn, 9);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_ptp_lac), testcasename(), g_pcu, g_sgsn, 10);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_ptp_lac_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_ptp_rac), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_ptp_rac_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_ptp_bvci), testcasename(), g_pcu, g_sgsn, 12);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_ptp_bvci_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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[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[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);
}
/* 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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_sig_bss), testcasename(), g_pcu, g_sgsn, 13);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_sig_lac), testcasename(), g_pcu, g_sgsn, 14);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_sig_lac_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_sig_rac), testcasename(), g_pcu, g_sgsn, 15);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_sig_rac_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_sig_bvci), testcasename(), g_pcu, g_sgsn, 16);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_ps_sig_bvci_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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[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[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[pcu_idx].receive(exp_rx) {
setverdict(fail, "Received paging on PTP BVC, expected SIGNALING BVC");
}
[] any from PCU.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.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.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.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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_ptp_bss), testcasename(), g_pcu, g_sgsn, 17);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_ptp_lac), testcasename(), g_pcu, g_sgsn, 18);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_ptp_lac_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_ptp_rac), testcasename(), g_pcu, g_sgsn, 19);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_ptp_rac_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_ptp_bvci), testcasename(), g_pcu, g_sgsn, 20);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_ptp_bvci_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_sig_bss), testcasename(), g_pcu, g_sgsn, 13);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_sig_lac), testcasename(), g_pcu, g_sgsn, 14);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_sig_lac_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_sig_rac), testcasename(), g_pcu, g_sgsn, 15);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_sig_rac_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_sig_bvci), testcasename(), g_pcu, g_sgsn, 16);
vc_conn.done;
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 {
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_paging_cs_sig_bvci_unknown), testcasename(), g_pcu, g_sgsn, 11);
vc_conn.done;
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
{
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_flush_ll), testcasename(), g_pcu, g_sgsn, 6);
vc_conn.done;
/* 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
{
var BSSGP_ConnHdlr vc_conn;
f_init();
vc_conn := f_start_handler(refers(f_TC_llc_discarded), testcasename(), g_pcu, g_sgsn, 6);
vc_conn.done;
/* 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_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 };
}
}
/* 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);
/* Start BVC-RESET procedure for BVCI=0 */
SGSN_MGMT.send(BssgpResetRequest:{cause:=BSSGP_CAUSE_OM_INTERVENTION}) to g_sgsn[0].vc_BSSGP;
/* Activate altsteps: One for each PCU NSE */
var ro_default defaults := {};
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();
}
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_unknown() );
/* 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_unknown() );
/* 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() );
}
}