pespin has uploaded this change for review.

View Change

sgsn: Move BSSGP_ConnHdlr code to its own file

This was we split generic code from test specific code, making it easier
to focus on new test and finding generic functions which can be reused.
This is similar to what we already use in tons of other testsuites.

Related: SYS#5435
Change-Id: I0591cab8cca5195b8648920d5f79acc536a4efac
---
A sgsn/BSSGP_ConnHdlr.ttcn
M sgsn/SGSN_Tests.ttcn
M sgsn/SGSN_Tests_Iu.ttcn
3 files changed, 924 insertions(+), 842 deletions(-)

git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/45/37545/1
diff --git a/sgsn/BSSGP_ConnHdlr.ttcn b/sgsn/BSSGP_ConnHdlr.ttcn
new file mode 100644
index 0000000..b906d43
--- /dev/null
+++ b/sgsn/BSSGP_ConnHdlr.ttcn
@@ -0,0 +1,902 @@
+module BSSGP_ConnHdlr {
+
+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_Types all;
+import from GSUP_Templates all;
+import from GSUP_Emulation 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 GTPv1C_CodecPort all;
+import from GTPv1U_CodecPort all;
+import from GTPC_Types all;
+import from GTPU_Types all;
+import from GTPv1C_Templates all;
+import from GTPv1U_Templates all;
+import from GTP_Emulation 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 MobileL3_MM_Types all;
+
+const integer NUM_GB := 3;
+type record length(NUM_GB) of BssgpCellId BssgpCellIds;
+
+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
+};
+
+template (value) SGSN_ConnHdlrNetworkPars t_NetPars(
+ template (value) boolean expect_ptmsi := true,
+ template (value) boolean expect_auth := true,
+ template (value) boolean expect_ciph := false) := {
+ expect_ptmsi := expect_ptmsi,
+ expect_auth := expect_auth,
+ expect_ciph := 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
+};
+
+function f_new_BSSGP_ConnHdlrPars(integer imsi_suffix,
+ template (value) BssgpCellIds cell_ids,
+ template (value) SGSN_ConnHdlrNetworkPars net_pars := t_NetPars(),
+ float t_guard := 30.0) return BSSGP_ConnHdlrPars {
+ var template (value) BSSGP_ConnHdlrPars pars;
+ 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 := cell_ids,
+ rnc_send_initial_ue := true,
+ vec := omit,
+ net := net_pars,
+ t_guard := t_guard,
+ sccp_addr_local := omit,
+ sccp_addr_peer := omit
+ }
+ return valueof(pars);
+}
+
+private altstep as_Tguard() runs on BSSGP_ConnHdlr {
+ [] g_Tguard.timeout {
+ setverdict(fail, "Tguard timeout");
+ mtc.stop;
+ }
+}
+
+type function bssgp_connhdlr_void_fn(charstring id) runs on BSSGP_ConnHdlr;
+
+/* first function called in every ConnHdlr */
+function f_handler_init(bssgp_connhdlr_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);
+}
+
+private function is_gb(integer ran_index) return boolean {
+ return ran_index < NUM_GB;
+}
+private 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));
+}
+
+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 RANAP_IEs.RAC rac := '00'O;
+ 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_PS(lai, rac, 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;
+}
+
+/* (copied from msc/BSC_ConnectionHandler.ttcn) */
+private altstep as_ciph_utran() runs on BSSGP_ConnHdlr
+{
+ [g_pars.net.expect_ciph] BSSAP.receive(tr_RANAP_SecurityModeCmdEnc(uia_algs := ?,
+ uia_key := oct2bit(g_pars.vec.ik),
+ key_sts := ?,
+ uea_algs := ?,
+ uea_key := oct2bit(g_pars.vec.ck))) {
+ var IntegrityProtectionAlgorithm uia_chosen := 0; /*standard_UMTS_integrity_algorithm_UIA1*/
+ var EncryptionAlgorithm uea_chosen := 1; /*standard_UMTS_encryption_algorith_UEA1*/
+ BSSAP.send(ts_RANAP_SecurityModeCompleteEnc(uia_chosen, uea_chosen));
+ }
+ [g_pars.net.expect_ciph] BSSAP.receive(tr_RANAP_SecurityModeCmdEnc(?,?,?,?,?)) {
+ setverdict(fail, "Invalid SecurityModeCommand (ciphering case)");
+ mtc.stop;
+ }
+ [not g_pars.net.expect_ciph] BSSAP.receive(tr_RANAP_SecurityModeCmd(uia_algs := ?,
+ uia_key := oct2bit(g_pars.vec.ik),
+ key_sts := ?)) {
+ var IntegrityProtectionAlgorithm uia_chosen := 0; /*standard_UMTS_integrity_algorithm_UIA1;*/
+ BSSAP.send(ts_RANAP_SecurityModeComplete(uia_chosen));
+ }
+ [not g_pars.net.expect_ciph] BSSAP.receive(tr_RANAP_SecurityModeCmd(?,?,?)) {
+ setverdict(fail, "Invalid SecurityModeCommand (non-ciphering case)");
+ mtc.stop;
+ }
+}
+
+/* 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 (value) 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)) {
+ as_ciph_utran();
+ 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 */
+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));
+ }
+}
+
+altstep as_gmm_gsup_lu_isd() runs on BSSGP_ConnHdlr {
+ [] GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)) {
+ var GSUP_PDU gsup := valueof(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn));
+ gsup.ies := gsup.ies & { valueof(ts_GSUP_IE_PdpInfo('00'O, char2oct("*"), ts_EuaIPv4Dyn, ''O)) };
+ GSUP.send(gsup);
+ GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi));
+ GSUP.send(ts_GSUP_UL_RES(g_pars.imsi));
+ }
+}
+
+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 (value) 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 */
+ as_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);
+}
+
+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;
+}
+
+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;
+ }
+ }
+}
+
+altstep as_routing_area_update_gb(integer ran_index := 0) runs on BSSGP_ConnHdlr {
+ var PDU_L3_SGSN_MS l3_mt;
+
+ [] 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);
+ }
+ [] BSSGP[ran_index].receive(tr_GMM_RAU_REJECT) {
+ setverdict(fail, "Unexpected RAU Reject");
+ mtc.stop;
+ }
+}
+altstep as_routing_area_update_iu(integer ran_index := 0) runs on BSSGP_ConnHdlr {
+ var PDU_DTAP_PS_MT mt;
+
+ [] 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);
+ }
+ [] BSSAP.receive(tr_PDU_DTAP_PS_MT(tr_GMM_RAU_REJECT)) {
+ setverdict(fail, "Unexpected RAU Reject");
+ mtc.stop;
+ }
+ [] 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;
+ }
+}
+altstep as_routing_area_update(integer ran_index := 0) runs on BSSGP_ConnHdlr {
+ [is_gb(ran_index)] as_routing_area_update_gb(ran_index);
+ [is_iu(ran_index)] as_routing_area_update_iu(ran_index);
+}
+
+function f_routing_area_update(RoutingAreaIdentificationV old_ra,
+ GprsUpdateType upd_type := GPRS_UPD_T_RA,
+ integer ran_index := 0,
+ float Tval := 2.0) runs on BSSGP_ConnHdlr {
+ var template (omit) OCT4 p_tmsi := omit;
+ timer T := Tval;
+
+ if (is_iu(ran_index)) {
+ p_tmsi := g_pars.p_tmsi;
+ }
+
+ f_send_l3(ts_GMM_RAU_REQ(f_mi_get_lv(), upd_type, old_ra, p_tmsi := p_tmsi), ran_index);
+
+ T.start;
+ alt {
+ [] as_routing_area_update(ran_index) { setverdict(pass); }
+ [is_gb(ran_index)] BSSGP[ran_index].receive { repeat; }
+ [is_iu(ran_index)] BSSAP.receive { repeat; }
+ [] T.timeout {
+ setverdict(fail, "Timeout completing the RAU procedure");
+ mtc.stop;
+ }
+ }
+}
+
+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 */
+};
+
+
+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;
+
+ BSSGP[ran_index].clear;
+ if (error_ind) {
+ var Gtp1uPeer peer := valueof(ts_GtpPeerU(apars.sgsn_ip_c));
+ GTP.send(ts_GTPU_ErrorIndication(peer, 0 /* seq */, apars.ggsn_tei_u, apars.ggsn_ip_u));
+ } else {
+ var Gtp1cPeer peer := valueof(ts_GtpPeerC(apars.sgsn_ip_c));
+ 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) Gtp1uPeer ts_GtpPeerU(octetstring ip) := {
+ connId := 1,
+ remName := f_inet_ntoa(ip),
+ remPort := GTP1U_PORT
+}
+
+template (value) Gtp1cPeer ts_GtpPeerC(octetstring ip) := {
+ connId := 1,
+ remName := f_inet_ntoa(ip),
+ remPort := GTP1C_PORT
+}
+
+function f_gtpu_send(inout PdpActPars apars, octetstring payload) runs on BSSGP_ConnHdlr {
+ var Gtp1uPeer peer := valueof(ts_GtpPeerU(apars.sgsn_ip_u));
+ GTP.send(ts_GTP1U_GPDU(peer, 0 /*seq*/, apars.sgsn_tei_u, payload));
+}
+
+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 */
+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 */
+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 Gtp1uPeer 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));
+ }
+}
+
+
+
+}
\ No newline at end of file
diff --git a/sgsn/SGSN_Tests.ttcn b/sgsn/SGSN_Tests.ttcn
index 9c73834..2cecafd 100644
--- a/sgsn/SGSN_Tests.ttcn
+++ b/sgsn/SGSN_Tests.ttcn
@@ -60,6 +60,7 @@

