3558 lines
113 KiB
Plaintext
3558 lines
113 KiB
Plaintext
module SGSN_Tests {
|
|
|
|
/* Osmocom SGSN test suite in TTCN-3
|
|
* (C) 2018-2019 Harald Welte <laforge@gnumonks.org>
|
|
* (C) 2018-2019 sysmocom - s.f.m.c. GmbH
|
|
* All rights reserved.
|
|
*
|
|
* Released under the terms of GNU General Public License, Version 2 or
|
|
* (at your option) any later version.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
friend module SGSN_Tests_Iu;
|
|
friend module SGSN_Tests_NS;
|
|
|
|
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 Osmocom_Gb_Types all;
|
|
import from SCCPasp_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 GSUP_Emulation all;
|
|
import from GSUP_Types all;
|
|
import from IPA_Emulation all;
|
|
|
|
import from RAN_Adapter all;
|
|
import from RAN_Emulation all;
|
|
import from RANAP_Templates all;
|
|
import from RANAP_PDU_Descriptions all;
|
|
import from RANAP_IEs all;
|
|
|
|
import from GTP_Emulation all;
|
|
import from GTP_Templates all;
|
|
import from GTP_CodecPort all;
|
|
import from GTPC_Types all;
|
|
import from GTPU_Types all;
|
|
|
|
import from LLC_Types all;
|
|
import from LLC_Templates all;
|
|
|
|
import from SNDCP_Types all;
|
|
|
|
import from TELNETasp_PortType all;
|
|
import from Osmocom_VTY_Functions all;
|
|
|
|
import from GSM_RR_Types all;
|
|
|
|
import from MobileL3_MM_Types all;
|
|
|
|
|
|
modulepar {
|
|
/* IP/port on which we run our internal GSUP/HLR emulation */
|
|
charstring mp_hlr_ip := "127.0.0.1";
|
|
integer mp_hlr_port := 4222;
|
|
charstring mp_ggsn_ip := "127.0.0.103";
|
|
integer mp_echo_interval := 5; /* in seconds. Only used in test enabling g_use_echo */
|
|
charstring mp_sgsn_gtp_ip := "127.0.0.10";
|
|
|
|
NSConfigurations mp_nsconfig := {
|
|
{
|
|
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",
|
|
data_weight := 1,
|
|
signalling_weight := 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",
|
|
data_weight := 1,
|
|
signalling_weight := 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",
|
|
data_weight := 1,
|
|
signalling_weight := 1
|
|
}
|
|
},
|
|
nsvci := 99
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
RAN_Configurations mp_ranap_cfg := {
|
|
{
|
|
transport := RANAP_TRANSPORT_IuCS,
|
|
sccp_service_type := "mtp3_itu",
|
|
sctp_addr := { 23908, "127.0.0.1", 2905, "127.0.0.1" },
|
|
own_pc := 195,
|
|
own_ssn := 142,
|
|
peer_pc := 188, /* 0.23.4 */
|
|
peer_ssn := 142,
|
|
sio := '83'O,
|
|
rctx := 2
|
|
}
|
|
}
|
|
};
|
|
|
|
const integer NUM_BVC_PER_NSE := 1;
|
|
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_GB := 3;
|
|
type record length(NUM_GB) of GbInstance GbInstances;
|
|
type record length(NUM_GB) of NSConfiguration NSConfigurations;
|
|
type record length(NUM_GB) of BssgpCellId BssgpCellIds;
|
|
|
|
const integer NUM_RNC := 1;
|
|
type record of RAN_Configuration RAN_Configurations;
|
|
|
|
type component test_CT {
|
|
var GbInstances g_gb;
|
|
var RAN_Adapter g_ranap[NUM_RNC];
|
|
var boolean g_ranap_enable := false;
|
|
|
|
var GSUP_Emulation_CT vc_GSUP;
|
|
var IPA_Emulation_CT vc_GSUP_IPA;
|
|
/* only to get events from IPA underneath GSUP */
|
|
port IPA_CTRL_PT GSUP_IPA_EVENT;
|
|
|
|
/* only needed at start to get the per-BVC references */
|
|
port BSSGP_CT_PROC_PT PROC;
|
|
|
|
/* used by RIM related test */
|
|
port BSSGP_PT RIM[NUM_GB];
|
|
port GTPEM_PT GTPC;
|
|
|
|
var GTP_Emulation_CT vc_GTP;
|
|
|
|
port TELNETasp_PT SGSNVTY;
|
|
|
|
var boolean g_initialized := false;
|
|
var boolean g_use_echo := false;
|
|
};
|
|
|
|
type component BSSGP_ConnHdlr extends BSSGP_Client_CT, GSUP_ConnHdlr, GTP_ConnHdlr, RAN_ConnHdlr {
|
|
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,
|
|
/* Tracks the RNC state. If true next L3 message will be sent with InitiualUe */
|
|
boolean rnc_send_initial_ue,
|
|
AuthVector vec optional,
|
|
SGSN_ConnHdlrNetworkPars net,
|
|
float t_guard,
|
|
/* only in IuPS / RANAP case */
|
|
SCCP_PAR_Address sccp_addr_local optional,
|
|
SCCP_PAR_Address sccp_addr_peer optional
|
|
};
|
|
|
|
/* Passed in RAN-INFO message from emulated neighbor using RIM */
|
|
const octetstring si1_default := '198fb100000000000000000000000000007900002b'O;
|
|
const octetstring si3_default := '1b753000f110236ec9033c2747407900003c0b2b2b'O;
|
|
const octetstring si13_default := '009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b'O;
|
|
const octetstring si_default := si1_default & si3_default & si13_default;
|
|
|
|
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, 2),
|
|
rac := int2oct(cell_id.ra_id.rac, 1)
|
|
}
|
|
return ret;
|
|
};
|
|
|
|
private function f_init_gb(inout GbInstance gb, charstring id, integer offset) runs on test_CT {
|
|
gb.vc_NS := NS_CT.create(id & "-NS" & int2str(offset));
|
|
gb.vc_BSSGP := BSSGP_CT.create(id & "-BSSGP" & int2str(offset));
|
|
/* 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[offset]));
|
|
gb.vc_BSSGP.start(BssgpStart(gb.cfg, testcasename()));
|
|
/* resolve the per-BVC component references */
|
|
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 RIM related port */
|
|
connect(gb.vc_BSSGP:RIM, self:RIM[offset]);
|
|
}
|
|
|
|
private function f_init_gsup(charstring id) runs on test_CT {
|
|
id := id & "-GSUP";
|
|
var GsupOps ops := {
|
|
create_cb := refers(GSUP_Emulation.ExpectedCreateCallback)
|
|
};
|
|
|
|
vc_GSUP_IPA := IPA_Emulation_CT.create(id & "-IPA");
|
|
vc_GSUP := GSUP_Emulation_CT.create(id);
|
|
|
|
map(vc_GSUP_IPA:IPA_PORT, system:IPA_CODEC_PT);
|
|
connect(vc_GSUP:GSUP, vc_GSUP_IPA:IPA_GSUP_PORT);
|
|
/* we use this hack to get events like ASP_IPA_EVENT_UP */
|
|
connect(vc_GSUP_IPA:IPA_CTRL_PORT, self:GSUP_IPA_EVENT);
|
|
|
|
vc_GSUP.start(GSUP_Emulation.main(ops, id));
|
|
vc_GSUP_IPA.start(IPA_Emulation.main_server(mp_hlr_ip, mp_hlr_port));
|
|
|
|
/* wait for incoming connection to GSUP port before proceeding */
|
|
timer T := 10.0;
|
|
T.start;
|
|
alt {
|
|
[] GSUP_IPA_EVENT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) { }
|
|
[] T.timeout {
|
|
setverdict(fail, "No connection to GSUP Port");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
}
|
|
|
|
private function f_init_gtp(charstring id) runs on test_CT {
|
|
id := id & "-GTP";
|
|
|
|
var GtpEmulationCfg gtp_cfg := {
|
|
gtpc_bind_ip := mp_ggsn_ip,
|
|
gtpc_bind_port := GTP1C_PORT,
|
|
gtpu_bind_ip := mp_ggsn_ip,
|
|
gtpu_bind_port := GTP1U_PORT,
|
|
sgsn_role := false
|
|
};
|
|
|
|
vc_GTP := GTP_Emulation_CT.create(id);
|
|
vc_GTP.start(GTP_Emulation.main(gtp_cfg));
|
|
}
|
|
|
|
friend function f_init_vty() runs on test_CT {
|
|
map(self:SGSNVTY, system:SGSNVTY);
|
|
f_vty_set_prompts(SGSNVTY);
|
|
f_vty_transceive(SGSNVTY, "enable");
|
|
f_vty_transceive(SGSNVTY, "reset sgsn state");
|
|
f_vty_config(SGSNVTY, "sgsn", "auth-policy remote");
|
|
}
|
|
|
|
private function f_vty_enable_echo_interval(boolean enable) runs on test_CT {
|
|
if (enable) {
|
|
f_vty_config(SGSNVTY, "sgsn", "ggsn 0 echo-interval " & int2str(mp_echo_interval));
|
|
} else {
|
|
f_vty_config(SGSNVTY, "sgsn", "ggsn 0 no echo-interval");
|
|
}
|
|
}
|
|
|
|
|
|
/* mcc_mnc is 24.008 10.5.5.15 encoded. 262 42 */
|
|
function f_init(BcdMccMnc mcc_mnc := '262F42'H) runs on test_CT {
|
|
var integer i;
|
|
|
|
if (g_initialized == true) {
|
|
return;
|
|
}
|
|
g_initialized := true;
|
|
g_gb[0].cfg := {
|
|
nsei := 96,
|
|
sgsn_role := false,
|
|
bvc := {
|
|
{
|
|
bvci := 196,
|
|
cell_id := {
|
|
ra_id := {
|
|
lai := {
|
|
mcc_mnc := mcc_mnc,
|
|
lac := 13135
|
|
},
|
|
rac := 0
|
|
},
|
|
cell_id := 20960
|
|
},
|
|
depth := BSSGP_DECODE_DEPTH_L3,
|
|
create_cb := refers(BSSGP_Emulation.DefaultCreateCallback)
|
|
}
|
|
}
|
|
};
|
|
g_gb[1].cfg := {
|
|
nsei := 97,
|
|
sgsn_role := false,
|
|
bvc := {
|
|
{
|
|
bvci := 210,
|
|
cell_id := {
|
|
ra_id := {
|
|
lai := {
|
|
mcc_mnc := mcc_mnc,
|
|
lac := 13200
|
|
},
|
|
rac := 0
|
|
},
|
|
cell_id := 20961
|
|
},
|
|
depth := BSSGP_DECODE_DEPTH_L3,
|
|
create_cb := refers(BSSGP_Emulation.DefaultCreateCallback)
|
|
}
|
|
}
|
|
};
|
|
g_gb[2].cfg := { /* [2] configured to have same RAC as [1] */
|
|
nsei := 98,
|
|
sgsn_role := false,
|
|
bvc := {
|
|
{
|
|
bvci := 220,
|
|
cell_id := {
|
|
ra_id := {
|
|
lai := {
|
|
mcc_mnc := mcc_mnc,
|
|
lac := 13200
|
|
},
|
|
rac := 0
|
|
},
|
|
cell_id := 20962
|
|
},
|
|
depth := BSSGP_DECODE_DEPTH_L3,
|
|
create_cb := refers(BSSGP_Emulation.DefaultCreateCallback)
|
|
}
|
|
}
|
|
};
|
|
|
|
f_init_vty();
|
|
f_init_gb(g_gb[0], "SGSN_Test-Gb0", 0);
|
|
f_init_gb(g_gb[1], "SGSN_Test-Gb1", 1);
|
|
f_init_gb(g_gb[2], "SGSN_Test-Gb2", 2);
|
|
|
|
if (g_ranap_enable) {
|
|
for (i := 0; i < NUM_RNC; i := i+1) {
|
|
f_ran_adapter_init(g_ranap[i], mp_ranap_cfg[i], "SGSN_Test_" & int2str(i), RNC_RanOps);
|
|
f_ran_adapter_start(g_ranap[i]);
|
|
}
|
|
}
|
|
f_init_gsup("SGSN_Test");
|
|
f_init_gtp("SGSN_Test");
|
|
f_vty_enable_echo_interval(g_use_echo);
|
|
}
|
|
|
|
function f_cleanup() runs on test_CT {
|
|
var integer i;
|
|
if (g_ranap_enable) {
|
|
for (i := 0; i < NUM_RNC; i := i+1) {
|
|
f_ran_adapter_cleanup(g_ranap[i]);
|
|
}
|
|
}
|
|
self.stop;
|
|
}
|
|
|
|
private function RncUnitdataCallback(RANAP_PDU ranap)
|
|
runs on RAN_Emulation_CT return template RANAP_PDU {
|
|
var template RANAP_PDU resp := omit;
|
|
|
|
log ("RANAP_RncUnitDataCallback");
|
|
/* answer all RESET with RESET ACK */
|
|
if (match(ranap, tr_RANAP_Reset)) {
|
|
log("RANAP_RncUnitdataCallback: Responding to RESET with RESET-ACK");
|
|
var CN_DomainIndicator dom;
|
|
dom := ranap.initiatingMessage.value_.Reset.protocolIEs[1].value_.cN_DomainIndicator;
|
|
resp := ts_RANAP_ResetAck(dom);
|
|
}
|
|
return resp;
|
|
}
|
|
|
|
const RanOps RNC_RanOps := {
|
|
ranap_create_cb := refers(RAN_Emulation.RanapExpectedCreateCallback),
|
|
ranap_unitdata_cb := refers(RncUnitdataCallback),
|
|
ps_domain := true,
|
|
decode_dtap := true,
|
|
role_ms := true,
|
|
protocol := RAN_PROTOCOL_RANAP,
|
|
transport := RANAP_TRANSPORT_IuCS,
|
|
use_osmux := false,
|
|
sccp_addr_local := omit,
|
|
sccp_addr_peer := omit
|
|
};
|
|
|
|
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 gb, integer imsi_suffix,
|
|
float t_guard := 30.0)
|
|
runs on test_CT return BSSGP_ConnHdlr {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
var SGSN_ConnHdlrNetworkPars net_pars := {
|
|
expect_ptmsi := true,
|
|
expect_auth := true,
|
|
expect_ciph := false
|
|
};
|
|
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 := {
|
|
gb[0].cfg.bvc[0].cell_id,
|
|
gb[1].cfg.bvc[0].cell_id,
|
|
gb[2].cfg.bvc[0].cell_id
|
|
},
|
|
rnc_send_initial_ue := true,
|
|
vec := omit,
|
|
net := net_pars,
|
|
t_guard := t_guard,
|
|
sccp_addr_local := omit,
|
|
sccp_addr_peer := omit
|
|
};
|
|
|
|
if (g_ranap_enable) {
|
|
pars.sccp_addr_local := g_ranap[0].sccp_addr_own;
|
|
pars.sccp_addr_peer := g_ranap[0].sccp_addr_peer;
|
|
}
|
|
|
|
vc_conn := BSSGP_ConnHdlr.create(id);
|
|
|
|
connect(vc_conn:BSSGP[0], gb[0].vc_BSSGP_BVC[0]:BSSGP_SP);
|
|
connect(vc_conn:BSSGP_SIG[0], gb[0].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
|
|
connect(vc_conn:BSSGP_PROC[0], gb[0].vc_BSSGP_BVC[0]:BSSGP_PROC);
|
|
connect(vc_conn:BSSGP_GLOBAL[0], gb[0].vc_BSSGP:GLOBAL);
|
|
|
|
connect(vc_conn:BSSGP[1], gb[1].vc_BSSGP_BVC[0]:BSSGP_SP);
|
|
connect(vc_conn:BSSGP_SIG[1], gb[1].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
|
|
connect(vc_conn:BSSGP_PROC[1], gb[1].vc_BSSGP_BVC[0]:BSSGP_PROC);
|
|
connect(vc_conn:BSSGP_GLOBAL[1], gb[1].vc_BSSGP:GLOBAL);
|
|
|
|
connect(vc_conn:BSSGP[2], gb[2].vc_BSSGP_BVC[0]:BSSGP_SP);
|
|
connect(vc_conn:BSSGP_SIG[2], gb[2].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
|
|
connect(vc_conn:BSSGP_PROC[2], gb[2].vc_BSSGP_BVC[0]:BSSGP_PROC);
|
|
connect(vc_conn:BSSGP_GLOBAL[2], gb[2].vc_BSSGP:GLOBAL);
|
|
|
|
/* FIXME: support multiple RNCs */
|
|
if (g_ranap_enable) {
|
|
connect(vc_conn:BSSAP, g_ranap[0].vc_RAN:CLIENT);
|
|
connect(vc_conn:BSSAP_PROC, g_ranap[0].vc_RAN:PROC);
|
|
}
|
|
|
|
connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT);
|
|
connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC);
|
|
|
|
connect(vc_conn:GTP, vc_GTP:CLIENT);
|
|
connect(vc_conn:GTP_PROC, vc_GTP:CLIENT_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 {
|
|
/* do some common stuff like setting up g_pars */
|
|
g_pars := pars;
|
|
|
|
llc := f_llc_create(false);
|
|
|
|
/* register with BSSGP core */
|
|
f_bssgp_client_register(g_pars.imsi, g_pars.tlli);
|
|
/* tell GSUP dispatcher to send this IMSI to us */
|
|
f_create_gsup_expect(hex2str(g_pars.imsi));
|
|
/* tell GTP dispatcher to send this IMSI to us */
|
|
f_gtp_register_imsi(g_pars.imsi);
|
|
|
|
g_Tguard.start(pars.t_guard);
|
|
activate(as_Tguard());
|
|
|
|
/* call the user-supplied test case function */
|
|
fn.apply(id);
|
|
f_bssgp_client_unregister(g_pars.imsi);
|
|
}
|
|
|
|
/* 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
|
|
*/
|
|
|
|
testcase TC_wait_ns_up() runs on test_CT {
|
|
f_init();
|
|
f_sleep(20.0);
|
|
f_cleanup();
|
|
}
|
|
|
|
friend function is_gb(integer ran_index) return boolean {
|
|
return ran_index < NUM_GB;
|
|
}
|
|
friend function is_iu(integer ran_index) return boolean {
|
|
return ran_index >= NUM_GB;
|
|
}
|
|
|
|
function f_send_llc(template (value) PDU_LLC llc_pdu, integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
var octetstring llc_enc := enc_PDU_LLC(valueof(llc_pdu));
|
|
BSSGP[ran_index].send(ts_BSSGP_UL_UD(g_pars.tlli, g_pars.bssgp_cell_id[ran_index], llc_enc));
|
|
}
|
|
|
|
private function f_send_l3_gmm_llc(template (value) PDU_L3_MS_SGSN l3_mo, integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
var octetstring l3_enc := enc_PDU_L3_MS_SGSN(valueof(l3_mo));
|
|
var BIT4 sapi := f_llc_sapi_by_l3_mo(valueof(l3_mo));
|
|
var integer n_u := f_llc_get_n_u_tx(llc[bit2int(sapi)]);
|
|
f_send_llc(ts_LLC_UI(l3_enc, sapi, '0'B, n_u), ran_index);
|
|
}
|
|
|
|
/* trigger sending of a RANAP InitialUE and wait for SCCP connection confirmation */
|
|
function f_send_l3_initial_ue(template (value) PDU_L3_MS_SGSN l3_mo) runs on BSSGP_ConnHdlr {
|
|
log("Sending InitialUE: ", l3_mo);
|
|
var octetstring l3_enc := enc_PDU_L3_MS_SGSN(valueof(l3_mo));
|
|
var RANAP_PDU ranap;
|
|
var LAI lai := {
|
|
pLMNidentity := '62F224'O,
|
|
lAC := '1234'O,
|
|
iE_Extensions := omit
|
|
};
|
|
var SAI sai := {
|
|
pLMNidentity := lai.pLMNidentity,
|
|
lAC := lai.lAC,
|
|
sAC := '0000'O, /* FIXME */
|
|
iE_Extensions := omit
|
|
};
|
|
var IuSignallingConnectionIdentifier sigc_id := int2bit(23, 24); /* FIXME */
|
|
var GlobalRNC_ID grnc_id := {
|
|
pLMNidentity := lai.pLMNidentity,
|
|
rNC_ID := 2342 /* FIXME */
|
|
};
|
|
|
|
ranap := valueof(ts_RANAP_initialUE_CS(lai, sai, l3_enc, sigc_id, grnc_id));
|
|
BSSAP.send(ts_RANAP_Conn_Req(g_pars.sccp_addr_peer, g_pars.sccp_addr_local, ranap));
|
|
alt {
|
|
[] BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_CONF_IND) {}
|
|
[] BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
|
|
setverdict(fail, "DISC.ind from SCCP");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* send a L3 (GMM/SM) message over whatever is the appropriate lower-layer bearer */
|
|
function f_send_l3(template (value) PDU_L3_MS_SGSN l3_mo, integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
if (is_iu(ran_index)) {
|
|
if (g_pars.rnc_send_initial_ue) {
|
|
g_pars.rnc_send_initial_ue := false;
|
|
f_send_l3_initial_ue(l3_mo);
|
|
} else {
|
|
BSSAP.send(ts_PDU_DTAP_PS_MO(l3_mo));
|
|
}
|
|
} else {
|
|
f_send_l3_gmm_llc(l3_mo, ran_index);
|
|
}
|
|
}
|
|
|
|
altstep as_mm_identity(integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
var MobileIdentityLV mi;
|
|
[is_gb(ran_index)] BSSGP[ran_index].receive(tr_GMM_ID_REQ('001'B)) {
|
|
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
|
|
f_send_l3(ts_GMM_ID_RESP(mi), ran_index);
|
|
repeat;
|
|
}
|
|
[is_iu(ran_index)] BSSAP.receive(tr_PDU_DTAP_PS_MT(tr_GMM_ID_REQ('001'B))) {
|
|
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
|
|
f_send_l3(ts_GMM_ID_RESP(mi), ran_index);
|
|
repeat;
|
|
}
|
|
[is_gb(ran_index)] BSSGP[ran_index].receive(tr_GMM_ID_REQ('010'B)) {
|
|
mi := valueof(ts_MI_IMEI_LV(g_pars.imei));
|
|
f_send_l3(ts_GMM_ID_RESP(mi), ran_index);
|
|
repeat;
|
|
}
|
|
[is_iu(ran_index)] BSSAP.receive(tr_PDU_DTAP_PS_MT(tr_GMM_ID_REQ('010'B))) {
|
|
mi := valueof(ts_MI_IMEI_LV(g_pars.imei));
|
|
f_send_l3(ts_GMM_ID_RESP(mi), ran_index);
|
|
repeat;
|
|
}
|
|
}
|
|
|
|
/* receive a L3 (GMM/SM) message over whatever is the appropriate lower-layer bearer */
|
|
function f_receive_l3(template PDU_L3_SGSN_MS rx_tpl := ?, integer ran_index := 0)
|
|
runs on BSSGP_ConnHdlr return PDU_L3_SGSN_MS {
|
|
var PDU_DTAP_PS_MT mt;
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
alt {
|
|
[is_gb(ran_index)] BSSGP[ran_index].receive(rx_tpl) -> value l3_mt { }
|
|
[is_iu(ran_index)] BSSAP.receive(tr_PDU_DTAP_PS_MT(rx_tpl)) -> value mt {
|
|
l3_mt := mt.dtap;
|
|
}
|
|
}
|
|
return l3_mt;
|
|
}
|
|
|
|
/* perform GMM authentication (if expected).
|
|
* Note, for umts_aka_challenge to work, the revisionLevelIndicatior needs to
|
|
* be 1 to mark R99 capability, in the GMM Attach Request, see f_gmm_attach(). */
|
|
function f_gmm_auth (boolean umts_aka_challenge := false, boolean force_gsm_sres := false, integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
var PDU_L3_MS_SGSN l3_mo;
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
var default di := activate(as_mm_identity(ran_index));
|
|
if (g_pars.net.expect_auth) {
|
|
var GSUP_IE auth_tuple;
|
|
var template AuthenticationParameterAUTNTLV autn;
|
|
|
|
if (umts_aka_challenge) {
|
|
g_pars.vec := f_gen_auth_vec_3g();
|
|
autn := {
|
|
elementIdentifier := '28'O,
|
|
lengthIndicator := lengthof(g_pars.vec.autn),
|
|
autnValue := g_pars.vec.autn
|
|
};
|
|
|
|
auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G3G(g_pars.vec.rand,
|
|
g_pars.vec.sres,
|
|
g_pars.vec.kc,
|
|
g_pars.vec.ik,
|
|
g_pars.vec.ck,
|
|
g_pars.vec.autn,
|
|
g_pars.vec.res));
|
|
log("GSUP sends 2G and 3G auth tuples", auth_tuple);
|
|
} else {
|
|
g_pars.vec := f_gen_auth_vec_2g();
|
|
autn := omit;
|
|
auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(g_pars.vec.rand,
|
|
g_pars.vec.sres,
|
|
g_pars.vec.kc));
|
|
log("GSUP sends only 2G auth tuple", auth_tuple);
|
|
}
|
|
|
|
GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi));
|
|
GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple));
|
|
|
|
var template PDU_L3_SGSN_MS auth_ciph_req := tr_GMM_AUTH_REQ(g_pars.vec.rand);
|
|
auth_ciph_req.msgs.gprs_mm.authenticationAndCipheringRequest.authenticationParameterAUTN := autn;
|
|
l3_mt := f_receive_l3(auth_ciph_req, ran_index);
|
|
var BIT4 ac_ref := l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.acReferenceNumber.valueField;
|
|
var template PDU_L3_MS_SGSN auth_ciph_resp := ts_GMM_AUTH_RESP_2G(ac_ref, g_pars.vec.sres);
|
|
|
|
if (umts_aka_challenge and not force_gsm_sres) {
|
|
/* set UMTS response instead */
|
|
auth_ciph_resp.msgs.gprs_mm.authenticationAndCipheringResponse.authenticationParResp := {
|
|
valueField := substr(g_pars.vec.res, 0, 4)
|
|
};
|
|
auth_ciph_resp.msgs.gprs_mm.authenticationAndCipheringResponse.authenticationRespParExt := {
|
|
elementIdentifier := '21'O,
|
|
lengthIndicator := lengthof(g_pars.vec.res) - 4,
|
|
valueField := substr(g_pars.vec.res, 4, lengthof(g_pars.vec.res) - 4)
|
|
};
|
|
}
|
|
|
|
l3_mo := valueof(auth_ciph_resp);
|
|
if (ispresent(l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.imeisvRequest) and
|
|
l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.imeisvRequest.valueField == '001'B) {
|
|
l3_mo.msgs.gprs_mm.authenticationAndCipheringResponse.imeisv :=
|
|
valueof(ts_MI_IMEISV_TLV(g_pars.imei & '0'H));
|
|
}
|
|
f_send_l3(l3_mo, ran_index);
|
|
|
|
/* Security Mode Command + Complete on Iu case */
|
|
if (is_iu(ran_index)) {
|
|
BSSAP.receive(tr_RANAP_SecurityModeCmd(uia_algs := ?, uia_key := oct2bit(g_pars.vec.ik),
|
|
key_sts := ?)) {
|
|
var IntegrityProtectionAlgorithm uia_chosen := 0; /* 0 = standard_UMTS_integrity_algorithm_UIA1 */
|
|
BSSAP.send(ts_RANAP_SecurityModeComplete(uia_chosen));
|
|
BSSAP.receive(tr_RANAP_CommonId(imsi_hex2oct(g_pars.imsi)))
|
|
}
|
|
}
|
|
} else {
|
|
/* wait for identity procedure */
|
|
f_sleep(1.0);
|
|
}
|
|
|
|
deactivate(di);
|
|
}
|
|
|
|
function f_upd_ptmsi_and_tlli(OCT4 p_tmsi, integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
g_pars.p_tmsi := p_tmsi;
|
|
/* update TLLI */
|
|
g_pars.tlli_old := g_pars.tlli;
|
|
g_pars.tlli := g_pars.p_tmsi or4b 'c0000000'O;
|
|
if (is_gb(ran_index)) {
|
|
f_bssgp_client_llgmm_assign(g_pars.tlli_old, g_pars.tlli, BSSGP_PROC[ran_index]);
|
|
}
|
|
}
|
|
|
|
function f_process_attach_accept(PDU_GMM_AttachAccept aa, integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
/* mandatory IE */
|
|
var hexstring aa_plmn := f_RAI_to_plmn_hexstr(aa.routingAreaIdentification);
|
|
/* we cannot use ran_index here, as it would overflow the cell_id object, since ran_idx > NUM_GB
|
|
* indicates an Iu RAN connection. All cells are expected to run the same MCC/MNC anyway... */
|
|
if (not (g_pars.bssgp_cell_id[0].ra_id.lai.mcc_mnc == aa_plmn)) {
|
|
setverdict(fail, "mismatching PLMN in Attach Accept: " & hex2str(aa_plmn)
|
|
& "; expected " & hex2str(g_pars.bssgp_cell_id[ran_index].ra_id.lai.mcc_mnc));
|
|
mtc.stop;
|
|
}
|
|
g_pars.ra := aa.routingAreaIdentification;
|
|
if (ispresent(aa.allocatedPTMSI)) {
|
|
if (not g_pars.net.expect_ptmsi) {
|
|
setverdict(fail, "unexpected P-TMSI allocation");
|
|
mtc.stop;
|
|
}
|
|
f_upd_ptmsi_and_tlli(aa.allocatedPTMSI.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi.octets,
|
|
ran_index);
|
|
}
|
|
if (ispresent(aa.msIdentity)) {
|
|
setverdict(fail, "unexpected TMSI allocation in non-combined attach");
|
|
mtc.stop;
|
|
}
|
|
/* P-TMSI.sig */
|
|
if (ispresent(aa.ptmsiSignature)) {
|
|
g_pars.p_tmsi_sig := aa.ptmsiSignature.valueField;
|
|
}
|
|
/* updateTimer */
|
|
// aa.readyTimer
|
|
/* T3302, T3319, T3323, T3312_ext, T3324 */
|
|
}
|
|
|
|
function f_process_rau_accept(PDU_GMM_RoutingAreaUpdateAccept ra, integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
/* mandatory IE */
|
|
g_pars.ra := ra.routingAreaId;
|
|
if (ispresent(ra.allocatedPTMSI)) {
|
|
if (not g_pars.net.expect_ptmsi) {
|
|
setverdict(fail, "unexpected P-TMSI allocation");
|
|
mtc.stop;
|
|
}
|
|
f_upd_ptmsi_and_tlli(ra.allocatedPTMSI.mobileIdentityLV.mobileIdentityV.oddEvenInd_identity.tmsi_ptmsi.octets,
|
|
ran_index);
|
|
}
|
|
if (ispresent(ra.msIdentity)) {
|
|
setverdict(fail, "unexpected TMSI allocation in non-combined attach");
|
|
mtc.stop;
|
|
}
|
|
/* P-TMSI.sig */
|
|
if (ispresent(ra.ptmsiSignature)) {
|
|
g_pars.p_tmsi_sig := ra.ptmsiSignature.valueField;
|
|
}
|
|
/* updateTimer */
|
|
// aa.readyTimer
|
|
/* T3302, T3319, T3323, T3312_ext, T3324 */
|
|
}
|
|
|
|
|
|
function f_random_RAI(HEX0_3n mcc := '262'H, HEX0_3n mnc := '42'H) return RoutingAreaIdentificationV {
|
|
return f_RAI(mcc, mnc, f_rnd_octstring(2), f_rnd_octstring(1));
|
|
}
|
|
|
|
/* return a MobileIdentityLV: P-TMSI if we have one, IMSI otherwise */
|
|
private function f_mi_get_lv() runs on BSSGP_ConnHdlr return MobileIdentityLV {
|
|
if (ispresent(g_pars.p_tmsi)) {
|
|
return valueof(ts_MI_TMSI_LV(g_pars.p_tmsi));
|
|
} else {
|
|
return valueof(ts_MI_IMSI_LV(g_pars.imsi));
|
|
}
|
|
}
|
|
|
|
private function f_gmm_gsup_lu_isd() runs on BSSGP_ConnHdlr {
|
|
var GSUP_PDU gsup;
|
|
/* Expect MSC to perform LU with HLR */
|
|
GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi));
|
|
gsup := valueof(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn));
|
|
gsup.ies := gsup.ies & { valueof(ts_GSUP_IE_PdpInfo(char2oct("*"), '0121'O, ''O)) };
|
|
GSUP.send(gsup);
|
|
GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi));
|
|
GSUP.send(ts_GSUP_UL_RES(g_pars.imsi));
|
|
}
|
|
|
|
friend function f_gmm_attach(boolean umts_aka_challenge, boolean force_gsm_sres, integer ran_index := 0,
|
|
template (omit) RoutingAreaIdentificationV old_ra := omit) runs on BSSGP_ConnHdlr {
|
|
var RoutingAreaIdentificationV old_ra_val;
|
|
var template PDU_L3_MS_SGSN attach_req;
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
|
|
if (istemplatekind(old_ra, "omit")) {
|
|
old_ra_val := f_random_RAI();
|
|
} else {
|
|
old_ra_val := valueof(old_ra);
|
|
}
|
|
|
|
attach_req := ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra_val, false, false, omit, omit);
|
|
/* indicate R99 capability of the MS to enable UMTS AKA in presence of
|
|
* 3G auth vectors */
|
|
attach_req.msgs.gprs_mm.attachRequest.msNetworkCapability.msNetworkCapabilityV.revisionLevelIndicatior := '1'B;
|
|
/* The thing is, if the solSACapability is 'omit', then the
|
|
* revisionLevelIndicatior is at the wrong place! */
|
|
attach_req.msgs.gprs_mm.attachRequest.msNetworkCapability.msNetworkCapabilityV.solSACapability := '0'B;
|
|
|
|
f_send_l3(attach_req, ran_index);
|
|
f_gmm_auth(umts_aka_challenge, force_gsm_sres, ran_index);
|
|
/* Expect SGSN to perform LU with HLR */
|
|
f_gmm_gsup_lu_isd();
|
|
|
|
l3_mt := f_receive_l3(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?), ran_index);
|
|
f_process_attach_accept(l3_mt.msgs.gprs_mm.attachAccept, ran_index);
|
|
|
|
/* FIXME: Extract P-TMSI, if any. Only send Complete if necessary */
|
|
f_send_l3(ts_GMM_ATTACH_COMPL, ran_index);
|
|
|
|
/* IuPS case: Expect Iu Release */
|
|
if (is_iu(ran_index)) {
|
|
as_iu_release_compl_disc();
|
|
}
|
|
|
|
/* Race condition
|
|
* It has shown, that GMM_ATTACH_COMPL might take some time to arrive at the SGSN through the layers.
|
|
* In TC hlr_location_cancel_request_update, the GMM_ATTACH_COMPL came 2ms too late, so that the Location Cancel Request
|
|
* arrived before it. This results in a test case failure.
|
|
* Delay execution by 50 ms
|
|
*/
|
|
f_sleep(0.05);
|
|
}
|
|
|
|
friend function f_bssgp_suspend(integer ran_idx := 0) runs on BSSGP_ConnHdlr return OCT1 {
|
|
timer T := 5.0;
|
|
var PDU_BSSGP rx_pdu;
|
|
BSSGP_GLOBAL[ran_idx].send(ts_BSSGP_SUSPEND(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id));
|
|
T.start;
|
|
alt {
|
|
[] BSSGP_GLOBAL[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;
|
|
}
|
|
[] BSSGP_GLOBAL[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;
|
|
BSSGP_GLOBAL[ran_idx].send(ts_BSSGP_RESUME(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id, susp_ref));
|
|
T.start;
|
|
alt {
|
|
[] BSSGP_GLOBAL[ran_idx].receive(tr_BSSGP_RESUME_ACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id));
|
|
[] BSSGP_GLOBAL[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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private function f_TC_attach(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_gmm_attach(false, false);
|
|
setverdict(pass);
|
|
}
|
|
|
|
testcase TC_attach() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach), testcasename(), g_gb, 1);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
testcase TC_attach_mnc3() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init('023042'H);
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach), testcasename(), g_gb, 1001);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_umts_aka_umts_res(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_gmm_attach(true, false);
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_attach_umts_aka_umts_res() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_umts_aka_umts_res), testcasename(), g_gb, 1002);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_umts_aka_gsm_sres(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_gmm_attach(true, true);
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_attach_umts_aka_gsm_sres() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_umts_aka_gsm_sres), testcasename(), g_gb, 1003);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* MS never responds to ID REQ, expect ATTACH REJECT */
|
|
private function f_TC_attach_auth_id_timeout(charstring id) runs on BSSGP_ConnHdlr {
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, false, false, omit, omit));
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_ID_REQ(?)) {
|
|
/* don't send ID Response */
|
|
repeat;
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT('09'O)) {
|
|
setverdict(pass);
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?)) {
|
|
setverdict(fail, "Wrong Attach Reject Cause");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
}
|
|
testcase TC_attach_auth_id_timeout() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_auth_id_timeout), testcasename(), g_gb, 2, 40.0);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* HLR never responds to SAI REQ, expect ATTACH REJECT */
|
|
private function f_TC_attach_auth_sai_timeout(charstring id) runs on BSSGP_ConnHdlr {
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, false, false, omit, omit));
|
|
alt {
|
|
[] as_mm_identity();
|
|
[] GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); { }
|
|
}
|
|
/* don't send SAI-response from HLR */
|
|
BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?));
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_attach_auth_sai_timeout() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_auth_sai_timeout), testcasename(), g_gb, 3);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* HLR rejects SAI, expect ATTACH REJECT */
|
|
private function f_TC_attach_auth_sai_reject(charstring id) runs on BSSGP_ConnHdlr {
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, false, false, omit, omit));
|
|
alt {
|
|
[] as_mm_identity();
|
|
[] GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi)); {
|
|
GSUP.send(ts_GSUP_SAI_ERR(g_pars.imsi, 23));
|
|
}
|
|
}
|
|
BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?));
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_attach_auth_sai_reject() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_auth_sai_reject), testcasename(), g_gb, 4);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* HLR never responds to UL REQ, expect ATTACH REJECT */
|
|
private function f_TC_attach_gsup_lu_timeout(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, false, false, omit, omit));
|
|
f_gmm_auth();
|
|
/* Expect MSC to perform LU with HLR */
|
|
GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi));
|
|
/* Never follow-up with ISD_REQ or UL_RES */
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?)) {
|
|
setverdict(pass);
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?)) -> value l3_mt {
|
|
f_process_attach_accept(l3_mt.msgs.gprs_mm.attachAccept);
|
|
setverdict(fail);
|
|
mtc.stop;
|
|
}
|
|
}
|
|
}
|
|
testcase TC_attach_gsup_lu_timeout() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_gsup_lu_timeout), testcasename(), g_gb, 5);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* HLR rejects UL REQ, expect ATTACH REJECT */
|
|
private function f_TC_attach_gsup_lu_reject(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, false, false, omit, omit));
|
|
f_gmm_auth();
|
|
/* Expect MSC to perform LU with HLR */
|
|
GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)) {
|
|
GSUP.send(ts_GSUP_UL_ERR(g_pars.imsi, 0));
|
|
}
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?)) {
|
|
setverdict(pass);
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?)) -> value l3_mt {
|
|
f_process_attach_accept(l3_mt.msgs.gprs_mm.attachAccept);
|
|
setverdict(fail);
|
|
mtc.stop;
|
|
}
|
|
}
|
|
}
|
|
testcase TC_attach_gsup_lu_reject() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_gsup_lu_reject), testcasename(), g_gb, 6);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
|
|
/* Attempt of combined GPRS + IMSI attach: network should ACK only GPRS attach */
|
|
private function f_TC_attach_combined(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, true, false, omit, omit));
|
|
f_gmm_auth();
|
|
/* Expect MSC to perform LU with HLR */
|
|
f_gmm_gsup_lu_isd();
|
|
|
|
BSSGP[0].receive(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?)) -> value l3_mt {
|
|
f_process_attach_accept(l3_mt.msgs.gprs_mm.attachAccept);
|
|
}
|
|
f_send_l3(ts_GMM_ATTACH_COMPL);
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_attach_combined() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_combined), testcasename(), g_gb, 7);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Attempt of GPRS ATTACH in 'accept all' mode */
|
|
private function f_TC_attach_accept_all(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
|
|
g_pars.net.expect_auth := false;
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, false, false, omit, omit));
|
|
f_gmm_auth();
|
|
BSSGP[0].receive(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?)) -> value l3_mt {
|
|
f_process_attach_accept(l3_mt.msgs.gprs_mm.attachAccept);
|
|
}
|
|
f_send_l3(ts_GMM_ATTACH_COMPL);
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_attach_accept_all() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
f_vty_config(SGSNVTY, "sgsn", "auth-policy accept-all");
|
|
vc_conn := f_start_handler(refers(f_TC_attach_accept_all), testcasename(), g_gb, 8);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Attempt of GPRS ATTACH in 'accept all' mode */
|
|
private function f_TC_attach_closed_foreign(charstring id) runs on BSSGP_ConnHdlr {
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
|
|
/* Simulate a foreign IMSI */
|
|
g_pars.imsi := '001010123456789'H;
|
|
f_bssgp_client_register(g_pars.imsi, g_pars.tlli);
|
|
|
|
g_pars.net.expect_auth := false;
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, false, false, omit, omit));
|
|
alt {
|
|
[] as_mm_identity();
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT('07'O)) {
|
|
setverdict(pass);
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?)) {
|
|
setverdict(pass);
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_ACCEPT(*, *, *)) {
|
|
setverdict(fail);
|
|
mtc.stop;
|
|
}
|
|
}
|
|
}
|
|
testcase TC_attach_closed() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
f_vty_config(SGSNVTY, "sgsn", "auth-policy closed");
|
|
/* test with foreign IMSI: Must Reject */
|
|
vc_conn := f_start_handler(refers(f_TC_attach_closed_foreign), testcasename(), g_gb, 9);
|
|
vc_conn.done;
|
|
/* test with home IMSI: Must Accept */
|
|
vc_conn := f_start_handler(refers(f_TC_attach_accept_all), testcasename(), g_gb, 10);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Routing Area Update from Unknown TLLI -> REJECT */
|
|
private function f_TC_rau_unknown(charstring id) runs on BSSGP_ConnHdlr {
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
|
|
f_send_l3(ts_GMM_RAU_REQ(f_mi_get_lv(), GPRS_UPD_T_RA, old_ra, false, omit, omit));
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_RAU_REJECT('0a'O)) { /* gmm cause: implicitly detached */
|
|
setverdict(pass);
|
|
}
|
|
/* FIXME: Expect XID RESET? */
|
|
[] BSSGP[0].receive { repeat; }
|
|
}
|
|
}
|
|
testcase TC_rau_unknown() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_rau_unknown), testcasename(), g_gb, 11);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_rau(charstring id) runs on BSSGP_ConnHdlr {
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
|
|
f_routing_area_update(g_pars.ra);
|
|
|
|
}
|
|
testcase TC_attach_rau() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_rau), testcasename(), g_gb, 12);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* general GPRS DETACH helper */
|
|
function f_detach_mo(BIT3 detach_type, boolean power_off, boolean expect_purge, integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
timer T := 5.0;
|
|
f_send_l3(ts_GMM_DET_REQ_MO(detach_type, power_off), ran_index);
|
|
if (expect_purge) {
|
|
GSUP.receive(tr_GSUP_PURGE_MS_REQ(g_pars.imsi, OSMO_GSUP_CN_DOMAIN_PS));
|
|
GSUP.send(ts_GSUP_PURGE_MS_RES(g_pars.imsi));
|
|
}
|
|
T.start;
|
|
alt {
|
|
[not expect_purge] GSUP.receive(tr_GSUP_PURGE_MS_REQ(?)) {
|
|
setverdict(fail, "Unexpected GSUP PURGE MS for unregistered TLLI");
|
|
mtc.stop;
|
|
}
|
|
[power_off] BSSGP[ran_index].receive(tr_GMM_DET_ACCEPT_MT) -> value l3_mt {
|
|
g_pars.ra := omit;
|
|
setverdict(fail, "Unexpected DETACH ACCEPT in power-off DETACH");
|
|
mtc.stop;
|
|
/* TODO: check if any PDP contexts are deactivated on network side? */
|
|
}
|
|
[power_off] T.timeout {
|
|
setverdict(pass);
|
|
}
|
|
[not power_off] BSSGP[ran_index].receive(tr_GMM_DET_ACCEPT_MT) -> value l3_mt {
|
|
g_pars.ra := omit;
|
|
setverdict(pass);
|
|
/* TODO: check if any PDP contexts are deactivated on network side? */
|
|
}
|
|
[] BSSGP[ran_index].receive(PDU_L3_SGSN_MS:?) -> value l3_mt {
|
|
if (power_off) {
|
|
setverdict(fail, "Unexpected Layer 3 package received in power-off DETACH");
|
|
} else {
|
|
setverdict(fail, "Unexpected Layer 3 package received in normal DETACH");
|
|
}
|
|
mtc.stop;
|
|
}
|
|
[] BSSGP[ran_index].receive { repeat; }
|
|
}
|
|
}
|
|
|
|
/* IMSI DETACH (non-power-off) for unknown TLLI */
|
|
private function f_TC_detach_unknown_nopoweroff(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_detach_mo(c_GMM_DTT_MO_GPRS, false, false);
|
|
}
|
|
testcase TC_detach_unknown_nopoweroff() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_detach_unknown_nopoweroff), testcasename(), g_gb, 13);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* IMSI DETACH (power-off) for unknown TLLI */
|
|
private function f_TC_detach_unknown_poweroff(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_detach_mo(c_GMM_DTT_MO_GPRS, true, false);
|
|
}
|
|
testcase TC_detach_unknown_poweroff() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_detach_unknown_poweroff), testcasename(), g_gb, 14);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* IMSI DETACH (non-power-off) for known TLLI */
|
|
private function f_TC_detach_nopoweroff(charstring id) runs on BSSGP_ConnHdlr {
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
|
|
f_detach_mo(c_GMM_DTT_MO_GPRS, false, true);
|
|
}
|
|
testcase TC_detach_nopoweroff() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_detach_nopoweroff), testcasename(), g_gb, 15);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* IMSI DETACH (power-off) for known TLLI */
|
|
private function f_TC_detach_poweroff(charstring id) runs on BSSGP_ConnHdlr {
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
|
|
f_detach_mo(c_GMM_DTT_MO_GPRS, true, true);
|
|
}
|
|
testcase TC_detach_poweroff() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_detach_poweroff), testcasename(), g_gb, 16);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
type record PdpActPars {
|
|
BIT3 tid, /* L3 Transaction ID */
|
|
BIT4 nsapi, /* SNDCP NSAPI */
|
|
BIT4 sapi, /* LLC SAPI */
|
|
QoSV qos, /* QoS parameters */
|
|
PDPAddressV addr, /* IP address */
|
|
octetstring apn optional, /* APN name */
|
|
ProtocolConfigOptionsV pco optional, /* protoco config opts */
|
|
OCT1 exp_rej_cause optional, /* expected SM reject cause */
|
|
OCT1 gtp_resp_cause, /* GTP response cause */
|
|
OCT4 chg_id, /* GTP Charging Identifier */
|
|
|
|
OCT4 ggsn_tei_c, /* GGSN TEI Control*/
|
|
OCT4 ggsn_tei_u, /* GGSN TEI User */
|
|
octetstring ggsn_ip_c, /* GGSN IP Control */
|
|
octetstring ggsn_ip_u, /* GGSN IP User */
|
|
OCT1 ggsn_restart_ctr, /* GGSN Restart Counter */
|
|
|
|
OCT4 sgsn_tei_c optional, /* SGSN TEI Control */
|
|
OCT4 sgsn_tei_u optional, /* SGSN TEI User */
|
|
octetstring sgsn_ip_c optional, /* SGSN IP Control */
|
|
octetstring sgsn_ip_u optional /* SGSN IP USer */
|
|
};
|
|
|
|
|
|
private function f_process_gtp_ctx_act_req(inout PdpActPars apars, PDU_GTPC gtpc) runs on BSSGP_ConnHdlr {
|
|
var GTPC_PDUs gtpc_rx := gtpc.gtpc_pdu;
|
|
apars.sgsn_tei_c := gtpc_rx.createPDPContextRequest.teidControlPlane.teidControlPlane;
|
|
apars.sgsn_tei_u := gtpc_rx.createPDPContextRequest.teidDataI.teidDataI;
|
|
apars.sgsn_ip_c := gtpc_rx.createPDPContextRequest.sgsn_addr_signalling.addressf;
|
|
apars.sgsn_ip_u := gtpc_rx.createPDPContextRequest.sgsn_addr_traffic.addressf;
|
|
f_gtp_register_teid(apars.ggsn_tei_c);
|
|
f_gtp_register_teid(apars.ggsn_tei_u);
|
|
}
|
|
|
|
function f_pdp_ctx_act(inout PdpActPars apars, boolean send_recovery := false, integer ran_index := 0)
|
|
runs on BSSGP_ConnHdlr {
|
|
var boolean exp_rej := ispresent(apars.exp_rej_cause);
|
|
var Gtp1cUnitdata g_ud;
|
|
var template Recovery_gtpc recovery := omit;
|
|
|
|
if (send_recovery) {
|
|
recovery := ts_Recovery(apars.ggsn_restart_ctr);
|
|
}
|
|
|
|
f_send_l3(ts_SM_ACT_PDP_REQ(apars.tid, apars.nsapi, apars.sapi, apars.qos, apars.addr,
|
|
apars.apn, apars.pco), ran_index);
|
|
GTP.receive(tr_GTPC_MsgType(?, createPDPContextRequest, ?)) -> value g_ud {
|
|
f_process_gtp_ctx_act_req(apars, g_ud.gtpc);
|
|
var integer seq_nr := oct2int(g_ud.gtpc.opt_part.sequenceNumber);
|
|
GTP.send(ts_GTPC_CreatePdpResp(g_ud.peer, seq_nr,
|
|
apars.sgsn_tei_c, apars.gtp_resp_cause,
|
|
apars.ggsn_tei_c, apars.ggsn_tei_u,
|
|
apars.nsapi,
|
|
apars.ggsn_ip_c, apars.ggsn_ip_u, apars.chg_id,
|
|
omit, recovery));
|
|
}
|
|
alt {
|
|
[exp_rej] BSSGP[ran_index].receive(tr_SM_ACT_PDP_REJ(apars.tid, apars.exp_rej_cause)) {
|
|
setverdict(pass);
|
|
}
|
|
[exp_rej] BSSGP[ran_index].receive(tr_SM_ACT_PDP_ACCEPT) {
|
|
setverdict(fail, "Unexpected PDP CTX ACT ACC");
|
|
mtc.stop;
|
|
}
|
|
[not exp_rej] BSSGP[ran_index].receive(tr_SM_ACT_PDP_REJ(apars.tid, ?)) {
|
|
setverdict(fail, "Unexpected PDP CTX ACT FAIL");
|
|
mtc.stop;
|
|
}
|
|
[not exp_rej] BSSGP[ran_index].receive(tr_SM_ACT_PDP_REJ(apars.tid, ?)) {
|
|
setverdict(fail, "Unexpected PDP CTX ACT FAIL");
|
|
mtc.stop;
|
|
}
|
|
[not exp_rej] BSSGP[ran_index].receive(tr_SM_ACT_PDP_ACCEPT(apars.tid, apars.sapi)) {
|
|
setverdict(pass);
|
|
}
|
|
[] as_xid(apars, ran_index);
|
|
}
|
|
}
|
|
|
|
function f_pdp_ctx_deact_mo(inout PdpActPars apars, OCT1 cause, integer ran_index := 0)
|
|
runs on BSSGP_ConnHdlr {
|
|
var boolean exp_rej := ispresent(apars.exp_rej_cause);
|
|
var Gtp1cUnitdata g_ud;
|
|
|
|
f_send_l3(ts_SM_DEACT_PDP_REQ_MO(apars.tid, cause, false, omit), ran_index);
|
|
GTP.receive(tr_GTPC_MsgType(?, deletePDPContextRequest, apars.ggsn_tei_c)) -> value g_ud {
|
|
var integer seq_nr := oct2int(g_ud.gtpc.opt_part.sequenceNumber);
|
|
BSSGP[ran_index].clear;
|
|
GTP.send(ts_GTPC_DeletePdpResp(g_ud.peer, seq_nr, apars.sgsn_tei_c, '7F'O));
|
|
}
|
|
alt {
|
|
[] BSSGP[ran_index].receive(tr_SM_DEACT_PDP_ACCEPT_MT(apars.tid)) {
|
|
setverdict(pass);
|
|
}
|
|
[] as_xid(apars, ran_index);
|
|
}
|
|
}
|
|
|
|
function f_pdp_ctx_deact_mt(inout PdpActPars apars, boolean error_ind := false, integer ran_index := 0)
|
|
runs on BSSGP_ConnHdlr {
|
|
var Gtp1cUnitdata g_ud;
|
|
var integer seq_nr := 23;
|
|
var GtpPeer peer := valueof(ts_GtpPeerC(apars.sgsn_ip_c));
|
|
|
|
BSSGP[ran_index].clear;
|
|
if (error_ind) {
|
|
GTP.send(ts_GTPU_ErrorIndication(peer, 0 /* seq */, apars.ggsn_tei_u, apars.ggsn_ip_u));
|
|
} else {
|
|
GTP.send(ts_GTPC_DeletePDP(peer, seq_nr, apars.sgsn_tei_c, apars.nsapi, '1'B));
|
|
}
|
|
|
|
timer T := 5.0;
|
|
T.start;
|
|
|
|
alt {
|
|
[] BSSGP[ran_index].receive(tr_SM_DEACT_PDP_REQ_MT(apars.tid, ?, true)) {
|
|
f_send_l3(ts_SM_DEACT_PDP_ACCEPT_MO(apars.tid), ran_index);
|
|
}
|
|
[not error_ind] GTP.receive(tr_GTPC_MsgType(?, deletePDPContextResponse, apars.ggsn_tei_c)) {
|
|
repeat;
|
|
}
|
|
[] T.timeout {
|
|
setverdict(fail, "Waiting for SM_DEACT_PDP_REQ_MT");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Table 10.5.156/3GPP TS 24.008 */
|
|
template (value) QoSV t_QosDefault := {
|
|
reliabilityClass := '011'B, /* unacknowledged GTP+LLC, acknowledged RLC */
|
|
delayClass := '100'B, /* best effort */
|
|
spare1 := '00'B,
|
|
precedenceClass := '010'B, /* normal */
|
|
spare2 := '0'B,
|
|
peakThroughput := '0000'B, /* subscribed */
|
|
meanThroughput := '00000'B, /* subscribed */
|
|
spare3 := '000'B,
|
|
deliverErroneusSDU := omit,
|
|
deliveryOrder := omit,
|
|
trafficClass := omit,
|
|
maxSDUSize := omit,
|
|
maxBitrateUplink := omit,
|
|
maxBitrateDownlink := omit,
|
|
sduErrorRatio := omit,
|
|
residualBER := omit,
|
|
trafficHandlingPriority := omit,
|
|
transferDelay := omit,
|
|
guaranteedBitRateUplink := omit,
|
|
guaranteedBitRateDownlink := omit,
|
|
sourceStatisticsDescriptor := omit,
|
|
signallingIndication := omit,
|
|
spare4 := omit,
|
|
maxBitrateDownlinkExt := omit,
|
|
guaranteedBitRateDownlinkExt := omit,
|
|
maxBitrateUplinkExt := omit,
|
|
guaranteedBitRateUplinkExt := omit,
|
|
maxBitrateDownlinkExt2 := omit,
|
|
guaranteedBitRateDownlinkExt2 := omit,
|
|
maxBitrateUplinkExt2 := omit,
|
|
guaranteedBitRateUplinkExt2 := omit
|
|
}
|
|
|
|
/* 10.5.6.4 / 3GPP TS 24.008 */
|
|
template (value) PDPAddressV t_AddrIPv4dyn := {
|
|
pdpTypeOrg := '0001'B, /* IETF */
|
|
spare := '0000'B,
|
|
pdpTypeNum := '21'O, /* IPv4 */
|
|
addressInfo := omit
|
|
}
|
|
template (value) PDPAddressV t_AddrIPv6dyn := {
|
|
pdpTypeOrg := '0001'B, /* IETF */
|
|
spare := '0000'B,
|
|
pdpTypeNum := '53'O, /* IPv6 */
|
|
addressInfo := omit
|
|
}
|
|
|
|
template (value) PdpActPars t_PdpActPars(charstring ggsn_ip) := {
|
|
tid := '000'B,
|
|
nsapi := '0101'B, /* < 5 are reserved */
|
|
sapi := '0011'B, /* 3/5/9/11 */
|
|
qos := t_QosDefault,
|
|
addr := t_AddrIPv4dyn,
|
|
apn := omit,
|
|
pco := omit,
|
|
exp_rej_cause := omit,
|
|
gtp_resp_cause := int2oct(128, 1),
|
|
chg_id := f_rnd_octstring(4),
|
|
|
|
/* FIXME: make below dynamic !! */
|
|
ggsn_tei_c := f_rnd_octstring(4),
|
|
ggsn_tei_u := f_rnd_octstring(4),
|
|
ggsn_ip_c := f_inet_addr(ggsn_ip),
|
|
ggsn_ip_u := f_inet_addr(ggsn_ip),
|
|
ggsn_restart_ctr := int2oct(2, 1),
|
|
|
|
sgsn_tei_c := omit,
|
|
sgsn_tei_u := omit,
|
|
sgsn_ip_c := omit,
|
|
sgsn_ip_u := omit
|
|
}
|
|
|
|
template (value) GtpPeer ts_GtpPeerU(octetstring ip) := {
|
|
connId := 1,
|
|
remName := f_inet_ntoa(ip),
|
|
remPort := GTP1U_PORT
|
|
}
|
|
|
|
template (value) GtpPeer ts_GtpPeerC(octetstring ip) := {
|
|
connId := 1,
|
|
remName := f_inet_ntoa(ip),
|
|
remPort := GTP1C_PORT
|
|
}
|
|
|
|
private function f_gtpu_send(inout PdpActPars apars, octetstring payload) runs on BSSGP_ConnHdlr {
|
|
var GtpPeer peer := valueof(ts_GtpPeerU(apars.sgsn_ip_u));
|
|
GTP.send(ts_GTP1U_GPDU(peer, 0 /*seq*/, apars.sgsn_tei_u, payload));
|
|
}
|
|
|
|
private altstep as_xid(PdpActPars apars, integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
[] BSSGP[ran_index].receive(tr_LLC_XID_MT_CMD(?, apars.sapi)) {
|
|
repeat;
|
|
}
|
|
}
|
|
|
|
template PDU_SN tr_SN_UD(template BIT4 nsapi, template octetstring payload) := {
|
|
pDU_SN_UNITDATA := {
|
|
nsapi := nsapi,
|
|
moreBit := ?,
|
|
snPduType := '1'B,
|
|
firstSegmentIndicator := ?,
|
|
spareBit := ?,
|
|
pcomp := ?,
|
|
dcomp := ?,
|
|
npduNumber := ?,
|
|
segmentNumber := ?,
|
|
npduNumberContinued := ?,
|
|
dataSegmentSnUnitdataPdu := payload
|
|
}
|
|
}
|
|
|
|
/* simple case: single segment, no compression */
|
|
template (value) PDU_SN ts_SN_UD(BIT4 nsapi, octetstring payload) := {
|
|
pDU_SN_UNITDATA := {
|
|
nsapi := nsapi,
|
|
moreBit := '0'B,
|
|
snPduType := '1'B,
|
|
firstSegmentIndicator := '1'B,
|
|
spareBit := '0'B,
|
|
pcomp := '0000'B,
|
|
dcomp := '0000'B,
|
|
npduNumber := '0000'B,
|
|
segmentNumber := '0000'B,
|
|
npduNumberContinued := '00'O,
|
|
dataSegmentSnUnitdataPdu := payload
|
|
}
|
|
}
|
|
|
|
/* Transceive given 'payload' as MT message from GTP -> OsmoSGSN -> Gb */
|
|
private function f_gtpu_xceive_mt(inout PdpActPars apars, octetstring payload, integer ran_index := 0, boolean expect_fwd := true)
|
|
runs on BSSGP_ConnHdlr {
|
|
timer T := 5.0;
|
|
/* Send PDU via GTP from our simulated GGSN to the SGSN */
|
|
f_gtpu_send(apars, payload);
|
|
T.start;
|
|
/* Expect PDU via BSSGP/LLC on simulated PCU from SGSN */
|
|
alt {
|
|
[] as_xid(apars, ran_index);
|
|
//[] BSSGP[ran_index].receive(tr_BD_SNDCP(apars.sapi, tr_SN_UD(apars.nsapi, payload)));
|
|
[expect_fwd] BSSGP[ran_index].receive(tr_SN_UD(apars.nsapi, payload));
|
|
[expect_fwd] T.timeout {
|
|
setverdict(fail, "Timeout waiting for GTP-U to appear on BSSGP");
|
|
mtc.stop;
|
|
}
|
|
[not expect_fwd] BSSGP[ran_index].receive(tr_SN_UD(apars.nsapi, payload)) {
|
|
setverdict(fail, "GTP-U forwarded to BSSGP but not expected")
|
|
mtc.stop;
|
|
}
|
|
[not expect_fwd] T.timeout {}
|
|
}
|
|
}
|
|
|
|
/* Transceive given 'payload' as MO message from Gb -> OsmoSGSN -> GTP */
|
|
private function f_gtpu_xceive_mo(inout PdpActPars apars, octetstring payload, integer ran_index := 0, uint9_t n_u := 0)
|
|
runs on BSSGP_ConnHdlr {
|
|
/* Send PDU via SNDCP/LLC/BSSGP/NS via simulated MS/PCU to the SGSN */
|
|
var GtpPeer peer := valueof(ts_GtpPeerU(apars.sgsn_ip_u));
|
|
var PDU_SN sndcp := valueof(ts_SN_UD(apars.nsapi, payload));
|
|
BSSGP[ran_index].send(ts_LLC_UI(enc_PDU_SN(sndcp), apars.sapi, '0'B, n_u));
|
|
/* Expect PDU via GTP from SGSN on simulated GGSN */
|
|
alt {
|
|
[] GTP.receive(tr_GTPU_GPDU(peer, apars.ggsn_tei_u, payload));
|
|
}
|
|
}
|
|
|
|
private function f_TC_attach_pdp_act(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
|
|
f_pdp_ctx_act(apars);
|
|
}
|
|
testcase TC_attach_pdp_act() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act), testcasename(), g_gb, 17);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* PDP Context activation for not-attached subscriber; expect fail */
|
|
private function f_TC_pdp_act_unattached(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
f_send_l3(ts_SM_ACT_PDP_REQ(apars.tid, apars.nsapi, apars.sapi, apars.qos, apars.addr,
|
|
apars.apn, apars.pco));
|
|
alt {
|
|
/* We might want toalso actually expect a PDPC CTX ACT REJ? */
|
|
[] BSSGP[0].receive(tr_GMM_DET_REQ_MT(?, ?)) {
|
|
setverdict(pass);
|
|
}
|
|
[] GTP.receive(tr_GTPC_MsgType(?, createPDPContextRequest, ?)) {
|
|
setverdict(fail, "Unexpected GTP PDP CTX ACT");
|
|
mtc.stop;
|
|
}
|
|
[] BSSGP[0].receive(tr_SM_ACT_PDP_ACCEPT(?, ?)) {
|
|
setverdict(fail, "Unexpected SM PDP CTX ACT ACK");
|
|
mtc.stop;
|
|
}
|
|
[] BSSGP[0].receive { repeat; }
|
|
}
|
|
}
|
|
testcase TC_pdp_act_unattached() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_pdp_act_unattached), testcasename(), g_gb, 18);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* ATTACH + PDP CTX ACT + user plane traffic */
|
|
private function f_TC_attach_pdp_act_user(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100));
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200));
|
|
}
|
|
testcase TC_attach_pdp_act_user() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act_user), testcasename(), g_gb, 19);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* ATTACH + PDP CTX ACT; reject from GGSN */
|
|
private function f_TC_attach_pdp_act_ggsn_reject(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
apars.gtp_resp_cause := int2oct(199, 1); /* no resources available */
|
|
apars.exp_rej_cause := '1a'O; /* insufficient resources */
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
}
|
|
testcase TC_attach_pdp_act_ggsn_reject() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act_ggsn_reject), testcasename(), g_gb, 20);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* ATTACH + PDP CTX ACT + user plane traffic + PDP CTX DEACT in MO direction */
|
|
private function f_TC_attach_pdp_act_user_deact_mo(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100));
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200));
|
|
|
|
f_pdp_ctx_deact_mo(apars, '00'O);
|
|
}
|
|
testcase TC_attach_pdp_act_user_deact_mo() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act_user_deact_mo), testcasename(), g_gb, 21);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* ATTACH + PDP CTX ACT + user plane traffic + PDP CTX DEACT in MT direction */
|
|
private function f_TC_attach_pdp_act_user_deact_mt(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100));
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200));
|
|
|
|
f_pdp_ctx_deact_mt(apars, false);
|
|
}
|
|
testcase TC_attach_pdp_act_user_deact_mt() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act_user_deact_mt), testcasename(), g_gb, 22);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Test MS sending a duplicate Deact PDP Ctx (OS#3956). */
|
|
private function f_TC_attach_pdp_act_deact_dup(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var Gtp1cUnitdata g_ud;
|
|
var integer i;
|
|
var OCT1 cause_regular_deact := '24'O;
|
|
|
|
/* first perform regular attach + PDP context act */
|
|
f_TC_attach(id);
|
|
f_pdp_ctx_act(apars);
|
|
|
|
f_send_l3_gmm_llc(ts_SM_DEACT_PDP_REQ_MO(apars.tid, cause_regular_deact, false, omit), 0);
|
|
f_send_l3_gmm_llc(ts_SM_DEACT_PDP_REQ_MO(apars.tid, cause_regular_deact, false, omit), 0);
|
|
|
|
for (i := 0; i < 2; i := i+1) {
|
|
GTP.receive(tr_GTPC_MsgType(?, deletePDPContextRequest, apars.ggsn_tei_c)) -> value g_ud {
|
|
var integer seq_nr := oct2int(g_ud.gtpc.opt_part.sequenceNumber);
|
|
log("Received deletePDPContextResponse " & int2str(i) & ", seq_nr=" & int2str(seq_nr));
|
|
GTP.send(ts_GTPC_DeletePdpResp(g_ud.peer, seq_nr, apars.sgsn_tei_c, '7F'O));
|
|
}
|
|
}
|
|
|
|
alt {
|
|
[] BSSGP[0].receive(tr_SM_DEACT_PDP_ACCEPT_MT(apars.tid)) {
|
|
setverdict(pass);
|
|
}
|
|
[] as_xid(apars, 0);
|
|
}
|
|
|
|
/* Make sure second DeactPdpAccept is sent: */
|
|
timer T := 2.0;
|
|
T.start;
|
|
alt {
|
|
[] BSSGP[0].receive(tr_SM_DEACT_PDP_ACCEPT_MT(apars.tid)) {
|
|
setverdict(fail, "Second SM_DEACT_PDP_ACCEPT_MT received");
|
|
}
|
|
[] T.timeout {
|
|
setverdict(pass);
|
|
}
|
|
}
|
|
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_attach_pdp_act_deact_dup() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act_deact_dup), testcasename(), g_gb, 46);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* ATTACH + ATTACH (2nd) */
|
|
private function f_TC_attach_forget_tlli_attach(charstring id) runs on BSSGP_ConnHdlr {
|
|
g_pars.t_guard := 5.0;
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
|
|
/* second to perform regular attach */
|
|
f_TC_attach(id);
|
|
}
|
|
|
|
|
|
testcase TC_attach_second_attempt() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_forget_tlli_attach), testcasename(), g_gb, 22);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_echo_timeout(charstring id) runs on BSSGP_ConnHdlr {
|
|
var Gtp1cUnitdata g_ud;
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var integer seq_nr;
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
|
|
/* Wait to receive first echo request and send initial Restart counter */
|
|
GTP.receive(tr_GTPC_MsgType(?, echoRequest, ?)) -> value g_ud {
|
|
BSSGP[0].clear;
|
|
seq_nr := oct2int(g_ud.gtpc.opt_part.sequenceNumber);
|
|
GTP.send(ts_GTPC_PONG(g_ud.peer, seq_nr, apars.ggsn_restart_ctr));
|
|
f_sleep(int2float(mp_echo_interval)); /* wait until around next echo is expected */
|
|
}
|
|
|
|
/* At some point next echo request not answered will timeout and SGSN
|
|
should drop the pdp ctx. Around T3 (3secs) * 6 (+ extra, a lot due to OS#4178): */
|
|
timer T := 3.0 * 6.0 + 16.0;
|
|
T.start;
|
|
alt {
|
|
[] BSSGP[0].receive(tr_SM_DEACT_PDP_REQ_MT(apars.tid, ?, true)) {
|
|
f_send_l3_gmm_llc(ts_SM_DEACT_PDP_ACCEPT_MO(apars.tid));
|
|
setverdict(pass);
|
|
}
|
|
[] GTP.receive(tr_GTPC_MsgType(?, deletePDPContextRequest, apars.ggsn_tei_c)) -> value g_ud {
|
|
/* SGSN currently doesn't send this message because it expects GGSN to be non-reachable anyway */
|
|
seq_nr := oct2int(g_ud.gtpc.opt_part.sequenceNumber);
|
|
log("Received deletePDPContextRequest seq_nr=" & int2str(seq_nr));
|
|
GTP.send(ts_GTPC_DeletePdpResp(g_ud.peer, seq_nr, apars.sgsn_tei_c, '7F'O));
|
|
repeat;
|
|
}
|
|
[] GTP.receive(tr_GTPC_MsgType(?, echoRequest, ?)) -> value g_ud {
|
|
seq_nr := oct2int(g_ud.gtpc.opt_part.sequenceNumber);
|
|
log("Received EchoRequest seq_nr=" & int2str(seq_nr));
|
|
repeat;
|
|
}
|
|
[] T.timeout {
|
|
setverdict(fail, "BSSGP DeactPdpReq not received");
|
|
mtc.stop;
|
|
}
|
|
[] as_xid(apars);
|
|
}
|
|
T.stop
|
|
|
|
setverdict(pass);
|
|
}
|
|
/* ATTACH + trigger Recovery procedure through CreatePdpResp */
|
|
testcase TC_attach_echo_timeout() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
g_use_echo := true;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_echo_timeout), testcasename(), g_gb, 67, 50.0);
|
|
vc_conn.done;
|
|
g_use_echo := false;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_restart_ctr_echo(charstring id) runs on BSSGP_ConnHdlr {
|
|
var Gtp1cUnitdata g_ud;
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* Activate a pdp context against the GGSN */
|
|
f_pdp_ctx_act(apars);
|
|
/* Wait to receive first echo request and send initial Restart counter */
|
|
GTP.receive(tr_GTPC_MsgType(?, echoRequest, ?)) -> value g_ud {
|
|
var integer seq_nr := oct2int(g_ud.gtpc.opt_part.sequenceNumber);
|
|
GTP.send(ts_GTPC_PONG(g_ud.peer, seq_nr, apars.ggsn_restart_ctr));
|
|
}
|
|
/* Wait to receive second echo request and send incremented Restart
|
|
counter. This will fake a restarted GGSN, and pdp ctx allocated
|
|
should be released by SGSN */
|
|
apars.ggsn_restart_ctr := int2oct(oct2int(apars.ggsn_restart_ctr) + 1, 1);
|
|
GTP.receive(tr_GTPC_MsgType(?, echoRequest, ?)) -> value g_ud {
|
|
var integer seq_nr := oct2int(g_ud.gtpc.opt_part.sequenceNumber);
|
|
GTP.send(ts_GTPC_PONG(g_ud.peer, seq_nr, apars.ggsn_restart_ctr));
|
|
}
|
|
var OCT1 cause_network_failure := int2oct(38, 1)
|
|
alt {
|
|
[] BSSGP[0].receive(tr_SM_DEACT_PDP_REQ_MT(apars.tid, cause_network_failure, true)) {
|
|
f_send_l3(ts_SM_DEACT_PDP_ACCEPT_MO(apars.tid));
|
|
setverdict(pass);
|
|
}
|
|
[] as_xid(apars);
|
|
}
|
|
setverdict(pass);
|
|
}
|
|
/* ATTACH + trigger Recovery procedure through EchoResp */
|
|
testcase TC_attach_restart_ctr_echo() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
g_use_echo := true
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_restart_ctr_echo), testcasename(), g_gb, 23, 30.0);
|
|
vc_conn.done;
|
|
g_use_echo := false
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_restart_ctr_create(charstring id) runs on BSSGP_ConnHdlr {
|
|
var Gtp1cUnitdata g_ud;
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var integer seq_nr := 23;
|
|
var GtpPeer peer;
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
|
|
/* Use this CTX ACT to send initial Restart counter to SGSN. */
|
|
apars.gtp_resp_cause := int2oct(199, 1); /* no resources available */
|
|
apars.exp_rej_cause := '1a'O; /* insufficient resources */
|
|
f_pdp_ctx_act(apars, true);
|
|
|
|
/* Increment restart_ctr. This will fake a restarted GGSN when CreatePdpResp is
|
|
/* received. */
|
|
apars.ggsn_restart_ctr := int2oct(oct2int(apars.ggsn_restart_ctr) + 1, 1);
|
|
|
|
/* FIXME: Once we can easily handle different pdp ctx simultaneously, it
|
|
would be great to have an active pdp context here before triggering
|
|
Recovery, and making sure the the DEACT request is sent by the SGSN.
|
|
*/
|
|
|
|
/* Activate a pdp context against the GGSN, send incremented Recovery
|
|
IE. This should trigger the recovery path, but still this specific
|
|
CTX activation should work. */
|
|
apars.exp_rej_cause := omit; /* default value for tests */
|
|
apars.gtp_resp_cause := int2oct(128, 1); /* default value for tests */
|
|
f_pdp_ctx_act(apars, true);
|
|
|
|
setverdict(pass);
|
|
}
|
|
/* ATTACH + trigger Recovery procedure through CreatePdpResp */
|
|
testcase TC_attach_restart_ctr_create() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_restart_ctr_create), testcasename(), g_gb, 24, 30.0);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* ATTACH + PDP CTX ACT + user plane traffic + PDP CTX DEACT in MT direction + trigger T3395 */
|
|
private function f_TC_attach_pdp_act_deact_mt_t3395_expire(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var integer seq_nr := 23;
|
|
var GtpPeer peer;
|
|
var integer i;
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
|
|
BSSGP[0].clear;
|
|
peer := valueof(ts_GtpPeerC(apars.sgsn_ip_c));
|
|
GTP.send(ts_GTPC_DeletePDP(peer, seq_nr, apars.sgsn_tei_c, apars.nsapi, '1'B));
|
|
|
|
for (i := 0; i < 5; i := i+1) {
|
|
alt {
|
|
[] BSSGP[0].receive(tr_SM_DEACT_PDP_REQ_MT(apars.tid, ?, true)) {}
|
|
[] as_xid(apars);
|
|
}
|
|
}
|
|
|
|
GTP.receive(tr_GTPC_MsgType(?, deletePDPContextResponse, apars.ggsn_tei_c)) {}
|
|
|
|
f_send_l3(ts_SM_DEACT_PDP_ACCEPT_MO(apars.tid));
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_attach_pdp_act_deact_mt_t3395_expire() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act_deact_mt_t3395_expire), testcasename(), g_gb, 25, 60.0);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* ATTACH + PDP CTX ACT dropped + retrans */
|
|
private function f_TC_attach_pdp_act_deact_gtp_retrans(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var Gtp1cUnitdata g_ud_first, g_ud_second;
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
|
|
/* then activate PDP context on the Gb side */
|
|
f_send_l3_gmm_llc(ts_SM_ACT_PDP_REQ(apars.tid, apars.nsapi, apars.sapi, apars.qos, apars.addr,
|
|
apars.apn, apars.pco), 0);
|
|
|
|
GTP.receive(tr_GTPC_MsgType(?, createPDPContextRequest, ?)) -> value g_ud_first {}
|
|
log("First createPDPContextRequest received, dropping & waiting for retransmission");
|
|
GTP.receive(tr_GTPC_MsgType(?, createPDPContextRequest, ?)) -> value g_ud_second {
|
|
if (g_ud_first != g_ud_second) {
|
|
setverdict(fail, "Retransmitted GTP message createPDPContextRequest is different from original one!");
|
|
mtc.stop;
|
|
}
|
|
f_process_gtp_ctx_act_req(apars, g_ud_second.gtpc);
|
|
var integer seq_nr := oct2int(g_ud_second.gtpc.opt_part.sequenceNumber);
|
|
GTP.send(ts_GTPC_CreatePdpResp(g_ud_second.peer, seq_nr,
|
|
apars.sgsn_tei_c, apars.gtp_resp_cause,
|
|
apars.ggsn_tei_c, apars.ggsn_tei_u,
|
|
apars.nsapi,
|
|
apars.ggsn_ip_c, apars.ggsn_ip_u, apars.chg_id,
|
|
omit, omit));
|
|
}
|
|
BSSGP[0].receive(tr_SM_ACT_PDP_ACCEPT) {}
|
|
|
|
/* Now the same with Deact */
|
|
f_send_l3_gmm_llc(ts_SM_DEACT_PDP_REQ_MO(apars.tid, '00'O, false, omit), 0);
|
|
GTP.receive(tr_GTPC_MsgType(?, deletePDPContextRequest, apars.ggsn_tei_c)) -> value g_ud_first {}
|
|
log("First deletePDPContextRequest received, dropping & waiting for retransmission");
|
|
GTP.receive(tr_GTPC_MsgType(?, deletePDPContextRequest, apars.ggsn_tei_c)) -> value g_ud_second {
|
|
if (g_ud_first != g_ud_second) {
|
|
setverdict(fail, "Retransmitted GTP message deletePDPContextRequest is different from original one!");
|
|
mtc.stop;
|
|
}
|
|
var integer seq_nr := oct2int(g_ud_second.gtpc.opt_part.sequenceNumber);
|
|
BSSGP[0].clear;
|
|
GTP.send(ts_GTPC_DeletePdpResp(g_ud_second.peer, seq_nr, apars.sgsn_tei_c, '7F'O));
|
|
}
|
|
alt {
|
|
[] BSSGP[0].receive(tr_SM_DEACT_PDP_ACCEPT_MT(apars.tid)) {
|
|
setverdict(pass);
|
|
}
|
|
[] as_xid(apars, 0);
|
|
}
|
|
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_attach_pdp_act_deact_gtp_retrans() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act_deact_gtp_retrans), testcasename(), g_gb, 27);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Test that SGSN GTP response retransmit queue works fine */
|
|
private function f_TC_attach_pdp_act_deact_gtp_retrans_resp(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var integer seq_nr := 23;
|
|
var Gtp1cUnitdata g_ud_first, g_ud_second;
|
|
var template Gtp1cUnitdata g_delete_req;
|
|
/* first perform regular attach + PDP context act */
|
|
f_TC_attach(id);
|
|
f_pdp_ctx_act(apars);
|
|
|
|
/* Now perform an MT DeleteCtxReq and emulate GGSN didn't receive response and sends a duplicated DeleteCtxReq */
|
|
BSSGP[0].clear;
|
|
var GtpPeer peer := valueof(ts_GtpPeerC(apars.sgsn_ip_c));
|
|
g_delete_req := ts_GTPC_DeletePDP(peer, seq_nr, apars.sgsn_tei_c, apars.nsapi, '1'B);
|
|
GTP.send(g_delete_req);
|
|
alt {
|
|
[] BSSGP[0].receive(tr_SM_DEACT_PDP_REQ_MT(apars.tid, ?, true)) {
|
|
f_send_l3_gmm_llc(ts_SM_DEACT_PDP_ACCEPT_MO(apars.tid), 0);
|
|
}
|
|
[] as_xid(apars, 0);
|
|
}
|
|
GTP.receive(tr_GTPC_MsgType(?, deletePDPContextResponse, apars.ggsn_tei_c)) -> value g_ud_first {
|
|
if (g_ud_first.gtpc.gtpc_pdu.deletePDPContextResponse.cause.causevalue != '80'O) {
|
|
setverdict(fail, "Received deletePDPContextResponse cause is not 'Request accepted'");
|
|
mtc.stop;
|
|
}
|
|
};
|
|
|
|
/* Send duplicate DeleteCtxReq */
|
|
log("First deletePDPContextResponse received, dropping & retransmitting retransmission of deletePDPContextRequest");
|
|
GTP.send(g_delete_req);
|
|
GTP.receive(tr_GTPC_MsgType(?, deletePDPContextResponse, apars.ggsn_tei_c)) -> value g_ud_second {
|
|
if (g_ud_first != g_ud_second) {
|
|
setverdict(fail, "Retransmitted GTP message deletePDPContextResponse is different from original one!");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
/* Let's send now a new DeleteCtxReq (increased seq_nr) to make sure it
|
|
* is handled differently by SGSN (expect "non-existent" cause) */
|
|
g_delete_req := ts_GTPC_DeletePDP(peer, seq_nr + 1, apars.sgsn_tei_c, apars.nsapi, '1'B);
|
|
GTP.send(g_delete_req);
|
|
/* Response with cause "non-existent" must be sent with TEID 0 according to specs */
|
|
GTP.receive(tr_GTPC_MsgType(?, deletePDPContextResponse, '00000000'O)) -> value g_ud_second {
|
|
if (g_ud_second.gtpc.gtpc_pdu.deletePDPContextResponse.cause.causevalue != 'C0'O) {
|
|
setverdict(fail, "Received deletePDPContextResponse cause is not 'Non-existent'");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_attach_pdp_act_deact_gtp_retrans_resp() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act_deact_gtp_retrans_resp), testcasename(), g_gb, 28);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_hlr_location_cancel_request_update(charstring id) runs on BSSGP_ConnHdlr {
|
|
/* MS: perform regular attach */
|
|
f_TC_attach(id);
|
|
|
|
/* HLR: cancel the location request */
|
|
GSUP.send(ts_GSUP_CL_REQ(g_pars.imsi, OSMO_GSUP_CANCEL_TYPE_UPDATE));
|
|
GSUP.receive(tr_GSUP_CL_RES(g_pars.imsi));
|
|
|
|
/* ensure no Detach Request got received */
|
|
timer T := 5.0;
|
|
T.start;
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_DET_REQ_MT(*, *, *)) {
|
|
T.stop;
|
|
setverdict(fail, "Unexpected GMM Detach Request");
|
|
mtc.stop;
|
|
}
|
|
[] T.timeout {
|
|
setverdict(pass);
|
|
mtc.stop;
|
|
}
|
|
[] BSSGP[0].receive {
|
|
repeat;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ATTACH + PDP CTX ACT + user plane traffic + ERROR IND in MT direction */
|
|
private function f_TC_attach_pdp_act_user_error_ind_ggsn(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200));
|
|
|
|
/* Send Error indication as response from upload PDU and expect deact towards MS */
|
|
f_pdp_ctx_deact_mt(apars, true);
|
|
}
|
|
testcase TC_attach_pdp_act_user_error_ind_ggsn() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act_user_error_ind_ggsn), testcasename(), g_gb, 26);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
testcase TC_hlr_location_cancel_request_update() runs on test_CT {
|
|
/* MS <-> SGSN: GMM Attach
|
|
* HLR -> SGSN: Cancel Location Request
|
|
* HLR <- SGSN: Cancel Location Ack
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_hlr_location_cancel_request_update), testcasename(), g_gb, 31);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
|
|
private function f_TC_hlr_location_cancel_request_withdraw(charstring id) runs on BSSGP_ConnHdlr {
|
|
/* MS: perform regular attach */
|
|
f_TC_attach(id);
|
|
|
|
/* HLR: cancel the location request */
|
|
GSUP.send(ts_GSUP_CL_REQ(g_pars.imsi, OSMO_GSUP_CANCEL_TYPE_WITHDRAW));
|
|
GSUP.receive(tr_GSUP_CL_RES(g_pars.imsi));
|
|
GSUP.send(ts_GSUP_UL_RES(g_pars.imsi));
|
|
|
|
/* MS: receive a Detach Request */
|
|
BSSGP[0].receive(tr_GMM_DET_REQ_MT(c_GMM_DTT_MT_IMSI_DETACH, ?, ?));
|
|
f_send_l3(ts_GMM_DET_ACCEPT_MO);
|
|
|
|
setverdict(pass);
|
|
}
|
|
|
|
testcase TC_hlr_location_cancel_request_withdraw() runs on test_CT {
|
|
/* MS <-> SGSN: GMM Attach
|
|
* HLR -> SGSN: Cancel Location Request
|
|
* HLR <- SGSN: Cancel Location Ack
|
|
* MS <- SGSN: Detach Request
|
|
* SGSN-> MS: Detach Complete
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_hlr_location_cancel_request_withdraw), testcasename(), g_gb, 29);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
|
|
private function f_hlr_location_cancel_request_unknown_subscriber(
|
|
charstring id,
|
|
GSUP_CancelType canceltype) runs on BSSGP_ConnHdlr {
|
|
|
|
/* HLR: cancel the location request */
|
|
GSUP.send(ts_GSUP_CL_REQ(g_pars.imsi, canceltype));
|
|
|
|
/* cause 2 = IMSI_UNKNOWN */
|
|
GSUP.receive(tr_GSUP_CL_ERR(g_pars.imsi, 2));
|
|
|
|
setverdict(pass);
|
|
}
|
|
|
|
private function f_TC_hlr_location_cancel_request_unknown_subscriber_withdraw(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_hlr_location_cancel_request_unknown_subscriber(id, OSMO_GSUP_CANCEL_TYPE_WITHDRAW);
|
|
}
|
|
|
|
testcase TC_hlr_location_cancel_request_unknown_subscriber_withdraw() runs on test_CT {
|
|
/* HLR -> SGSN: Cancel Location Request
|
|
* HLR <- SGSN: Cancel Location Error
|
|
*/
|
|
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_hlr_location_cancel_request_unknown_subscriber_withdraw), testcasename(), g_gb, 30);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_hlr_location_cancel_request_unknown_subscriber_update(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_hlr_location_cancel_request_unknown_subscriber(id, OSMO_GSUP_CANCEL_TYPE_WITHDRAW);
|
|
}
|
|
|
|
testcase TC_hlr_location_cancel_request_unknown_subscriber_update() runs on test_CT {
|
|
/* HLR -> SGSN: Cancel Location Request
|
|
* HLR <- SGSN: Cancel Location Error
|
|
*/
|
|
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_hlr_location_cancel_request_unknown_subscriber_update), testcasename(), g_gb, 30);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_detach_check_subscriber_list(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_TC_attach(id);
|
|
f_detach_mo(c_GMM_DTT_MO_GPRS, true, true);
|
|
}
|
|
|
|
testcase TC_attach_detach_check_subscriber_list() runs on test_CT {
|
|
/* MS <-> SGSN: Attach
|
|
* MS -> SGSN: Detach Req (Power off)
|
|
* VTY -> SGSN: Check if MS is NOT in subscriber cache
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
var integer id := 33;
|
|
var charstring imsi := hex2str(f_gen_imsi(id));
|
|
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_detach_check_subscriber_list), testcasename(), g_gb, id);
|
|
vc_conn.done;
|
|
|
|
f_vty_transceive_not_match(SGSNVTY, "show subscriber cache", pattern "* IMSI: {imsi}*");
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Attempt an attach, but loose the Identification Request (IMEI) */
|
|
private function f_TC_attach_no_imei_response(charstring id) runs on BSSGP_ConnHdlr {
|
|
var integer count_req := 0;
|
|
var MobileIdentityLV mi;
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), f_random_RAI(), true, false, omit, omit));
|
|
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?)) {
|
|
/* break */
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ID_REQ('001'B)) {
|
|
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
|
|
f_send_l3(ts_GMM_ID_RESP(mi));
|
|
repeat;
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ID_REQ('010'B)) {
|
|
/* ignore ID REQ IMEI */
|
|
count_req := count_req + 1;
|
|
repeat;
|
|
}
|
|
}
|
|
if (count_req != 5) {
|
|
setverdict(fail, "Did not received GMM ID Request Type IMEI 5 times!");
|
|
mtc.stop;
|
|
}
|
|
setverdict(pass);
|
|
}
|
|
|
|
testcase TC_attach_no_imei_response() runs on test_CT {
|
|
/* MS -> SGSN: Attach Request IMSI
|
|
* MS <- SGSN: Identity Request IMSI (optional)
|
|
* MS -> SGSN: Identity Response IMSI (optional)
|
|
* MS <- SGSN: Identity Request IMEI
|
|
* MS -x SGSN: no response
|
|
* MS <- SGSN: re-send: Identity Request IMEI 4x
|
|
* MS <- SGSN: Attach Reject
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_no_imei_response), testcasename(), g_gb, 32, 60.0);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Attempt an attach, but loose the Identification Request (IMSI) */
|
|
private function f_TC_attach_no_imsi_response(charstring id) runs on BSSGP_ConnHdlr {
|
|
var integer count_req := 0;
|
|
var MobileIdentityLV mi;
|
|
|
|
/* set p_tmsi to use it in Attach Req via f_mi_get_lv() */
|
|
g_pars.p_tmsi := 'c0000035'O;
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), f_random_RAI(), true, false, omit, omit));
|
|
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?)) {
|
|
/* break */
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ID_REQ('001'B)) {
|
|
/* ignore ID REQ IMSI */
|
|
count_req := count_req + 1;
|
|
repeat;
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ID_REQ('010'B)) {
|
|
mi := valueof(ts_MI_IMEI_LV(g_pars.imei));
|
|
f_send_l3(ts_GMM_ID_RESP(mi));
|
|
repeat;
|
|
}
|
|
}
|
|
if (count_req != 5) {
|
|
setverdict(fail, "Did not received GMM ID Request Type IMSI 5 times!");
|
|
mtc.stop;
|
|
}
|
|
setverdict(pass);
|
|
}
|
|
|
|
testcase TC_attach_no_imsi_response() runs on test_CT {
|
|
/* MS -> SGSN: Attach Request TMSI (unknown)
|
|
* MS <- SGSN: Identity Request IMEI (optional)
|
|
* MS -> SGSN: Identity Response IMEI (optional)
|
|
* MS <- SGSN: Identity Request IMSI
|
|
* MS -x SGSN: no response
|
|
* MS <- SGSN: re-send: Identity Request IMSI 4x
|
|
* MS <- SGSN: Attach Reject
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_no_imsi_response), testcasename(), g_gb, 35, 60.0);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_sgsn_vty_destroy_subscriber_imsi(TELNETasp_PT pt, charstring imsi) {
|
|
f_vty_transceive(pt, "update-subscriber imsi " & imsi & " destroy");
|
|
}
|
|
|
|
testcase TC_attach_check_subscriber_list() runs on test_CT {
|
|
/* MS <-> SGSN: Attach
|
|
* VTY -> SGSN: Check if MS is in subscriber cache
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
var integer id := 34;
|
|
var charstring imsi := hex2str(f_gen_imsi(id));
|
|
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach), testcasename(), g_gb, id);
|
|
vc_conn.done;
|
|
|
|
f_vty_transceive_match(SGSNVTY, "show subscriber cache", pattern "* IMSI: {imsi}*");
|
|
f_sgsn_vty_destroy_subscriber_imsi(SGSNVTY, imsi);
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_closed_imsi_added(charstring id) runs on BSSGP_ConnHdlr {
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
|
|
/* unregister the old IMSI */
|
|
f_bssgp_client_unregister(g_pars.imsi);
|
|
/* Simulate a foreign IMSI */
|
|
g_pars.imsi := '001010123456700'H;
|
|
f_bssgp_client_register(g_pars.imsi, g_pars.tlli);
|
|
|
|
/* there is no auth */
|
|
g_pars.net.expect_auth := false;
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, false, false, omit, omit));
|
|
f_gmm_auth();
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?)) {
|
|
setverdict(fail, "Received unexpected GMM Attach REJECT");
|
|
mtc.stop;
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_ACCEPT(*, *, *)) -> value l3_mt {
|
|
f_process_attach_accept(l3_mt.msgs.gprs_mm.attachAccept);
|
|
f_send_l3(ts_GMM_ATTACH_COMPL);
|
|
setverdict(pass);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function f_TC_attach_closed_add_vty(charstring id) runs on BSSGP_ConnHdlr {
|
|
|
|
f_TC_attach_closed_foreign(id);
|
|
f_TC_attach_closed_imsi_added(id);
|
|
|
|
}
|
|
|
|
|
|
testcase TC_attach_closed_add_vty() runs on test_CT {
|
|
/* VTY-> SGSN: policy close
|
|
* MS -> SGSN: Attach Request
|
|
* MS <- SGSN: Identity Request IMSI
|
|
* MS -> SGSN: Identity Response IMSI
|
|
* MS <- SGSN: Attach Reject
|
|
* VTY-> SGSN: policy imsi-acl add IMSI
|
|
* MS -> SGSN: Attach Request
|
|
* MS <- SGSN: Identity Request IMSI
|
|
* MS -> SGSN: Identity Response IMSI
|
|
* MS <- SGSN: Identity Request IMEI
|
|
* MS -> SGSN: Identity Response IMEI
|
|
* MS <- SGSN: Attach Accept
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
f_vty_config(SGSNVTY, "sgsn", "auth-policy closed");
|
|
f_vty_config(SGSNVTY, "sgsn", "imsi-acl del 001010123456789");
|
|
f_vty_config(SGSNVTY, "sgsn", "imsi-acl del 001010123456700");
|
|
f_vty_config(SGSNVTY, "sgsn", "imsi-acl add 001010123456700");
|
|
/* test with foreign IMSI: Must Reject */
|
|
vc_conn := f_start_handler(refers(f_TC_attach_closed_add_vty), testcasename(), g_gb, 9);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Attempt an attach, but never answer a Attach Complete */
|
|
private function f_TC_attach_check_complete_resend(charstring id) runs on BSSGP_ConnHdlr {
|
|
var integer count_req := 0;
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), f_random_RAI(), true, false, omit, omit));
|
|
f_gmm_auth();
|
|
/* Expect SGSN to perform LU with HLR */
|
|
f_gmm_gsup_lu_isd();
|
|
|
|
timer T := 10.0;
|
|
T.start;
|
|
alt {
|
|
[] T.timeout {
|
|
/* break */
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_ACCEPT(*, *, *)) {
|
|
/* ignore */
|
|
count_req := count_req + 1;
|
|
T.start;
|
|
repeat;
|
|
}
|
|
}
|
|
if (count_req != 5) {
|
|
setverdict(fail, "Did not received GMM Attach Complete.");
|
|
mtc.stop;
|
|
}
|
|
setverdict(pass);
|
|
}
|
|
|
|
testcase TC_attach_check_complete_resend() runs on test_CT {
|
|
/* MS -> SGSN: Attach Request IMSI
|
|
* MS <- SGSN: Identity Request *
|
|
* MS -> SGSN: Identity Response *
|
|
* MS <- SGSN: Attach Complete 5x
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_check_complete_resend), testcasename(), g_gb, 36, 60.0);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
friend function f_routing_area_update(RoutingAreaIdentificationV ra, integer ran_index := 0) runs on BSSGP_ConnHdlr {
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
var PDU_DTAP_PS_MT mt;
|
|
var template OCT4 p_tmsi := omit;
|
|
|
|
if (is_iu(ran_index)) {
|
|
p_tmsi := g_pars.p_tmsi;
|
|
}
|
|
/* then send RAU */
|
|
f_send_l3(ts_GMM_RAU_REQ(f_mi_get_lv(), GPRS_UPD_T_RA, g_pars.ra, false, omit, omit, p_tmsi), ran_index);
|
|
alt {
|
|
[is_gb(ran_index)] BSSGP[ran_index].receive(tr_GMM_RAU_ACCEPT) -> value l3_mt {
|
|
f_process_rau_accept(l3_mt.msgs.gprs_mm.routingAreaUpdateAccept, ran_index);
|
|
f_send_l3(ts_GMM_RAU_COMPL, ran_index);
|
|
setverdict(pass);
|
|
}
|
|
[is_iu(ran_index)] BSSAP.receive(tr_PDU_DTAP_PS_MT(tr_GMM_RAU_ACCEPT)) -> value mt {
|
|
f_process_rau_accept(mt.dtap.msgs.gprs_mm.routingAreaUpdateAccept, ran_index);
|
|
f_send_l3(ts_GMM_RAU_COMPL, ran_index);
|
|
setverdict(pass);
|
|
}
|
|
|
|
[is_gb(ran_index)] BSSGP[ran_index].receive(tr_GMM_RAU_REJECT) {
|
|
setverdict(fail, "Unexpected RAU Reject");
|
|
mtc.stop;
|
|
}
|
|
[is_iu(ran_index)] BSSAP.receive(tr_PDU_DTAP_PS_MT(tr_GMM_RAU_REJECT)) {
|
|
setverdict(fail, "Unexpected RAU Reject");
|
|
mtc.stop;
|
|
}
|
|
|
|
[is_iu(ran_index)] BSSAP.receive(tr_RANAP_SecurityModeCmd(uia_algs := ?, uia_key := oct2bit(g_pars.vec.ik),
|
|
key_sts := ?)) {
|
|
var IntegrityProtectionAlgorithm uia_chosen := 0; /* 0 = standard_UMTS_integrity_algorithm_UIA1 */
|
|
BSSAP.send(ts_RANAP_SecurityModeComplete(uia_chosen));
|
|
BSSAP.receive(tr_RANAP_CommonId(imsi_hex2oct(g_pars.imsi)))
|
|
repeat;
|
|
}
|
|
[is_gb(ran_index)] BSSGP[ran_index].receive { repeat; }
|
|
[is_iu(ran_index)] BSSAP.receive { repeat; }
|
|
}
|
|
}
|
|
|
|
private function f_TC_attach_rau_a_a(charstring id) runs on BSSGP_ConnHdlr {
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
|
|
/* then send RAU */
|
|
f_routing_area_update(g_pars.ra);
|
|
|
|
/* do another RAU */
|
|
f_routing_area_update(g_pars.ra);
|
|
|
|
f_detach_mo(c_GMM_DTT_MO_GPRS, true, true);
|
|
}
|
|
|
|
testcase TC_attach_rau_a_a() runs on test_CT {
|
|
/* MS <-> SGSN: Successful Attach
|
|
* MS -> SGSN: Routing Area Update Request
|
|
* MS <- SGSN: Routing Area Update Accept
|
|
* MS -> SGSN: Routing Area Update Request
|
|
* MS <- SGSN: Routing Area Update Accept
|
|
* MS -> SGSN: Detach (PowerOff)
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_rau_a_a), testcasename(), g_gb, 37);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_rau_a_b(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_TC_attach(id);
|
|
|
|
log("attach complete sending rau");
|
|
f_routing_area_update(g_pars.ra, 0);
|
|
|
|
log("rau complete unregistering");
|
|
f_bssgp_client_unregister(g_pars.imsi);
|
|
f_bssgp_client_register(g_pars.imsi, g_pars.tlli, BSSGP_PROC[1]);
|
|
|
|
log("sending second RAU via different RA");
|
|
f_routing_area_update(f_cellid_to_RAI(g_pars.bssgp_cell_id[1]), 1);
|
|
|
|
f_detach_mo(c_GMM_DTT_MO_GPRS, true, true, 1);
|
|
}
|
|
|
|
testcase TC_attach_rau_a_b() runs on test_CT {
|
|
/* MS <-> SGSN: Successful Attach
|
|
* MS -> SGSN: Routing Area _a_ Update Request
|
|
* MS <- SGSN: Routing Area _a_ Update Accept
|
|
* MS -> SGSN: Routing Area _b_ Update Request
|
|
* MS <- SGSN: Routing Area _b_ Update Accept
|
|
* MS -> SGSN: Detach (PowerOff)
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_rau_a_b), testcasename(), g_gb, 38);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_gmm_attach_req_while_gmm_attach(charstring id) runs on BSSGP_ConnHdlr {
|
|
var integer count_req := 0;
|
|
var MobileIdentityLV mi;
|
|
var RoutingAreaIdentificationV rand_rai := f_random_RAI();
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), rand_rai, true, false, omit, omit));
|
|
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?)) {
|
|
setverdict(fail, "Unexpected GMM ATTACH REJECT");
|
|
mtc.stop;
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ID_REQ('001'B)) {
|
|
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
|
|
f_send_l3(ts_GMM_ID_RESP(mi));
|
|
repeat;
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ID_REQ('010'B)) {
|
|
/* send out a second GMM_Attach Request.
|
|
* If the SGSN follows the rules, this 2nd ATTACH REQ should be ignored, because
|
|
* of the same content */
|
|
f_send_l3(ts_GMM_ATTACH_REQ(f_mi_get_lv(), rand_rai, true, false, omit, omit));
|
|
mi := valueof(ts_MI_IMEI_LV(g_pars.imei));
|
|
f_send_l3(ts_GMM_ID_RESP(mi));
|
|
}
|
|
}
|
|
f_sleep(1.0);
|
|
|
|
/* we've sent already a IMEI answer, we should NOT asked again for IMEI */
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_ID_REQ('001'B)) {
|
|
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
|
|
f_send_l3(ts_GMM_ID_RESP(mi));
|
|
repeat;
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ID_REQ('010'B)) {
|
|
setverdict(fail, "Unexpected GMM ID REQ (IMEI).");
|
|
mtc.stop;
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_REJECT(?)) {
|
|
setverdict(fail, "Unexpected GMM ATTACH REJECT");
|
|
mtc.stop;
|
|
}
|
|
[] BSSGP[0].receive(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?)) -> value l3_mt {
|
|
f_process_attach_accept(l3_mt.msgs.gprs_mm.attachAccept);
|
|
f_send_l3(ts_GMM_ATTACH_COMPL);
|
|
setverdict(pass);
|
|
/* FIXME: Extract P-TMSI, if any. Only send Complete if necessary */
|
|
}
|
|
}
|
|
}
|
|
|
|
testcase TC_attach_gmm_attach_req_while_gmm_attach() runs on test_CT {
|
|
/* Testing if the SGSN ignore Attach Request with the exact same content */
|
|
/* MS -> SGSN: Attach Request IMSI
|
|
* MS <- SGSN: Identity Request IMSI (optional)
|
|
* MS -> SGSN: Identity Response IMSI (optional)
|
|
* MS <- SGSN: Identity Request IMEI
|
|
* MS -> SGSN: Attach Request (2nd)
|
|
* MS <- SGSN: Identity Response IMEI
|
|
* MS <- SGSN: Attach Accept
|
|
* MS -> SGSN: Attach Complete
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
f_vty_config(SGSNVTY, "sgsn", "auth-policy accept-all");
|
|
vc_conn := f_start_handler(refers(f_TC_attach_gmm_attach_req_while_gmm_attach), testcasename(), g_gb, 39);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_usim_resync(charstring id) runs on BSSGP_ConnHdlr {
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
|
|
var template PDU_L3_MS_SGSN attach_req := ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, false, false, omit, omit);
|
|
|
|
/* send Attach Request */
|
|
/* indicate R99 capability of the MS to enable UMTS AKA in presence of
|
|
* 3G auth vectors */
|
|
attach_req.msgs.gprs_mm.attachRequest.msNetworkCapability.msNetworkCapabilityV.revisionLevelIndicatior := '1'B;
|
|
/* The thing is, if the solSACapability is 'omit', then the
|
|
* revisionLevelIndicatior is at the wrong place! */
|
|
attach_req.msgs.gprs_mm.attachRequest.msNetworkCapability.msNetworkCapabilityV.solSACapability := '0'B;
|
|
f_send_l3(attach_req);
|
|
|
|
/* do the auth */
|
|
var PDU_L3_MS_SGSN l3_mo;
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
var default di := activate(as_mm_identity());
|
|
|
|
var GSUP_IE auth_tuple;
|
|
var template AuthenticationParameterAUTNTLV autn;
|
|
|
|
g_pars.vec := f_gen_auth_vec_3g();
|
|
autn := {
|
|
elementIdentifier := '28'O,
|
|
lengthIndicator := lengthof(g_pars.vec.autn),
|
|
autnValue := g_pars.vec.autn
|
|
};
|
|
auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G3G(g_pars.vec.rand,
|
|
g_pars.vec.sres,
|
|
g_pars.vec.kc,
|
|
g_pars.vec.ik,
|
|
g_pars.vec.ck,
|
|
g_pars.vec.autn,
|
|
g_pars.vec.res));
|
|
log("GSUP sends 2G and 3G auth tuples", auth_tuple);
|
|
GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi));
|
|
GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple));
|
|
|
|
var template PDU_L3_SGSN_MS auth_ciph_req := tr_GMM_AUTH_REQ(g_pars.vec.rand);
|
|
auth_ciph_req.msgs.gprs_mm.authenticationAndCipheringRequest.authenticationParameterAUTN := autn;
|
|
BSSGP[0].receive(auth_ciph_req) -> value l3_mt;
|
|
|
|
/* send the gmm auth failure with resync IE */
|
|
f_send_l3(ts_GMM_AUTH_FAIL_UMTS_AKA_RESYNC(g_pars.vec.auts));
|
|
|
|
/* wait for the GSUP resync request */
|
|
GSUP.receive(tr_GSUP_SAI_REQ_UMTS_AKA_RESYNC(
|
|
g_pars.imsi,
|
|
g_pars.vec.auts,
|
|
g_pars.vec.rand));
|
|
|
|
/* generate new key material */
|
|
g_pars.vec := f_gen_auth_vec_3g();
|
|
autn := {
|
|
elementIdentifier := '28'O,
|
|
lengthIndicator := lengthof(g_pars.vec.autn),
|
|
autnValue := g_pars.vec.autn
|
|
};
|
|
|
|
auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G3G(g_pars.vec.rand,
|
|
g_pars.vec.sres,
|
|
g_pars.vec.kc,
|
|
g_pars.vec.ik,
|
|
g_pars.vec.ck,
|
|
g_pars.vec.autn,
|
|
g_pars.vec.res));
|
|
/* send new key material */
|
|
GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple));
|
|
|
|
/* wait for the new Auth Request */
|
|
auth_ciph_req := tr_GMM_AUTH_REQ(g_pars.vec.rand);
|
|
auth_ciph_req.msgs.gprs_mm.authenticationAndCipheringRequest.authenticationParameterAUTN := autn;
|
|
BSSGP[0].receive(auth_ciph_req) -> value l3_mt;
|
|
var BIT4 ac_ref := l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.acReferenceNumber.valueField;
|
|
var template PDU_L3_MS_SGSN auth_ciph_resp := ts_GMM_AUTH_RESP_2G(ac_ref, g_pars.vec.sres);
|
|
auth_ciph_resp := ts_GMM_AUTH_RESP_2G(ac_ref, g_pars.vec.sres);
|
|
auth_ciph_resp.msgs.gprs_mm.authenticationAndCipheringResponse.authenticationParResp := {
|
|
valueField := substr(g_pars.vec.res, 0, 4)
|
|
};
|
|
auth_ciph_resp.msgs.gprs_mm.authenticationAndCipheringResponse.authenticationRespParExt := {
|
|
elementIdentifier := '21'O,
|
|
lengthIndicator := lengthof(g_pars.vec.res) - 4,
|
|
valueField := substr(g_pars.vec.res, 4, lengthof(g_pars.vec.res) - 4)
|
|
};
|
|
l3_mo := valueof(auth_ciph_resp);
|
|
if (ispresent(l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.imeisvRequest) and
|
|
l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.imeisvRequest.valueField == '001'B) {
|
|
l3_mo.msgs.gprs_mm.authenticationAndCipheringResponse.imeisv :=
|
|
valueof(ts_MI_IMEISV_TLV(g_pars.imei & '0'H));
|
|
}
|
|
f_send_l3(l3_mo);
|
|
deactivate(di);
|
|
|
|
/* Expect SGSN to perform LU with HLR */
|
|
f_gmm_gsup_lu_isd();
|
|
|
|
BSSGP[0].receive(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?)) -> value l3_mt {
|
|
f_process_attach_accept(l3_mt.msgs.gprs_mm.attachAccept);
|
|
}
|
|
f_send_l3(ts_GMM_ATTACH_COMPL);
|
|
setverdict(pass);
|
|
}
|
|
|
|
testcase TC_attach_usim_resync() runs on test_CT {
|
|
/* MS -> SGSN: Attach Request
|
|
* MS <- SGSN: Identity Request IMSI
|
|
* MS -> SGSN: Identity Response IMSI
|
|
* MS <- SGSN: Identity Request IMEI
|
|
* MS -> SGSN: Identity Response IMEI
|
|
* HLR<- SGSN: SAI Request
|
|
* HLR-> SGSN: SAI Response
|
|
* MS <- SGSN: Auth Request
|
|
* MS -> SGSN: Auth Failure (with AUTS)
|
|
* HLR<- SGSN: SAI Request (with AUTS & RAND)
|
|
* HLR-> SGSN: SAI Response (new key material)
|
|
* MS <- SGSN: Auth Request (new key material)
|
|
* MS -> SGSN: Auth Response
|
|
* MS <- SGSN: Attach Accept
|
|
* MS -> SGSN: Attach Complete
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_attach_usim_resync), testcasename(), g_gb, 40);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
|
|
/* Send LLC NULL to see if the SGSN survives it (OS#3952) */
|
|
private function f_TC_llc_null(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_gmm_attach(false, false);
|
|
f_sleep(1.0);
|
|
f_send_llc(ts_LLC_NULL('0'B, c_LLC_SAPI_LLGMM, LLC_CR_UL_CMD));
|
|
/* try to detach to check if SGSN is still alive */
|
|
f_detach_mo(c_GMM_DTT_MO_GPRS, true, true);
|
|
}
|
|
testcase TC_llc_null() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_llc_null), testcasename(), g_gb, 41);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Send LLC SABM to see if the SGSN rejects it properly with DM */
|
|
private function f_TC_llc_sabm_dm_llgmm(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_gmm_attach(false, false);
|
|
f_sleep(1.0);
|
|
f_send_llc(ts_LLC_SABM({}, '1'B, c_LLC_SAPI_LLGMM, LLC_CR_UL_CMD));
|
|
BSSGP[0].receive(tr_LLC_DM(?, c_LLC_SAPI_LLGMM, LLC_CR_DL_RSP));
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_llc_sabm_dm_llgmm() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_llc_sabm_dm_llgmm), testcasename(), g_gb, 42);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Send LLC SABM to see if the SGSN rejects it properly with DM */
|
|
private function f_TC_llc_sabm_dm_ll5(charstring id) runs on BSSGP_ConnHdlr {
|
|
f_gmm_attach(false, false);
|
|
f_sleep(1.0);
|
|
f_send_llc(ts_LLC_SABM({}, '1'B, c_LLC_SAPI_LL5, LLC_CR_UL_CMD));
|
|
BSSGP[0].receive(tr_LLC_DM(?, c_LLC_SAPI_LL5, LLC_CR_DL_RSP));
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_llc_sabm_dm_ll5() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_llc_sabm_dm_ll5), testcasename(), g_gb, 43);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* test XID handshake with empty L3 info: expect empty return (some phones require that, OS#3426 */
|
|
private function f_TC_xid_empty_l3(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var template (value) XID_Information xid;
|
|
var template XID_Information xid_rx;
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
|
|
/* start MO XID */
|
|
xid := { ts_XID_L3(''O) };
|
|
xid_rx := { tr_XID_L3(''O) };
|
|
f_send_llc(ts_LLC_XID_MO_CMD(xid, apars.sapi));
|
|
alt {
|
|
[] BSSGP[0].receive(tr_LLC_XID(xid_rx, apars.sapi));
|
|
[] as_xid(apars);
|
|
}
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_xid_empty_l3() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_xid_empty_l3), testcasename(), g_gb, 44);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_xid_n201u(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var template (value) XID_Information xid;
|
|
var template XID_Information xid_rx;
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
|
|
/* start MO XID */
|
|
xid := { ts_XID_N201U(1234) };
|
|
xid_rx := { tr_XID_N201U(1234) };
|
|
f_send_llc(ts_LLC_XID_MO_CMD(xid, apars.sapi));
|
|
alt {
|
|
[] BSSGP[0].receive(tr_LLC_XID_MT_RSP(xid_rx, apars.sapi));
|
|
[] as_xid(apars);
|
|
}
|
|
setverdict(pass);
|
|
}
|
|
testcase TC_xid_n201u() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_xid_n201u), testcasename(), g_gb, 45);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_pdp_act_gmm_detach(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
/* do a normal detach */
|
|
f_detach_mo(c_GMM_DTT_MO_GPRS, false, true);
|
|
}
|
|
|
|
testcase TC_attach_pdp_act_gmm_detach() runs on test_CT {
|
|
/* MS -> SGSN: Attach Request
|
|
* MS <-> SGSN: [..]
|
|
* MS -> SGSN: Attach Complete
|
|
* MS -> SGSN: PDP Activate Request
|
|
* MS <- SGSN: PDP Activate Accept
|
|
* MS -> SGSN: GMM Detach Request
|
|
* MS <- SGSN: GMM Detach Accept
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_pdp_act_gmm_detach), testcasename(), g_gb, 26);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private function f_TC_attach_req_id_req_ra_update(charstring id) runs on BSSGP_ConnHdlr {
|
|
var RoutingAreaIdentificationV old_ra := f_random_RAI();
|
|
var RoutingAreaIdentificationV new_ra := f_random_RAI();
|
|
while (old_ra == new_ra) { new_ra := f_random_RAI(); };
|
|
var template PDU_L3_MS_SGSN attach_req := ts_GMM_ATTACH_REQ(f_mi_get_lv(), old_ra, false, false, omit, omit);
|
|
var PDU_L3_SGSN_MS l3_mt;
|
|
|
|
f_send_l3(attach_req, 0);
|
|
|
|
BSSGP[0].receive(tr_GMM_ID_REQ(?));
|
|
|
|
f_send_l3(ts_GMM_RAU_REQ(f_mi_get_lv(), GPRS_UPD_T_RA, new_ra, false, omit, omit));
|
|
alt {
|
|
[] BSSGP[0].receive(tr_GMM_RAU_REJECT('0a'O)) {
|
|
setverdict(pass);
|
|
}
|
|
[] BSSGP[0].receive { repeat; }
|
|
}
|
|
}
|
|
|
|
/* This test triggers crash in osmo-sgsn before osmo-sgsn.git I64fa5cf1b427d3abb99e553e584897261a827ce6.
|
|
* See OS#3957 and OS#4245 for more information.
|
|
*/
|
|
testcase TC_attach_req_id_req_ra_update() runs on test_CT {
|
|
/*
|
|
* MS --> SGSN: Attach Req (TMSI, RAI=901-70-356-101)
|
|
* MS <-- SGSN: Identity Request (IMEI)
|
|
* MS --> SGSN: RA Updating (RAI=901-70-2758-208)
|
|
*/
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_attach_req_id_req_ra_update), testcasename(), g_gb, 47);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
private altstep as_nopaging_ps(integer ran_idx := 0) runs on BSSGP_ConnHdlr {
|
|
var PDU_BSSGP rx;
|
|
[] BSSGP_SIG[ran_idx].receive(tr_BSSGP_PS_PAGING(?)) -> value rx {
|
|
setverdict(fail, "Received unexpected PS PAGING: ", rx);
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
/* SUSPEND, then DL traffic: should not pass + no paging expected */
|
|
private function f_TC_suspend_nopaging(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var default d;
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100));
|
|
|
|
/* now suspend GPRS */
|
|
f_bssgp_suspend();
|
|
|
|
d := activate(as_nopaging_ps());
|
|
|
|
/* at this point we don't expect any downlink traffic at all, neither actual LLC/SNDCP data,
|
|
* nor any related paging requests */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), expect_fwd := false);
|
|
|
|
deactivate(d);
|
|
}
|
|
testcase TC_suspend_nopaging() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_suspend_nopaging), testcasename(), g_gb, 48);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
|
|
/* SUSPEND, then RESUME: data expected to flow after explicit resume */
|
|
private function f_TC_suspend_resume(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var OCT1 susp_ref;
|
|
var default d;
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100));
|
|
|
|
/* now suspend GPRS */
|
|
susp_ref := f_bssgp_suspend();
|
|
|
|
d := activate(as_nopaging_ps());
|
|
|
|
/* at this point we don't expect any downlink traffic at all, neither actual LLC/SNDCP data,
|
|
* nor any related paging requests */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), expect_fwd := false);
|
|
|
|
deactivate(d);
|
|
|
|
/* resume GPRS */
|
|
f_bssgp_resume(susp_ref);
|
|
|
|
/* now data should be flowing again */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100));
|
|
}
|
|
testcase TC_suspend_resume() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_suspend_resume), testcasename(), g_gb, 49);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* SUSPEND, then RAU: data expected to flow after implicit resume */
|
|
private function f_TC_suspend_rau(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var default d;
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100));
|
|
|
|
/* now suspend GPRS */
|
|
f_bssgp_suspend();
|
|
|
|
d := activate(as_nopaging_ps());
|
|
|
|
/* at this point we don't expect any downlink traffic at all, neither actual LLC/SNDCP data,
|
|
* nor any related paging requests */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), expect_fwd := false);
|
|
|
|
deactivate(d);
|
|
|
|
/* perform RAU (implicit RESUME) */
|
|
f_routing_area_update(g_pars.ra);
|
|
|
|
/* give SGSN some time to actually receve + process the RAU Complete we sent */
|
|
f_sleep(0.5);
|
|
|
|
/* now data should be flowing again */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100));
|
|
|
|
}
|
|
testcase TC_suspend_rau() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_suspend_rau), testcasename(), g_gb, 50);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
|
|
/* wait for T3314 expiration and check that PS PAGING is created on DL PDU */
|
|
private function f_TC_paging_ps(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
var default d;
|
|
|
|
/* first perform regular attach */
|
|
f_TC_attach(id);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100));
|
|
|
|
/* now wait for T3314 expiration (test_CT below has reduced it to 3s) */
|
|
f_sleep(5.0);
|
|
|
|
/* now data should be flowing again, but with PS PAGING */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100));
|
|
BSSGP_SIG[0].receive(tr_BSSGP_PS_PAGING(?));
|
|
|
|
/* FIXME: simulate paging response */
|
|
/* FIXME: verify PDU actually arrives only after paging response was successful */
|
|
|
|
}
|
|
testcase TC_paging_ps() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
f_vty_config(SGSNVTY, "sgsn", "timer 3314 3");
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_TC_paging_ps), testcasename(), g_gb, 51);
|
|
vc_conn.done;
|
|
f_vty_config(SGSNVTY, "sgsn", "timer 3314 default");
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Run a RIM single report procedure over the sgsn. Since the SGSN will only do a transparent routing of the
|
|
* RIM messages this basically tests if the message is correctly transfered from one GB interface to the
|
|
* other and vice versa. */
|
|
testcase TC_bssgp_rim_single_report() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
|
|
timer T := 2.0;
|
|
|
|
var template RIM_Routing_Address dst_addr;
|
|
var template RIM_Routing_Address src_addr;
|
|
var template RAN_Information_Request_RIM_Container req_cont;
|
|
var template RAN_Information_RIM_Container res_cont;
|
|
var template PDU_BSSGP bssgp_rim_pdu;
|
|
var template PDU_BSSGP bssgp_rim_pdu_expect;
|
|
|
|
dst_addr := t_RIM_Routing_Address_cid(g_gb[1].cfg.bvc[0].cell_id);
|
|
src_addr := t_RIM_Routing_Address_cid(g_gb[0].cfg.bvc[0].cell_id);
|
|
|
|
|
|
/* Send NACC Ran information request to SGSN at GB interface #0. We epect the SGSN to forward this request
|
|
* based on the cell id in dst_addr to GB interface #1. */
|
|
req_cont := ts_RAN_Information_Request_RIM_Container(ts_RIM_Application_Identity(RIM_APP_ID_NACC),
|
|
ts_RIM_Sequence_Number(1),
|
|
ts_RIM_PDU_Indications(false, RIM_PDU_TYPE_SING_REP),
|
|
ts_RIM_Protocol_Version_Number(1),
|
|
tsu_RAN_Information_Request_Application_Container_NACC(g_gb[1].cfg.bvc[0].cell_id),
|
|
omit);
|
|
bssgp_rim_pdu := ts_RAN_INFORMATION_REQUEST(ts_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, dst_addr),
|
|
ts_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, src_addr),
|
|
req_cont);
|
|
bssgp_rim_pdu_expect := tr_RAN_INFORMATION_REQUEST(tr_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, dst_addr),
|
|
tr_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, src_addr),
|
|
tr_RAN_Information_Request_RIM_Container);
|
|
RIM[0].send(bssgp_rim_pdu);
|
|
T.start;
|
|
alt {
|
|
[] RIM[1].receive(bssgp_rim_pdu_expect) {
|
|
setverdict(pass);
|
|
}
|
|
[] RIM[1].receive {
|
|
setverdict(fail, "Unexpected BSSGP RIM PDU received");
|
|
}
|
|
[] T.timeout {
|
|
setverdict(fail, "No BSSGP RIM PDU received");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
/* Now also emulate also the response as well and send it back on GB interface #1. Expect the result on
|
|
* GB interface #0 */
|
|
res_cont := ts_RAN_Information_RIM_Container(ts_RIM_Application_Identity(RIM_APP_ID_NACC),
|
|
ts_RIM_Sequence_Number(2),
|
|
ts_RIM_PDU_Indications(false, RIM_PDU_TYPE_SING_REP),
|
|
ts_RIM_Protocol_Version_Number(1),
|
|
tsu_ApplContainer_or_ApplErrContainer_NACC(tsu_ApplContainer_NACC(g_gb[0].cfg.bvc[0].cell_id, false, 3, si_default)),
|
|
omit);
|
|
bssgp_rim_pdu := ts_PDU_BSSGP_RAN_INFORMATION(ts_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, src_addr),
|
|
ts_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, dst_addr),
|
|
res_cont);
|
|
bssgp_rim_pdu_expect := tr_PDU_BSSGP_RAN_INFORMATION(tr_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, src_addr),
|
|
tr_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, dst_addr),
|
|
?);
|
|
RIM[1].send(bssgp_rim_pdu);
|
|
T.start;
|
|
alt {
|
|
[] RIM[0].receive(bssgp_rim_pdu_expect) {
|
|
setverdict(pass);
|
|
}
|
|
[] RIM[0].receive {
|
|
setverdict(fail, "Unexpected BSSGP RIM PDU received");
|
|
}
|
|
[] T.timeout {
|
|
setverdict(fail, "No BSSGP RIM PDU received");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
f_cleanup();
|
|
}
|
|
|
|
testcase TC_rim_eutran_to_geran() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
/* connect RIM related port */
|
|
connect(vc_GTP:CLIENT_DEFAULT, self:GTPC);
|
|
|
|
var GtpPeer peer := {
|
|
connId := 1,
|
|
remName := mp_sgsn_gtp_ip,
|
|
remPort := GTP1C_PORT
|
|
}
|
|
|
|
var template (value) RIM_Routing_Address_GTPC gtpc_dst_addr, gtpc_src_addr;
|
|
var template (value) RAN_Information_Request_RIM_Container_GTPC gtpc_rim_req_cont;
|
|
var template (value) PDU_BSSGP_RAN_INFORMATION_REQUEST_GTPC gtpc_bssgp_cont;
|
|
var template (value) Gtp1cUnitdata gtpc_pdu;
|
|
|
|
gtpc_dst_addr := t_GTPC_RIM_Routing_Address_cid(g_gb[1].cfg.bvc[0].cell_id);
|
|
gtpc_src_addr := t_GTPC_RIM_Routing_Address_enbid(g_gb[1].cfg.bvc[0].cell_id, tac := 3, gnbid := '12345678123456'O);
|
|
|
|
gtpc_rim_req_cont := ts_GTPC_RAN_Information_Request_RIM_Container(ts_GTPC_RIM_Application_Identity(RIM_APP_ID_NACC),
|
|
ts_GTPC_RIM_Sequence_Number(1),
|
|
ts_GTPC_RIM_PDU_Indications(false, RIM_PDU_TYPE_SING_REP),
|
|
ts_GTPC_RIM_Protocol_Version_Number(1),
|
|
tsu_GTPC_RAN_Information_Request_Application_Container_NACC(g_gb[1].cfg.bvc[0].cell_id),
|
|
omit);
|
|
gtpc_bssgp_cont := ts_GTPC_RAN_Information_Request(ts_GTPC_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, gtpc_dst_addr),
|
|
ts_GTPC_RIM_Routing_Information(RIM_ADDR_EUTRAN_NODEB_ID, gtpc_src_addr),
|
|
gtpc_rim_req_cont);
|
|
gtpc_pdu := ts_GTPC_RANInfoRelay(peer, ts_RANTransparentContainer_RAN_INFO_REQ(gtpc_bssgp_cont));
|
|
GTPC.send(gtpc_pdu);
|
|
|
|
var template RIM_Routing_Address bssgp_dst_addr, bssgp_src_addr;
|
|
var template PDU_BSSGP bssgp_rim_pdu_expect;
|
|
bssgp_dst_addr := t_RIM_Routing_Address_cid(g_gb[1].cfg.bvc[0].cell_id);
|
|
bssgp_src_addr := t_RIM_Routing_Address_enbid(g_gb[1].cfg.bvc[0].cell_id, tac := 3, gnbid := '12345678123456'O);
|
|
bssgp_rim_pdu_expect := tr_RAN_INFORMATION_REQUEST(tr_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, bssgp_dst_addr),
|
|
tr_RIM_Routing_Information(RIM_ADDR_EUTRAN_NODEB_ID, bssgp_src_addr),
|
|
tr_RAN_Information_Request_RIM_Container);
|
|
timer T := 2.0;
|
|
T.start;
|
|
alt {
|
|
[] RIM[1].receive(bssgp_rim_pdu_expect) {
|
|
setverdict(pass);
|
|
T.stop;
|
|
}
|
|
[] RIM[1].receive {
|
|
setverdict(fail, "Unexpected BSSGP RIM PDU received");
|
|
}
|
|
[] T.timeout {
|
|
setverdict(fail, "No BSSGP RIM PDU received");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
/* Now also emulate also the response as well and send it back on GB
|
|
interface #1. Expect the result on * GTPC */
|
|
var template RAN_Information_RIM_Container res_cont;
|
|
var template PDU_BSSGP bssgp_rim_pdu;
|
|
res_cont := ts_RAN_Information_RIM_Container(ts_RIM_Application_Identity(RIM_APP_ID_NACC),
|
|
ts_RIM_Sequence_Number(2),
|
|
ts_RIM_PDU_Indications(false, RIM_PDU_TYPE_SING_REP),
|
|
ts_RIM_Protocol_Version_Number(1),
|
|
tsu_ApplContainer_or_ApplErrContainer_NACC(tsu_ApplContainer_NACC(g_gb[1].cfg.bvc[0].cell_id, false, 3, si_default)),
|
|
omit);
|
|
bssgp_rim_pdu := ts_PDU_BSSGP_RAN_INFORMATION(ts_RIM_Routing_Information(RIM_ADDR_EUTRAN_NODEB_ID, bssgp_src_addr),
|
|
ts_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, bssgp_dst_addr),
|
|
res_cont);
|
|
RIM[1].send(bssgp_rim_pdu);
|
|
|
|
var template RAN_Information_RIM_Container_GTPC rim_cont;
|
|
var template PDU_BSSGP_RAN_INFORMATION_GTPC gtpc_bssgp_cont_ack;
|
|
var template Gtp1cUnitdata gtpc_pdu_exp;
|
|
rim_cont := tr_GTPC_RAN_Information_RIM_Container(ts_GTPC_RIM_Application_Identity(RIM_APP_ID_NACC),
|
|
ts_GTPC_RIM_Sequence_Number(2),
|
|
ts_GTPC_RIM_PDU_Indications(false, RIM_PDU_TYPE_SING_REP),
|
|
ts_GTPC_RIM_Protocol_Version_Number(1),
|
|
tru_GTPC_ApplContainer_or_ApplErrContainer_NACC(tru_GTPC_ApplContainer_NACC(g_gb[1].cfg.bvc[0].cell_id, false, 3, si_default)),
|
|
omit);
|
|
gtpc_bssgp_cont_ack := tr_GTPC_RAN_Information(tr_GTPC_RIM_Routing_Information(RIM_ADDR_EUTRAN_NODEB_ID, gtpc_src_addr),
|
|
tr_GTPC_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, gtpc_dst_addr),
|
|
rim_cont);
|
|
gtpc_pdu_exp := tr_GTPC_RANInfoRelay(peer, tr_RANTransparentContainer_RAN_INFO(gtpc_bssgp_cont_ack));
|
|
|
|
T.start;
|
|
alt {
|
|
[] GTPC.receive(gtpc_pdu_exp) {
|
|
setverdict(pass);
|
|
T.stop;
|
|
}
|
|
[] GTPC.receive {
|
|
setverdict(fail, "Unexpected GTPC RIM PDU received");
|
|
}
|
|
[] T.timeout {
|
|
setverdict(fail, "No GTPC RIM PDU received");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Test if the SGSN routes traffic to new cell after the MS attached to it */
|
|
private function f_TC_cell_change_different_rai_ci_attach(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
/* first perform regular attach */
|
|
f_gmm_attach(false, false, ran_index := 0);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars, ran_index := 0);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), ran_index := 0);
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200), ran_index := 0);
|
|
|
|
/* Now attach on different cell: */
|
|
f_bssgp_client_unregister(g_pars.imsi, BSSGP_PROC[0]);
|
|
f_bssgp_client_register(g_pars.imsi, g_pars.tlli, BSSGP_PROC[1]);
|
|
g_pars.net.expect_auth := false;
|
|
f_gmm_attach(false, false, ran_index := 1, old_ra := f_cellid_to_RAI(g_pars.bssgp_cell_id[0]));
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), ran_index := 1);
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200), ran_index := 1, n_u := 1);
|
|
}
|
|
testcase TC_cell_change_different_rai_ci_attach() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_cell_change_different_rai_ci_attach), testcasename(), g_gb, 68);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Test if the SGSN routes traffic to new cell after the MS attached to it */
|
|
/* Assumption: g_gb[1] and g_gb[2] configured with same RAC */
|
|
private function f_TC_cell_change_different_ci_attach(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
f_bssgp_client_unregister(g_pars.imsi, BSSGP_PROC[0]);
|
|
f_bssgp_client_register(g_pars.imsi, g_pars.tlli, BSSGP_PROC[1]);
|
|
|
|
/* first perform regular attach */
|
|
f_gmm_attach(false, false, ran_index := 1);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars, ran_index := 1);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), ran_index := 1);
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200), ran_index := 1);
|
|
|
|
/* Now attach on different cell: */
|
|
f_bssgp_client_unregister(g_pars.imsi, BSSGP_PROC[1]);
|
|
f_bssgp_client_register(g_pars.imsi, g_pars.tlli, BSSGP_PROC[2]);
|
|
g_pars.net.expect_auth := false;
|
|
f_gmm_attach(false, false, ran_index := 2, old_ra := f_cellid_to_RAI(g_pars.bssgp_cell_id[1]));
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), ran_index := 2);
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200), ran_index := 2, n_u := 1);
|
|
}
|
|
testcase TC_cell_change_different_ci_attach() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_cell_change_different_ci_attach), testcasename(), g_gb, 69);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Test if the SGSN silently drops MO data message coming from new BVCI if RAC changed (eg. cell change) */
|
|
private function f_TC_cell_change_different_rai_ci_data(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
/* first perform regular attach */
|
|
f_gmm_attach(false, false, ran_index := 0);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars, ran_index := 0);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), ran_index := 0);
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200), ran_index := 0);
|
|
|
|
/* Send some data over new bvci, it should be silently discarded since
|
|
* RAC changed and SGSN expects a RAU to occur in that case */
|
|
f_bssgp_client_register(g_pars.imsi, g_pars.tlli, BSSGP_PROC[1]);
|
|
var octetstring payload := f_rnd_octstring(200);
|
|
var PDU_SN sndcp := valueof(ts_SN_UD(apars.nsapi, payload));
|
|
BSSGP[1].send(ts_LLC_UI(enc_PDU_SN(sndcp), apars.sapi, '0'B, 1));
|
|
var GtpPeer peer := valueof(ts_GtpPeerU(apars.sgsn_ip_u));
|
|
timer T := 2.0;
|
|
T.start;
|
|
alt {
|
|
[] GTP.receive(tr_GTPU_GPDU(peer, apars.ggsn_tei_u, payload)) {
|
|
setverdict(fail, "Unexpected GTP message");
|
|
}
|
|
[] T.timeout { setverdict(pass); }
|
|
}
|
|
|
|
/* Expect SGSN to continue routing DL data to last known NSEI+BVCI */
|
|
f_bssgp_client_unregister(g_pars.imsi, BSSGP_PROC[1]);
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), ran_index := 0);
|
|
}
|
|
testcase TC_cell_change_different_rai_ci_data() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_cell_change_different_rai_ci_data), testcasename(), g_gb, 70);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
/* Test if the SGSN routes traffic to new cell after the MS switched cell without re-attaching */
|
|
/* Assumption: g_gb[1] and g_gb[2] configured with same RAC */
|
|
private function f_TC_cell_change_different_ci_data(charstring id) runs on BSSGP_ConnHdlr {
|
|
var PdpActPars apars := valueof(t_PdpActPars(mp_ggsn_ip));
|
|
|
|
f_bssgp_client_unregister(g_pars.imsi, BSSGP_PROC[0]);
|
|
f_bssgp_client_register(g_pars.imsi, g_pars.tlli, BSSGP_PROC[1]);
|
|
|
|
/* first perform regular attach */
|
|
f_gmm_attach(false, false, ran_index := 1);
|
|
/* then activate PDP context */
|
|
f_pdp_ctx_act(apars, ran_index := 1);
|
|
/* then transceive a downlink PDU */
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), ran_index := 1);
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200), ran_index := 1);
|
|
|
|
/* Now attach on different cell: */
|
|
f_bssgp_client_unregister(g_pars.imsi, BSSGP_PROC[1]);
|
|
f_bssgp_client_register(g_pars.imsi, g_pars.tlli, BSSGP_PROC[2]);
|
|
|
|
f_gtpu_xceive_mo(apars, f_rnd_octstring(200), ran_index := 2, n_u := 1);
|
|
f_gtpu_xceive_mt(apars, f_rnd_octstring(100), ran_index := 2);
|
|
}
|
|
testcase TC_cell_change_different_ci_data() runs on test_CT {
|
|
var BSSGP_ConnHdlr vc_conn;
|
|
f_init();
|
|
vc_conn := f_start_handler(refers(f_TC_cell_change_different_ci_data), testcasename(), g_gb, 71);
|
|
vc_conn.done;
|
|
f_cleanup();
|
|
}
|
|
|
|
control {
|
|
execute( TC_attach() );
|
|
execute( TC_attach_mnc3() );
|
|
execute( TC_attach_umts_aka_umts_res() );
|
|
execute( TC_attach_umts_aka_gsm_sres() );
|
|
execute( TC_attach_auth_id_timeout() );
|
|
execute( TC_attach_auth_sai_timeout() );
|
|
execute( TC_attach_auth_sai_reject() );
|
|
execute( TC_attach_gsup_lu_timeout() );
|
|
execute( TC_attach_gsup_lu_reject() );
|
|
execute( TC_attach_combined() );
|
|
execute( TC_attach_accept_all() );
|
|
execute( TC_attach_closed() );
|
|
execute( TC_attach_no_imei_response() );
|
|
execute( TC_attach_no_imsi_response() );
|
|
execute( TC_attach_closed_add_vty(), 20.0 );
|
|
execute( TC_attach_check_subscriber_list(), 20.0 );
|
|
execute( TC_attach_detach_check_subscriber_list(), 20.0 );
|
|
execute( TC_attach_check_complete_resend() );
|
|
execute( TC_hlr_location_cancel_request_update(), 20.0 );
|
|
execute( TC_hlr_location_cancel_request_withdraw(), 20.0 );
|
|
execute( TC_hlr_location_cancel_request_unknown_subscriber_withdraw(), 20.0 );
|
|
execute( TC_hlr_location_cancel_request_unknown_subscriber_update(), 20.0 );
|
|
execute( TC_rau_unknown() );
|
|
execute( TC_attach_rau() );
|
|
execute( TC_attach_rau_a_a() );
|
|
execute( TC_attach_rau_a_b() );
|
|
execute( TC_attach_usim_resync() );
|
|
execute( TC_detach_unknown_nopoweroff() );
|
|
execute( TC_detach_unknown_poweroff() );
|
|
execute( TC_detach_nopoweroff() );
|
|
execute( TC_detach_poweroff() );
|
|
execute( TC_attach_pdp_act() );
|
|
execute( TC_pdp_act_unattached() );
|
|
execute( TC_attach_pdp_act_user() );
|
|
execute( TC_attach_pdp_act_ggsn_reject() );
|
|
execute( TC_attach_pdp_act_user_deact_mo() );
|
|
execute( TC_attach_pdp_act_user_deact_mt() );
|
|
execute( TC_attach_pdp_act_deact_dup() );
|
|
execute( TC_attach_second_attempt() );
|
|
execute( TC_attach_echo_timeout() );
|
|
execute( TC_attach_restart_ctr_echo() );
|
|
execute( TC_attach_restart_ctr_create() );
|
|
execute( TC_attach_pdp_act_deact_mt_t3395_expire() );
|
|
execute( TC_attach_pdp_act_deact_gtp_retrans() );
|
|
execute( TC_attach_pdp_act_deact_gtp_retrans_resp() );
|
|
execute( TC_attach_pdp_act_user_error_ind_ggsn() );
|
|
execute( TC_attach_pdp_act_gmm_detach() );
|
|
execute( TC_attach_gmm_attach_req_while_gmm_attach() );
|
|
|
|
execute( TC_xid_empty_l3() );
|
|
execute( TC_xid_n201u() );
|
|
|
|
execute( TC_llc_null() );
|
|
execute( TC_llc_sabm_dm_llgmm() );
|
|
execute( TC_llc_sabm_dm_ll5() );
|
|
|
|
execute( TC_suspend_nopaging() );
|
|
execute( TC_suspend_resume() );
|
|
execute( TC_suspend_rau() );
|
|
execute( TC_paging_ps() );
|
|
|
|
execute( TC_bssgp_rim_single_report() );
|
|
execute( TC_rim_eutran_to_geran() );
|
|
|
|
execute( TC_cell_change_different_rai_ci_attach() );
|
|
execute( TC_cell_change_different_rai_ci_data() );
|
|
execute( TC_cell_change_different_ci_attach() );
|
|
execute( TC_cell_change_different_ci_data() );
|
|
|
|
/* At the end, may crash osmo-sgsn, see OS#3957, OS#4245 */
|
|
execute( TC_attach_req_id_req_ra_update() );
|
|
}
|
|
|
|
|
|
|
|
}
|