706 lines
18 KiB
Plaintext
706 lines
18 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;
|
|
|
|
modulepar {
|
|
/* IP/port on which we run our internal GSUP/HLR emulation */
|
|
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
|
|
}
|
|
}
|
|
}
|
|
};
|
|
NSConfigurations mp_nsconfig_pcu := {
|
|
{
|
|
nsei := 96,
|
|
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 := 97
|
|
}
|
|
}
|
|
},
|
|
{
|
|
nsei := 97,
|
|
role_sgsn := false,
|
|
handle_sns := false,
|
|
nsvc := {
|
|
{
|
|
provider := {
|
|
ip := {
|
|
address_family := AF_INET,
|
|
local_udp_port := 21011,
|
|
local_ip := "127.0.0.1",
|
|
remote_udp_port := 23000,
|
|
remote_ip := "127.0.0.1"
|
|
}
|
|
},
|
|
nsvci := 98
|
|
}
|
|
}
|
|
},
|
|
{
|
|
nsei := 98,
|
|
role_sgsn := false,
|
|
handle_sns := false,
|
|
nsvc := {
|
|
{
|
|
provider := {
|
|
ip := {
|
|
address_family := AF_INET,
|
|
local_udp_port := 21012,
|
|
local_ip := "127.0.0.1",
|
|
remote_udp_port := 23000,
|
|
remote_ip := "127.0.0.1"
|
|
}
|
|
},
|
|
nsvci := 99
|
|
}
|
|
}
|
|
}
|
|
};
|
|
BssgpConfigs mp_gbconfigs := {
|
|
{
|
|
nsei := 96,
|
|
sgsn_role := false,
|
|
bvc := {
|
|
{
|
|
bvci := 196,
|
|
cell_id := {
|
|
ra_id := {
|
|
lai := {
|
|
mcc_mnc := c_mcc_mnc,
|
|
lac := 13135
|
|
},
|
|
rac := 0
|
|
},
|
|
cell_id := 20960
|
|
},
|
|
depth := BSSGP_DECODE_DEPTH_BSSGP,
|
|
create_cb := refers(BSSGP_Emulation.DefaultCreateCallback)
|
|
}
|
|
}
|
|
}, {
|
|
nsei := 97,
|
|
sgsn_role := false,
|
|
bvc := {
|
|
{
|
|
bvci := 210,
|
|
cell_id := {
|
|
ra_id := {
|
|
lai := {
|
|
mcc_mnc := c_mcc_mnc,
|
|
lac := 13200
|
|
},
|
|
rac := 0
|
|
},
|
|
cell_id := 20961
|
|
},
|
|
depth := BSSGP_DECODE_DEPTH_BSSGP,
|
|
create_cb := refers(BSSGP_Emulation.DefaultCreateCallback)
|
|
}
|
|
}
|
|
}, {
|
|
nsei := 98,
|
|
sgsn_role := false,
|
|
bvc := {
|
|
{
|
|
bvci := 220,
|
|
cell_id := {
|
|
ra_id := {
|
|
lai := {
|
|
mcc_mnc := c_mcc_mnc,
|
|
lac := 13300
|
|
},
|
|
rac := 0
|
|
},
|
|
cell_id := 20962
|
|
},
|
|
depth := BSSGP_DECODE_DEPTH_BSSGP,
|
|
create_cb := refers(BSSGP_Emulation.DefaultCreateCallback)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const integer NUM_BVC_PER_NSE := 3;
|
|
type record GbInstance {
|
|
NS_CT vc_NS,
|
|
BSSGP_CT vc_BSSGP,
|
|
BSSGP_BVC_CT vc_BSSGP_BVC[NUM_BVC_PER_NSE],
|
|
BssgpConfig cfg
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
type component BSSGP_ConnHdlr {
|
|
port BSSGP_PT PCU[NUM_PCU];
|
|
port BSSGP_PT PCU_SIG[NUM_PCU];
|
|
port BSSGP_PROC_PT PCU_PROC[NUM_PCU];
|
|
port BSSGP_PT SGSN[NUM_SGSN];
|
|
port BSSGP_PT SGSN_SIG[NUM_SGSN];
|
|
port BSSGP_PROC_PT SGSN_PROC[NUM_SGSN];
|
|
|
|
var BSSGP_ConnHdlrPars g_pars;
|
|
timer g_Tguard;
|
|
var LLC_Entities llc;
|
|
}
|
|
|
|
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,
|
|
BssgpCellIds bssgp_cell_id,
|
|
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_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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
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];
|
|
/* concatenate all the PCU-side BVCs for the SGSN side */
|
|
g_sgsn[0].cfg.bvc := g_sgsn[0].cfg.bvc & mp_gbconfigs[i].bvc;
|
|
}
|
|
|
|
f_init_vty();
|
|
for (i := 0; i < lengthof(mp_nsconfig_sgsn); i := i+1) {
|
|
f_init_gb_sgsn(g_sgsn[0], "GbProxy_Test", 0);
|
|
}
|
|
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 := 5.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 {
|
|
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,
|
|
bssgp_cell_id := { pcu[0].cfg.bvc[0].cell_id, pcu[1].cfg.bvc[0].cell_id, pcu[2].cfg.bvc[0].cell_id },
|
|
t_guard := t_guard
|
|
};
|
|
|
|
vc_conn := BSSGP_ConnHdlr.create(id);
|
|
// PDU side
|
|
connect(vc_conn:PCU[0], pcu[0].vc_BSSGP_BVC[0]:BSSGP_SP);
|
|
connect(vc_conn:PCU_SIG[0], pcu[0].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
|
|
connect(vc_conn:PCU_PROC[0], pcu[0].vc_BSSGP_BVC[0]:BSSGP_PROC);
|
|
connect(vc_conn:PCU[1], pcu[1].vc_BSSGP_BVC[0]:BSSGP_SP);
|
|
connect(vc_conn:PCU_SIG[1], pcu[1].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
|
|
connect(vc_conn:PCU_PROC[1], pcu[1].vc_BSSGP_BVC[0]:BSSGP_PROC);
|
|
connect(vc_conn:PCU[2], pcu[2].vc_BSSGP_BVC[0]:BSSGP_SP);
|
|
connect(vc_conn:PCU_SIG[2], pcu[2].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
|
|
connect(vc_conn:PCU_PROC[2], pcu[2].vc_BSSGP_BVC[0]:BSSGP_PROC);
|
|
// SGSN side
|
|
connect(vc_conn:SGSN[0], sgsn[0].vc_BSSGP_BVC[0]:BSSGP_SP);
|
|
connect(vc_conn:SGSN_SIG[0], sgsn[0].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
|
|
connect(vc_conn:SGSN_PROC[0], sgsn[0].vc_BSSGP_BVC[0]:BSSGP_PROC);
|
|
|
|
vc_conn.start(f_handler_init(fn, id, pars));
|
|
return vc_conn;
|
|
}
|
|
|
|
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);
|
|
|
|
/* register for our IMSI + TLLI */
|
|
for (i := 0; i < sizeof(SGSN_PROC); i := i+1) {
|
|
f_client_register(g_pars.imsi, g_pars.tlli, SGSN_PROC[i]);
|
|
}
|
|
for (i := 0; i < sizeof(PCU_PROC); i := i+1) {
|
|
f_client_register(g_pars.imsi, g_pars.tlli, PCU_PROC[i]);
|
|
}
|
|
|
|
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) runs on BSSGP_ConnHdlr {
|
|
var PDU_BSSGP rx;
|
|
timer T := 1.0;
|
|
|
|
PCU[pcu_idx].send(tx);
|
|
T.start;
|
|
alt {
|
|
[] 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;
|
|
}
|
|
[] 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_sgsn2pcu(template (value) PDU_BSSGP tx, template (present) PDU_BSSGP exp_rx,
|
|
integer sgsn_idx:= 0, integer pcu_idx := 0) runs on BSSGP_ConnHdlr {
|
|
var PDU_BSSGP rx;
|
|
timer T := 1.0;
|
|
|
|
SGSN[sgsn_idx].send(tx);
|
|
T.start;
|
|
alt {
|
|
[] 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;
|
|
}
|
|
[] 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 {
|
|
timer T := 5.0;
|
|
var PDU_BSSGP rx_pdu;
|
|
PCU_SIG[ran_idx].send(ts_BSSGP_SUSPEND(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id));
|
|
T.start;
|
|
alt {
|
|
[] PCU_SIG[ran_idx].receive(tr_BSSGP_SUSPEND_ACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].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, g_pars.bssgp_cell_id[ran_idx].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 {
|
|
timer T := 5.0;
|
|
PCU_SIG[ran_idx].send(ts_BSSGP_RESUME(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id, susp_ref));
|
|
T.start;
|
|
alt {
|
|
[] PCU_SIG[ran_idx].receive(tr_BSSGP_RESUME_ACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id));
|
|
[] PCU_SIG[ran_idx].receive(tr_BSSGP_RESUME_NACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].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 i;
|
|
|
|
for (i := 0; i < 1024; i := i+1) {
|
|
var octetstring payload := f_rnd_octstring(i);
|
|
var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_UL_UD(g_pars.tlli, g_pars.bssgp_cell_id[0], 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, g_pars.bssgp_cell_id[0], payload);
|
|
|
|
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 < 1024; 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));
|
|
/* 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));
|
|
|
|
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();
|
|
}
|
|
|
|
|
|
|
|
|
|
control {
|
|
execute( TC_BVC_bringup() );
|
|
execute( TC_ul_unitdata() );
|
|
execute( TC_dl_unitdata() );
|
|
execute( TC_ra_capability() );
|
|
}
|
|
|
|
|
|
}
|