|
|
|
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.2";
|
|
|
|
integer mp_echo_interval := 5; /* in seconds. Only used in test enabling g_use_echo */
|
|
|
|
|
|
|
|
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"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
nsvci := 97
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
nsei := 97,
|
|
|
|
role_sgsn := false,
|
|
|
|
handle_sns := false,
|
|
|
|
nsvc := {
|
|
|
|
{
|
|
|
|
provider := {
|
|
|
|
ip := {
|
|
|
|
address_family := AF_INET,
|
|
|
|
local_udp_port := 21011,
|
|
|
|
local_ip := "127.0.0.1",
|
|
|
|
remote_udp_port := 23000,
|
|
|
|
remote_ip := "127.0.0.1"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
nsvci := 98
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
nsei := 98,
|
|
|
|
role_sgsn := false,
|
|
|
|
handle_sns := false,
|
|
|
|
nsvc := {
|
|
|
|
{
|
|
|
|
provider := {
|
|
|
|
ip := {
|
|
|
|
address_family := AF_INET,
|
|
|
|
local_udp_port := 21012,
|
|
|
|
local_ip := "127.0.0.1",
|
|
|
|
remote_udp_port := 23000,
|
|
|
|
remote_ip := "127.0.0.1"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
nsvci := 99
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
private function f_cellid_to_RAI(in BssgpCellId cell_id) return RoutingAreaIdentificationV {
|
|
|
|
/* mcc_mnc is encoded as of 24.008 10.5.5.15 */
|
|
|
|
var BcdMccMnc mcc_mnc := cell_id.ra_id.lai.mcc_mnc;
|
|
|
|
|
|
|
|
var RoutingAreaIdentificationV ret := {
|
|
|
|
mccDigit1 := mcc_mnc[0],
|
|
|
|
mccDigit2 := mcc_mnc[1],
|
|
|
|
mccDigit3 := mcc_mnc[2],
|
|
|
|
mncDigit3 := mcc_mnc[3],
|
|
|
|
mncDigit1 := mcc_mnc[4],
|
|
|
|
mncDigit2 := mcc_mnc[5],
|
|
|
|
lac := int2oct(cell_id.ra_id.lai.lac, 16),
|
|
|
|
rac := int2oct(cell_id.ra_id.rac, 8)
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
|
|
|
|
private function f_init_gb(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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
BSSGP_Emulation: add BssgpDecodeDepth
Make the decoding level (BSSGP, LLC, SNDCP, L3) configurable, so the
existing PCU tests, that expect messages only decoded to the BSSGP
level, can pass again. Move the SNDCP decoding in f_dec_bssgp above the
L3 decoding, so f_dec_bssgp goes through the layers in the reverse order
of f_send_bssgp_dec.
I have verified, that all testsuites using the BSSGP Emulation (SGSN,
PCU, PCU-SNS) are still working with this patch.
Related: OS#4180
Fixes: 955aa94504510139a12d223071cf49ef90788a3d ("BSSGP_Emulation: Abandon "BssgpDecoded" intermediate structure")
Change-Id: I8f76385528c1de98c557cee451c0e0dfd182b605
4 years ago
|
|
|
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,
|
BSSGP_Emulation: add BssgpDecodeDepth
Make the decoding level (BSSGP, LLC, SNDCP, L3) configurable, so the
existing PCU tests, that expect messages only decoded to the BSSGP
level, can pass again. Move the SNDCP decoding in f_dec_bssgp above the
L3 decoding, so f_dec_bssgp goes through the layers in the reverse order
of f_send_bssgp_dec.
I have verified, that all testsuites using the BSSGP Emulation (SGSN,
PCU, PCU-SNS) are still working with this patch.
Related: OS#4180
Fixes: 955aa94504510139a12d223071cf49ef90788a3d ("BSSGP_Emulation: Abandon "BssgpDecoded" intermediate structure")
Change-Id: I8f76385528c1de98c557cee451c0e0dfd182b605
4 years ago
|
|
|
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 := {
|
|
|
|
nsei := 98,
|
BSSGP_Emulation: add BssgpDecodeDepth
Make the decoding level (BSSGP, LLC, SNDCP, L3) configurable, so the
existing PCU tests, that expect messages only decoded to the BSSGP
level, can pass again. Move the SNDCP decoding in f_dec_bssgp above the
L3 decoding, so f_dec_bssgp goes through the layers in the reverse order
of f_send_bssgp_dec.
I have verified, that all testsuites using the BSSGP Emulation (SGSN,
PCU, PCU-SNS) are still working with this patch.
Related: OS#4180
Fixes: 955aa94504510139a12d223071cf49ef90788a3d ("BSSGP_Emulation: Abandon "BssgpDecoded" intermediate structure")
Change-Id: I8f76385528c1de98c557cee451c0e0dfd182b605
4 years ago
|
|
|
sgsn_role := false,
|
|
|
|
bvc := {
|
|
|
|
{
|
|
|
|
bvci := 220,
|
|
|
|
cell_id := {
|
|
|
|
ra_id := {
|
|
|
|
lai := {
|
|
|
|
mcc_mnc := mcc_mnc,
|
|
|
|
lac := 13300
|
|
|
|
},
|
|
|
|
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) runs on BSSGP_ConnHdlr {
|
|
|
|
/* mandatory IE */
|
|
|
|
var hexstring aa_plmn := f_RAI_to_plmn_hexstr(aa.routingAreaIdentification);
|
|
|
|
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[0].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);
|
|
|
|
}
|
|
|
|
if (ispresent(aa.msIdentity)) {
|
|
|
|
setverdict(fail, "unexpected TMSI allocation in non-combined attach");
|
|
|
|
mtc.stop;
|
|
|
|
}
|
|