import from MobileL3_MM_Types all;

+import from BSSGP_ConnHdlr all;

modulepar {
/* IP/port on which we run our internal GSUP/HLR emulation */
@@ -161,7 +162,6 @@
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;
@@ -191,43 +191,6 @@
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;
@@ -463,40 +426,18 @@
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,
+function f_start_handler(bssgp_connhdlr_void_fn fn, charstring id, GbInstances gb, integer imsi_suffix,
float t_guard := 30.0, boolean expect_ciph := false)
runs on test_CT return BSSGP_ConnHdlr {
+ var BSSGP_ConnHdlrPars pars;
var BSSGP_ConnHdlr vc_conn;
- var SGSN_ConnHdlrNetworkPars net_pars := {
- expect_ptmsi := true,
- expect_auth := true,
- expect_ciph := expect_ciph
- };
- 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 := {
+ var BssgpCellIds cell_ids := {
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
- };
-
+ }
+ pars := f_new_BSSGP_ConnHdlrPars(imsi_suffix, cell_ids, t_NetPars(expect_ciph := expect_ciph));
if (g_ranap_enable) {
pars.sccp_addr_local := g_ranap[0].sccp_addr_own;
pars.sccp_addr_peer := g_ranap[0].sccp_addr_peer;
@@ -535,36 +476,6 @@
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
@@ -585,392 +496,6 @@
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 RANAP_IEs.RAC rac := '00'O;
- 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_PS(lai, rac, 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;
-}
-
-/* (copied from msc/BSC_ConnectionHandler.ttcn) */
-private altstep as_ciph_utran() runs on BSSGP_ConnHdlr
-{
- [g_pars.net.expect_ciph] BSSAP.receive(tr_RANAP_SecurityModeCmdEnc(uia_algs := ?,
- uia_key := oct2bit(g_pars.vec.ik),
- key_sts := ?,
- uea_algs := ?,
- uea_key := oct2bit(g_pars.vec.ck))) {
- var IntegrityProtectionAlgorithm uia_chosen := 0; /*standard_UMTS_integrity_algorithm_UIA1*/
- var EncryptionAlgorithm uea_chosen := 1; /*standard_UMTS_encryption_algorith_UEA1*/
- BSSAP.send(ts_RANAP_SecurityModeCompleteEnc(uia_chosen, uea_chosen));
- }
- [g_pars.net.expect_ciph] BSSAP.receive(tr_RANAP_SecurityModeCmdEnc(?,?,?,?,?)) {
- setverdict(fail, "Invalid SecurityModeCommand (ciphering case)");
- mtc.stop;
- }
- [not g_pars.net.expect_ciph] BSSAP.receive(tr_RANAP_SecurityModeCmd(uia_algs := ?,
- uia_key := oct2bit(g_pars.vec.ik),
- key_sts := ?)) {
- var IntegrityProtectionAlgorithm uia_chosen := 0; /*standard_UMTS_integrity_algorithm_UIA1;*/
- BSSAP.send(ts_RANAP_SecurityModeComplete(uia_chosen));
- }
- [not g_pars.net.expect_ciph] BSSAP.receive(tr_RANAP_SecurityModeCmd(?,?,?)) {
- setverdict(fail, "Invalid SecurityModeCommand (non-ciphering case)");
- mtc.stop;
- }
-}
-
-/* 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 (value) 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)) {
- as_ciph_utran();
- 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 altstep as_gmm_gsup_lu_isd() runs on BSSGP_ConnHdlr {
- [] GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi)) {
- var GSUP_PDU gsup := valueof(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn));
- gsup.ies := gsup.ies & { valueof(ts_GSUP_IE_PdpInfo('00'O, char2oct("*"), ts_EuaIPv4Dyn, ''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 (value) 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 */
- as_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);
@@ -1450,303 +975,6 @@
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;
-
- BSSGP[ran_index].clear;
- if (error_ind) {
- var Gtp1uPeer peer := valueof(ts_GtpPeerU(apars.sgsn_ip_c));
- GTP.send(ts_GTPU_ErrorIndication(peer, 0 /* seq */, apars.ggsn_tei_u, apars.ggsn_ip_u));
- } else {
- var Gtp1cPeer peer := valueof(ts_GtpPeerC(apars.sgsn_ip_c));
- 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) Gtp1uPeer ts_GtpPeerU(octetstring ip) := {
- connId := 1,
- remName := f_inet_ntoa(ip),
- remPort := GTP1U_PORT
-}
-
-template (value) Gtp1cPeer 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 Gtp1uPeer 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 Gtp1uPeer 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));

