osmo-ttcn3-hacks/sgsn/SGSN_Tests.ttcn

523 lines
14 KiB
Plaintext
Raw Normal View History

module SGSN_Tests {
import from General_Types all;
import from Osmocom_Types 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 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 TELNETasp_PortType all;
import from Osmocom_VTY_Functions 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;
};
type record GbInstance {
NS_CT vc_NS,
BSSGP_CT vc_BSSGP,
BssgpConfig cfg
};
type component test_CT {
var GbInstance g_gb[3];
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;
port TELNETasp_PT SGSNVTY;
var boolean g_initialized := false;
};
type component BSSGP_ConnHdlr extends BSSGP_Client_CT, GSUP_ConnHdlr {
var BSSGP_ConnHdlrPars g_pars;
timer g_Tguard;
}
type record SGSN_ConnHdlrNetworkPars {
boolean expect_ptmsi,
boolean expect_auth,
boolean expect_ciph
};
type record BSSGP_ConnHdlrPars {
/* IMEI of the simulated ME */
hexstring imei,
/* IMEI 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,
/* TLLI of the simulated MS */
OCT4 tlli,
RoutingAreaIdentificationV ra optional,
BssgpCellId bssgp_cell_id,
AuthVector vec optional,
SGSN_ConnHdlrNetworkPars net,
float t_guard
};
private function f_init_gb(inout GbInstance gb) runs on test_CT {
gb.vc_NS := NS_CT.create;
gb.vc_BSSGP := BSSGP_CT.create;
/* connect lower end of BSSGP emulation with NS upper port */
connect(gb.vc_BSSGP:BSCP, gb.vc_NS:NS_SP);
/* connect lower end of NS emulation to NS codec port (on top of IPL4) */
map(gb.vc_NS:NSCP, system:NS_CODEC_PORT);
gb.vc_NS.start(NSStart());
gb.vc_BSSGP.start(BssgpStart(gb.cfg));
}
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(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP)) { }
[] T.timeout {
setverdict(fail, "No connection to GSUP Port");
self.stop;
}
}
}
private 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_config(SGSNVTY, "sgsn", "auth-policy remote");
}
function f_init() runs on test_CT {
if (g_initialized == true) {
return;
}
g_initialized := true;
g_gb[0].cfg := {
nsei := 96,
bvci := 196,
cell_id := {
ra_id := {
lai := {
mcc_mnc := '26242F'H, lac := 13135},
rac := 0
},
cell_id := 20960
},
sgsn_role := false
};
f_init_gb(g_gb[0]);
f_init_gsup("SGSN_Test");
f_init_vty();
}
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, GbInstance 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,
tlli := f_gprs_tlli_random(),
ra := omit,
bssgp_cell_id := gb.cfg.cell_id,
vec := omit,
net := net_pars,
t_guard := t_guard
};
vc_conn := BSSGP_ConnHdlr.create(id);
connect(vc_conn:BSSGP, gb.vc_BSSGP:BSSGP_SP);
connect(vc_conn:BSSGP_PROC, gb.vc_BSSGP:BSSGP_PROC);
connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT);
connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_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");
self.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;
/* register with BSSGP core */
f_bssgp_client_register(g_pars.imsi, g_pars.tlli, g_pars.bssgp_cell_id);
/* tell GSUP dispatcher to send this IMSI to us */
f_create_gsup_expect(hex2str(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:
* RAU without Attach
* Detach without Attach
* SM procedures without attach / RAU
* ATTACH / RAU
** with / without authentication
** with / without P-TMSI allocation
** timeout from HLR on SAI
** timeout from HLR on UL
** reject from HLR on SAI
** reject from HLR on UL
* 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
** reject from GGSN
*/
testcase TC_wait_ns_up() runs on test_CT {
f_init();
f_sleep(20.0);
}
altstep as_mm_identity() runs on BSSGP_ConnHdlr {
var MobileIdentityLV mi;
[] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ID_REQ('001'B))) {
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
BSSGP.send(ts_GMM_ID_RESP(mi));
repeat;
}
[] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ID_REQ('010'B))) {
mi := valueof(ts_MI_IMEI_LV(g_pars.imei));
BSSGP.send(ts_GMM_ID_RESP(mi));
repeat;
}
}
function f_gmm_auth () runs on BSSGP_ConnHdlr {
var BssgpDecoded bd;
var PDU_L3_MS_SGSN l3_mo;
var PDU_L3_SGSN_MS l3_mt;
var default di := activate(as_mm_identity());
if (g_pars.net.expect_auth) {
g_pars.vec := f_gen_auth_vec_2g();
var GSUP_IE auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(g_pars.vec.rand,
g_pars.vec.sres,
g_pars.vec.kc));
GSUP.receive(tr_GSUP_SAI_REQ(g_pars.imsi));
GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple));
BSSGP.receive(tr_BD_L3_MT(tr_GMM_AUTH_REQ(g_pars.vec.rand))) -> value bd;
l3_mt := bd.l3_mt;
var BIT4 ac_ref := l3_mt.msgs.gprs_mm.authenticationAndCipheringRequest.acReferenceNumber.valueField;
l3_mo := valueof(ts_GMM_AUTH_RESP_2G(ac_ref, g_pars.vec.sres));
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));
}
BSSGP.send(l3_mo);
} else {
/* wait for identity procedure */
f_sleep(1.0);
}
deactivate(di);
}
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));
}
private function f_TC_attach(charstring id) runs on BSSGP_ConnHdlr {
var MobileIdentityLV mi;
var RoutingAreaIdentificationV old_ra := f_random_RAI();
if (ispresent(g_pars.p_tmsi)) {
mi := valueof(ts_MI_TMSI_LV(g_pars.p_tmsi));
} else {
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
}
BSSGP.send(ts_GMM_ATTACH_REQ(mi, 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_ISD_REQ(g_pars.imsi, g_pars.msisdn));
GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi));
GSUP.send(ts_GSUP_UL_RES(g_pars.imsi));
BSSGP.receive(tr_BD_L3_MT(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?)));
BSSGP.send(ts_GMM_ATTACH_COMPL);
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[0], 1);
vc_conn.done;
}
/* MS never responds to ID REQ, expect ATTACH REJECT */
private function f_TC_attach_auth_id_timeout(charstring id) runs on BSSGP_ConnHdlr {
var MobileIdentityLV mi;
var RoutingAreaIdentificationV old_ra := f_random_RAI();
if (ispresent(g_pars.p_tmsi)) {
mi := valueof(ts_MI_TMSI_LV(g_pars.p_tmsi));
} else {
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
}
BSSGP.send(ts_GMM_ATTACH_REQ(mi, old_ra, false, false, omit, omit));
alt {
[] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ID_REQ(?))) {
/* don't send ID Response */
repeat;
}
[] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ATTACH_REJECT('09'O))) {
setverdict(pass);
}
[] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ATTACH_REJECT(?))) {
setverdict(fail, "Wrong Attach Reject Cause");
}
}
}
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[0], 2, 40.0);
vc_conn.done;
}
/* HLR never responds to SAI REQ, expect ATTACH REJECT */
private function f_TC_attach_auth_sai_timeout(charstring id) runs on BSSGP_ConnHdlr {
var MobileIdentityLV mi;
var RoutingAreaIdentificationV old_ra := f_random_RAI();
if (ispresent(g_pars.p_tmsi)) {
mi := valueof(ts_MI_TMSI_LV(g_pars.p_tmsi));
} else {
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
}
BSSGP.send(ts_GMM_ATTACH_REQ(mi, 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.receive(tr_BD_L3_MT(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[0], 3);
vc_conn.done;
}
/* HLR never responds to UL REQ, expect ATTACH REJECT */
private function f_TC_attach_gsup_lu_timeout(charstring id) runs on BSSGP_ConnHdlr {
var MobileIdentityLV mi;
var RoutingAreaIdentificationV old_ra := f_random_RAI();
if (ispresent(g_pars.p_tmsi)) {
mi := valueof(ts_MI_TMSI_LV(g_pars.p_tmsi));
} else {
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
}
BSSGP.send(ts_GMM_ATTACH_REQ(mi, 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.receive(tr_BD_L3_MT(tr_GMM_ATTACH_REJECT(?))) {
setverdict(pass);
}
[] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?))) {
setverdict(fail);
}
}
}
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[0], 4);
vc_conn.done;
}
/* 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 MobileIdentityLV mi;
var RoutingAreaIdentificationV old_ra := f_random_RAI();
if (ispresent(g_pars.p_tmsi)) {
mi := valueof(ts_MI_TMSI_LV(g_pars.p_tmsi));
} else {
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
}
BSSGP.send(ts_GMM_ATTACH_REQ(mi, old_ra, true, 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_ISD_REQ(g_pars.imsi, g_pars.msisdn));
GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi));
GSUP.send(ts_GSUP_UL_RES(g_pars.imsi));
BSSGP.receive(tr_BD_L3_MT(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?)));
BSSGP.send(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[0], 5);
vc_conn.done;
}
/* Attempt of GPRS ATTACH in 'accept all' mode */
private function f_TC_attach_accept_all(charstring id) runs on BSSGP_ConnHdlr {
var MobileIdentityLV mi;
var RoutingAreaIdentificationV old_ra := f_random_RAI();
g_pars.net.expect_auth := false;
if (ispresent(g_pars.p_tmsi)) {
mi := valueof(ts_MI_TMSI_LV(g_pars.p_tmsi));
} else {
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
}
BSSGP.send(ts_GMM_ATTACH_REQ(mi, old_ra, false, false, omit, omit));
f_gmm_auth();
BSSGP.receive(tr_BD_L3_MT(tr_GMM_ATTACH_ACCEPT('001'B, ?, ?)));
BSSGP.send(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[0], 6);
vc_conn.done;
}
/* Attempt of GPRS ATTACH in 'accept all' mode */
private function f_TC_attach_closed_foreign(charstring id) runs on BSSGP_ConnHdlr {
var MobileIdentityLV mi;
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.bssgp_cell_id);
g_pars.net.expect_auth := false;
if (ispresent(g_pars.p_tmsi)) {
mi := valueof(ts_MI_TMSI_LV(g_pars.p_tmsi));
} else {
mi := valueof(ts_MI_IMSI_LV(g_pars.imsi));
}
BSSGP.send(ts_GMM_ATTACH_REQ(mi, old_ra, false, false, omit, omit));
alt {
[] as_mm_identity();
[] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ATTACH_REJECT('07'O))) {
setverdict(pass);
}
[] BSSGP.receive(tr_BD_L3_MT(tr_GMM_ATTACH_REJECT(?))) {
setverdict(pass);
}
}
}
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[0], 7);
vc_conn.done;
/* test with home IMSI: Must Accept */
vc_conn := f_start_handler(refers(f_TC_attach_accept_all), testcasename(), g_gb[0], 8);
vc_conn.done;
}
control {
execute( TC_attach() );
execute( TC_attach_auth_id_timeout() );
execute( TC_attach_auth_sai_timeout() );
execute( TC_attach_gsup_lu_timeout() );
execute( TC_attach_combined() );
execute( TC_attach_accept_all() );
execute( TC_attach_closed() );
}
}