You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
osmo-ttcn3-hacks/sgsn/SGSN_Tests.ttcn

3206 lines
99 KiB

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,
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 := {
nsei := 98,
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;
}