@@ -2631,70 +1859,6 @@
f_cleanup();
}

-friend altstep as_routing_area_update_gb(integer ran_index := 0) runs on BSSGP_ConnHdlr {
- var PDU_L3_SGSN_MS l3_mt;
-
- [] 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);
- }
- [] BSSGP[ran_index].receive(tr_GMM_RAU_REJECT) {
- setverdict(fail, "Unexpected RAU Reject");
- mtc.stop;
- }
-}
-friend altstep as_routing_area_update_iu(integer ran_index := 0) runs on BSSGP_ConnHdlr {
- var PDU_DTAP_PS_MT mt;
-
- [] 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);
- }
- [] BSSAP.receive(tr_PDU_DTAP_PS_MT(tr_GMM_RAU_REJECT)) {
- setverdict(fail, "Unexpected RAU Reject");
- mtc.stop;
- }
- [] 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;
- }
-}
-friend altstep as_routing_area_update(integer ran_index := 0) runs on BSSGP_ConnHdlr {
- [is_gb(ran_index)] as_routing_area_update_gb(ran_index);
- [is_iu(ran_index)] as_routing_area_update_iu(ran_index);
-}
-
-friend function f_routing_area_update(RoutingAreaIdentificationV old_ra,
- GprsUpdateType upd_type := GPRS_UPD_T_RA,
- integer ran_index := 0,
- float Tval := 2.0) runs on BSSGP_ConnHdlr {
- var template (omit) OCT4 p_tmsi := omit;
- timer T := Tval;
-
- if (is_iu(ran_index)) {
- p_tmsi := g_pars.p_tmsi;
- }
-
- f_send_l3(ts_GMM_RAU_REQ(f_mi_get_lv(), upd_type, old_ra, p_tmsi := p_tmsi), ran_index);
-
- T.start;
- alt {
- [] as_routing_area_update(ran_index) { setverdict(pass); }
- [is_gb(ran_index)] BSSGP[ran_index].receive { repeat; }
- [is_iu(ran_index)] BSSAP.receive { repeat; }
- [] T.timeout {
- setverdict(fail, "Timeout completing the RAU procedure");
- mtc.stop;
- }
- }
-}
-
private function f_TC_attach_rau_a_a(charstring id) runs on BSSGP_ConnHdlr {
/* first perform regular attach */
f_TC_attach(id);
diff --git a/sgsn/SGSN_Tests_Iu.ttcn b/sgsn/SGSN_Tests_Iu.ttcn
index 0a589b9..9825150 100644
--- a/sgsn/SGSN_Tests_Iu.ttcn
+++ b/sgsn/SGSN_Tests_Iu.ttcn
@@ -12,6 +12,8 @@
import from RANAP_PDU_Descriptions all;
import from RANAP_IEs all;

+import from BSSGP_ConnHdlr all;
+
private function f_init() runs on test_CT {
g_ranap_enable := true;
SGSN_Tests.f_init();

To view, visit change 37545. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I0591cab8cca5195b8648920d5f79acc536a4efac
Gerrit-Change-Number: 37545
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin@sysmocom.de>
Gerrit-MessageType: newchange