| module GBProxy_Tests { |
| |
| /* Osmocom GBProxy test suite in TTCN-3 |
| * (C) 2020 sysmocom - s.f.m.c. GmbH |
| * All rights reserved. |
| * |
| * Author: Daniel Willmann <dwillmann@sysmocom.de> |
| |
| * 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 |
| */ |
| |
| 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 SCCPasp_Types all; |
| import from Osmocom_Gb_Types all; |
| |
| import from MobileL3_CommonIE_Types all; |
| import from MobileL3_GMM_SM_Types all; |
| import from MobileL3_Types all; |
| import from L3_Templates all; |
| import from L3_Common all; |
| |
| import from TELNETasp_PortType all; |
| import from Osmocom_VTY_Functions all; |
| |
| import from LLC_Types all; |
| import from LLC_Templates all; |
| |
| import from GSM_RR_Types all; |
| |
| /* mcc_mnc is 24.008 10.5.5.15 encoded. 262 42 */ |
| const BcdMccMnc c_mcc_mnc := '262F42'H; |
| |
| modulepar { |
| /* IP/port on which we run our internal GSUP/HLR emulation */ |
| NSConfigurations mp_nsconfig_sgsn := { |
| { |
| nsei := 101, |
| role_sgsn := true, |
| handle_sns := false, |
| nsvc := { |
| { |
| provider := { |
| ip := { |
| address_family := AF_INET, |
| local_udp_port := 7777, |
| local_ip := "127.0.0.1", |
| remote_udp_port := 23000, |
| remote_ip := "127.0.0.1" |
| } |
| }, |
| nsvci := 101 |
| } |
| } |
| } |
| }; |
| NSConfigurations mp_nsconfig_pcu := { |
| { |
| 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 |
| } |
| } |
| } |
| }; |
| BssgpConfigs mp_gbconfigs := { |
| { |
| nsei := 96, |
| sgsn_role := false, |
| bvc := { |
| { |
| bvci := 196, |
| cell_id := { |
| ra_id := { |
| lai := { |
| mcc_mnc := c_mcc_mnc, |
| lac := 13135 |
| }, |
| rac := 0 |
| }, |
| cell_id := 20960 |
| }, |
| depth := BSSGP_DECODE_DEPTH_BSSGP, |
| create_cb := refers(BSSGP_Emulation.DefaultCreateCallback) |
| } |
| } |
| }, { |
| nsei := 97, |
| sgsn_role := false, |
| bvc := { |
| { |
| bvci := 210, |
| cell_id := { |
| ra_id := { |
| lai := { |
| mcc_mnc := c_mcc_mnc, |
| lac := 13200 |
| }, |
| rac := 0 |
| }, |
| cell_id := 20961 |
| }, |
| depth := BSSGP_DECODE_DEPTH_BSSGP, |
| create_cb := refers(BSSGP_Emulation.DefaultCreateCallback) |
| } |
| } |
| }, { |
| nsei := 98, |
| sgsn_role := false, |
| bvc := { |
| { |
| bvci := 220, |
| cell_id := { |
| ra_id := { |
| lai := { |
| mcc_mnc := c_mcc_mnc, |
| lac := 13300 |
| }, |
| rac := 0 |
| }, |
| cell_id := 20962 |
| }, |
| depth := BSSGP_DECODE_DEPTH_BSSGP, |
| create_cb := refers(BSSGP_Emulation.DefaultCreateCallback) |
| } |
| } |
| } |
| } |
| }; |
| |
| type record GbInstance { |
| NS_CT vc_NS, |
| BSSGP_CT vc_BSSGP, |
| BSSGP_BVC_CTs vc_BSSGP_BVC, |
| BssgpConfig cfg |
| }; |
| type record of BSSGP_BVC_CT BSSGP_BVC_CTs |
| |
| const integer NUM_PCU := 3; |
| type record of GbInstance GbInstances; |
| type record of BssgpConfig BssgpConfigs; |
| type record of NSConfiguration NSConfigurations; |
| type record of BssgpCellId BssgpCellIds; |
| |
| const integer NUM_SGSN := 1; |
| |
| type component test_CT { |
| var GbInstances g_pcu; |
| var GbInstances g_sgsn; |
| |
| port BSSGP_CT_PROC_PT PROC; |
| |
| port BSSGP_BVC_MGMT_PT SGSN_MGMT; |
| port BSSGP_BVC_MGMT_PT PCU_MGMT; |
| |
| port TELNETasp_PT GBPVTY; |
| |
| var boolean g_initialized := false; |
| var boolean g_use_echo := false; |
| }; |
| |
| type component BSSGP_ConnHdlr { |
| /* array of per-BVC ports on the PCU side */ |
| port BSSGP_PT PCU[NUM_PCU]; |
| port BSSGP_PT PCU_SIG[NUM_PCU]; |
| port BSSGP_PROC_PT PCU_PROC[NUM_PCU]; |
| /* component reference to the component to which we're currently connected */ |
| var BSSGP_BVC_CT pcu_ct[NUM_PCU]; |
| |
| /* array of per-BVC ports on the SGSN side */ |
| port BSSGP_PT SGSN[NUM_SGSN]; |
| port BSSGP_PT SGSN_SIG[NUM_SGSN]; |
| port BSSGP_PROC_PT SGSN_PROC[NUM_SGSN]; |
| /* component reference to the component to which we're currently connected */ |
| var BSSGP_BVC_CT sgsn_ct[NUM_PCU]; |
| |
| 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, |
| GbInstances pcu, |
| GbInstances sgsn, |
| float t_guard |
| }; |
| |
| 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_pcu(inout GbInstance gb, charstring id, integer offset) runs on test_CT { |
| var charstring ns_id := id & "-NS(PCU[" & int2str(offset) & "])"; |
| var charstring bssgp_id := id & "-BSSGP(PCU[" & int2str(offset) & "])"; |
| gb.vc_NS := NS_CT.create(ns_id); |
| gb.vc_BSSGP := BSSGP_CT.create(bssgp_id); |
| /* 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_pcu[offset], ns_id)); |
| gb.vc_BSSGP.start(BssgpStart(gb.cfg, bssgp_id)); |
| |
| for (var integer i := 0; i < lengthof(gb.cfg.bvc); i := i + 1) { |
| connect(self:PROC, gb.vc_BSSGP:PROC); |
| gb.vc_BSSGP_BVC[i] := f_bssgp_get_bvci_ct(gb.cfg.bvc[i].bvci, PROC); |
| disconnect(self:PROC, gb.vc_BSSGP:PROC); |
| connect(self:PCU_MGMT, gb.vc_BSSGP_BVC[i]:MGMT); |
| } |
| } |
| |
| private function f_init_gb_sgsn(inout GbInstance gb, charstring id, integer offset) runs on test_CT { |
| var charstring ns_id := id & "-NS(SGSN[" & int2str(offset) & "])"; |
| var charstring bssgp_id := id & "-BSSGP(SGSN[" & int2str(offset) & "])"; |
| gb.vc_NS := NS_CT.create(ns_id); |
| gb.vc_BSSGP := BSSGP_CT.create(bssgp_id); |
| /* 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_sgsn[offset], ns_id)); |
| gb.vc_BSSGP.start(BssgpStart(gb.cfg, bssgp_id)); |
| |
| for (var integer i := 0; i < lengthof(gb.cfg.bvc); i := i + 1) { |
| connect(self:PROC, gb.vc_BSSGP:PROC); |
| gb.vc_BSSGP_BVC[i] := f_bssgp_get_bvci_ct(gb.cfg.bvc[i].bvci, PROC); |
| disconnect(self:PROC, gb.vc_BSSGP:PROC); |
| connect(self:SGSN_MGMT, gb.vc_BSSGP_BVC[i]:MGMT); |
| } |
| } |
| |
| |
| private function f_init_vty() runs on test_CT { |
| map(self:GBPVTY, system:GBPVTY); |
| f_vty_set_prompts(GBPVTY); |
| f_vty_transceive(GBPVTY, "enable"); |
| } |
| |
| type record of integer ro_integer; |
| |
| private function ro_integer_contains(ro_integer r, integer x) return boolean { |
| for (var integer j := 0; j < lengthof(r); j := j+1) { |
| if (r[j] == x) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| function f_init() runs on test_CT { |
| var ro_integer bvci_unblocked := {}; |
| var BssgpStatusIndication bsi; |
| var integer i; |
| |
| if (g_initialized == true) { |
| return; |
| } |
| g_initialized := true; |
| |
| g_sgsn[0].cfg := { |
| nsei := mp_nsconfig_sgsn[0].nsei, |
| sgsn_role := true, |
| bvc := { } |
| } |
| for (i := 0; i < lengthof(mp_gbconfigs); i := i+1) { |
| g_pcu[i].cfg := mp_gbconfigs[i]; |
| /* concatenate all the PCU-side BVCs for the SGSN side */ |
| g_sgsn[0].cfg.bvc := g_sgsn[0].cfg.bvc & mp_gbconfigs[i].bvc; |
| } |
| |
| f_init_vty(); |
| for (i := 0; i < lengthof(mp_nsconfig_sgsn); i := i+1) { |
| f_init_gb_sgsn(g_sgsn[i], "GbProxy_Test", i); |
| } |
| f_sleep(4.0); |
| for (i := 0; i < lengthof(mp_nsconfig_pcu); i := i+1) { |
| f_init_gb_pcu(g_pcu[i], "GbProxy_Test", i); |
| } |
| |
| /* wait until all BVC are unblocked on both sides */ |
| timer T := 15.0; |
| T.start; |
| alt { |
| [] SGSN_MGMT.receive(BssgpStatusIndication:{*, ?, BVC_S_UNBLOCKED}) -> value bsi { |
| bvci_unblocked := bvci_unblocked & { bsi.bvci }; |
| if (lengthof(bvci_unblocked) != lengthof(g_sgsn[0].cfg.bvc)) { |
| repeat; |
| } |
| } |
| [] SGSN_MGMT.receive(BssgpStatusIndication:{*, ?, ?}) { |
| repeat; |
| } |
| [] SGSN_MGMT.receive { |
| setverdict(fail, "Received unexpected message on SGSN_MGMT"); |
| mtc.stop; |
| } |
| |
| [] PCU_MGMT.receive(BssgpStatusIndication:{*, ?, BVC_S_UNBLOCKED}) -> value bsi { |
| repeat; |
| } |
| [] PCU_MGMT.receive(BssgpStatusIndication:{*, ?, ?}) { |
| repeat; |
| } |
| [] PCU_MGMT.receive(BssgpResetIndication:{0}) { |
| repeat; |
| } |
| [] PCU_MGMT.receive { |
| setverdict(fail, "Received unexpected message on PCU_MGMT"); |
| mtc.stop; |
| } |
| |
| [] T.timeout { |
| setverdict(fail, "Timeout waiting for unblock of all BVCs"); |
| mtc.stop; |
| } |
| } |
| |
| /* iterate over list and check all BVCI */ |
| for (i := 0; i < lengthof(g_sgsn[0].cfg.bvc); i := i+1) { |
| var BssgpBvci bvci := g_sgsn[0].cfg.bvc[i].bvci; |
| if (not ro_integer_contains(bvci_unblocked, bvci)) { |
| setverdict(fail, "BVCI=", bvci, " was not unblocked during start-up"); |
| mtc.stop; |
| } |
| } |
| } |
| |
| function f_cleanup() runs on test_CT { |
| self.stop; |
| } |
| |
| 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 pcu, GbInstances sgsn, integer imsi_suffix, |
| float t_guard := 30.0) |
| runs on test_CT return BSSGP_ConnHdlr { |
| var BSSGP_ConnHdlr vc_conn; |
| |
| 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, |
| pcu := g_pcu, |
| sgsn := g_sgsn, |
| t_guard := t_guard |
| }; |
| |
| vc_conn := BSSGP_ConnHdlr.create(id); |
| |
| vc_conn.start(f_handler_init(fn, id, pars)); |
| return vc_conn; |
| } |
| |
| /* Connect the PCU-side per-BVC ports (PCU/PCU_SIG/PCU_PROC) array slot 'port_idx' to specified per-BVC component */ |
| private function f_connect_to_pcu_bvc(integer port_idx, BSSGP_BVC_CT bvc_ct) runs on BSSGP_ConnHdlr { |
| if (PCU[port_idx].checkstate("Connected")) { |
| /* unregister + disconnect from old BVC */ |
| f_client_unregister(g_pars.imsi, PCU_PROC[port_idx]); |
| disconnect(self:PCU[port_idx], pcu_ct[port_idx]:BSSGP_SP); |
| disconnect(self:PCU_SIG[port_idx], pcu_ct[port_idx]:BSSGP_SP_SIG); |
| disconnect(self:PCU_PROC[port_idx], pcu_ct[port_idx]:BSSGP_PROC); |
| } |
| /* connect to new BVC and register us */ |
| connect(self:PCU[port_idx], bvc_ct:BSSGP_SP); |
| connect(self:PCU_SIG[port_idx], bvc_ct:BSSGP_SP_SIG); |
| connect(self:PCU_PROC[port_idx], bvc_ct:BSSGP_PROC); |
| f_client_register(g_pars.imsi, g_pars.tlli, PCU_PROC[port_idx]); |
| pcu_ct[port_idx] := bvc_ct; |
| } |
| |
| /* Connect the SGSN-side per-BVC ports (SGSN/SGSN_SIG/SGSN_PROC) array slot 'port_idx' to specified per-BVC component */ |
| private function f_connect_to_sgsn_bvc(integer port_idx, BSSGP_BVC_CT bvc_ct) runs on BSSGP_ConnHdlr { |
| if (SGSN[port_idx].checkstate("Connected")) { |
| /* unregister + disconnect from old BVC */ |
| f_client_unregister(g_pars.imsi, SGSN_PROC[port_idx]); |
| disconnect(self:SGSN[port_idx], sgsn_ct[port_idx]:BSSGP_SP); |
| disconnect(self:SGSN_SIG[port_idx], sgsn_ct[port_idx]:BSSGP_SP_SIG); |
| disconnect(self:SGSN_PROC[port_idx], sgsn_ct[port_idx]:BSSGP_PROC); |
| } |
| /* connect to new BVC and register us */ |
| connect(self:SGSN[port_idx], bvc_ct:BSSGP_SP); |
| connect(self:SGSN_SIG[port_idx], bvc_ct:BSSGP_SP_SIG); |
| connect(self:SGSN_PROC[port_idx], bvc_ct:BSSGP_PROC); |
| f_client_register(g_pars.imsi, g_pars.tlli, SGSN_PROC[port_idx]); |
| sgsn_ct[port_idx] := bvc_ct; |
| } |
| |
| 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 { |
| var integer i; |
| /* do some common stuff like setting up g_pars */ |
| g_pars := pars; |
| |
| llc := f_llc_create(false); |
| |
| /* default connections on PCU side: First BVC of each NSE/PCU */ |
| for (i := 0; i < lengthof(g_pars.pcu); i := i+1) { |
| f_connect_to_pcu_bvc(i, g_pars.pcu[i].vc_BSSGP_BVC[0]); |
| } |
| |
| /* default connections on SGSN side: First BVC of each NSE/SGSN */ |
| for (i := 0; i < lengthof(g_pars.sgsn); i := i+1) { |
| f_connect_to_sgsn_bvc(i, g_pars.sgsn[i].vc_BSSGP_BVC[0]); |
| } |
| |
| g_Tguard.start(pars.t_guard); |
| activate(as_Tguard()); |
| |
| /* call the user-supplied test case function */ |
| fn.apply(id); |
| } |
| |
| private function f_client_register(hexstring imsi, OCT4 tlli, BSSGP_PROC_PT PT) |
| runs on BSSGP_ConnHdlr { |
| PT.call(BSSGP_register_client:{imsi, tlli}) { |
| [] PT.getreply(BSSGP_register_client:{imsi, tlli}) {}; |
| } |
| } |
| |
| private function f_client_unregister(hexstring imsi, BSSGP_PROC_PT PT) |
| runs on BSSGP_ConnHdlr { |
| PT.call(BSSGP_unregister_client:{imsi}) { |
| [] PT.getreply(BSSGP_unregister_client:{imsi}) {}; |
| } |
| } |
| |
| /* Send 'tx' on PTP-BVCI from PCU; expect 'rx' on SGSN */ |
| friend function f_pcu2sgsn(template (value) PDU_BSSGP tx, template (present) PDU_BSSGP exp_rx, |
| integer pcu_idx := 0, integer sgsn_idx := 0) runs on BSSGP_ConnHdlr { |
| var PDU_BSSGP rx; |
| timer T := 1.0; |
| |
| PCU[pcu_idx].send(tx); |
| T.start; |
| alt { |
| [] SGSN[sgsn_idx].receive(exp_rx) { |
| setverdict(pass); |
| } |
| [] SGSN[sgsn_idx].receive(PDU_BSSGP:?) -> value rx { |
| setverdict(fail, "Unexpected BSSGP on SGSN side: ", rx); |
| mtc.stop; |
| } |
| [] T.timeout { |
| setverdict(fail, "Timeout waiting for BSSGP on SGSN side: ", rx); |
| mtc.stop; |
| } |
| } |
| } |
| |
| /* Send 'tx' on PTP-BVCI from SGSN; expect 'rx' on PCU */ |
| friend function f_sgsn2pcu(template (value) PDU_BSSGP tx, template (present) PDU_BSSGP exp_rx, |
| integer sgsn_idx:= 0, integer pcu_idx := 0) runs on BSSGP_ConnHdlr { |
| var PDU_BSSGP rx; |
| timer T := 1.0; |
| |
| SGSN[sgsn_idx].send(tx); |
| T.start; |
| alt { |
| [] PCU[pcu_idx].receive(exp_rx) { |
| setverdict(pass); |
| } |
| [] PCU[pcu_idx].receive(PDU_BSSGP:?) -> value rx { |
| setverdict(fail, "Unexpected BSSGP on PCU side: ", rx); |
| mtc.stop; |
| } |
| [] T.timeout { |
| setverdict(fail, "Timeout waiting for BSSGP on PCU side: ", rx); |
| mtc.stop; |
| } |
| } |
| } |
| |
| /* 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 |
| */ |
| |
| private function f_TC_BVC_bringup(charstring id) runs on BSSGP_ConnHdlr { |
| f_sleep(5.0); |
| setverdict(pass); |
| } |
| |
| testcase TC_BVC_bringup() runs on test_CT { |
| var BSSGP_ConnHdlr vc_conn; |
| f_init(); |
| |
| vc_conn := f_start_handler(refers(f_TC_BVC_bringup), testcasename(), g_pcu, g_sgsn, 51); |
| vc_conn.done; |
| |
| f_cleanup(); |
| } |
| |
| friend function f_bssgp_suspend(integer ran_idx := 0) runs on BSSGP_ConnHdlr return OCT1 { |
| var BssgpBvcConfig bvcc := g_pars.pcu[ran_idx].cfg.bvc[0]; |
| timer T := 5.0; |
| var PDU_BSSGP rx_pdu; |
| PCU_SIG[ran_idx].send(ts_BSSGP_SUSPEND(g_pars.tlli, bvcc.cell_id.ra_id)); |
| T.start; |
| alt { |
| [] PCU_SIG[ran_idx].receive(tr_BSSGP_SUSPEND_ACK(g_pars.tlli, bvcc.cell_id.ra_id, ?)) -> value rx_pdu { |
| return rx_pdu.pDU_BSSGP_SUSPEND_ACK.suspend_Reference_Number.suspend_Reference_Number_value; |
| } |
| [] PCU_SIG[ran_idx].receive(tr_BSSGP_SUSPEND_NACK(g_pars.tlli, bvcc.cell_id.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 { |
| var BssgpBvcConfig bvcc := g_pars.pcu[ran_idx].cfg.bvc[0]; |
| timer T := 5.0; |
| PCU_SIG[ran_idx].send(ts_BSSGP_RESUME(g_pars.tlli, bvcc.cell_id.ra_id, susp_ref)); |
| T.start; |
| alt { |
| [] PCU_SIG[ran_idx].receive(tr_BSSGP_RESUME_ACK(g_pars.tlli, bvcc.cell_id.ra_id)); |
| [] PCU_SIG[ran_idx].receive(tr_BSSGP_RESUME_NACK(g_pars.tlli, bvcc.cell_id.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; |
| } |
| } |
| } |
| |
| |
| /* send uplink-unitdata of a variety of different sizes; expect it to show up on SGSN */ |
| private function f_TC_ul_unitdata(charstring id) runs on BSSGP_ConnHdlr { |
| var integer ran_idx := 0; |
| var BssgpBvcConfig bvcc := g_pars.pcu[ran_idx].cfg.bvc[0]; |
| var integer i; |
| |
| for (i := 0; i < 1024; i := i+1) { |
| var octetstring payload := f_rnd_octstring(i); |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_UL_UD(g_pars.tlli, bvcc.cell_id, payload); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_UL_UD(g_pars.tlli, bvcc.cell_id, payload); |
| |
| f_pcu2sgsn(pdu_tx, pdu_rx); |
| } |
| setverdict(pass); |
| } |
| |
| testcase TC_ul_unitdata() runs on test_CT |
| { |
| var BSSGP_ConnHdlr vc_conn; |
| f_init(); |
| |
| vc_conn := f_start_handler(refers(f_TC_ul_unitdata), testcasename(), g_pcu, g_sgsn, 1); |
| vc_conn.done; |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| |
| f_cleanup(); |
| } |
| |
| /* send downlink-unitdata of a variety of different sizes; expect it to show up on PCU */ |
| private function f_TC_dl_unitdata(charstring id) runs on BSSGP_ConnHdlr { |
| var integer i; |
| |
| for (i := 0; i < 1024; i := i+1) { |
| var octetstring payload := f_rnd_octstring(i); |
| var template (value) PDU_BSSGP pdu_tx := |
| ts_BSSGP_DL_UD(g_pars.tlli, payload, omit, ts_BSSGP_IMSI(g_pars.imsi)); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := |
| tr_BSSGP_DL_UD(g_pars.tlli, payload, tr_BSSGP_IMSI(g_pars.imsi)); |
| |
| f_sgsn2pcu(pdu_tx, pdu_rx); |
| } |
| setverdict(pass); |
| } |
| |
| testcase TC_dl_unitdata() runs on test_CT |
| { |
| var BSSGP_ConnHdlr vc_conn; |
| f_init(); |
| |
| vc_conn := f_start_handler(refers(f_TC_dl_unitdata), testcasename(), g_pcu, g_sgsn, 2); |
| vc_conn.done; |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| |
| f_cleanup(); |
| } |
| |
| private function f_TC_ra_capability(charstring id) runs on BSSGP_ConnHdlr { |
| var integer i; |
| |
| for (i := 0; i < 10; i := i+1) { |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_RA_CAP(g_pars.tlli, { ts_RaCapRec_BSSGP }); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_RA_CAP(g_pars.tlli, { tr_RaCapRec_BSSGP }) |
| |
| f_sgsn2pcu(pdu_tx, pdu_rx); |
| } |
| setverdict(pass); |
| } |
| testcase TC_ra_capability() runs on test_CT |
| { |
| var BSSGP_ConnHdlr vc_conn; |
| f_init(); |
| |
| vc_conn := f_start_handler(refers(f_TC_ra_capability), testcasename(), g_pcu, g_sgsn, 3); |
| vc_conn.done; |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| |
| f_cleanup(); |
| } |
| |
| private function f_TC_ra_capability_upd(charstring id) runs on BSSGP_ConnHdlr { |
| var integer i; |
| var OCT1 tag; |
| for (i := 0; i < 10; i := i+1) { |
| tag := int2oct(23 + i, 1); |
| var template (value) PDU_BSSGP pdu_tx := ts_BSSGP_RA_CAP_UPD(g_pars.tlli, tag); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| var template (present) PDU_BSSGP pdu_rx := tr_BSSGP_RA_CAP_UPD(g_pars.tlli, tag) |
| |
| f_pcu2sgsn(pdu_tx, pdu_rx); |
| |
| pdu_tx := ts_BSSGP_RA_CAP_UPD_ACK(g_pars.tlli, tag, '42'O); |
| /* we cannot use pdu_tx as there are some subtle differences in the length field :/ */ |
| pdu_rx := tr_BSSGP_RA_CAP_UPD_ACK(g_pars.tlli, tag, '42'O) |
| |
| f_sgsn2pcu(pdu_tx, pdu_rx); |
| } |
| setverdict(pass); |
| } |
| testcase TC_ra_capability_upd() runs on test_CT |
| { |
| var BSSGP_ConnHdlr vc_conn; |
| f_init(); |
| |
| vc_conn := f_start_handler(refers(f_TC_ra_capability_upd), testcasename(), g_pcu, g_sgsn, 3); |
| vc_conn.done; |
| /* TODO: start multiple handlers (UEs) on various cells on same and other NSEs */ |
| |
| f_cleanup(); |
| } |
| |
| |
| |
| |
| control { |
| execute( TC_BVC_bringup() ); |
| execute( TC_ul_unitdata() ); |
| execute( TC_dl_unitdata() ); |
| execute( TC_ra_capability() ); |
| execute( TC_ra_capability_upd() ); |
| } |
| |
| |
| } |