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.
12691 lines
438 KiB
12691 lines
438 KiB
module BSC_Tests {
|
|
|
|
/* Integration Tests for OsmoBSC
|
|
* (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
|
|
* 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
|
|
*
|
|
* This test suite tests OsmoBSC while emulating both multiple BTS + MS as
|
|
* well as the MSC. See README for more details.
|
|
*
|
|
* There are test cases that run in so-called 'handler mode' and test cases
|
|
* that run directly on top of the BSSAP and RSL CodecPorts. The "handler mode"
|
|
* tests abstract the multiplexing/demultiplexing of multiple SCCP connections
|
|
* and/or RSL channels and are hence suitable for higher-level test cases, while
|
|
* the "raw" tests directly on top of the CodecPorts are more suitable for lower-
|
|
* level testing.
|
|
*/
|
|
|
|
friend module BSC_Tests_VAMOS;
|
|
friend module BSC_Tests_CBSP;
|
|
friend module BSC_Tests_LCLS;
|
|
|
|
import from Misc_Helpers all;
|
|
import from General_Types all;
|
|
import from Osmocom_Types all;
|
|
import from GSM_Types all;
|
|
import from IPL4asp_Types all;
|
|
|
|
import from BSSAP_Types all;
|
|
import from RAN_Adapter all;
|
|
import from BSSAP_LE_Adapter all;
|
|
import from BSSAP_LE_CodecPort all;
|
|
import from BSSAP_LE_Types all;
|
|
import from BSSLAP_Types all;
|
|
import from BSSAP_CodecPort all;
|
|
import from BSSMAP_Templates all;
|
|
import from IPA_Emulation all;
|
|
import from IPA_CodecPort all;
|
|
import from IPA_Types all;
|
|
import from IPA_Testing all;
|
|
import from RSL_Types all;
|
|
import from RSL_Emulation all;
|
|
import from MGCP_Emulation all;
|
|
import from MGCP_Templates all;
|
|
import from MGCP_Types all;
|
|
import from MGCP_CodecPort all;
|
|
|
|
import from Osmocom_CTRL_Functions all;
|
|
import from Osmocom_CTRL_Types all;
|
|
import from Osmocom_CTRL_Adapter all;
|
|
|
|
import from StatsD_Types all;
|
|
import from StatsD_CodecPort all;
|
|
import from StatsD_CodecPort_CtrlFunct all;
|
|
import from StatsD_Checker all;
|
|
|
|
import from Osmocom_VTY_Functions all;
|
|
import from TELNETasp_PortType all;
|
|
|
|
import from MobileL3_CommonIE_Types all;
|
|
import from MobileL3_Types all;
|
|
import from MobileL3_RRM_Types all;
|
|
import from L3_Templates all;
|
|
import from GSM_RR_Types all;
|
|
|
|
import from SCCP_Templates all;
|
|
import from BSSMAP_Templates all;
|
|
import from BSSMAP_LE_Templates all;
|
|
|
|
import from SCCPasp_Types all;
|
|
|
|
import from GSM_SystemInformation all;
|
|
import from GSM_RestOctets all;
|
|
import from TCCConversion_Functions all;
|
|
|
|
const integer NUM_TRX := 4;
|
|
const integer NUM_BTS := 3;
|
|
const integer NUM_BTS_CFG := 4; /* we have 4 BTS in the osmo-bsc.cfg (for inter-BSC HO tests) but use only 3 */
|
|
const integer NUM_TRX_CFG := 1; /* we support up to 4 TRX per BTS, but have only 1 TRX per BTS in osmo-bsc.cfg */
|
|
const integer NUM_MSC := 3;
|
|
const integer NUM_MGW := 2;
|
|
const float T3101_MAX := 12.0;
|
|
|
|
/* make sure to sync this with the osmo-bts.cfg you're using */
|
|
const integer NUM_TCHH_PER_BTS := 2;
|
|
const integer NUM_TCHF_PER_BTS := 4;
|
|
const integer NUM_SDCCH_PER_BTS := 3;
|
|
|
|
friend type record BtsTrxIdx {
|
|
uint8_t bts,
|
|
uint8_t trx
|
|
}
|
|
|
|
private type record BtsParams {
|
|
integer trx_num,
|
|
integer tsc
|
|
}
|
|
|
|
/* Default Training Sequence Code expected for bts[i]:
|
|
* BTS 0 has BSIC 10 (and no explicit timeslot training_sequence_code config), so expecting TSC = (BSIC & 7) = 2.
|
|
* BTS 1 has BSIC 11, TSC = (BSIC & 7) = 3.
|
|
* BTS 2 has BSIC 12, TSC = (BSIC & 7) = 4.
|
|
* BTS 2 has BSIC 12, TSC = (BSIC & 7) = 4.
|
|
*/
|
|
private const BtsParams c_BtsParams[NUM_BTS_CFG] := {
|
|
/* BTS0 */ { trx_num := 1, tsc := 2 },
|
|
/* BTS1 */ { trx_num := 1, tsc := 3 },
|
|
/* BTS2 */ { trx_num := 4, tsc := 4 },
|
|
/* BTS3 */ { trx_num := 1, tsc := 4 }
|
|
}
|
|
|
|
private const RSL_IE_Body c_mr_conf_5_90 :=
|
|
valueof(RSL_IE_Body:{multirate_cfg := ts_RSL_MultirateCfg(true, 0, '00000100'B /* 5,90k */)});
|
|
|
|
/* per-BTS state which we keep */
|
|
type record BTS_State {
|
|
/* component reference to the IPA_Client component used for RSL */
|
|
IPA_Client rsl
|
|
}
|
|
|
|
/* Default list of counters for an 'msc' entity. */
|
|
const CounterNameVals counternames_msc_mscpool := {
|
|
{ "mscpool:subscr:new", 0 },
|
|
{ "mscpool:subscr:known", 0 },
|
|
{ "mscpool:subscr:reattach", 0 },
|
|
{ "mscpool:subscr:attach_lost", 0 },
|
|
{ "mscpool:subscr:paged", 0 }
|
|
};
|
|
|
|
/* List of global mscpool counters, not related to a specific 'msc' entity. */
|
|
const CounterNameVals counternames_bsc_mscpool := {
|
|
{ "mscpool:subscr:no_msc", 0 }
|
|
};
|
|
|
|
/* Default list of counters for 'bsc' and 'bts' entities. */
|
|
const CounterNameVals counternames_bsc_bts_handover := {
|
|
{ "assignment:attempted", 0 },
|
|
{ "assignment:completed", 0 },
|
|
{ "assignment:stopped", 0 },
|
|
{ "assignment:no_channel", 0 },
|
|
{ "assignment:timeout", 0 },
|
|
{ "assignment:failed", 0 },
|
|
{ "assignment:error", 0 },
|
|
|
|
{ "handover:attempted", 0 },
|
|
{ "handover:completed", 0 },
|
|
{ "handover:stopped", 0 },
|
|
{ "handover:no_channel", 0 },
|
|
{ "handover:timeout", 0 },
|
|
{ "handover:failed", 0 },
|
|
{ "handover:error", 0 },
|
|
|
|
{ "intra_cell_ho:attempted", 0 },
|
|
{ "intra_cell_ho:completed", 0 },
|
|
{ "intra_cell_ho:stopped", 0 },
|
|
{ "intra_cell_ho:no_channel", 0 },
|
|
{ "intra_cell_ho:timeout", 0 },
|
|
{ "intra_cell_ho:failed", 0 },
|
|
{ "intra_cell_ho:error", 0 },
|
|
|
|
{ "intra_bsc_ho:attempted", 0 },
|
|
{ "intra_bsc_ho:completed", 0 },
|
|
{ "intra_bsc_ho:stopped", 0 },
|
|
{ "intra_bsc_ho:no_channel", 0 },
|
|
{ "intra_bsc_ho:timeout", 0 },
|
|
{ "intra_bsc_ho:failed", 0 },
|
|
{ "intra_bsc_ho:error", 0 },
|
|
|
|
{ "interbsc_ho_out:attempted", 0 },
|
|
{ "interbsc_ho_out:completed", 0 },
|
|
{ "interbsc_ho_out:stopped", 0 },
|
|
{ "interbsc_ho_out:timeout", 0 },
|
|
{ "interbsc_ho_out:failed", 0 },
|
|
{ "interbsc_ho_out:error", 0 },
|
|
|
|
{ "interbsc_ho_in:attempted", 0 },
|
|
{ "interbsc_ho_in:completed", 0 },
|
|
{ "interbsc_ho_in:stopped", 0 },
|
|
{ "interbsc_ho_in:no_channel", 0 },
|
|
{ "interbsc_ho_in:timeout", 0 },
|
|
{ "interbsc_ho_in:failed", 0 },
|
|
{ "interbsc_ho_in:error", 0 }
|
|
};
|
|
|
|
const CounterNameVals counternames_bts_handover := {
|
|
{ "incoming_intra_bsc_ho:attempted", 0 },
|
|
{ "incoming_intra_bsc_ho:completed", 0 },
|
|
{ "incoming_intra_bsc_ho:stopped", 0 },
|
|
{ "incoming_intra_bsc_ho:no_channel", 0 },
|
|
{ "incoming_intra_bsc_ho:timeout", 0 },
|
|
{ "incoming_intra_bsc_ho:failed", 0 },
|
|
{ "incoming_intra_bsc_ho:error", 0 }
|
|
};
|
|
|
|
/* Set of all System Information received during one RSL port's startup.
|
|
* Note that some System Information may be sent on RSL, but lacking actual SI data, to indicate that the BTS should not
|
|
* broadcast that SI type. That will be reflected as 'omit' here.
|
|
*/
|
|
type record SystemInformationConfig {
|
|
SystemInformationType1 si1 optional,
|
|
SystemInformationType2 si2 optional,
|
|
SystemInformationType2bis si2bis optional,
|
|
SystemInformationType2ter si2ter optional,
|
|
SI2quaterRestOctetsList si2quater optional,
|
|
SystemInformationType3 si3 optional,
|
|
SystemInformationType4 si4 optional,
|
|
SystemInformationType13 si13 optional,
|
|
SystemInformationType5 si5 optional,
|
|
SystemInformationType5bis si5bis optional,
|
|
SystemInformationType5ter si5ter optional,
|
|
SystemInformationType6 si6 optional
|
|
};
|
|
|
|
const SystemInformationConfig SystemInformationConfig_omit := {
|
|
si1 := omit,
|
|
si2 := omit,
|
|
si2bis := omit,
|
|
si2ter := omit,
|
|
si2quater := omit,
|
|
si3 := omit,
|
|
si4 := omit,
|
|
si13 := omit,
|
|
si5 := omit,
|
|
si5bis := omit,
|
|
si5ter := omit,
|
|
si6 := omit
|
|
};
|
|
|
|
/* tr_EUTRAN_CellDesc with defaults used in BSC_Tests.ttcn */
|
|
template EUTRAN_CellDesc tr_EUTRAN_CellDesc_default(template (present) uint16_t e_arfcn := ?,
|
|
template uint3_t meas_bw := 3)
|
|
:= tr_EUTRAN_CellDesc(e_arfcn := e_arfcn,
|
|
meas_bw_presence := '1'B,
|
|
meas_bw := meas_bw);
|
|
|
|
/* tr_EUTRAN_NeighbourCells with defaults used in BSC_Tests.ttcn */
|
|
template EUTRAN_NeighbourCells tr_EUTRAN_NeighbourCells_default(template (present) EUTRAN_CellDescs cell_desc_list := { tr_EUTRAN_CellDesc_default },
|
|
template uint3_t prio := 3,
|
|
template (present) uint5_t thresh_high := 20,
|
|
template uint5_t thresh_low := 10,
|
|
template uint5_t qrxlevmin := 22)
|
|
:= tr_EUTRAN_NeighbourCells(
|
|
cell_desc_list := cell_desc_list,
|
|
prio_presence := '1'B,
|
|
prio := prio,
|
|
thresh_high := thresh_high,
|
|
thresh_low_presence := '1'B,
|
|
thresh_low := thresh_low,
|
|
qrxlevmin_presence := '1'B,
|
|
qrxlevmin := qrxlevmin);
|
|
|
|
template SystemInformationConfig SystemInformationConfig_default := {
|
|
si1 := {
|
|
cell_chan_desc := '8FB38000000000000000000000000000'O,
|
|
rach_control := {
|
|
max_retrans := RACH_MAX_RETRANS_7,
|
|
tx_integer := '1001'B,
|
|
cell_barr_access := false,
|
|
re_not_allowed := true,
|
|
acc := '0000010000000000'B
|
|
},
|
|
rest_octets := ?
|
|
},
|
|
si2 := {
|
|
bcch_freq_list := '00000000000000000000000000000000'O,
|
|
ncc_permitted := '11111111'B,
|
|
rach_control := {
|
|
max_retrans := RACH_MAX_RETRANS_7,
|
|
tx_integer := '1001'B,
|
|
cell_barr_access := false,
|
|
re_not_allowed := true,
|
|
acc := '0000010000000000'B
|
|
}
|
|
},
|
|
si2bis := omit,
|
|
si2ter := {
|
|
extd_bcch_freq_list := '8E320000000000000000000000000800'O,
|
|
rest_octets := ?
|
|
},
|
|
si2quater := {
|
|
tr_SI2quaterRestOctets_EUTRAN( repeated_neigh_cells := { tr_EUTRAN_NeighbourCells_default } )
|
|
},
|
|
si3 := {
|
|
cell_id := 0,
|
|
lai := {
|
|
mcc_mnc := '001F01'H,
|
|
lac := 1
|
|
},
|
|
ctrl_chan_desc := {
|
|
msc_r99 := true,
|
|
att := true,
|
|
bs_ag_blks_res := 1,
|
|
ccch_conf := CCHAN_DESC_1CCCH_COMBINED,
|
|
si22ind := false,
|
|
cbq3 := CBQ3_IU_MODE_NOT_SUPPORTED,
|
|
spare := '00'B,
|
|
bs_pa_mfrms := 3,
|
|
t3212 := 30
|
|
},
|
|
cell_options := {
|
|
dn_ind := false,
|
|
pwrc := false,
|
|
dtx := MS_SHALL_USE_UL_DTX,
|
|
radio_link_tout_div4 := 7
|
|
},
|
|
cell_sel_par := {
|
|
cell_resel_hyst_2dB := 2,
|
|
ms_txpwr_max_cch := 7,
|
|
acs := '0'B,
|
|
neci := true,
|
|
rxlev_access_min := 0
|
|
},
|
|
rach_control := {
|
|
max_retrans := RACH_MAX_RETRANS_7,
|
|
tx_integer := '1001'B,
|
|
cell_barr_access := false,
|
|
re_not_allowed := true,
|
|
acc := '0000010000000000'B
|
|
},
|
|
rest_octets := {
|
|
sel_params := {
|
|
presence := '0'B,
|
|
params := omit
|
|
},
|
|
pwr_offset := {
|
|
presence := '0'B,
|
|
offset := omit
|
|
},
|
|
si_2ter_ind := '1'B,
|
|
early_cm_ind := '0'B,
|
|
sched_where := {
|
|
presence := '0'B,
|
|
where := omit
|
|
},
|
|
gprs_ind := {
|
|
presence := '1'B,
|
|
ind := {
|
|
ra_colour := 0,
|
|
si13_pos := '0'B
|
|
}
|
|
},
|
|
umts_early_cm_ind := '1'B,
|
|
si2_quater_ind := {
|
|
presence := '1'B,
|
|
ind := '0'B
|
|
},
|
|
iu_mode_ind := omit,
|
|
si21_ind := {
|
|
presence := '0'B,
|
|
pos := omit
|
|
}
|
|
}
|
|
},
|
|
si4 := {
|
|
lai := {
|
|
mcc_mnc := '001F01'H,
|
|
lac := 1
|
|
},
|
|
cell_sel_par := {
|
|
cell_resel_hyst_2dB := 2,
|
|
ms_txpwr_max_cch := 7,
|
|
acs := '0'B,
|
|
neci := true,
|
|
rxlev_access_min := 0
|
|
},
|
|
rach_control := {
|
|
max_retrans := RACH_MAX_RETRANS_7,
|
|
tx_integer := '1001'B,
|
|
cell_barr_access := false,
|
|
re_not_allowed := true,
|
|
acc := '0000010000000000'B
|
|
},
|
|
cbch_chan_desc := {
|
|
iei := '64'O,
|
|
v := {
|
|
chan_nr := {
|
|
u := {
|
|
sdcch4 := {
|
|
tag := '001'B,
|
|
sub_chan := 2
|
|
}
|
|
},
|
|
tn := 0
|
|
},
|
|
tsc := 2,
|
|
h := false,
|
|
arfcn := 871,
|
|
maio_hsn := omit
|
|
}
|
|
},
|
|
cbch_mobile_alloc := omit,
|
|
rest_octets := {
|
|
sel_params := {
|
|
presence := '0'B,
|
|
params := omit
|
|
},
|
|
pwr_offset := {
|
|
presence := '0'B,
|
|
offset := omit
|
|
},
|
|
gprs_ind := {
|
|
presence := '1'B,
|
|
ind := {
|
|
ra_colour := 0,
|
|
si13_pos := '0'B
|
|
}
|
|
},
|
|
s_presence := '0'B,
|
|
s := omit
|
|
}
|
|
},
|
|
si13 := {
|
|
rest_octets := {
|
|
presence := '1'B,
|
|
bcch_change_mark := ?,
|
|
si_change_field := '0000'B,
|
|
presence2 := '0'B,
|
|
si13_change_mark := omit,
|
|
gprs_ma := omit,
|
|
zero := '0'B, /* PBCCH not present in cell */
|
|
rac := 0,
|
|
spgc_ccch_sup := '0'B,
|
|
priority_access_thr := '110'B,
|
|
network_control_order := '00'B,
|
|
gprs_cell_opts := {
|
|
nmo := '01'B,
|
|
t3168 := '011'B,
|
|
t3192 := '010'B,
|
|
drx_timer_max := '011'B,
|
|
access_burst_type := '0'B,
|
|
control_ack_type := '1'B,
|
|
bs_cv_max := 15,
|
|
pan_presence := '1'B,
|
|
pan_dec := 1,
|
|
pan_inc := 1,
|
|
pan_max := '111'B,
|
|
ext_info_presence := ?,
|
|
ext_info_length := *,
|
|
ext_info := *
|
|
},
|
|
gprs_pwr_ctrl_params := {
|
|
alpha := 0,
|
|
t_avg_w := '10000'B,
|
|
t_avg_t := '10000'B,
|
|
pc_meas_chan := '0'B,
|
|
n_avg_i := '1000'B
|
|
}
|
|
}
|
|
},
|
|
si5 := {
|
|
bcch_freq_list := '10000000000000000000000000000000'O
|
|
},
|
|
si5bis := omit,
|
|
si5ter := {
|
|
extd_bcch_freq_list := '9E050020000000000000000000000000'O
|
|
},
|
|
si6 := {
|
|
cell_id := 0,
|
|
lai := {
|
|
mcc_mnc := '001F01'H,
|
|
lac := 1
|
|
},
|
|
cell_options := {
|
|
dtx_ext := '1'B,
|
|
pwrc := false,
|
|
dtx := '01'B,
|
|
radio_link_timeout := '0111'B
|
|
},
|
|
ncc_permitted := '11111111'B,
|
|
rest_octets := {
|
|
pch_nch_info := ?,
|
|
vbs_vgcs_options := ?,
|
|
dtm_support := '0'B,
|
|
rac := omit,
|
|
max_lapdm := omit,
|
|
band_ind := '0'B /* C0 ARFCN indicates 1800 band */
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/* List of all the System Information received on all RSL ports */
|
|
type record of SystemInformationConfig SystemInformationConfig_list;
|
|
|
|
function f_sysinfo_dec_raw(inout SystemInformationConfig si, RSL_Message rsl)
|
|
{
|
|
var RSL_IE_Body sysinfo_type_ie;
|
|
var RSL_IE_SysinfoType si_type;
|
|
var octetstring data;
|
|
|
|
if (f_rsl_find_ie(rsl, RSL_IE_SYSINFO_TYPE, sysinfo_type_ie) == false) {
|
|
setverdict(fail, "Cannot find RSL_IE_SYSINFO_TYPE");
|
|
mtc.stop;
|
|
}
|
|
si_type := sysinfo_type_ie.sysinfo_type;
|
|
|
|
if (rsl.msg_type == RSL_MT_BCCH_INFO) {
|
|
var RSL_IE_Body bcch_ie;
|
|
if (f_rsl_find_ie(rsl, RSL_IE_FULL_BCCH_INFO, bcch_ie)) {
|
|
data := bcch_ie.other.payload;
|
|
}
|
|
} else if (rsl.msg_type == RSL_MT_SACCH_FILL) {
|
|
var RSL_IE_Body l3_ie;
|
|
if (f_rsl_find_ie(rsl, RSL_IE_L3_INFO, l3_ie)) {
|
|
data := l3_ie.l3_info.payload;
|
|
}
|
|
} else {
|
|
setverdict(fail, "Don't understand this System Information message");
|
|
mtc.stop;
|
|
}
|
|
|
|
var boolean handled := false;
|
|
|
|
if (rsl.msg_type == RSL_MT_BCCH_INFO) {
|
|
handled := true;
|
|
|
|
if (si_type == RSL_SYSTEM_INFO_1) {
|
|
if (not isbound(data)) {
|
|
si.si1 := omit;
|
|
} else {
|
|
si.si1 := dec_SystemInformation(data).payload.si1;
|
|
}
|
|
} else if (si_type == RSL_SYSTEM_INFO_2) {
|
|
if (not isbound(data)) {
|
|
si.si2 := omit;
|
|
} else {
|
|
si.si2 := dec_SystemInformation(data).payload.si2;
|
|
}
|
|
} else if (si_type == RSL_SYSTEM_INFO_2bis) {
|
|
if (not isbound(data)) {
|
|
si.si2bis := omit;
|
|
} else {
|
|
si.si2bis := dec_SystemInformation(data).payload.si2bis;
|
|
}
|
|
} else if (si_type == RSL_SYSTEM_INFO_2ter) {
|
|
if (not isbound(data)) {
|
|
si.si2ter := omit;
|
|
} else {
|
|
si.si2ter := dec_SystemInformation(data).payload.si2ter;
|
|
}
|
|
} else if (si_type == RSL_SYSTEM_INFO_2quater) {
|
|
if (not isbound(data)) {
|
|
si.si2quater := {};
|
|
} else {
|
|
var SystemInformationType2quater decoded := dec_SystemInformation(data).payload.si2quater;
|
|
/* this is a *record* of SI2quaterRestOctets! (multiplexed) */
|
|
si.si2quater[decoded.rest_octets.si2quater_index] := decoded.rest_octets;
|
|
}
|
|
} else if (si_type == RSL_SYSTEM_INFO_3) {
|
|
if (not isbound(data)) {
|
|
si.si3 := omit;
|
|
} else {
|
|
si.si3 := dec_SystemInformation(data).payload.si3;
|
|
}
|
|
} else if (si_type == RSL_SYSTEM_INFO_4) {
|
|
if (not isbound(data)) {
|
|
si.si4 := omit;
|
|
} else {
|
|
si.si4 := dec_SystemInformation(data).payload.si4;
|
|
}
|
|
} else if (si_type == RSL_SYSTEM_INFO_13) {
|
|
if (not isbound(data)) {
|
|
si.si13 := omit;
|
|
} else {
|
|
si.si13 := dec_SystemInformation(data).payload.si13;
|
|
}
|
|
} else {
|
|
handled := false;
|
|
}
|
|
} else if (rsl.msg_type == RSL_MT_SACCH_FILL) {
|
|
handled := true;
|
|
|
|
if (si_type == RSL_SYSTEM_INFO_5) {
|
|
if (not isbound(data)) {
|
|
si.si5 := omit;
|
|
} else {
|
|
si.si5 := dec_SystemInformation(data).payload.si5;
|
|
}
|
|
} else if (si_type == RSL_SYSTEM_INFO_5bis) {
|
|
if (not isbound(data)) {
|
|
si.si5bis := omit;
|
|
} else {
|
|
si.si5bis := dec_SystemInformation(data).payload.si5bis;
|
|
}
|
|
} else if (si_type == RSL_SYSTEM_INFO_5ter) {
|
|
if (not isbound(data)) {
|
|
si.si5ter := omit;
|
|
} else {
|
|
si.si5ter := dec_SystemInformation(data).payload.si5ter;
|
|
}
|
|
} else if (si_type == RSL_SYSTEM_INFO_6) {
|
|
if (not isbound(data)) {
|
|
si.si6 := omit;
|
|
} else {
|
|
si.si6 := dec_SystemInformation(data).payload.si6;
|
|
}
|
|
} else {
|
|
handled := false;
|
|
}
|
|
}
|
|
|
|
if (not handled) {
|
|
setverdict(fail, "Unexpected SI type in ", rsl.msg_type, " message: ", si_type);
|
|
}
|
|
}
|
|
|
|
friend function gen_l3_valid_payload(hexstring imsi := ''H) return octetstring {
|
|
var octetstring l3_payload;
|
|
if (lengthof(imsi) == 0) {
|
|
imsi := f_rnd_imsi('00101'H);
|
|
}
|
|
l3_payload := enc_PDU_ML3_MS_NW(valueof(ts_LU_REQ(LU_Type_IMSI_Attach, ts_MI_LV(ts_MI_IMSI(imsi)))));
|
|
return l3_payload;
|
|
}
|
|
|
|
type component test_CT extends CTRL_Adapter_CT {
|
|
/* Array of per-BTS/TRX state */
|
|
var BTS_State bts[NUM_BTS][NUM_TRX];
|
|
/* RSL common Channel Port (for RSL_Emulation) */
|
|
port RSL_CCHAN_PT RSL_CCHAN[NUM_BTS];
|
|
/* array of per-BTS/TRX RSL test ports */
|
|
port IPA_RSL_PT IPA_RSL[NUM_BTS][NUM_TRX];
|
|
port IPA_CODEC_PT IPA; /* Required for compilation of TC_rsl_unknown_unit_id() */
|
|
/* CTRL muxed over IPA in SCCPlite conn BSC<->MSC (or BSC-NAT) */
|
|
port IPA_CTRL_PT SCCPLITE_IPA_CTRL;
|
|
/* Configure/manage IPA_Emulation per-BTS/TRX port: */
|
|
port IPA_CFG_PT IPA_CFG_PORT[NUM_BTS][NUM_TRX];
|
|
|
|
var MGCP_Emulation_CT vc_MGCP[NUM_MGW];
|
|
var integer g_nr_mgw; /* number of vc_MGCP to initialize */
|
|
port TELNETasp_PT BSCVTY;
|
|
|
|
/* StatsD */
|
|
var StatsD_Checker_CT vc_STATSD;
|
|
|
|
var RAN_Adapter g_bssap[NUM_MSC];
|
|
var BSSAP_LE_Adapter g_bssap_le;
|
|
/* for old legacy-tests only */
|
|
port BSSAP_CODEC_PT BSSAP;
|
|
port BSSAP_LE_CODEC_PT BSSAP_LE;
|
|
|
|
/* are we initialized yet */
|
|
var boolean g_initialized := false;
|
|
|
|
var boolean g_handler_mode := false;
|
|
|
|
/* Osmux is enabled through VTY */
|
|
var boolean g_osmux_enabled_cn := false;
|
|
var boolean g_osmux_enabled_bts := false;
|
|
|
|
/*Configure T(tias) over VTY, seconds */
|
|
var integer g_bsc_sccp_timer_ias := 7 * 60;
|
|
/*Configure T(tiar) over VTY, seconds */
|
|
var integer g_bsc_sccp_timer_iar := 15 * 60;
|
|
|
|
/* global test case guard timer (actual timeout value is set in f_init()) */
|
|
timer T_guard := 30.0;
|
|
|
|
var CounterNameValsList g_ctr_msc;
|
|
var CounterNameValsList g_ctr_bsc;
|
|
var CounterNameValsList g_ctr_bts;
|
|
|
|
/* System Information bytes as received during RSL startup, for each RSL[idx]. */
|
|
var SystemInformationConfig_list g_system_information := {};
|
|
}
|
|
|
|
type record of charstring phys_chan_configs;
|
|
modulepar {
|
|
/* IP address at which the BSC can be reached */
|
|
charstring mp_bsc_ip := "127.0.0.1";
|
|
/* port number to which to establish the IPA OML connections */
|
|
integer mp_bsc_oml_port := 3002;
|
|
/* port number to which to establish the IPA RSL connections */
|
|
integer mp_bsc_rsl_port := 3003;
|
|
/* port number to which to establish the IPA CTRL connection */
|
|
integer mp_bsc_ctrl_port := 4249;
|
|
/* port number to which to listen for STATSD metrics */
|
|
integer mp_bsc_statsd_port := 8125;
|
|
/* IP address at which the test binds */
|
|
charstring mp_test_ip := "127.0.0.1";
|
|
|
|
RAN_Configurations mp_bssap_cfg := {
|
|
{
|
|
transport := BSSAP_TRANSPORT_AoIP,
|
|
sccp_service_type := "mtp3_itu",
|
|
sctp_addr := { 23905, "127.0.0.1", 2905, "127.0.0.1" },
|
|
own_pc := 185, /* 0.23.1 first MSC emulation */
|
|
own_ssn := 254,
|
|
peer_pc := 187, /* 0.23.3 osmo-bsc */
|
|
peer_ssn := 254,
|
|
sio := '83'O,
|
|
rctx := 1
|
|
},
|
|
{
|
|
transport := BSSAP_TRANSPORT_AoIP,
|
|
sccp_service_type := "mtp3_itu",
|
|
sctp_addr := { 23906, "127.0.0.1", 2905, "127.0.0.1" },
|
|
own_pc := 2, /* 0.0.2 second MSC emulation */
|
|
own_ssn := 254,
|
|
peer_pc := 187, /* 0.23.3 osmo-bsc */
|
|
peer_ssn := 254,
|
|
sio := '83'O,
|
|
rctx := 2
|
|
},
|
|
{
|
|
transport := BSSAP_TRANSPORT_AoIP,
|
|
sccp_service_type := "mtp3_itu",
|
|
sctp_addr := { 23907, "127.0.0.1", 2905, "127.0.0.1" },
|
|
own_pc := 3, /* 0.0.3 third MSC emulation */
|
|
own_ssn := 254,
|
|
peer_pc := 187, /* 0.23.3 osmo-bsc */
|
|
peer_ssn := 254,
|
|
sio := '83'O,
|
|
rctx := 3
|
|
}
|
|
};
|
|
|
|
/* Must match per BTS config in osmo-bsc.cfg */
|
|
phys_chan_configs phys_chan_config := {
|
|
"CCCH+SDCCH4+CBCH",
|
|
"TCH/F",
|
|
"TCH/F",
|
|
"TCH/F",
|
|
"TCH/F",
|
|
"TCH/H",
|
|
"PDCH",
|
|
"PDCH"
|
|
};
|
|
|
|
BSSAP_LE_Configuration mp_bssap_le_cfg := {
|
|
sccp_service_type := "mtp3_itu",
|
|
sctp_addr := { 23908, "127.0.0.1", 2905, "127.0.0.1" },
|
|
own_pc := 190, /* 0.23.6 SMLC emulation */
|
|
own_ssn := 252, /* SMLC side SSN */
|
|
peer_pc := 187, /* 0.23.3 osmo-bsc */
|
|
peer_ssn := 250, /* BSC side SSN */
|
|
sio := '83'O,
|
|
rctx := 6
|
|
};
|
|
boolean mp_enable_lcs_tests := true;
|
|
|
|
/* Value set in osmo-bsc.cfg "ms max power" */
|
|
uint8_t mp_exp_ms_power_level := 7;
|
|
|
|
/* Whether to check for memory leaks */
|
|
boolean mp_verify_talloc_count := true;
|
|
}
|
|
|
|
friend function f_gen_test_hdlr_pars(integer bssap_idx := 0) return TestHdlrParams {
|
|
|
|
var TestHdlrParams pars := valueof(t_def_TestHdlrPars);
|
|
if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
|
|
pars.aoip := true;
|
|
} else {
|
|
pars.aoip := false;
|
|
}
|
|
pars.exp_ms_power_level := mp_exp_ms_power_level;
|
|
pars.mscpool.bssap_idx := bssap_idx;
|
|
pars.expect_tsc := c_BtsParams[0].tsc;
|
|
pars.imsi := f_rnd_imsi('00101'H);
|
|
pars.imei := f_rnd_imei('00101'H);
|
|
|
|
log(testcasename(), ": using IMSI ", pars.imsi);
|
|
|
|
return pars;
|
|
}
|
|
|
|
/* Convenience functions for rate counters using g_ctr_msc. */
|
|
|
|
private function f_ctrs_msc_init(integer mscs_count := NUM_MSC, CounterNameVals counternames := counternames_msc_mscpool) runs on test_CT {
|
|
g_ctr_msc := f_counter_name_vals_get_n(IPA_CTRL, "msc", mscs_count, counternames);
|
|
log("initial msc rate counters: ", g_ctr_msc);
|
|
}
|
|
|
|
private function f_ctrs_msc_add(integer msc_nr, charstring countername, integer val := 1) runs on test_CT {
|
|
f_counter_name_vals_list_add(g_ctr_msc, msc_nr, countername, val);
|
|
}
|
|
|
|
/* f_ctrs_msc_init();
|
|
* f_do_thing(on_msc := 0);
|
|
* f_do_thing(on_msc := 0);
|
|
* f_do_other(on_msc := 1);
|
|
* f_ctrs_msc_add(0, "thing", 2);
|
|
* f_ctrs_msc_add(1, "other");
|
|
* f_ctrs_msc_verify();
|
|
*/
|
|
private function f_ctrs_msc_verify() runs on test_CT {
|
|
log("verifying msc rate counters: ", g_ctr_msc);
|
|
f_counter_name_vals_expect_n(IPA_CTRL, "msc", g_ctr_msc);
|
|
}
|
|
|
|
/* convenience: f_ctrs_msc_add() and f_ctrs_msc_verify() in one call.
|
|
* f_ctrs_msc_init();
|
|
* f_do_thing(on_msc := 0);
|
|
* f_do_thing(on_msc := 0);
|
|
* f_do_thing(on_msc := 0);
|
|
* f_ctrs_msc_expect(0, "thing", 3);
|
|
*/
|
|
private function f_ctrs_msc_expect(integer msc_nr, charstring countername, integer val := 1) runs on test_CT {
|
|
f_ctrs_msc_add(msc_nr, countername, val);
|
|
f_ctrs_msc_verify();
|
|
}
|
|
|
|
/* Convenience functions for rate counters using g_ctr_bts, always also including g_ctr_bsc. */
|
|
|
|
private function f_ctrs_bts_init(integer bts_count := NUM_BTS, CounterNameVals counternames := counternames_bsc_bts_handover) runs on test_CT {
|
|
g_ctr_bts := f_counter_name_vals_get_n(IPA_CTRL, "bts", bts_count, counternames);
|
|
log("initial bts rate counters: ", g_ctr_bts);
|
|
}
|
|
|
|
function f_ctrs_bsc_and_bts_init(integer bts_count := NUM_BTS, CounterNameVals counternames := counternames_bsc_bts_handover) runs on test_CT {
|
|
f_ctrs_bts_init(bts_count, counternames);
|
|
f_ctrs_bsc_init(counternames);
|
|
}
|
|
|
|
private function f_ctrs_bsc_and_bts_handover_init(integer bts_count := NUM_BTS) runs on test_CT {
|
|
var CounterNameVals bts_names := counternames_bsc_bts_handover & counternames_bts_handover;
|
|
f_ctrs_bts_init(bts_count, bts_names);
|
|
f_ctrs_bsc_init(counternames_bsc_bts_handover);
|
|
}
|
|
|
|
private function f_ctrs_bts_add(integer bts_nr, charstring countername, integer val := 1) runs on test_CT {
|
|
f_counter_name_vals_list_add(g_ctr_bts, bts_nr, countername, val);
|
|
}
|
|
|
|
private function f_ctrs_bsc_and_bts_add(integer bts_nr, charstring countername, integer val := 1) runs on test_CT {
|
|
f_ctrs_bts_add(bts_nr, countername, val);
|
|
f_ctrs_bsc_add(countername, val);
|
|
}
|
|
|
|
function f_ctrs_bts_verify() runs on test_CT {
|
|
f_counter_name_vals_expect_n(IPA_CTRL, "bts", g_ctr_bts);
|
|
}
|
|
|
|
/* f_ctrs_bsc_and_bts_init();
|
|
* f_do_thing(on_bts := 0);
|
|
* f_do_thing(on_bts := 0);
|
|
* f_do_other(on_bts := 1);
|
|
* f_ctrs_bsc_and_bts_add(0, "thing", 2);
|
|
* f_ctrs_bsc_and_bts_add(1, "other");
|
|
* f_ctrs_bsc_and_bts_verify();
|
|
*/
|
|
private function f_ctrs_bsc_and_bts_verify() runs on test_CT {
|
|
f_ctrs_bts_verify();
|
|
f_ctrs_bsc_verify();
|
|
}
|
|
|
|
/* convenience: f_ctrs_bsc_and_bts_add() and f_ctrs_bsc_and_bts_verify() in one call.
|
|
* f_ctrs_bsc_and_bts_init();
|
|
* f_do_thing(on_bts := 0);
|
|
* f_do_thing(on_bts := 0);
|
|
* f_do_thing(on_bts := 0);
|
|
* f_ctrs_bsc_and_bts_expect(0, "thing", 3);
|
|
*/
|
|
private function f_ctrs_bsc_and_bts_expect(integer bts_nr, charstring countername, integer val := 1) runs on test_CT {
|
|
f_ctrs_bsc_and_bts_add(bts_nr, countername, val);
|
|
f_ctrs_bsc_and_bts_verify();
|
|
}
|
|
|
|
|
|
/* Convenience functions for rate counters using g_ctr_bsc. */
|
|
|
|
private function f_ctrs_bsc_init(CounterNameVals counternames := counternames_bsc_bts_handover) runs on test_CT {
|
|
g_ctr_bsc := f_counter_name_vals_get_n(IPA_CTRL, "bsc", 1, counternames);
|
|
log("initial bsc rate counters: ", g_ctr_bsc);
|
|
}
|
|
|
|
private function f_ctrs_bsc_add(charstring countername, integer val := 1) runs on test_CT {
|
|
f_counter_name_vals_list_add(g_ctr_bsc, 0, countername, val);
|
|
}
|
|
|
|
/* f_ctrs_bsc_init();
|
|
* f_do_thing();
|
|
* f_do_thing();
|
|
* f_do_other();
|
|
* f_ctrs_bsc_add("thing", 2);
|
|
* f_ctrs_bsc_add("other");
|
|
* f_ctrs_bsc_verify();
|
|
*/
|
|
private function f_ctrs_bsc_verify() runs on test_CT {
|
|
f_counter_name_vals_expect_n(IPA_CTRL, "bsc", g_ctr_bsc);
|
|
}
|
|
|
|
/* convenience: f_ctrs_bsc_add() and f_ctrs_bsc_verify() in one call.
|
|
* f_ctrs_bsc_init();
|
|
* f_do_thing();
|
|
* f_ctrs_bsc_expect("thing", 1);
|
|
*/
|
|
private function f_ctrs_bsc_expect(charstring countername, integer val := 1) runs on test_CT {
|
|
f_ctrs_bsc_add(countername, val);
|
|
f_ctrs_bsc_verify();
|
|
}
|
|
|
|
|
|
friend function f_shutdown_helper(boolean ho := false) runs on test_CT {
|
|
/* Run the subscr and conn leak test only when the VTY is initialized */
|
|
if (BSCVTY.checkstate("Mapped") and mp_verify_talloc_count) {
|
|
f_verify_talloc_count(BSCVTY, {"struct bsc_subscr", "struct gsm_subscriber_connection"});
|
|
}
|
|
|
|
/* Reset handover related configuration */
|
|
if (ho) {
|
|
f_bts_0_cfg(BSCVTY,
|
|
{"no neighbors",
|
|
"neighbor-list mode manual-si5",
|
|
"neighbor-list add arfcn 100",
|
|
"neighbor-list add arfcn 200",
|
|
"si5 neighbor-list add arfcn 10",
|
|
"si5 neighbor-list add arfcn 20",
|
|
"handover algorithm 1"});
|
|
}
|
|
|
|
all component.stop;
|
|
setverdict(pass);
|
|
mtc.stop;
|
|
}
|
|
|
|
private function f_legacy_bssap_reset(integer bssap_idx := 0) runs on test_CT {
|
|
var BSSAP_N_UNITDATA_ind ud_ind;
|
|
var boolean reset_received := false;
|
|
timer T := 5.0;
|
|
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap[bssap_idx].sccp_addr_peer, g_bssap[bssap_idx].sccp_addr_own,
|
|
ts_BSSMAP_Reset(0, g_osmux_enabled_cn)));
|
|
T.start;
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap[bssap_idx].sccp_addr_own, g_bssap[bssap_idx].sccp_addr_peer,
|
|
tr_BSSMAP_ResetAck(g_osmux_enabled_cn))) {
|
|
log("BSSMAP: Received RESET-ACK in response to RESET, we're ready to go!");
|
|
}
|
|
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_osmux_enabled_cn))) -> value ud_ind {
|
|
log("BSSMAP: Respoding to inbound RESET with RESET-ACK");
|
|
BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
|
|
ts_BSSMAP_ResetAck(g_osmux_enabled_cn)));
|
|
reset_received := true;
|
|
repeat;
|
|
}
|
|
[] BSSAP.receive { repeat; }
|
|
[] T.timeout {
|
|
log("BSSMAP: Timeout waiting for RESET-ACK after sending RESET");
|
|
/* If we received a RESET after ours was sent, it
|
|
may be a race condition where the other peer beacame
|
|
available after we sent it, but we are in a desired
|
|
state anyway, so go forward. */
|
|
if (not reset_received) {
|
|
setverdict(fail);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type record IPA_Client {
|
|
/* IPA Emulation component reference */
|
|
IPA_Emulation_CT vc_IPA,
|
|
/* Unit-ID and other CCM parameters to use for IPA client emulation */
|
|
IPA_CCM_Parameters ccm_pars,
|
|
/* String identifier for this IPA Client */
|
|
charstring id,
|
|
/* Associated RSL Emulation Component (if any). Only used in "Handler mode" */
|
|
RSL_Emulation_CT vc_RSL optional
|
|
}
|
|
|
|
/*! Start the IPA/RSL related bits for one IPA_Client.
|
|
* \param clnt IPA_Client for which to establish
|
|
* \param bsc_host IP address / hostname of the BSC
|
|
* \param bsc_port TCP port number of the BSC
|
|
* \param idx BTS/TRX index values
|
|
* \param handler_mode Start an RSL_Emulation_CT component (true) or not (false) */
|
|
function f_ipa_rsl_start(inout IPA_Client clnt, charstring bsc_host, PortNumber bsc_port,
|
|
BtsTrxIdx idx := {0, 0}, boolean handler_mode := false)
|
|
runs on test_CT {
|
|
timer T := 10.0;
|
|
|
|
clnt.id := "IPA-BTS" & int2str(idx.bts) & "-TRX" & int2str(idx.trx) & "-RSL";
|
|
clnt.vc_IPA := IPA_Emulation_CT.create(clnt.id & "-IPA") alive;
|
|
clnt.ccm_pars := c_IPA_default_ccm_pars;
|
|
clnt.ccm_pars.name := "Osmocom TTCN-3 BTS Simulator";
|
|
clnt.ccm_pars.unit_id := int2str(1234 + idx.bts) & "/0/" & int2str(idx.trx);
|
|
if (handler_mode) {
|
|
clnt.vc_RSL := RSL_Emulation_CT.create(clnt.id & "-RSL") alive;
|
|
connect(clnt.vc_RSL:CCHAN_PT, self:RSL_CCHAN[idx.bts]);
|
|
}
|
|
|
|
map(clnt.vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
|
|
connect(clnt.vc_IPA:CFG_PORT, self:IPA_CFG_PORT[idx.bts][idx.trx]);
|
|
if (handler_mode) {
|
|
connect(clnt.vc_IPA:IPA_RSL_PORT, clnt.vc_RSL:IPA_PT);
|
|
} else {
|
|
connect(clnt.vc_IPA:IPA_RSL_PORT, self:IPA_RSL[idx.bts][idx.trx]);
|
|
}
|
|
|
|
var integer local_port := 10000 + idx.bts * 1000 + idx.trx;
|
|
clnt.vc_IPA.start(IPA_Emulation.main_client(bsc_host, bsc_port, "", local_port, clnt.ccm_pars));
|
|
if (handler_mode) {
|
|
clnt.vc_RSL.start(RSL_Emulation.main());
|
|
return;
|
|
}
|
|
|
|
/* wait for IPA RSL link to connect and send ID ACK */
|
|
T.start;
|
|
alt {
|
|
[] IPA_RSL[idx.bts][idx.trx].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK)) {
|
|
T.stop;
|
|
}
|
|
[] IPA_RSL[idx.bts][idx.trx].receive(ASP_IPA_Event:?) { repeat }
|
|
[] IPA_RSL[idx.bts][idx.trx].receive { repeat }
|
|
[] T.timeout {
|
|
setverdict(fail, "Timeout RSL waiting for ASP_IPA_EVENT_ID_ACK");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
}
|
|
|
|
function f_ipa_rsl_stop(inout IPA_Client clnt, BtsTrxIdx idx := {0, 0}) runs on test_CT {
|
|
var IPL4asp_Types.Result res := {
|
|
errorCode := omit,
|
|
connId := omit,
|
|
os_error_code := omit,
|
|
os_error_text := omit
|
|
};
|
|
|
|
if (not isbound(clnt) or not isbound(clnt.vc_IPA)) {
|
|
return;
|
|
}
|
|
|
|
/* Alive components don't finish sockets (TCP FIN) when they are
|
|
* stopped. Hence, we need to manually call close() on them to make sure
|
|
* the IUT knows about it. */
|
|
f_ipa_cfg_disconnect(IPA_CFG_PORT[idx.bts][idx.trx], res);
|
|
|
|
clnt.vc_IPA.stop;
|
|
if (isbound(clnt.vc_RSL)) {
|
|
clnt.vc_RSL.stop;
|
|
}
|
|
}
|
|
|
|
/* Wait for the OML connection to be brought up by the external osmo-bts-omldummy */
|
|
function f_wait_oml(integer bts_nr, charstring status, float secs_max) runs on test_CT {
|
|
timer T := secs_max;
|
|
T.start;
|
|
while (true) {
|
|
if (f_ctrl_get_bts(IPA_CTRL, bts_nr, "oml-connection-state") == status) {
|
|
T.stop;
|
|
/* the 'degraded' state exists from OML connection time, and we have to wait
|
|
* until all MO's are initialized */
|
|
T.start(1.0);
|
|
T.timeout;
|
|
return;
|
|
}
|
|
f_sleep(0.1);
|
|
if (not T.running) {
|
|
setverdict(fail, "Timeout waiting for BTS" & int2str(bts_nr) & " oml-connection-state ", status);
|
|
mtc.stop;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* global altstep for global guard timer; also takes care of responding RESET witH RESET-ACK */
|
|
altstep as_Tguard() runs on test_CT {
|
|
var BSSAP_N_UNITDATA_ind ud_ind;
|
|
[] T_guard.timeout {
|
|
setverdict(fail, "Timeout of T_guard");
|
|
mtc.stop;
|
|
}
|
|
/* always respond with RESET ACK to RESET */
|
|
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_osmux_enabled_cn))) -> value ud_ind {
|
|
BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
|
|
ts_BSSMAP_ResetAck(g_osmux_enabled_cn)));
|
|
repeat;
|
|
}
|
|
}
|
|
|
|
altstep no_bssmap_reset() runs on test_CT {
|
|
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_osmux_enabled_cn))) {
|
|
setverdict(fail, "unexpected BSSMAP Reset");
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
function f_init_mgcp(integer mgw_nr, charstring id) runs on test_CT {
|
|
id := id & "-MGCP-" & int2str(mgw_nr);
|
|
|
|
var MGCPOps ops := {
|
|
create_cb := refers(MGCP_Emulation.ExpectedCreateCallback),
|
|
unitdata_cb := refers(MGCP_Emulation.DummyUnitdataCallback)
|
|
};
|
|
var MGCP_conn_parameters mgcp_pars := {
|
|
callagent_ip := mp_bsc_ip,
|
|
callagent_udp_port := -1,
|
|
mgw_ip := mp_test_ip,
|
|
mgw_udp_port := 2427 + mgw_nr,
|
|
/* Enable it for SCCPlite, since we have 2 MGCP sockets towards MGW (UDP one +
|
|
the one with MGCP over IPA forwarded from MSC one) */
|
|
multi_conn_mode := (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_SCCPlite_SERVER)
|
|
};
|
|
|
|
vc_MGCP[mgw_nr] := MGCP_Emulation_CT.create(id) alive;
|
|
vc_MGCP[mgw_nr].start(MGCP_Emulation.main(ops, mgcp_pars, id));
|
|
}
|
|
|
|
/* Enable or disable (current default) Osmux. When enabling, BSSMAP Reset
|
|
* contains extra IE (OsmuxSupport) and osmo-bsc will handle AssignReq with
|
|
* OsmuxCID IE.
|
|
*/
|
|
private function f_vty_allow_osmux_cn(boolean allow) runs on test_CT {
|
|
f_vty_enter_cfg_msc(BSCVTY, 0);
|
|
if (allow) {
|
|
f_vty_transceive(BSCVTY, "osmux on");
|
|
} else {
|
|
f_vty_transceive(BSCVTY, "osmux off");
|
|
}
|
|
f_vty_transceive(BSCVTY, "exit");
|
|
f_vty_transceive(BSCVTY, "exit");
|
|
}
|
|
|
|
function f_init_vty(charstring id := "foo") runs on test_CT {
|
|
if (BSCVTY.checkstate("Mapped")) {
|
|
/* skip initialization if already executed once */
|
|
return;
|
|
}
|
|
map(self:BSCVTY, system:BSCVTY);
|
|
f_vty_set_prompts(BSCVTY);
|
|
f_vty_transceive(BSCVTY, "enable");
|
|
f_cs7_inst_0_cfg(BSCVTY, {"sccp-timer ias " & int2str(g_bsc_sccp_timer_ias),
|
|
"sccp-timer iar " & int2str(g_bsc_sccp_timer_iar)});
|
|
}
|
|
|
|
friend function f_logp(TELNETasp_PT pt, charstring log_msg)
|
|
{
|
|
// log on TTCN3 log output
|
|
log(log_msg);
|
|
// log in stderr log
|
|
if (pt.checkstate("Mapped")) {
|
|
f_vty_transceive(pt, "logp lglobal notice TTCN3 f_logp(): " & log_msg);
|
|
}
|
|
}
|
|
|
|
private function f_sysinfo_seen(integer rsl_idx, RSL_Message rsl) runs on test_CT
|
|
{
|
|
if (rsl_idx >= lengthof(g_system_information)) {
|
|
g_system_information[rsl_idx] := SystemInformationConfig_omit
|
|
}
|
|
f_sysinfo_dec_raw(g_system_information[rsl_idx], rsl);
|
|
}
|
|
|
|
altstep as_catch_RSL_sysinfo(integer rsl_idx) runs on test_CT {
|
|
var ASP_RSL_Unitdata rx_rsl_ud;
|
|
|
|
/* For handler_mode := false, receiving the RSL bootstrap messages directly on IPA_RSL */
|
|
[] IPA_RSL[rsl_idx][0].receive(tr_ASP_RSL_UD(tr_RSL_NO_BCCH_INFO)) -> value rx_rsl_ud {
|
|
f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
|
|
repeat;
|
|
}
|
|
[] IPA_RSL[rsl_idx][0].receive(tr_ASP_RSL_UD(tr_RSL_BCCH_INFO)) -> value rx_rsl_ud {
|
|
f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
|
|
repeat;
|
|
}
|
|
[] IPA_RSL[rsl_idx][0].receive(tr_ASP_RSL_UD(tr_RSL_NO_SACCH_FILL)) -> value rx_rsl_ud {
|
|
f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
|
|
repeat;
|
|
}
|
|
[] IPA_RSL[rsl_idx][0].receive(tr_ASP_RSL_UD(tr_RSL_SACCH_FILL)) -> value rx_rsl_ud {
|
|
f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
|
|
repeat;
|
|
}
|
|
|
|
/* For handler_mode := true, receiving the RSL bootstrap messages via RSL_Emulation */
|
|
[] RSL_CCHAN[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_NO_BCCH_INFO)) -> value rx_rsl_ud {
|
|
f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
|
|
repeat;
|
|
}
|
|
[] RSL_CCHAN[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_BCCH_INFO)) -> value rx_rsl_ud {
|
|
f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
|
|
repeat;
|
|
}
|
|
[] RSL_CCHAN[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_NO_SACCH_FILL)) -> value rx_rsl_ud {
|
|
f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
|
|
repeat;
|
|
}
|
|
[] RSL_CCHAN[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_SACCH_FILL)) -> value rx_rsl_ud {
|
|
f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
|
|
repeat;
|
|
}
|
|
}
|
|
|
|
/* TODO: use BooleanList from COMMON/src/General_Types.ttcn */
|
|
private type record of boolean my_BooleanList;
|
|
|
|
private function f_vty_msc_allow_attach(TELNETasp_PT pt, my_BooleanList allow_attach_list)
|
|
{
|
|
var charstring config := f_vty_transceive_ret(pt, "show running-config");
|
|
|
|
for (var integer msc_nr := 0; msc_nr < sizeof(allow_attach_list); msc_nr := msc_nr+1) {
|
|
if (f_strstr(config, "\nmsc " & int2str(msc_nr) & "\n") < 0) {
|
|
/* There is no 'msc N' for this msc_nr in the running config, so don't create an empty msc by
|
|
* stepping into that config node. */
|
|
log("msc ", msc_nr, " is not configured, skipping");
|
|
continue;
|
|
}
|
|
f_vty_enter_cfg_msc(pt, msc_nr);
|
|
if (allow_attach_list[msc_nr]) {
|
|
/* strict := false: ignore if osmo-bsc does not support this config option (latest build) */
|
|
f_vty_transceive(pt, "allow-attach", strict := false);
|
|
} else {
|
|
f_vty_transceive(pt, "no allow-attach", strict := false);
|
|
}
|
|
f_vty_transceive(pt, "exit");
|
|
f_vty_transceive(pt, "exit");
|
|
}
|
|
}
|
|
|
|
private function f_bssap_idx_init(integer bssap_idx) runs on test_CT {
|
|
/* Call a function of our 'parent component' RAN_Adapter_CT to start the
|
|
* MSC-side BSSAP emulation */
|
|
if (g_handler_mode) {
|
|
var RanOps ranops := MSC_RanOps;
|
|
ranops.use_osmux := g_osmux_enabled_cn;
|
|
f_ran_adapter_init(g_bssap[bssap_idx], mp_bssap_cfg[bssap_idx], "VirtMSC", ranops);
|
|
connect(self:SCCPLITE_IPA_CTRL, g_bssap[bssap_idx].vc_RAN:CTRL_CLIENT);
|
|
f_ran_adapter_start(g_bssap[bssap_idx]);
|
|
} else {
|
|
f_ran_adapter_init(g_bssap[bssap_idx], mp_bssap_cfg[bssap_idx], "VirtMSC", omit);
|
|
connect(self:BSSAP, g_bssap[bssap_idx].vc_SCCP:SCCP_SP_PORT);
|
|
f_ran_adapter_start(g_bssap[bssap_idx]);
|
|
f_legacy_bssap_reset();
|
|
}
|
|
}
|
|
|
|
private function f_bssap_idx_disconnect(integer bssap_idx) runs on test_CT {
|
|
f_ran_adapter_cleanup(g_bssap[bssap_idx]);
|
|
}
|
|
|
|
/* global initialization function
|
|
* \param nr_bts Number of BTSs we should start/bring up
|
|
* \param handler_mode Start an RSL_Emulation_CT component (true) or not (false).
|
|
* \param nr_msc Number of virtual MSCs to bring up to connect to osmo-bsc.
|
|
*/
|
|
function f_init(integer nr_bts := NUM_BTS, boolean handler_mode := false,
|
|
integer nr_msc := 1, integer nr_mgw := 1, float guard_timeout := 30.0) runs on test_CT {
|
|
var integer bssap_idx;
|
|
|
|
if (g_initialized) {
|
|
return;
|
|
}
|
|
g_initialized := true;
|
|
|
|
T_guard.start(guard_timeout);
|
|
activate(as_Tguard());
|
|
|
|
f_init_vty("VirtMSC");
|
|
f_vty_allow_osmux_cn(g_osmux_enabled_cn);
|
|
|
|
var my_BooleanList allow_attach := { false, false, false };
|
|
f_init_statsd("VirtMSC", vc_STATSD, mp_test_ip, mp_bsc_statsd_port);
|
|
|
|
/* Make sure each MSC's internal state is "DISCONNECTED" at first */
|
|
for (bssap_idx := 0; bssap_idx < NUM_MSC; bssap_idx := bssap_idx+1) {
|
|
f_vty_transceive(BSCVTY, "msc " & int2str(bssap_idx) & " bssmap reset", strict := false);
|
|
}
|
|
|
|
g_handler_mode := handler_mode;
|
|
for (bssap_idx := 0; bssap_idx < nr_msc; bssap_idx := bssap_idx+1) {
|
|
allow_attach[bssap_idx] := true;
|
|
f_bssap_idx_init(bssap_idx);
|
|
}
|
|
|
|
if (mp_enable_lcs_tests) {
|
|
if (handler_mode) {
|
|
f_bssap_le_adapter_init(g_bssap_le, mp_bssap_le_cfg, "VirtSMLC", SMLC_BssapLeOps);
|
|
} else {
|
|
f_bssap_le_adapter_init(g_bssap_le, mp_bssap_le_cfg, "VirtSMLC", omit);
|
|
connect(self:BSSAP_LE, g_bssap_le.vc_SCCP:SCCP_SP_PORT);
|
|
}
|
|
f_bssap_le_adapter_start(g_bssap_le);
|
|
}
|
|
|
|
/* start the test with exactly all enabled MSCs allowed to attach */
|
|
f_vty_msc_allow_attach(BSCVTY, allow_attach);
|
|
|
|
f_ipa_ctrl_start_client(mp_bsc_ip, mp_bsc_ctrl_port);
|
|
|
|
g_nr_mgw := nr_mgw;
|
|
for (var integer i := 0; i < g_nr_mgw; i := i+1) {
|
|
f_init_mgcp(i, "VirtMGW");
|
|
}
|
|
|
|
for (var integer i := 0; i < nr_bts; i := i+1) {
|
|
f_init_bts(i, c_BtsParams[i].trx_num, handler_mode);
|
|
}
|
|
|
|
/* Emit a marker to appear in the SUT's own logging output */
|
|
f_logp(BSCVTY, testcasename() & "() start");
|
|
}
|
|
|
|
function f_init_bts(integer bts_idx := 0,
|
|
integer trx_num := NUM_TRX_CFG,
|
|
boolean handler_mode := false)
|
|
runs on test_CT {
|
|
/* wait until osmo-bts-omldummy has respawned */
|
|
f_wait_oml(bts_idx, "degraded", 5.0);
|
|
|
|
/* start RSL connection(s) */
|
|
for (var integer trx_idx := 0; trx_idx < trx_num; trx_idx := trx_idx + 1) {
|
|
f_ipa_rsl_start(bts[bts_idx][trx_idx].rsl,
|
|
mp_bsc_ip, mp_bsc_rsl_port,
|
|
{bts_idx, trx_idx}, handler_mode);
|
|
}
|
|
/* wait until BSC tells us "connected" */
|
|
f_wait_oml(bts_idx, "connected", 5.0);
|
|
|
|
/* Set up BTS with VTY commands: */
|
|
f_vty_enter_cfg_bts(BSCVTY, bts_idx);
|
|
if (g_osmux_enabled_bts) {
|
|
f_vty_transceive(BSCVTY, "osmux on");
|
|
} else {
|
|
f_vty_transceive(BSCVTY, "osmux off");
|
|
}
|
|
f_vty_transceive(BSCVTY, "end");
|
|
}
|
|
|
|
function f_init_bts_and_check_sysinfo(integer bts_idx := 0,
|
|
integer trx_num := NUM_TRX_CFG,
|
|
boolean handler_mode := false,
|
|
template SystemInformationConfig expect_si)
|
|
runs on test_CT {
|
|
var default sysinfo := activate(as_catch_RSL_sysinfo(bts_idx));
|
|
|
|
f_init_bts(bts_idx, trx_num, handler_mode);
|
|
|
|
/* Give some time to (hopefully/most likely) collect all system informations from RSL startup.
|
|
* We could stop as soon as all expected SI are received, but then we might miss SI that we don't expect and
|
|
* that might be sent afterwards. So rather give a generous timeout and be quite sure to catch all SI.
|
|
*/
|
|
f_sleep(5.0);
|
|
log("RSL ", bts_idx, " SYSTEM INFORMATION: ", g_system_information[bts_idx]);
|
|
|
|
deactivate(sysinfo);
|
|
|
|
if (match(g_system_information[bts_idx], expect_si)) {
|
|
setverdict(pass);
|
|
} else {
|
|
log("RSL ", bts_idx, ": EXPECTED SI: ", expect_si);
|
|
log("RSL ", bts_idx, ": GOT SI: ", g_system_information[bts_idx]);
|
|
setverdict(fail, "received SI does not match expectations");
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* expect to receive a RSL message matching a specified template on a given BTS / TRX */
|
|
function f_exp_ipa_rx(template (present) RSL_Message t_rx,
|
|
BtsTrxIdx idx := {0, 0},
|
|
float Tval := 2.0)
|
|
runs on test_CT return RSL_Message {
|
|
var ASP_RSL_Unitdata rx_rsl_ud;
|
|
timer T := Tval;
|
|
|
|
T.start;
|
|
alt {
|
|
[] IPA_RSL[idx.bts][idx.trx].receive(tr_ASP_RSL_UD(t_rx, ?)) -> value rx_rsl_ud {
|
|
T.stop;
|
|
}
|
|
[] IPA_RSL[idx.bts][idx.trx].receive { repeat; }
|
|
[] T.timeout {
|
|
setverdict(fail, "Timeout expecting ", t_rx);
|
|
mtc.stop;
|
|
}
|
|
}
|
|
return rx_rsl_ud.rsl;
|
|
}
|
|
|
|
/* helper function to transmit RSL on a given BTS/stream */
|
|
function f_ipa_tx(template (value) RSL_Message t_tx,
|
|
BtsTrxIdx idx := {0, 0},
|
|
IpaStreamId sid := IPAC_PROTO_RSL_TRX0)
|
|
runs on test_CT {
|
|
IPA_RSL[idx.bts][idx.trx].send(ts_ASP_RSL_UD(t_tx, sid));
|
|
}
|
|
|
|
|
|
/* verify we get a CHAN_ACT after CHAN RQD */
|
|
testcase TC_chan_act_noreply() runs on test_CT {
|
|
var BSSAP_N_UNITDATA_ind ud_ind;
|
|
var RSL_Message rsl_unused;
|
|
|
|
f_init(1);
|
|
|
|
f_ipa_tx(ts_RSL_CHAN_RQD('23'O, 23));
|
|
rsl_unused := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
const CounterNameVals counternames_bts_chreq := {
|
|
{ "chreq:total", 0 },
|
|
{ "chreq:attempted_emerg", 0 },
|
|
{ "chreq:attempted_call", 0 },
|
|
{ "chreq:attempted_location_upd", 0 },
|
|
{ "chreq:attempted_pag", 0 },
|
|
{ "chreq:attempted_pdch", 0 },
|
|
{ "chreq:attempted_other", 0 },
|
|
{ "chreq:attempted_unknown", 0 },
|
|
{ "chreq:successful", 0 },
|
|
{ "chreq:successful_emerg", 0 },
|
|
{ "chreq:successful_call", 0 },
|
|
{ "chreq:successful_location_upd", 0 },
|
|
{ "chreq:successful_pag", 0 },
|
|
{ "chreq:successful_pdch", 0 },
|
|
{ "chreq:successful_other", 0 },
|
|
{ "chreq:successful_unknown", 0 },
|
|
{ "chreq:no_channel", 0 },
|
|
{ "chreq:max_delay_exceeded", 0 }
|
|
};
|
|
|
|
/* verify the "chreq:*" counters */
|
|
private function f_chan_act_counter(OCT1 ra, charstring chreq_ctr_suffix) runs on test_CT
|
|
{
|
|
var GsmFrameNumber fn := 23;
|
|
|
|
f_logp(BSCVTY, "f_chan_act_counter(" & chreq_ctr_suffix & ")");
|
|
|
|
var RSL_Message rx_rsl;
|
|
f_ipa_tx(ts_RSL_CHAN_RQD(ra, fn));
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
|
|
var RslChannelNr chan_nr := rx_rsl.ies[0].body.chan_nr;
|
|
|
|
f_ctrs_bts_add(0, "chreq:total");
|
|
f_ctrs_bts_add(0, "chreq:attempted_" & chreq_ctr_suffix);
|
|
f_ctrs_bts_verify();
|
|
|
|
f_ipa_tx(ts_RSL_CHAN_ACT_ACK(chan_nr, fn+10));
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_IMM_ASSIGN(0));
|
|
|
|
f_ctrs_bts_add(0, "chreq:successful");
|
|
f_ctrs_bts_add(0, "chreq:successful_" & chreq_ctr_suffix);
|
|
f_ctrs_bts_verify();
|
|
|
|
/* test is done, release RSL Conn Fail Ind to clean up */
|
|
f_ipa_tx(ts_RSL_CONN_FAIL_IND(chan_nr, RSL_ERR_RADIO_LINK_FAIL));
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL), Tval := 10.0);
|
|
f_ipa_tx(ts_RSL_RF_CHAN_REL_ACK(chan_nr));
|
|
f_sleep(1.0);
|
|
}
|
|
|
|
testcase TC_chan_act_counter() runs on test_CT {
|
|
var BSSAP_N_UNITDATA_ind ud_ind;
|
|
var integer chreq_total;
|
|
var RSL_Message rsl_unused;
|
|
|
|
f_init(1);
|
|
|
|
f_vty_allow_emerg_bts(true, 0);
|
|
|
|
f_ctrs_bts_init(1, counternames_bts_chreq);
|
|
|
|
/* emergency call: RA & 0xe0 == 0xa0 --> CHREQ_T_EMERG_CALL */
|
|
f_chan_act_counter('a3'O, "emerg");
|
|
|
|
/* voice TCH/H: RA & 0xf0 == 0x40 --> CHREQ_T_VOICE_CALL_TCH_H */
|
|
f_chan_act_counter('43'O, "call");
|
|
|
|
/* LU: RA & 0xf0 == 0x00 --> CHREQ_T_LOCATION_UPD */
|
|
f_chan_act_counter('03'O, "location_upd");
|
|
|
|
/* Paging: RA & 0xf0 == 0x20 --> CHREQ_T_PAG_R_TCH_F */
|
|
f_chan_act_counter('23'O, "pag");
|
|
/* Paging: RA & 0xf0 == 0x30 --> CHREQ_T_PAG_R_TCH_FH */
|
|
f_chan_act_counter('33'O, "pag");
|
|
|
|
/* LU: RA & 0xfc == 0x78 --> CHREQ_T_PDCH_TWO_PHASE */
|
|
/* no PCU, so PDCH not allowed. Skip this test for now. */
|
|
/* f_chan_act_counter('7b'O, "pdch"); */
|
|
|
|
/* LU: RA & 0xf0 == 0x10 --> CHREQ_T_SDCCH */
|
|
f_chan_act_counter('13'O, "other");
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* CHAN RQD -> CHAN ACT -> CHAN ACT ACK -> RF CHAN REL */
|
|
private function f_TC_chan_act_ack_noest(OCT1 ra := '23'O) runs on test_CT {
|
|
var RSL_Message rx_rsl;
|
|
|
|
/* Send CHAN RQD and wait for allocation; acknowledge it */
|
|
var RslChannelNr chan_nr := f_chreq_act_ack(ra);
|
|
|
|
/* expect BSC to disable the channel again if there's no RLL EST IND */
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL), Tval := T3101_MAX);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Normal variant */
|
|
testcase TC_chan_act_ack_noest() runs on test_CT {
|
|
f_init(1);
|
|
f_TC_chan_act_ack_noest();
|
|
}
|
|
|
|
/* Emergency call variant */
|
|
testcase TC_chan_act_ack_noest_emerg() runs on test_CT {
|
|
/* See also: 3GPP TS 04.08, Table 9.9, ra=101xxxxx */
|
|
f_init(1);
|
|
f_vty_allow_emerg_bts(true, 0);
|
|
f_TC_chan_act_ack_noest(ra := 'A5'O);
|
|
}
|
|
|
|
/* Emergency call variant, but emergency calls are not allowed */
|
|
testcase TC_chan_rqd_emerg_deny() runs on test_CT {
|
|
/* See also: 3GPP TS 04.08, Table 9.9, ra=101xxxxx */
|
|
|
|
var RSL_Message rx_rsl;
|
|
var GsmRrMessage rr;
|
|
|
|
f_init(1);
|
|
f_vty_allow_emerg_bts(false, 0);
|
|
|
|
IPA_RSL[0][0].clear;
|
|
f_ipa_tx(ts_RSL_CHAN_RQD('A5'O, 23));
|
|
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeC(RSL_MT_IMMEDIATE_ASSIGN_CMD));
|
|
rr := dec_GsmRrMessage(rx_rsl.ies[1].body.full_imm_ass_info.payload);
|
|
if (rr.header.message_type == IMMEDIATE_ASSIGNMENT_REJECT) {
|
|
setverdict(pass);
|
|
} else {
|
|
setverdict(fail, "immediate assignment not rejected");
|
|
}
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior if MSC never answers to CR */
|
|
testcase TC_chan_act_ack_est_ind_noreply() runs on test_CT {
|
|
var RslLinkId main_dcch := valueof(ts_RslLinkID_DCCH(0));
|
|
var IpaStreamId sid := IPAC_PROTO_RSL_TRX0;
|
|
var RSL_Message rx_rsl;
|
|
var ASP_RSL_Unitdata rx_rsl_ud;
|
|
var octetstring l3_payload := gen_l3_valid_payload();
|
|
|
|
f_init(1);
|
|
|
|
/* Send CHAN RQD and wait for allocation; acknowledge it */
|
|
var RslChannelNr chan_nr := f_chreq_act_ack();
|
|
|
|
f_ipa_tx(ts_RSL_EST_IND(chan_nr, valueof(ts_RslLinkID_DCCH(0)), l3_payload));
|
|
|
|
BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(l3_payload)));
|
|
|
|
/* expect BSC to disable the channel again if there's no response from MSC */
|
|
/* MS waits 20s (T3210) at LU; 10s (T3230) at CM SERV REQ and 5s (T3220) AT detach */
|
|
f_expect_chan_rel(chan_nr, expect_rll_rel_req := false);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior if MSC answers with CREF to CR */
|
|
testcase TC_chan_act_ack_est_ind_refused() runs on test_CT {
|
|
var BSSAP_N_CONNECT_ind rx_c_ind;
|
|
var RSL_Message rx_rsl;
|
|
var octetstring l3_payload := gen_l3_valid_payload();
|
|
|
|
f_init(1);
|
|
|
|
/* Send CHAN RQD and wait for allocation; acknowledge it */
|
|
var RslChannelNr chan_nr := f_chreq_act_ack();
|
|
|
|
f_ipa_tx(ts_RSL_EST_IND(chan_nr, valueof(ts_RslLinkID_DCCH(0)), l3_payload));
|
|
|
|
BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(l3_payload))) -> value rx_c_ind;
|
|
BSSAP.send(ts_BSSAP_DISC_req(rx_c_ind.connectionId, 0));
|
|
|
|
/* expect BSC to disable the channel */
|
|
f_expect_chan_rel(chan_nr, expect_rll_rel_req := false);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* CHAN RQD -> CHAN ACT -> CHAN ACT NACK -> RF CHAN REL */
|
|
testcase TC_chan_act_nack() runs on test_CT {
|
|
var RSL_Message rx_rsl;
|
|
var integer chact_nack;
|
|
|
|
f_init(1);
|
|
|
|
chact_nack := f_ctrl_get_ratectr_abs(IPA_CTRL, "bts", 0, "chan_act:nack");
|
|
|
|
f_ipa_tx(ts_RSL_CHAN_RQD('33'O, 33));
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
|
|
var RslChannelNr chan_nr := rx_rsl.ies[0].body.chan_nr;
|
|
|
|
f_ipa_tx(ts_RSL_CHAN_ACT_NACK(chan_nr, RSL_ERR_EQUIPMENT_FAIL));
|
|
|
|
/* wait for some time to hope the NACK arrives before the CTRL GET below */
|
|
f_sleep(0.5);
|
|
|
|
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bts", 0, "chan_act:nack", chact_nack+1);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test for channel exhaustion due to RACH overload */
|
|
testcase TC_chan_exhaustion() runs on test_CT {
|
|
var ASP_RSL_Unitdata rsl_ud;
|
|
var integer i;
|
|
var integer chreq_total, chreq_nochan;
|
|
|
|
f_init(1);
|
|
|
|
chreq_total := f_ctrl_get_ratectr_abs(IPA_CTRL, "bts", 0, "chreq:total");
|
|
chreq_nochan := f_ctrl_get_ratectr_abs(IPA_CTRL, "bts", 0, "chreq:no_channel");
|
|
|
|
/* GSM 44.018 Table 9.1.8.2:
|
|
* RA = '33'O -> Establishment cause = 0011xxxx (MS dual rate capable and asks for "TCH/H or TCH/F").
|
|
* With current setup, expect 4xSDCCH + 4xTCH/F + 1xTCH/H to succeed */
|
|
for (i := 0; i < NUM_TCHF_PER_BTS + NUM_TCHH_PER_BTS + NUM_SDCCH_PER_BTS; i := i+1) {
|
|
var RslChannelNr chan_nr := f_chreq_act_ack('33'O, i);
|
|
}
|
|
|
|
IPA_RSL[0][0].clear;
|
|
|
|
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bts", 0, "chreq:total",
|
|
chreq_total + NUM_TCHF_PER_BTS + NUM_TCHH_PER_BTS + NUM_SDCCH_PER_BTS);
|
|
|
|
/* now expect additional channel activations to fail */
|
|
f_ipa_tx(ts_RSL_CHAN_RQD('42'O, 42));
|
|
|
|
alt {
|
|
[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV))) {
|
|
setverdict(fail, "Received CHAN ACT ACK without resources?!?");
|
|
}
|
|
[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr_RSL_IMM_ASSIGN(?))) -> value rsl_ud {
|
|
var GsmRrMessage rr;
|
|
/* match on IMM ASS REJ */
|
|
rr := dec_GsmRrMessage(rsl_ud.rsl.ies[1].body.full_imm_ass_info.payload);
|
|
if (rr.header.message_type == IMMEDIATE_ASSIGNMENT_REJECT) {
|
|
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bts", 0, "chreq:total",
|
|
chreq_total + NUM_TCHF_PER_BTS + NUM_TCHH_PER_BTS + NUM_SDCCH_PER_BTS+1);
|
|
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bts", 0, "chreq:no_channel",
|
|
chreq_nochan+1);
|
|
setverdict(pass);
|
|
} else {
|
|
repeat;
|
|
}
|
|
}
|
|
[] IPA_RSL[0][0].receive { repeat; }
|
|
}
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test channel deactivation due to silence from MS */
|
|
testcase TC_chan_deact_silence() runs on test_CT {
|
|
var RslChannelNr chan_nr;
|
|
|
|
f_init(1);
|
|
|
|
/* Request for a dedicated channel */
|
|
chan_nr := f_chreq_act_ack('23'O);
|
|
|
|
/* Wait some time until the channel is released */
|
|
f_sleep(2.0);
|
|
|
|
/* Expect CHANnel RELease */
|
|
alt {
|
|
[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL))) {
|
|
log("Received CHANnel RELease");
|
|
setverdict(pass);
|
|
}
|
|
[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr_RSL_IMM_ASSIGN(?))) {
|
|
/* See OS#3709, OsmoBSC should not send Immediate
|
|
* Assignment Reject since a dedicated channel was
|
|
* already allocated, and Immediate Assignment was
|
|
* already sent. */
|
|
setverdict(fail, "Unexpected Immediate Assignment!");
|
|
}
|
|
[] IPA_RSL[0][0].receive {
|
|
setverdict(fail, "Unexpected RSL message!");
|
|
}
|
|
}
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/***********************************************************************
|
|
* Assignment Testing
|
|
***********************************************************************/
|
|
|
|
/* Verify that the BSC refuses any BSSAP connection from the MSC (They are all BSC->MSC direction,
|
|
* except for the inter-BSC handover, MT side) */
|
|
testcase TC_outbound_connect(integer bssap_idx := 0) runs on test_CT {
|
|
f_init(1);
|
|
|
|
BSSAP.send(ts_BSSAP_CONNECT_req(g_bssap[bssap_idx].sccp_addr_peer, g_bssap[bssap_idx].sccp_addr_own,
|
|
2342, ts_BSSMAP_AssignmentReq));
|
|
BSSAP.receive(tr_BSSAP_DISC_ind(2342, ?, ?));
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior if MSC answers with CREF to CR */
|
|
testcase TC_assignment_cic_only(integer bssap_idx := 0) runs on test_CT {
|
|
var BSSAP_N_CONNECT_ind rx_c_ind;
|
|
var RSL_Message rx_rsl;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
|
|
/* send assignment without AoIP IEs */
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_AssignmentReq(ts_BSSMAP_IE_CIC(0, 1))));
|
|
} else {
|
|
/* Send assignment without CIC in IPA case */
|
|
var BSSMAP_IE_AoIP_TransportLayerAddress tla :=
|
|
valueof(ts_BSSMAP_IE_AoIP_TLA4('01020304'O, 2342));
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_AssignmentReq(omit, tla)));
|
|
}
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_AssignmentComplete)) {
|
|
setverdict(fail, "AoIP BSC cannot accept ASSIGNMENT without AoIP Transport IE");
|
|
}
|
|
/* TODO: Actually expect GSM0808_CAUSE_REQ_A_IF_TYPE_NOT_SUPP */
|
|
[] BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_AssignmentFail)) {
|
|
setverdict(pass);
|
|
}
|
|
[] BSSAP.receive { repeat; }
|
|
}
|
|
f_perform_clear_test_ct(dt);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* generate an assignment request for either AoIP or SCCPlite */
|
|
function f_gen_ass_req(boolean osmux_enabled := false, integer bssap_idx := 0, charstring aoip_tla := "1.2.3.4") return PDU_BSSAP {
|
|
var PDU_BSSAP ass_cmd;
|
|
var BSSMAP_IE_Osmo_OsmuxCID osmux_cid := valueof(ts_OsmuxCID(0));
|
|
if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
|
|
var BSSMAP_IE_AoIP_TransportLayerAddress tla :=
|
|
valueof(f_ts_BSSMAP_IE_AoIP_TLA(aoip_tla, 2342));
|
|
if (osmux_enabled) {
|
|
ass_cmd := valueof(ts_BSSMAP_AssignmentReq(omit, tla, osmux_cid));
|
|
} else {
|
|
ass_cmd := valueof(ts_BSSMAP_AssignmentReq(omit, tla));
|
|
}
|
|
} else {
|
|
var BSSMAP_IE_CircuitIdentityCode cic := valueof(ts_BSSMAP_IE_CIC(0,1));
|
|
ass_cmd := valueof(ts_BSSMAP_AssignmentReq(cic, omit));
|
|
}
|
|
return ass_cmd;
|
|
}
|
|
|
|
function f_gen_handover_req(integer bssap_idx := 0, charstring aoip_tla := "1.2.3.4",
|
|
template (value) BSSMAP_IE_CellIdentifier cell_id_source := ts_CellID_LAC_CI(1, 1),
|
|
template (omit) BSSMAP_oldToNewBSSIEs oldToNewBSSIEs := omit,
|
|
template (omit) TestHdlrEncrParams enc := omit) return PDU_BSSAP {
|
|
var PDU_BSSAP ho_req;
|
|
|
|
var BSSMAP_IE_EncryptionInformation encryptionInformation :=
|
|
valueof(ts_BSSMAP_IE_EncrInfo('0000000000000000'O,'01'O));
|
|
var template (omit) BSSMAP_IE_ChosenEncryptionAlgorithm chosenEncryptionAlgorithm := omit;
|
|
var template (omit) BSSMAP_IE_KC128 kc128 := omit;
|
|
if (ispresent(enc)) {
|
|
var TestHdlrEncrParams v_enc := valueof(enc);
|
|
encryptionInformation := valueof(ts_BSSMAP_IE_EncrInfo(v_enc.enc_key, v_enc.enc_alg_permitted));
|
|
if (ispresent(v_enc.enc_alg_chosen)) {
|
|
chosenEncryptionAlgorithm := valueof(
|
|
ts_BSSMAP_IE_ChosenEncryptionAlgorithm(int2oct(enum2int(
|
|
f_cipher_mode_bssmap_to_rsl(v_enc.enc_alg_chosen)), 1)));
|
|
}
|
|
if (ispresent(v_enc.enc_kc128)) {
|
|
kc128 := ts_BSSMAP_IE_Kc128(v_enc.enc_kc128);
|
|
}
|
|
}
|
|
|
|
if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
|
|
var BSSMAP_IE_AoIP_TransportLayerAddress tla :=
|
|
valueof(f_ts_BSSMAP_IE_AoIP_TLA(aoip_tla, 2342));
|
|
ho_req := valueof(ts_BSSMAP_HandoverRequest(omit, tla,
|
|
cell_id_source := cell_id_source,
|
|
oldToNewBSSIEs := oldToNewBSSIEs,
|
|
encryptionInformation := encryptionInformation,
|
|
chosenEncryptionAlgorithm := chosenEncryptionAlgorithm,
|
|
kC128 := kc128,
|
|
/* on AoIP, allow "all" codecs (until we add more concise
|
|
* tests) */
|
|
codecList := ts_BSSMAP_IE_CodecList(
|
|
{ts_CodecAMR_F, ts_CodecAMR_H,
|
|
ts_CodecEFR, ts_CodecFR, ts_CodecHR})));
|
|
} else {
|
|
var BSSMAP_IE_CircuitIdentityCode cic := valueof(ts_BSSMAP_IE_CIC(0,1));
|
|
ho_req := valueof(ts_BSSMAP_HandoverRequest(cic, omit,
|
|
cell_id_source := cell_id_source,
|
|
oldToNewBSSIEs := oldToNewBSSIEs,
|
|
encryptionInformation := encryptionInformation,
|
|
chosenEncryptionAlgorithm := chosenEncryptionAlgorithm,
|
|
kC128 := kc128));
|
|
}
|
|
return ho_req;
|
|
}
|
|
|
|
/* generate an assignment complete template for either AoIP or SCCPlite */
|
|
function f_gen_exp_compl(integer bssap_idx := 0)
|
|
runs on MSC_ConnHdlr return template PDU_BSSAP {
|
|
var template PDU_BSSAP exp_compl;
|
|
if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
|
|
var template BSSMAP_IE_Osmo_OsmuxCID exp_osmux_cid := omit;
|
|
if (g_pars.use_osmux_cn) {
|
|
var template (present) INT1 exp_cid := ?;
|
|
if (isbound(g_media.mgcp_conn[0].local_osmux_cid) and isbound(g_media.mgcp_conn[1].local_osmux_cid)) {
|
|
exp_cid := (g_media.mgcp_conn[0].local_osmux_cid, g_media.mgcp_conn[1].local_osmux_cid);
|
|
} else if (isbound(g_media.mgcp_conn[0].local_osmux_cid)) {
|
|
exp_cid := g_media.mgcp_conn[0].local_osmux_cid;
|
|
} else if (isbound(g_media.mgcp_conn[1].local_osmux_cid)) {
|
|
exp_cid := g_media.mgcp_conn[1].local_osmux_cid;
|
|
}
|
|
exp_osmux_cid := tr_OsmuxCID(exp_cid);
|
|
}
|
|
exp_compl := tr_BSSMAP_AssignmentComplete(omit, ?, exp_osmux_cid);
|
|
} else {
|
|
/* CIC is optional "*" as the MSC allocated it */
|
|
exp_compl := tr_BSSMAP_AssignmentComplete(*, omit, omit);
|
|
}
|
|
return exp_compl;
|
|
}
|
|
|
|
/* Run everything required up to sending a caller-specified assignment command and expect response */
|
|
function f_assignment_exp(PDU_BSSAP ass_cmd, template PDU_BSSAP exp, charstring fail_text)
|
|
runs on test_CT return DchanTuple {
|
|
var BSSAP_N_CONNECT_ind rx_c_ind;
|
|
var RSL_Message rx_rsl;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
/* send assignment without AoIP IEs */
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ass_cmd));
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_AssignmentComplete)) {
|
|
if (ischosen(exp.pdu.bssmap.assignmentComplete)) {
|
|
setverdict(pass);
|
|
} else {
|
|
setverdict(fail, fail_text);
|
|
}
|
|
}
|
|
[] BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_AssignmentFail)) {
|
|
if (ischosen(exp.pdu.bssmap.assignmentFailure)) {
|
|
setverdict(pass);
|
|
} else {
|
|
setverdict(fail, fail_text);
|
|
}
|
|
}
|
|
[] BSSAP.receive { repeat; }
|
|
}
|
|
return dt;
|
|
}
|
|
|
|
private function f_tc_assignment_csd(charstring data_rate_str, OCT1 data_rate, boolean transp := true) runs on MSC_ConnHdlr {
|
|
var template PDU_BSSAP exp_compl := f_gen_exp_compl();
|
|
var PDU_BSSAP ass_cmd := f_gen_ass_req();
|
|
var SDP_FIELD_PayloadType pt_csd := PT_CSD;
|
|
|
|
ass_cmd.pdu.bssmap.assignmentRequest.channelType := valueof(ts_BSSMAP_IE_ChannelTypeCSD);
|
|
ass_cmd.pdu.bssmap.assignmentRequest.codecList := valueof(ts_BSSMAP_IE_CodecList({ts_CodecCSData}));
|
|
|
|
/* Non-transparent service (3GPP TS 48.008 § 3.2.2.11, oct 5, bit 7) */
|
|
if (not transp) {
|
|
data_rate := data_rate or4b '40'O;
|
|
}
|
|
|
|
ass_cmd.pdu.bssmap.assignmentRequest.channelType.speechId_DataIndicator := data_rate;
|
|
|
|
log("-----------------------------------------------");
|
|
log("Assignment req with data rate: " & data_rate_str);
|
|
log("-----------------------------------------------");
|
|
|
|
f_establish_fully(ass_cmd, exp_compl);
|
|
|
|
if (g_media.bts.rtp_pt != enum2int(pt_csd)) {
|
|
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("unexpected RTP payload type: ", g_media.bts.rtp_pt));
|
|
}
|
|
|
|
f_perform_clear();
|
|
f_create_mgcp_delete_ep(g_media.mgcp_ep);
|
|
}
|
|
private function f_tc_assignment_csd_all(charstring id) runs on MSC_ConnHdlr {
|
|
/* Data rates that require multi-slot HSCSD assignment are not tested
|
|
* on purpose (not supported): T_32k0, T_28k8, NT_43k5, NT_29k0 */
|
|
f_tc_assignment_csd("T_14k4", GSM0808_DATA_RATE_TRANSP_14k4);
|
|
f_tc_assignment_csd("T_9k6", GSM0808_DATA_RATE_TRANSP_9k6);
|
|
f_tc_assignment_csd("T_4k8", GSM0808_DATA_RATE_TRANSP_4k8);
|
|
f_tc_assignment_csd("T_2k4", GSM0808_DATA_RATE_TRANSP_2k4);
|
|
f_tc_assignment_csd("T_1k2", GSM0808_DATA_RATE_TRANSP_1k2);
|
|
f_tc_assignment_csd("T_600", GSM0808_DATA_RATE_TRANSP_600);
|
|
f_tc_assignment_csd("T_1200_75", GSM0808_DATA_RATE_TRANSP_1200_75);
|
|
|
|
f_tc_assignment_csd("NT_12000_6000", GSM0808_DATA_RATE_NON_TRANSP_12000_6000, false);
|
|
f_tc_assignment_csd("NT_14k5", GSM0808_DATA_RATE_NON_TRANSP_14k5, false);
|
|
f_tc_assignment_csd("NT_12k0", GSM0808_DATA_RATE_NON_TRANSP_12k0, false);
|
|
f_tc_assignment_csd("NT_6k0", GSM0808_DATA_RATE_NON_TRANSP_6k0, false);
|
|
}
|
|
testcase TC_assignment_csd() runs on test_CT {
|
|
if (Misc_Helpers.f_osmo_repo_is("nightly")) { /* osmo-bsc > 1.10.0 */
|
|
var MSC_ConnHdlr vc_conn;
|
|
var TestHdlrParams pars := f_gen_test_hdlr_pars();
|
|
pars.encr := valueof(t_EncrParams('01'O, f_rnd_octstring(8)));
|
|
|
|
f_init(1, true, guard_timeout := 120.0);
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(refers(f_tc_assignment_csd_all), pars);
|
|
vc_conn.done;
|
|
} else {
|
|
var template PDU_BSSAP exp_fail := tr_BSSMAP_AssignmentFail;
|
|
var PDU_BSSAP ass_cmd := f_gen_ass_req();
|
|
ass_cmd.pdu.bssmap.assignmentRequest.channelType := valueof(ts_BSSMAP_IE_ChannelTypeCSD);
|
|
//exp_fail.pdu.bssmap.assignmentFailure.cause.causeValue := int2bit(enum2int(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_UNAVAIL), 7);
|
|
var DchanTuple dt := f_assignment_exp(ass_cmd, exp_fail, "BSC accepted Assignment for CSD");
|
|
f_perform_clear_test_ct(dt);
|
|
}
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_assignment_ctm() runs on test_CT {
|
|
var template PDU_BSSAP exp_fail := tr_BSSMAP_AssignmentFail;
|
|
var PDU_BSSAP ass_cmd := f_gen_ass_req();
|
|
ass_cmd.pdu.bssmap.assignmentRequest.channelType := valueof(ts_BSSMAP_IE_ChannelTypeCTM);
|
|
//exp_fail.pdu.bssmap.assignmentFailure.cause.causeValue := int2bit(enum2int(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_UNAVAIL), 7);
|
|
var DchanTuple dt := f_assignment_exp(ass_cmd, exp_fail, "BSC accepted Assignment for Speech+CTM");
|
|
f_perform_clear_test_ct(dt);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
type record DchanTuple {
|
|
integer sccp_conn_id,
|
|
RslChannelNr rsl_chan_nr,
|
|
BtsTrxIdx idx
|
|
}
|
|
|
|
type record of DchanTuple DchanTuples;
|
|
|
|
/* Send CHAN RQD and wait for allocation; acknowledge it */
|
|
private function f_chreq_act_ack(OCT1 ra := '23'O,
|
|
GsmFrameNumber fn := 23,
|
|
BtsTrxIdx idx := {0, 0})
|
|
runs on test_CT return RslChannelNr {
|
|
var RSL_Message rx_rsl;
|
|
f_ipa_tx(ts_RSL_CHAN_RQD(ra, fn), {idx.bts, 0});
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV), idx);
|
|
var RslChannelNr chan_nr := rx_rsl.ies[0].body.chan_nr;
|
|
f_ipa_tx(ts_RSL_CHAN_ACT_ACK(chan_nr, fn+10), idx);
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_IMM_ASSIGN(0), {idx.bts, 0});
|
|
return chan_nr;
|
|
}
|
|
|
|
/* helper function to establish a dedicated channel via BTS and MSC */
|
|
function f_est_dchan(OCT1 ra, GsmFrameNumber fn, octetstring l3,
|
|
BtsTrxIdx idx := {0, 0})
|
|
runs on test_CT return DchanTuple {
|
|
var BSSAP_N_CONNECT_ind rx_c_ind;
|
|
var DchanTuple dt;
|
|
|
|
/* Send CHAN RQD and wait for allocation; acknowledge it */
|
|
dt.rsl_chan_nr := f_chreq_act_ack(ra, fn, idx);
|
|
|
|
f_ipa_tx(ts_RSL_EST_IND(dt.rsl_chan_nr, valueof(ts_RslLinkID_DCCH(0)), l3), idx);
|
|
|
|
BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(l3))) -> value rx_c_ind;
|
|
dt.sccp_conn_id := rx_c_ind.connectionId;
|
|
BSSAP.send(ts_BSSAP_CONNECT_res(dt.sccp_conn_id));
|
|
|
|
dt.idx := idx;
|
|
return dt;
|
|
}
|
|
|
|
/* Like f_est_dchan(), but for the first lchan of a dynamic timeslot: first ACK the deactivation of PDCH. */
|
|
function f_est_dchan_dyn(OCT1 ra, GsmFrameNumber fn, octetstring l3,
|
|
BtsTrxIdx idx := {0, 0})
|
|
runs on test_CT return DchanTuple {
|
|
var BSSAP_N_CONNECT_ind rx_c_ind;
|
|
var DchanTuple dt;
|
|
|
|
/* Send CHAN RQD */
|
|
var RSL_Message rx_rsl;
|
|
f_ipa_tx(ts_RSL_CHAN_RQD(ra, fn), {idx.bts, 0});
|
|
|
|
/* The dyn TS first deactivates PDCH */
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL), idx, Tval := T3101_MAX);
|
|
dt.rsl_chan_nr := rx_rsl.ies[0].body.chan_nr;
|
|
f_ipa_tx(ts_RSL_RF_CHAN_REL_ACK(dt.rsl_chan_nr), idx);
|
|
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV), idx);
|
|
dt.rsl_chan_nr := rx_rsl.ies[0].body.chan_nr;
|
|
|
|
/* Now activates the signalling channel */
|
|
f_ipa_tx(ts_RSL_CHAN_ACT_ACK(dt.rsl_chan_nr, fn+10), idx);
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_IMM_ASSIGN(0), {idx.bts, 0});
|
|
|
|
f_ipa_tx(ts_RSL_EST_IND(dt.rsl_chan_nr, valueof(ts_RslLinkID_DCCH(0)), l3), idx);
|
|
|
|
BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(l3))) -> value rx_c_ind;
|
|
dt.sccp_conn_id := rx_c_ind.connectionId;
|
|
BSSAP.send(ts_BSSAP_CONNECT_res(dt.sccp_conn_id));
|
|
|
|
dt.idx := idx;
|
|
return dt;
|
|
}
|
|
|
|
/* expect RF CAN REL from BTS, acknowledge it and clear the MSC side */
|
|
private function f_exp_chan_rel_and_clear(DchanTuple dt)
|
|
runs on test_CT {
|
|
var RSL_Message rx_rsl;
|
|
/* expect BSC to disable the channel */
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL), dt.idx, Tval := T3101_MAX);
|
|
/* respond with CHAN REL ACK */
|
|
f_ipa_tx(ts_RSL_RF_CHAN_REL_ACK(dt.rsl_chan_nr), dt.idx);
|
|
|
|
/* expect Clear Complete from BSC */
|
|
BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearComplete));
|
|
|
|
/* MSC disconnects as instructed. */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
}
|
|
|
|
/* Test behavior of channel release after unilateral RLL REL IND (DISC from MS) */
|
|
testcase TC_chan_rel_rll_rel_ind() runs on test_CT {
|
|
var BSSAP_N_DATA_ind rx_di;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
|
|
/* simulate RLL REL IND */
|
|
f_ipa_tx(ts_RSL_REL_IND(dt.rsl_chan_nr, valueof(ts_RslLinkID_DCCH(0))));
|
|
|
|
/* expect Clear Request on MSC side */
|
|
BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearRequest)) -> value rx_di;
|
|
|
|
/* Instruct BSC to clear channel */
|
|
var BssmapCause cause := bit2int(rx_di.userData.pdu.bssmap.clearRequest.cause.causeValue);
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommand(cause)));
|
|
|
|
/* expect BSC to disable the channel */
|
|
f_exp_chan_rel_and_clear(dt);
|
|
|
|
/* wait for SCCP emulation to do its job */
|
|
f_sleep(1.0);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior of channel release after CONN FAIL IND from BTS */
|
|
testcase TC_chan_rel_conn_fail() runs on test_CT {
|
|
var BSSAP_N_DATA_ind rx_di;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
|
|
/* Sending CONN FAIL IND immediately may trigger a race condition.
|
|
* Give the BSC some time to process a new SCCP connection (OS#5823). */
|
|
f_sleep(0.2);
|
|
|
|
/* simulate CONN FAIL IND */
|
|
f_ipa_tx(ts_RSL_CONN_FAIL_IND(dt.rsl_chan_nr, RSL_ERR_RADIO_LINK_FAIL));
|
|
/* TODO: different cause values? */
|
|
|
|
/* expect Clear Request from BSC */
|
|
BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearRequest)) -> value rx_di;
|
|
|
|
/* Instruct BSC to clear channel */
|
|
var BssmapCause cause := bit2int(rx_di.userData.pdu.bssmap.clearRequest.cause.causeValue);
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommand(cause)));
|
|
|
|
/* expect BSC to disable the channel */
|
|
f_exp_chan_rel_and_clear(dt);
|
|
|
|
/* wait for SCCP emulation to do its job */
|
|
f_sleep(1.0);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior of early CONN FAIL IND from BTS (before EST IND!) */
|
|
/* See also https://www.osmocom.org/issues/3182 */
|
|
testcase TC_early_conn_fail() runs on test_CT {
|
|
var RSL_Message rx_rsl;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
/* BTS->BSC: Send CHAN RQD and wait for allocation; acknowledge it */
|
|
dt.rsl_chan_nr := f_chreq_act_ack(f_rnd_ra_cs(), 23);
|
|
|
|
/* BTS->BSC: simulate CONN FAIL IND */
|
|
f_ipa_tx(ts_RSL_CONN_FAIL_IND(dt.rsl_chan_nr, RSL_ERR_RADIO_LINK_FAIL));
|
|
|
|
/* BTS->BSC: Expect RF channel release from BSC on Abis */
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL), Tval := 10.0);
|
|
|
|
/* BTS<-BSC: respond with CHAN REL ACK */
|
|
f_ipa_tx(ts_RSL_RF_CHAN_REL_ACK(dt.rsl_chan_nr));
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior of late CONN FAIL IND from BTS (ater REL IND!) */
|
|
/* See also https://www.osmocom.org/issues/3182 */
|
|
testcase TC_late_conn_fail() runs on test_CT {
|
|
var RSL_Message rx_rsl;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
|
|
/* BSC<-MSC: Instruct BSC to clear connection */
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommand(0)));
|
|
|
|
/* BTS->BSC: expect BSC to deactivate SACCH */
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_DEACT_SACCH(dt.rsl_chan_nr));
|
|
|
|
/* BTS->BSC: simulate a late CONN FAIL IND from BTS */
|
|
f_ipa_tx(ts_RSL_CONN_FAIL_IND(dt.rsl_chan_nr, RSL_ERR_RADIO_LINK_FAIL));
|
|
|
|
/* BTS<-BSC: Expect RF channel release from BSC on Abis */
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL), Tval := 10.0);
|
|
/* BTS->BSC: respond with CHAN REL ACK */
|
|
f_ipa_tx(ts_RSL_RF_CHAN_REL_ACK(dt.rsl_chan_nr));
|
|
|
|
/* BSC->MSC: expect Clear Complete from BSC */
|
|
BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearComplete));
|
|
|
|
/* BSC<-MSC: MSC disconnects as requested. */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
private function f_TC_stats_conn_fail(charstring id) runs on MSC_ConnHdlr {
|
|
var template PDU_BSSAP exp_fail := tr_BSSMAP_AssignmentFail;
|
|
var PDU_BSSAP ass_cmd := f_gen_ass_req();
|
|
|
|
f_statsd_reset();
|
|
|
|
/* Establish SDCCH (invalid DataIndicator for exp_fail) */
|
|
ass_cmd.pdu.bssmap.assignmentRequest.channelType := valueof(ts_BSSMAP_IE_ChannelTypeCSD);
|
|
ass_cmd.pdu.bssmap.assignmentRequest.channelType.speechId_DataIndicator := 'ff'O;
|
|
f_establish_fully(ass_cmd, exp_fail);
|
|
|
|
/* Expect stats to be 0 */
|
|
var StatsDExpects expect := {
|
|
{name := "TTCN3.bts.0.chan.rf_fail", mtype := "c", min := 0, max := 0},
|
|
{name := "TTCN3.bts.0.chan.rf_fail_sdcch", mtype := "c", min := 0, max := 0}
|
|
};
|
|
f_statsd_expect(expect);
|
|
|
|
/* Simulate CONN FAIL IND on SDCCH */
|
|
RSL.send(ts_ASP_RSL_UD(
|
|
ts_RSL_CONN_FAIL_IND(g_chan_nr, RSL_ERR_RADIO_LINK_FAIL),
|
|
IPAC_PROTO_RSL_TRX0));
|
|
|
|
f_sleep(1.0);
|
|
|
|
/* Expect stats to be 1 */
|
|
expect := {
|
|
{name := "TTCN3.bts.0.chan.rf_fail", mtype := "c", min := 1, max := 1},
|
|
{name := "TTCN3.bts.0.chan.rf_fail_sdcch", mtype := "c", min := 1, max := 1}
|
|
};
|
|
f_statsd_expect(expect);
|
|
BSSAP.receive(tr_BSSMAP_ClearRequest);
|
|
f_perform_clear();
|
|
}
|
|
testcase TC_stats_conn_fail() runs on test_CT {
|
|
var TestHdlrParams pars := f_gen_test_hdlr_pars();
|
|
var MSC_ConnHdlr vc_conn;
|
|
|
|
f_init(1, true);
|
|
f_sleep(1.0);
|
|
|
|
vc_conn := f_start_handler(refers(f_TC_stats_conn_fail), pars);
|
|
vc_conn.done;
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
function f_expect_chan_rel(RslChannelNr rsl_chan_nr,
|
|
BtsTrxIdx idx := {0, 0},
|
|
boolean expect_deact_sacch := true,
|
|
boolean expect_rr_chan_rel := true,
|
|
boolean expect_rll_rel_req := true,
|
|
boolean handle_rll_rel := true,
|
|
template CellSelIndValue expect_cells := omit,
|
|
template (present) RR_Cause expect_rr_cause := ?
|
|
) runs on test_CT {
|
|
|
|
var RslLinkId main_dcch := valueof(ts_RslLinkID_DCCH(0));
|
|
var boolean got_deact_sacch := false;
|
|
var boolean got_rr_chan_rel := false;
|
|
var boolean got_rll_rel_req := false;
|
|
var ASP_RSL_Unitdata ud;
|
|
var RSL_IE_Body l3_ie;
|
|
var PDU_ML3_NW_MS l3;
|
|
var RR_Cause got_cause;
|
|
log("f_expect_chan_rel() expecting: expect_deact_sacch=", expect_deact_sacch, " expect_rr_chan_rel=", expect_rr_chan_rel,
|
|
" expect_rll_rel_req=", expect_rll_rel_req);
|
|
alt {
|
|
[] IPA_RSL[idx.bts][idx.trx].receive(tr_ASP_RSL_UD(tr_RSL_DEACT_SACCH(rsl_chan_nr))) {
|
|
got_deact_sacch := true;
|
|
repeat;
|
|
}
|
|
[] IPA_RSL[idx.bts][idx.trx].receive(tr_ASP_RSL_UD(tr_RSL_DATA_REQ(rsl_chan_nr, ?, decmatch tr_RRM_RR_RELEASE))) -> value ud {
|
|
got_rr_chan_rel := true;
|
|
|
|
if (f_rsl_find_ie(ud.rsl, RSL_IE_L3_INFO, l3_ie) == false) {
|
|
setverdict(fail, "cannot find L3");
|
|
mtc.stop;
|
|
}
|
|
l3 := dec_PDU_ML3_NW_MS(l3_ie.l3_info.payload);
|
|
|
|
if (not istemplatekind(expect_cells, "omit")) {
|
|
var CellSelIndValue cells := dec_CellSelIndValue(
|
|
l3.msgs.rrm.channelRelease.cellSelectionIndicator.cellSelectionIndicatorValue);
|
|
|
|
log("GOT RR CHANNEL RELEASE WITH CELLS: ", cells);
|
|
if (match(cells, expect_cells)) {
|
|
setverdict(pass);
|
|
} else {
|
|
log("EXPECTED CELLS: ", expect_cells);
|
|
setverdict(fail, "Received cells list on RR Channel Release does not match expectations");
|
|
}
|
|
}
|
|
|
|
int2enum(oct2int(l3.msgs.rrm.channelRelease.rRCause.valuePart), got_cause);
|
|
log("GOT CAUSE CODE: ", l3.msgs.rrm.channelRelease.rRCause.valuePart, " = ", got_cause);
|
|
if (match(got_cause, expect_rr_cause)) {
|
|
setverdict(pass);
|
|
} else {
|
|
log("EXPECTED CAUSE CODE: ", expect_rr_cause);
|
|
setverdict(fail, "Received RR Channel Release Cause code does not match expectations");
|
|
}
|
|
repeat;
|
|
}
|
|
[] IPA_RSL[idx.bts][idx.trx].receive(tr_ASP_RSL_UD(tr_RSL_REL_REQ(rsl_chan_nr, ?))) {
|
|
got_rll_rel_req := true;
|
|
/* FIXME: Why are we getting this for LinkID SACCH? */
|
|
if (handle_rll_rel) {
|
|
f_ipa_tx(ts_RSL_REL_CONF(rsl_chan_nr, main_dcch));
|
|
}
|
|
repeat;
|
|
}
|
|
[] IPA_RSL[idx.bts][idx.trx].receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL))) {
|
|
/* respond with CHAN REL ACK */
|
|
f_ipa_tx(ts_RSL_RF_CHAN_REL_ACK(rsl_chan_nr));
|
|
}
|
|
/* ignore any user data */
|
|
[] IPA_RSL[idx.bts][idx.trx].receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeR(?))) {
|
|
repeat;
|
|
}
|
|
}
|
|
|
|
log("f_expect_chan_rel() summary: got_deact_sacch=", got_deact_sacch, " got_rr_chan_rel=", got_rr_chan_rel,
|
|
" got_rll_rel_req=", got_rll_rel_req);
|
|
|
|
if (expect_deact_sacch != got_deact_sacch) {
|
|
setverdict(fail, "f_expect_chan_rel(): expect_deact_sacch=", expect_deact_sacch, " got_deact_sacch=", got_deact_sacch);
|
|
}
|
|
if (expect_rr_chan_rel != got_rr_chan_rel) {
|
|
setverdict(fail, "f_expect_chan_rel(): expect_rr_chan_rel=", expect_rr_chan_rel, " got_rr_chan_rel=", got_rr_chan_rel);
|
|
}
|
|
if (expect_rll_rel_req != got_rll_rel_req) {
|
|
setverdict(fail, "f_expect_chan_rel(): expect_rll_rel_req=", expect_rll_rel_req, " got_rll_rel_req=", got_rll_rel_req);
|
|
}
|
|
}
|
|
|
|
/* Test behavior of channel release after hard Clear Command from MSC */
|
|
testcase TC_chan_rel_hard_clear() runs on test_CT {
|
|
var BSSAP_N_DATA_ind rx_di;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
|
|
/* Instruct BSC to clear channel */
|
|
var BssmapCause cause := 0;
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommand(cause)));
|
|
|
|
/* expect Clear Complete from BSC on A */
|
|
BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearComplete)) {
|
|
/* release the SCCP connection */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
}
|
|
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
function f_TC_chan_rel_last_eutran_plmn_hard_clear(boolean tx_csfb_ind) runs on test_CT {
|
|
var BSSAP_N_DATA_ind rx_di;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
/* Send CommonID with some random PLMN (BSC doesn't take it into account
|
|
/* yet when generating the EUTRAN neigh list in RR CHannel Release) */
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_CommonId('001019876543210'H, '323454'O)));
|
|
|
|
/* Instruct BSC to clear channel */
|
|
var BssmapCause cause := 0;
|
|
if (tx_csfb_ind) {
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommandCSFB(cause)));
|
|
} else {
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommand(cause)));
|
|
}
|
|
|
|
/* expect Clear Complete from BSC on A */
|
|
BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearComplete)) {
|
|
/* release the SCCP connection */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
}
|
|
|
|
/* 1 neighbor is added by default in osmo-bts.cfg and
|
|
SystemInformationConfig_default, use that: */
|
|
var template CellSelIndValue exp_cells := f_tr_rr_chan_rel_earfcns(1);
|
|
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false, expect_cells := exp_cells);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior of RR Channel rRelease after Clear Command without CSFB indicator
|
|
from MSC, previously receiving any CommonID containing the "Last Used E-UTRAN
|
|
PLMN Id". According to spec (3GPP TS 48.008 sec 3.1.30) that's the bit requesting
|
|
EUTRAN neighbor list sent later on by BSC in RR Channel, so receiving CSFB
|
|
Indicator or not shouldn't matter at all. */
|
|
testcase TC_chan_rel_last_eutran_plmn_hard_clear_no_csfb() runs on test_CT {
|
|
f_TC_chan_rel_last_eutran_plmn_hard_clear(false);
|
|
}
|
|
|
|
/* Test behavior of RR Channel rRelease after Clear Command with CSFB indicator from
|
|
MSC, previously receiving any CommonID containing the "Last Used E-UTRAN PLMN
|
|
Id". According to spec (3GPP TS 48.008 sec 3.1.30) that's the bit requesting
|
|
EUTRAN neighbor list sent later on by BSC in RR Channel. */
|
|
testcase TC_chan_rel_last_eutran_plmn_hard_clear_csfb() runs on test_CT {
|
|
f_TC_chan_rel_last_eutran_plmn_hard_clear(true);
|
|
}
|
|
|
|
/* Test behavior of RR Channel Release after Clear Command with CSFB indicator from
|
|
MSC, without receiving any CommonID containing the "Last Used E-UTRAN PLMN
|
|
Id". According to spec (TS 48.008 version 16.0.0 Release 16 "3.2.1.21") the
|
|
CSFB Indicator should not be used anymore, and hence, there should be no
|
|
EUTRAN neighbor list sent by BSC in RR Channel release since no CommonId with
|
|
Last Used E-UTRAN PLMN Id" IE was sent for this conn. */
|
|
testcase TC_chan_rel_hard_clear_csfb() runs on test_CT {
|
|
var BSSAP_N_DATA_ind rx_di;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
|
|
/* Instruct BSC to clear channel */
|
|
var BssmapCause cause := 0;
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommandCSFB(cause)));
|
|
|
|
/* expect Clear Complete from BSC on A */
|
|
BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearComplete)) {
|
|
/* release the SCCP connection */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
}
|
|
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior of channel release after hard RLSD from MSC */
|
|
testcase TC_chan_rel_hard_rlsd() runs on test_CT {
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
|
|
/* release the SCCP connection */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior of channel release after hard RLSD from MSC and MS is not responding to RLL REL REQ */
|
|
testcase TC_chan_rel_hard_rlsd_ms_dead() runs on test_CT {
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
|
|
/* release the SCCP connection */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior of channel release after BSSMAP RESET from MSC */
|
|
testcase TC_chan_rel_a_reset() runs on test_CT {
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
|
|
/* Clear the queue, it might still contain stuff like IMMEDIATE ASSIGN */
|
|
IPA_RSL[0][0].clear;
|
|
|
|
/* perform BSSAP RESET, expect RESET ACK and DISC.ind on connection */
|
|
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap[0].sccp_addr_peer, g_bssap[0].sccp_addr_own, ts_BSSMAP_Reset(0, g_osmux_enabled_cn)));
|
|
interleave {
|
|
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap[0].sccp_addr_own, g_bssap[0].sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled_cn))) { }
|
|
[] BSSAP.receive(tr_BSSAP_DISC_ind(dt.sccp_conn_id, ?, ?)) { }
|
|
}
|
|
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Verify T(iar) triggers and releases the channel */
|
|
testcase TC_chan_rel_sccp_tiar_timeout() runs on test_CT {
|
|
var DchanTuple dt;
|
|
|
|
/* Set T(iar) in BSC low enough that it will trigger before other side
|
|
has time to keep alive with a T(ias). Keep recommended ratio of
|
|
T(iar) >= T(ias)*2 */
|
|
g_bsc_sccp_timer_ias := 2;
|
|
g_bsc_sccp_timer_iar := 5;
|
|
|
|
f_init(1);
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
private function f_tc_chan_rel_rr_cause(myBSSMAP_Cause clear_cmd_cause,
|
|
template (present) RR_Cause expect_rr_cause)
|
|
runs on test_CT
|
|
{
|
|
var DchanTuple dt;
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
var BssmapCause cause := 0;
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommand(enum2int(clear_cmd_cause))));
|
|
BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearComplete)) {
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
}
|
|
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false, expect_rr_cause := expect_rr_cause);
|
|
}
|
|
|
|
/* Test that Clear Command cause codes affect the RR Channel Release cause code */
|
|
testcase TC_chan_rel_rr_cause() runs on test_CT {
|
|
f_init(1);
|
|
|
|
f_tc_chan_rel_rr_cause(GSM0808_CAUSE_CALL_CONTROL, GSM48_RR_CAUSE_NORMAL);
|
|
f_tc_chan_rel_rr_cause(GSM0808_CAUSE_HANDOVER_SUCCESSFUL, GSM48_RR_CAUSE_NORMAL);
|
|
f_tc_chan_rel_rr_cause(GSM0808_CAUSE_PREEMPTION, GSM48_RR_CAUSE_PREMPTIVE_REL);
|
|
f_tc_chan_rel_rr_cause(GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
|
|
f_tc_chan_rel_rr_cause(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE, GSM48_RR_CAUSE_ABNORMAL_UNSPEC);
|
|
f_tc_chan_rel_rr_cause(GSM0808_CAUSE_EQUIPMENT_FAILURE, GSM48_RR_CAUSE_ABNORMAL_UNSPEC);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior if RSL EST IND for non-active channel */
|
|
testcase TC_rll_est_ind_inact_lchan() runs on test_CT {
|
|
timer T := 2.0;
|
|
|
|
f_init(1);
|
|
|
|
var RslChannelNr chan_nr := valueof(t_RslChanNr_Bm(6));
|
|
var octetstring l3_payload := gen_l3_valid_payload();
|
|
f_ipa_tx(ts_RSL_EST_IND(chan_nr, valueof(ts_RslLinkID_DCCH(0)), l3_payload));
|
|
|
|
T.start;
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(l3_payload))) {
|
|
setverdict(fail, "MSC received COMPL L3 for non-active lchan");
|
|
}
|
|
[] BSSAP.receive {}
|
|
[] IPA_RSL[0][0].receive {}
|
|
[] T.timeout {}
|
|
}
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior if RSL EST IND for invalid SAPI */
|
|
testcase TC_rll_est_ind_inval_sapi1() runs on test_CT {
|
|
var RslChannelNr chan_nr;
|
|
var octetstring l3_payload;
|
|
|
|
f_init(1);
|
|
|
|
chan_nr := f_chreq_act_ack();
|
|
l3_payload := gen_l3_valid_payload();
|
|
|
|
f_ipa_tx(ts_RSL_EST_IND(chan_nr, valueof(ts_RslLinkID_DCCH(1)), l3_payload));
|
|
|
|
timer T := 2.0;
|
|
T.start;
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(l3_payload))) {
|
|
setverdict(fail, "MSC received COMPL L3 for invalid SAPI 1");
|
|
}
|
|
[] BSSAP.receive { repeat; }
|
|
[] IPA_RSL[0][0].receive { repeat; }
|
|
[] T.timeout {}
|
|
}
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior if RSL EST IND for invalid SAPI */
|
|
testcase TC_rll_est_ind_inval_sapi3() runs on test_CT {
|
|
timer T := 2.0;
|
|
|
|
f_init(1);
|
|
|
|
var RslChannelNr chan_nr := f_chreq_act_ack();
|
|
var octetstring l3_payload := gen_l3_valid_payload();
|
|
|
|
f_ipa_tx(ts_RSL_EST_IND(chan_nr, valueof(ts_RslLinkID_DCCH(3)), l3_payload));
|
|
|
|
T.start;
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(l3_payload))) {
|
|
setverdict(fail, "MSC received COMPL L3 for invalid SAPI 3");
|
|
}
|
|
[] BSSAP.receive { repeat; }
|
|
[] IPA_RSL[0][0].receive { repeat; }
|
|
[] T.timeout {}
|
|
}
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Test behavior if RSL EST IND for invalid SACCH */
|
|
testcase TC_rll_est_ind_inval_sacch() runs on test_CT {
|
|
timer T := 2.0;
|
|
|
|
f_init(1);
|
|
|
|
var RslChannelNr chan_nr := f_chreq_act_ack();
|
|
var octetstring l3_payload := gen_l3_valid_payload();
|
|
|
|
f_ipa_tx(ts_RSL_EST_IND(chan_nr, valueof(ts_RslLinkID_SACCH(0)), l3_payload));
|
|
|
|
T.start;
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(l3_payload))) {
|
|
setverdict(fail, "MSC received COMPL L3 for invalid Link SACCH");
|
|
}
|
|
[] BSSAP.receive { repeat; }
|
|
[] IPA_RSL[0][0].receive { repeat; }
|
|
[] T.timeout {}
|
|
}
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Verify DLCI / RSL Link ID conversion for MO/MT messages on SAPI0/SAPI3 */
|
|
private function f_TC_tch_dlci_link_id_sapi(charstring id) runs on MSC_ConnHdlr {
|
|
var template PDU_BSSAP exp_compl := f_gen_exp_compl();
|
|
var PDU_BSSAP ass_cmd := f_gen_ass_req();
|
|
|
|
ass_cmd.pdu.bssmap.assignmentRequest.channelType := valueof(ts_BSSMAP_IE_ChannelType);
|
|
ass_cmd.pdu.bssmap.assignmentRequest.codecList := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
|
|
|
|
f_establish_fully(ass_cmd, exp_compl);
|
|
|
|
/* SAPI0 has already been established by f_establish_fully(), establish SAPI3 */
|
|
RSL.send(ts_RSL_EST_IND(g_chan_nr, ts_RslLinkID_SACCH(3), '0904'O));
|
|
/* Expect BSSAP/DTAP on SAPI3 (DLCI IE) */
|
|
BSSAP.receive(PDU_BSSAP:{
|
|
discriminator := '1'B,
|
|
spare := '0000000'B,
|
|
dlci := 'C3'O,
|
|
lengthIndicator := ?,
|
|
pdu := { dtap := '0904'O }
|
|
});
|
|
|
|
/* Send messages on DCCH/SAPI0 and ACCH/SAPI3 */
|
|
for (var integer i := 0; i < 32; i := i + 1) {
|
|
var octetstring l3 := '09'O & f_rnd_octstring(14);
|
|
var template (value) RslLinkId link_id;
|
|
var template (value) OCT1 dlci;
|
|
|
|
if (i mod 2 == 0) {
|
|
/* SAPI0 on FACCH or SDCCH */
|
|
link_id := ts_RslLinkID_DCCH(0);
|
|
dlci := '80'O;
|
|
} else {
|
|
/* SAPI3 on SACCH */
|
|
link_id := ts_RslLinkID_SACCH(3);
|
|
dlci := 'C3'O;
|
|
}
|
|
|
|
/* Send MO message: RSL -> BSSAP */
|
|
f_mo_l3_transceive(RSL, link_id, dlci, l3);
|
|
/* Send MT message: BSSAP -> RSL */
|
|
f_mt_l3_transceive(RSL, link_id, dlci, l3);
|
|
}
|
|
f_perform_clear();
|
|
}
|
|
testcase TC_tch_dlci_link_id_sapi() runs on test_CT {
|
|
var TestHdlrParams pars := f_gen_test_hdlr_pars();
|
|
var MSC_ConnHdlr vc_conn;
|
|
|
|
f_init(1, true);
|
|
f_sleep(1.0);
|
|
|
|
vc_conn := f_start_handler(refers(f_TC_tch_dlci_link_id_sapi), pars);
|
|
vc_conn.done;
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
private function f_exp_sapi_n_reject(template (present) GsmSapi sapi := ?,
|
|
template (present) myBSSMAP_Cause cause := ?,
|
|
template (present) BIT2 cc := ?,
|
|
float T_val := 2.0)
|
|
runs on test_CT {
|
|
var BSSAP_N_DATA_ind rx_di;
|
|
timer T;
|
|
|
|
var template (present) BSSMAP_IE_Cause tr_cause := tr_BSSMAP_IE_Cause(cause);
|
|
var template (present) PDU_BSSAP tr_pdu := tr_BSSMAP_SAPInReject(sapi);
|
|
|
|
T.start(T_val);
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_DATA_ind(?, tr_pdu)) -> value rx_di {
|
|
var BSSMAP_IE_Cause rx_cause := rx_di.userData.pdu.bssmap.sAPInReject.cause;
|
|
if (not match(rx_cause, tr_cause)) {
|
|
setverdict(fail, "Rx unexpected Cause IE: ",
|
|
rx_cause, " vs expected ", tr_cause);
|
|
}
|
|
|
|
/* Who ever on the earth decided to define this field as two separate bits?!? */
|
|
var BIT2 rx_cc := rx_di.userData.pdu.bssmap.sAPInReject.dLCI.c2
|
|
& rx_di.userData.pdu.bssmap.sAPInReject.dLCI.c1;
|
|
if (not match(rx_cc, cc)) {
|
|
setverdict(fail, "Rx unexpected Control Channel type: ",
|
|
rx_cc, " vs expected ", cc);
|
|
}
|
|
|
|
setverdict(pass);
|
|
}
|
|
[] BSSAP.receive(BSSAP_N_DATA_ind:?) -> value rx_di {
|
|
setverdict(fail, "Rx unexpected BSSAP PDU: ", rx_di);
|
|
}
|
|
[] T.timeout {
|
|
setverdict(fail, "Timeout waiting for BSSMAP SAPI N Reject");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check if we get SAPI N Reject on receipt of unexpected RLL RELease INDication */
|
|
testcase TC_rll_rel_ind_sapi_n_reject() runs on test_CT {
|
|
var RSL_Message rx_rsl;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
/* MS establishes a SAPI=0 link on DCCH */
|
|
dt := f_est_dchan(f_rnd_ra_cs(), 23, gen_l3_valid_payload());
|
|
|
|
/* MSC sends some data on (not yet established) SAPI=3 link */
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSAP_DTAP(gen_l3_valid_payload(), '03'O)));
|
|
/* BSC attempts to establish a SAPI=3 link on DCCH */
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_EST_REQ(dt.rsl_chan_nr, tr_RslLinkID_DCCH(3)));
|
|
|
|
/* MS sends unexpected RELease INDication on SAPI=3 */
|
|
f_ipa_tx(ts_RSL_REL_IND(dt.rsl_chan_nr, ts_RslLinkID_DCCH(3)));
|
|
/* We expect to receive BSSMAP SAPI N Reject message from the BSC */
|
|
f_exp_sapi_n_reject(3, GSM0808_CAUSE_MS_NOT_EQUIPPED);
|
|
|
|
/* Clean up the connection */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Check if we get SAPI N Reject on receipt of unexpected RLL ERROR INDication */
|
|
testcase TC_rll_err_ind_sapi_n_reject() runs on test_CT {
|
|
var RSL_Message rx_rsl;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
/* MS establishes a SAPI=0 link on DCCH */
|
|
dt := f_est_dchan(f_rnd_ra_cs(), 23, gen_l3_valid_payload());
|
|
|
|
/* MSC sends some data on (not yet established) SAPI=3 link */
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSAP_DTAP(gen_l3_valid_payload(), '03'O)));
|
|
/* BSC attempts to establish a SAPI=3 link on DCCH */
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_EST_REQ(dt.rsl_chan_nr, tr_RslLinkID_DCCH(3)));
|
|
|
|
/* BTS sends unexpected ERROR INDication on SAPI=3 */
|
|
f_ipa_tx(ts_RSL_ERROR_IND(dt.rsl_chan_nr, ts_RslLinkID_DCCH(3), ''O));
|
|
/* We expect to receive BSSMAP SAPI N Reject message from the BSC */
|
|
f_exp_sapi_n_reject(3, GSM0808_CAUSE_BSS_NOT_EQUIPPED);
|
|
|
|
/* Clean up the connection */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Check if we get SAPI N Reject due to a SAPI=3 link establishment timeout */
|
|
testcase TC_rll_timeout_sapi_n_reject() runs on test_CT {
|
|
var RSL_Message rx_rsl;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
/* MS establishes a SAPI=0 link on DCCH */
|
|
dt := f_est_dchan(f_rnd_ra_cs(), 23, gen_l3_valid_payload());
|
|
|
|
/* MSC sends some data on (not yet established) SAPI=3 link */
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSAP_DTAP(gen_l3_valid_payload(), '03'O)));
|
|
/* BSC attempts to establish a SAPI=3 link on DCCH */
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_EST_REQ(dt.rsl_chan_nr, tr_RslLinkID_DCCH(3)));
|
|
|
|
/* MS does not respond, so the link establishment timeout triggers SAPI N Reject */
|
|
f_exp_sapi_n_reject(3, GSM0808_CAUSE_BSS_NOT_EQUIPPED, T_val := 8.0);
|
|
|
|
/* Clean up the connection */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Check DLCI CC (Control Channel type) bits in SAPI N Reject */
|
|
testcase TC_rll_sapi_n_reject_dlci_cc() runs on test_CT {
|
|
var RSL_Message rx_rsl;
|
|
var DchanTuple dt;
|
|
|
|
f_init(1);
|
|
|
|
/* MS establishes a SAPI=0 link on DCCH */
|
|
dt := f_est_dchan(f_rnd_ra_cs(), 23, gen_l3_valid_payload());
|
|
|
|
/* MSC sends some data on (not yet established) SAPI=3 link */
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSAP_DTAP(gen_l3_valid_payload(), '03'O)));
|
|
/* BSC attempts to establish a SAPI=3 link on DCCH */
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_EST_REQ(dt.rsl_chan_nr, tr_RslLinkID_DCCH(3)));
|
|
|
|
/* MS sends unexpected ERROR INDication on DCCH/ACCH SAPI=3 */
|
|
f_ipa_tx(ts_RSL_ERROR_IND(dt.rsl_chan_nr, ts_RslLinkID_DCCH(3), ''O));
|
|
f_exp_sapi_n_reject(3, GSM0808_CAUSE_BSS_NOT_EQUIPPED, '10'B);
|
|
|
|
/* Clean up the connection */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si_default() runs on test_CT {
|
|
f_init(0);
|
|
f_init_bts_and_check_sysinfo(0, expect_si := SystemInformationConfig_default);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* We're testing SI2quater with lists of EARFCNs. Instead of just incrementing EARFCNs, also pick some from the edges of
|
|
* the entire value range. This function provides the same EARFCN numbers for the same earfcn_index */
|
|
private function f_test_si2quater_earfcn_by_idx(integer earfcn_index) return uint16_t
|
|
{
|
|
select (earfcn_index) {
|
|
case (0) {
|
|
/* E-ARFCN 111 is already added in the osmo-bsc.cfg */
|
|
return 111;
|
|
}
|
|
case (1) {
|
|
return 1;
|
|
}
|
|
case (2) {
|
|
return 0;
|
|
}
|
|
case (3) {
|
|
return 65535;
|
|
}
|
|
case else {
|
|
return 23 * (earfcn_index - 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
function f_test_si2quater(integer total_earfcns, template SystemInformationConfig expect_si,
|
|
template CellSelIndValue expect_cells := omit) runs on test_CT {
|
|
|
|
f_init(0);
|
|
|
|
/* E-ARFCN 111 is already added in the osmo-bsc.cfg, so only add more arfcns if total_earfcns > 1 */
|
|
for (var integer i := 1; i < total_earfcns; i := i + 1) {
|
|
f_bts_0_cfg(BSCVTY, {"si2quater neighbor-list add earfcn " & int2str(f_test_si2quater_earfcn_by_idx(i))
|
|
& " thresh-hi 20 thresh-lo 10 prio 3 qrxlv 22 meas 3"});
|
|
}
|
|
|
|
f_init_bts_and_check_sysinfo(0, expect_si := expect_si);
|
|
|
|
if (not istemplatekind(expect_cells, "omit")) {
|
|
/* Also check that RR Channel Release contains these EARFCNs.
|
|
* (copied code from TC_chan_rel_hard_clear_csfb) */
|
|
var BSSAP_N_DATA_ind rx_di;
|
|
var DchanTuple dt;
|
|
|
|
dt := f_est_dchan('23'O, 23, gen_l3_valid_payload());
|
|
/* Send CommonID with some random PLMN (BSC doesn't take it into account
|
|
* yet when generating the EUTRAN neigh list in RR CHannel Release) */
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_CommonId('001019876543210'H, '323454'O)));
|
|
|
|
/* Instruct BSC to clear channel */
|
|
var BssmapCause cause := 0;
|
|
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommandCSFB(cause)));
|
|
|
|
/* expect Clear Complete from BSC on A */
|
|
BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearComplete)) {
|
|
/* release the SCCP connection */
|
|
BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
|
|
}
|
|
|
|
f_expect_chan_rel(dt.rsl_chan_nr, expect_rll_rel_req := false, expect_cells := expect_cells);
|
|
}
|
|
|
|
for (var integer i := 1; i < total_earfcns; i := i + 1) {
|
|
f_bts_0_cfg(BSCVTY, {"si2quater neighbor-list del earfcn " & int2str(f_test_si2quater_earfcn_by_idx(i))});
|
|
}
|
|
}
|
|
|
|
private function f_tr_si2quater_earfcns(integer count) return template SI2quaterRestOctetsList
|
|
{
|
|
var template SI2quaterRestOctetsList si2quater := {};
|
|
var integer si2quater_count := (count + 2) / 3;
|
|
|
|
for (var integer i := 0; i < count; i := i + 1) {
|
|
var integer earfcn := f_test_si2quater_earfcn_by_idx(i);
|
|
var integer index := i / 3;
|
|
var integer earfcn_index := i mod 3;
|
|
if (index >= lengthof(si2quater)) {
|
|
si2quater[index] := tr_SI2quaterRestOctets_EUTRAN(index := index, count := si2quater_count - 1);
|
|
}
|
|
si2quater[index].rel_additions.rel5.rel6.rel7.rel8.prio_eutran_params_desc.desc.eutran_params_desc.desc.repeated_neigh_cells[0].cell_desc_list[earfcn_index] := tr_EUTRAN_CellDesc_default(e_arfcn := earfcn);
|
|
}
|
|
|
|
return si2quater;
|
|
}
|
|
|
|
private function f_tr_rr_chan_rel_earfcns(integer count) return template CellSelIndValue
|
|
{
|
|
var template CellSelIndValue_EUTRAN_Descrs cells := {};
|
|
|
|
/* the lte neighbors must match the config & vty to pass this test */
|
|
for (var integer i := 0; i < count; i := i + 1) {
|
|
var integer earfcn := f_test_si2quater_earfcn_by_idx(i);
|
|
cells[i] := tr_CellSelIndValue_EUTRAN_Descr(earfcn, '1'B, 3);
|
|
}
|
|
|
|
return tr_CellSelIndValue_EUTRAN(cells);
|
|
}
|
|
|
|
private function f_tc_si2quater_n_earfcns(integer n) runs on test_CT
|
|
{
|
|
var template SystemInformationConfig sic := SystemInformationConfig_default;
|
|
sic.si2quater := f_tr_si2quater_earfcns(n);
|
|
var template CellSelIndValue cells := f_tr_rr_chan_rel_earfcns(n);
|
|
f_test_si2quater(n, sic, cells);
|
|
}
|
|
|
|
testcase TC_si2quater_2_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(2);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si2quater_3_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(3);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si2quater_4_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(4);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si2quater_5_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(5);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si2quater_6_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(6);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si2quater_12_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(12);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si2quater_23_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(23);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si2quater_32_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(32);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si2quater_33_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(33);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si2quater_42_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(42);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_si2quater_48_earfcns() runs on test_CT {
|
|
f_tc_si2quater_n_earfcns(48);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* verify the VTY error response when adding too many EARFCNs, and showing that osmo-bsc still sends 16 SI2quater with
|
|
* 48 EARFCNs. */
|
|
testcase TC_si2quater_49_earfcns() runs on test_CT {
|
|
var template SystemInformationConfig sic := SystemInformationConfig_default;
|
|
sic.si2quater := f_tr_si2quater_earfcns(48); /* 48, not 49! */
|
|
f_init(0);
|
|
|
|
for (var integer i := 1; i < 48; i := i + 1) {
|
|
f_bts_0_cfg(BSCVTY, {"si2quater neighbor-list add earfcn " & int2str(f_test_si2quater_earfcn_by_idx(i))
|
|
& " thresh-hi 20 thresh-lo 10 prio 3 qrxlv 22 meas 3"});
|
|
}
|
|
|
|
/* The 49th EARFCN no longer fits, expect VTY error */
|
|
f_vty_enter_cfg_bts(BSCVTY, 0);
|
|
var charstring vty_error;
|
|
vty_error := f_vty_transceive_ret(BSCVTY,
|
|
"si2quater neighbor-list add earfcn 70 thresh-hi 20 thresh-lo 10 prio 3 qrxlv 22 meas 3")
|
|
f_vty_transceive(BSCVTY, "end");
|
|
|
|
if (f_strstr(vty_error, "Unable to add ARFCN 70") >= 0) {
|
|
log("Got expected VTY error: ", vty_error);
|
|
setverdict(pass);
|
|
} else {
|
|
setverdict(fail, "Expected the 49th EUTRAN ARFCN to be rejected by vty config, got: ", vty_error);
|
|
}
|
|
|
|
f_init_bts_and_check_sysinfo(0, expect_si := sic);
|
|
|
|
for (var integer i := 1; i < 48; i := i + 1) {
|
|
f_bts_0_cfg(BSCVTY, {"si2quater neighbor-list del earfcn " & int2str(f_test_si2quater_earfcn_by_idx(i))});
|
|
}
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
private function f_acc09_count_allowed(AccessControlClass acc) return uint8_t
|
|
{
|
|
var uint8_t count := 0;
|
|
for (var integer i := 5; i < 16; i := i + 1) {
|
|
if (acc[i] == '0'B) { /* the list marks barred, we count allowed */
|
|
count := count + 1;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
private function f_recv_next_si1(integer rsl_idx := 0) runs on test_CT return SystemInformationType1
|
|
{
|
|
var ASP_RSL_Unitdata rx_rsl_ud;
|
|
var SystemInformationType1 last_si1;
|
|
|
|
timer T := 30.0;
|
|
T.start;
|
|
alt {
|
|
[] IPA_RSL[rsl_idx][0].receive(tr_ASP_RSL_UD((tr_RSL_NO_BCCH_INFO,
|
|
tr_RSL_BCCH_INFO,
|
|
tr_RSL_NO_SACCH_FILL,
|
|
tr_RSL_SACCH_FILL))) -> value rx_rsl_ud {
|
|
f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
|
|
if (g_system_information[rsl_idx].si1 == omit) {
|
|
repeat;
|
|
}
|
|
last_si1 := g_system_information[rsl_idx].si1;
|
|
g_system_information[rsl_idx].si1 := omit;
|
|
T.stop;
|
|
}
|
|
[] IPA_RSL[rsl_idx][0].receive { repeat; }
|
|
[] T.timeout { setverdict(fail, "Timeout receiving next SI1"); }
|
|
}
|
|
return last_si1;
|
|
}
|
|
|
|
/* verify ACC rotate feature */
|
|
testcase TC_si_acc_rotate() runs on test_CT {
|
|
var template SystemInformationConfig sic := SystemInformationConfig_default;
|
|
var SystemInformationType1 last_si1;
|
|
var AccessControlClass acc;
|
|
var uint8_t count;
|
|
var integer times_allowed[10] := { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
f_init(0, guard_timeout := 60.0);
|
|
|
|
f_bts_0_cfg(BSCVTY, {"rach access-control-class 5 barred",
|
|
"access-control-class-rotate 3",
|
|
"access-control-class-rotate-quantum 1"});
|
|
|
|
/* Init and get first sysinfo */
|
|
f_init_bts_and_check_sysinfo(0, expect_si := ?);
|
|
|
|
for (var integer i:= 0; i < 20; i := i + 1) {
|
|
last_si1 := f_recv_next_si1(0);
|
|
acc := last_si1.rach_control.acc;
|
|
count := f_acc09_count_allowed(acc);
|
|
log("RSL: GOT SI1 ACC len=", count, ": ", acc);
|
|
|
|
if (count != 3) {
|
|
log("RSL: EXPECTED SI ACC len=3");
|
|
setverdict(fail, "received SI does not match expectations");
|
|
break;
|
|
}
|
|
|
|
for (var integer j := 0; j < 10; j := j + 1) {
|
|
if (acc[16 - 1 - j] == '0'B) { /* the list marks barred, we count allowed */
|
|
times_allowed[j] := times_allowed[j] + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var integer j := 0; j < 10; j := j + 1) {
|
|
log("ACC", j, " allowed ", times_allowed[j], " times" );
|
|
if (j != 5 and times_allowed[j] < 3) {
|
|
setverdict(fail, "ACC", j, " ERROR: allowed ", times_allowed[j], " < 1 times");
|
|
} else if (j == 5 and times_allowed[j] > 0) {
|
|
setverdict(fail, "ACC", j, " ERROR: allowed ", times_allowed[j], " > 0 times");
|
|
}
|
|
}
|
|
|
|
f_bts_0_cfg(BSCVTY, {"access-control-class-rotate 10",
|
|
"rach access-control-class 5 allowed"});
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* verify ACC startup ramp+rotate feature */
|
|
testcase TC_si_acc_ramp_rotate() runs on test_CT {
|
|
var template SystemInformationConfig sic := SystemInformationConfig_default;
|
|
var SystemInformationType1 last_si1;
|
|
var AccessControlClass acc;
|
|
var ASP_RSL_Unitdata rx_rsl_ud;
|
|
var uint8_t count;
|
|
var uint8_t prev_count;
|
|
var integer times_allowed[10] := { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
f_init(0, guard_timeout := 80.0);
|
|
|
|
f_bts_0_cfg(BSCVTY, {"rach access-control-class 4 barred",
|
|
"access-control-class-rotate 0",
|
|
"access-control-class-rotate-quantum 1",
|
|
"access-control-class-ramping",
|
|
"access-control-class-ramping-step-interval 5",
|
|
"access-control-class-ramping-step-size 5"});
|
|
|
|
/* Init and get first sysinfo */
|
|
f_init_bts_and_check_sysinfo(0, expect_si := ?);
|
|
last_si1 := g_system_information[0].si1;
|
|
acc := last_si1.rach_control.acc;
|
|
count := f_acc09_count_allowed(acc);
|
|
/* Adm subset size was set to 0 above, so wait until all ACC are barred */
|
|
while (count > 0) {
|
|
last_si1 := f_recv_next_si1(0);
|
|
acc := last_si1.rach_control.acc;
|
|
count := f_acc09_count_allowed(acc);
|
|
log("RSL: wait len()=0: GOT SI1 ACC len=", count, ": ", acc);
|
|
}
|
|
|
|
/* Increase adm subset size, we should see ramping start up */
|
|
f_bts_0_cfg(BSCVTY, {"access-control-class-rotate 10"});
|
|
prev_count := 0;
|
|
while (true) {
|
|
last_si1 := f_recv_next_si1(0);
|
|
acc := last_si1.rach_control.acc;
|
|
count := f_acc09_count_allowed(acc);
|
|
log("RSL: GOT SI1 ACC len=", count, ": ", acc);
|
|
|
|
if (prev_count > count) {
|
|
setverdict(fail, "ACC allowed count dropped while expecting grow: ", prev_count, " -> ", count);
|
|
break;
|
|
}
|
|
|
|
if (count == 9) {
|
|
break; /* Maximum reached (10 - 1 perm barred), done here */
|
|
}
|
|
|
|
prev_count := count;
|
|
}
|
|
|
|
setverdict(pass);
|
|
|
|
f_bts_0_cfg(BSCVTY, {"access-control-class-rotate 10",
|
|
"rach access-control-class 4 allowed",
|
|
"no access-control-class-ramping"});
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_ctrl_msc_connection_status() runs on test_CT {
|
|
var charstring ctrl_resp;
|
|
|
|
f_init(1);
|
|
|
|
/* See https://osmocom.org/issues/2729 */
|
|
f_ctrl_get_exp(IPA_CTRL, "msc_connection_status", "connected");
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
testcase TC_ctrl_msc0_connection_status() runs on test_CT {
|
|
var charstring ctrl_resp;
|
|
|
|
f_init(1);
|
|
|
|
f_ctrl_get_exp(IPA_CTRL, "msc.0.connection_status", "connected");
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Verify correct stats on the number of configured and connected MSCs */
|
|
private function f_tc_stat_num_msc_connected_msc_connhdlr(integer expect_num_msc_connected) runs on MSC_ConnHdlr {
|
|
g_pars := f_gen_test_hdlr_pars();
|
|
var StatsDExpects expect := {
|
|
{ name := "TTCN3.bsc.0.num_msc.connected", mtype := "g", min := expect_num_msc_connected, max := expect_num_msc_connected },
|
|
{ name := "TTCN3.bsc.0.num_msc.total", mtype := "g", min := NUM_MSC, max := NUM_MSC }
|
|
};
|
|
f_statsd_expect(expect);
|
|
}
|
|
|
|
private function f_tc_stat_num_msc_connected_test_ct(void_fn tc_fn, integer nr_msc) runs on test_CT
|
|
{
|
|
var MSC_ConnHdlr vc_conn;
|
|
|
|
f_init(nr_bts := 1, handler_mode := true, nr_msc := nr_msc);
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(tc_fn);
|
|
vc_conn.done;
|
|
|
|
/* Also verify stat exposed on CTRL interface */
|
|
f_ctrl_get_exp(IPA_CTRL, "stat_item.last.bsc.0.num_msc:connected", int2str(nr_msc));
|
|
f_ctrl_get_exp(IPA_CTRL, "stat_item.last.bsc.0.num_msc:total", int2str(NUM_MSC));
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Verify that when 1 MSC is active, that num_msc:connected reports 1. */
|
|
private function f_tc_stat_num_msc_connected_1(charstring id) runs on MSC_ConnHdlr {
|
|
f_tc_stat_num_msc_connected_msc_connhdlr(1);
|
|
}
|
|
testcase TC_stat_num_msc_connected_1() runs on test_CT {
|
|
f_tc_stat_num_msc_connected_test_ct(refers(f_tc_stat_num_msc_connected_1), 1);
|
|
}
|
|
|
|
/* Verify that when 2 MSCs are active, that num_msc:connected reports 2. */
|
|
private function f_tc_stat_num_msc_connected_2(charstring id) runs on MSC_ConnHdlr {
|
|
f_tc_stat_num_msc_connected_msc_connhdlr(2);
|
|
}
|
|
testcase TC_stat_num_msc_connected_2() runs on test_CT {
|
|
f_tc_stat_num_msc_connected_test_ct(refers(f_tc_stat_num_msc_connected_2), 2);
|
|
}
|
|
|
|
/* Verify that when 3 MSCs are active, that num_msc:connected reports 3. */
|
|
private function f_tc_stat_num_msc_connected_3(charstring id) runs on MSC_ConnHdlr {
|
|
f_tc_stat_num_msc_connected_msc_connhdlr(3);
|
|
}
|
|
testcase TC_stat_num_msc_connected_3() runs on test_CT {
|
|
f_tc_stat_num_msc_connected_test_ct(refers(f_tc_stat_num_msc_connected_3), 3);
|
|
}
|
|
|
|
/* Verify correct stats on the number of configured and connected MSCs */
|
|
private function f_tc_stat_num_bts_connected_msc_connhdlr(integer expect_num_bts_connected) runs on MSC_ConnHdlr {
|
|
var integer num_trx_connected := 0;
|
|
var integer num_trx_total := 0;
|
|
|
|
for (var integer i := 0; i < lengthof(c_BtsParams); i := i + 1) {
|
|
var integer trx_num := c_BtsParams[i].trx_num;
|
|
num_trx_total := num_trx_total + trx_num;
|
|
if (i < expect_num_bts_connected) {
|
|
num_trx_connected := num_trx_connected + trx_num;
|
|
}
|
|
}
|
|
|
|
var StatsDExpects expect := {
|
|
{ name := "TTCN3.bsc.0.num_bts.oml_connected", mtype := "g", min := expect_num_bts_connected, max := NUM_BTS_CFG },
|
|
{ name := "TTCN3.bsc.0.num_bts.all_trx_rsl_connected", mtype := "g", min := expect_num_bts_connected, max := expect_num_bts_connected },
|
|
{ name := "TTCN3.bsc.0.num_bts.total", mtype := "g", min := NUM_BTS_CFG, max := NUM_BTS_CFG },
|
|
{ name := "TTCN3.bsc.0.num_trx.rsl_connected", mtype := "g", min := num_trx_connected, max := num_trx_connected },
|
|
{ name := "TTCN3.bsc.0.num_trx.total", mtype := "g", min := num_trx_total, max := num_trx_total }
|
|
};
|
|
|
|
g_pars := f_gen_test_hdlr_pars();
|
|
f_statsd_expect(expect);
|
|
}
|
|
|
|
private function f_tc_stat_num_bts_connected_test_ct(void_fn tc_fn, integer nr_bts) runs on test_CT {
|
|
var integer num_trx_connected := 0;
|
|
var integer num_trx_total := 0;
|
|
var MSC_ConnHdlr vc_conn;
|
|
|
|
f_init(nr_bts := nr_bts, handler_mode := true, nr_msc := 1);
|
|
f_sleep(1.0);
|
|
vc_conn := f_start_handler(tc_fn);
|
|
vc_conn.done;
|
|
|
|
for (var integer i := 0; i < lengthof(c_BtsParams); i := i + 1) {
|
|
var integer trx_num := c_BtsParams[i].trx_num;
|
|
num_trx_total := num_trx_total + trx_num;
|
|
if (i < nr_bts) {
|
|
num_trx_connected := num_trx_connected + trx_num;
|
|
}
|
|
}
|
|
|
|
/* Also verify stat exposed on CTRL interface */
|
|
f_ctrl_get_exp(IPA_CTRL, "stat_item.last.bsc.0.num_bts:all_trx_rsl_connected", int2str(nr_bts));
|
|
f_ctrl_get_exp(IPA_CTRL, "stat_item.last.bsc.0.num_bts:total", int2str(NUM_BTS_CFG));
|
|
f_ctrl_get_exp(IPA_CTRL, "stat_item.last.bsc.0.num_trx:rsl_connected", int2str(num_trx_connected));
|
|
f_ctrl_get_exp(IPA_CTRL, "stat_item.last.bsc.0.num_trx:total", int2str(num_trx_total));
|
|
|
|
/* Verify rf_states exposed on CTRL interface */
|
|
var charstring expect_net_rf_states := "";
|
|
for (var integer i := 0; i < NUM_BTS_CFG; i := i + 1) {
|
|
var charstring expect_bts_rf_states := "";
|
|
|
|
for (var integer j := 0; j < c_BtsParams[i].trx_num; j := j + 1) {
|
|
expect_bts_rf_states := expect_bts_rf_states &
|
|
int2str(i) & "," & int2str(j) & ",";
|
|
if (i < NUM_BTS) {
|
|
/* In these tests, OML for the first NUM_BTS are always connected via osmo-bts-omldummy */
|
|
expect_bts_rf_states := expect_bts_rf_states & "operational,unlocked,";
|
|
} else {
|
|
/* For remaining i < NUM_BTS_CFG, OML is not connected, i.e. inoperational */
|
|
expect_bts_rf_states := expect_bts_rf_states & "inoperational,locked,";
|
|
}
|
|
/* The RF policy is still global in osmo-bsc, i.e. always "on" */
|
|
expect_bts_rf_states := expect_bts_rf_states & "on,";
|
|
if (i < nr_bts) {
|
|
/* For BTS where RSL is connected, the RSL state will be "up" */
|
|
expect_bts_rf_states := expect_bts_rf_states & "rsl-up;";
|
|
} else {
|
|
expect_bts_rf_states := expect_bts_rf_states & "rsl-down;";
|
|
}
|
|
}
|
|
|
|
f_ctrl_get_exp(IPA_CTRL, "bts." & int2str(i) & ".rf_states", expect_bts_rf_states);
|
|
expect_net_rf_states := expect_net_rf_states & expect_bts_rf_states;
|
|
}
|
|
f_ctrl_get_exp(IPA_CTRL, "rf_states", expect_net_rf_states);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Verify that when 1 BTS is connected, that num_{bts,trx}:*_connected reports 1. */
|
|
private function f_tc_stat_num_bts_connected_1(charstring id) runs on MSC_ConnHdlr {
|
|
f_tc_stat_num_bts_connected_msc_connhdlr(1);
|
|
}
|
|
testcase TC_stat_num_bts_connected_1() runs on test_CT {
|
|
f_tc_stat_num_bts_connected_test_ct(refers(f_tc_stat_num_bts_connected_1), 1);
|
|
}
|
|
|
|
/* Verify that when 2 BTS is connected, that num_{bts,trx}:*_connected reports 2. */
|
|
private function f_tc_stat_num_bts_connected_2(charstring id) runs on MSC_ConnHdlr {
|
|
f_tc_stat_num_bts_connected_msc_connhdlr(2);
|
|
}
|
|
testcase TC_stat_num_bts_connected_2() runs on test_CT {
|
|
f_tc_stat_num_bts_connected_test_ct(refers(f_tc_stat_num_bts_connected_2), 2);
|
|
}
|
|
|
|
/* Verify that when 3 BTS is connected, that num_{bts,trx}:*_connected reports 3. */
|
|
private function f_tc_stat_num_bts_connected_3(charstring id) runs on MSC_ConnHdlr {
|
|
f_tc_stat_num_bts_connected_msc_connhdlr(3);
|
|
}
|
|
testcase TC_stat_num_bts_connected_3() runs on test_CT {
|
|
f_tc_stat_num_bts_connected_test_ct(refers(f_tc_stat_num_bts_connected_3), 3);
|
|
}
|
|
|
|
testcase TC_ctrl() runs on test_CT {
|
|
var charstring ctrl_resp;
|
|
|
|
f_init(1);
|
|
|
|
/* all below values must match the osmo-bsc.cfg config file used */
|
|
|
|
f_ctrl_get_exp(IPA_CTRL, "mcc", "001");
|
|
f_ctrl_get_exp(IPA_CTRL, "mnc", "01");
|
|
f_ctrl_get_exp(IPA_CTRL, "number-of-bts", "4");
|
|
|
|
var integer bts_nr := 0;
|
|
f_ctrl_get_exp_bts(IPA_CTRL, bts_nr, "location-area-code", "1");
|
|
f_ctrl_get_exp_bts(IPA_CTRL, bts_nr, "cell-identity", "0");
|
|
f_ctrl_get_exp_bts(IPA_CTRL, bts_nr, "oml-connection-state", "connected");
|
|
f_ctrl_get_exp_bts(IPA_CTRL, bts_nr, "gprs-mode", "gprs");
|
|
f_ctrl_get_exp_bts(IPA_CTRL, bts_nr, "rf_state", "operational,unlocked,on");
|
|
f_ctrl_get_exp_trx(IPA_CTRL, bts_nr, 0, "arfcn", "871");
|
|
f_ctrl_get_exp_trx(IPA_CTRL, bts_nr, 0, "max-power-reduction", "20");
|
|
|
|
var integer uptime := str2int(f_ctrl_get_bts(IPA_CTRL, bts_nr, "oml-uptime"));
|
|
f_sleep(2.0);
|
|
if (str2int(f_ctrl_get_bts(IPA_CTRL, bts_nr, "oml-uptime")) < uptime+1) {
|
|
setverdict(fail, "oml-uptime not incrementing as expected");
|
|
}
|
|
/* TODO: Disconnect RSL, imply that OML is disconnected and check for uptime zero? */
|
|
|
|
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bsc", 0, "paging:attempted", 0);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Verify that Upon receival of SET "location", BSC forwards a TRAP
|
|
"location-state" over the SCCPlite IPA conn */
|
|
testcase TC_ctrl_location() runs on test_CT {
|
|
var MSC_ConnHdlr vc_conn;
|
|
var integer bts_nr := 0;
|
|
|
|
f_init(1, true);
|
|
f_sleep(1.0);
|
|
|
|
f_ctrl_set_bts(IPA_CTRL, bts_nr, "location", "1234567,fix3d,0.340000,0.560000,0.780000");
|
|
f_ctrl_exp_trap(SCCPLITE_IPA_CTRL, "bts." & int2str(bts_nr) & ".location-state",
|
|
"1234567,fix3d,0.340000,0.560000,0.780000,operational,unlocked,on,001,01");
|
|
|
|
f_ctrl_set(SCCPLITE_IPA_CTRL, "rf_locked", "1");
|
|
f_sleep(2.0);
|
|
|
|
f_ctrl_set_bts(IPA_CTRL, bts_nr, "location", "1234888,fix3d,0.350000,0.570000,0.790000");
|
|
f_ctrl_exp_trap(SCCPLITE_IPA_CTRL, "bts." & int2str(bts_nr) & ".location-state",
|
|
"1234888,fix3d,0.350000,0.570000,0.790000,operational,locked,off,001,01");
|
|
|
|
/* should match the one from config */
|
|
f_ctrl_set(SCCPLITE_IPA_CTRL, "rf_locked", "0");
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* Paging Testing
|
|
***********************************************************************/
|
|
|
|
type record Cell_Identity {
|
|
GsmMcc mcc,
|
|
GsmMnc mnc,
|
|
GsmLac lac,
|
|
GsmCellId ci
|
|
};
|
|
private const Cell_Identity cid := { '001'H, '01'H, 1, 0 };
|
|
private const Cell_Identity unknown_cid := { '678'H, 'f90'H, 1, 0 };
|
|
|
|
type set of integer BtsIdList;
|
|
|
|
private function f_bts_in_list(integer bts_id, BtsIdList bts_ids) return boolean {
|
|
for (var integer j := 0; j < sizeof(bts_ids); j := j + 1) {
|
|
if (bts_id == bts_ids[j]) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* core paging test helper function; used by most paging test cases */
|
|
private function f_pageing_helper(hexstring imsi,
|
|
template BSSMAP_FIELD_CellIdentificationList cid_list,
|
|
BtsIdList bts_ids := { 0 },
|
|
template RSL_ChanNeeded rsl_chneed := omit,
|
|
template (omit) OCT4 tmsi := omit) runs on test_CT
|
|
{
|
|
var template BSSMAP_IE_ChannelNeeded bssmap_chneed;
|
|
var template MobileIdentityV mi;
|
|
var RSL_Message rx_rsl;
|
|
var integer paging_group := hex2int(imsi[lengthof(imsi)-1]);
|
|
var integer i;
|
|
|
|
f_init();
|
|
|
|
/* Clear the queue, it might still contain stuff like BCCH FILLING */
|
|
for (i := 0; i < NUM_BTS; i := i + 1) {
|
|
IPA_RSL[i][0].clear;
|
|
}
|
|
|
|
if (isvalue(rsl_chneed)) {
|
|
/* The values of 08.08 3.2.2.36 and 08.58 9.3.40 are luckily identical */
|
|
bssmap_chneed := ts_BSSMAP_IE_ChanNeeded(int2bit(enum2int(valueof(rsl_chneed)),2));
|
|
} else {
|
|
bssmap_chneed := omit;
|
|
}
|
|
|
|
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap[0].sccp_addr_peer, g_bssap[0].sccp_addr_own,
|
|
ts_BSSMAP_Paging(imsi, cid_list, tmsi, bssmap_chneed)));
|
|
|
|
if (not istemplatekind(tmsi, "omit")) {
|
|
mi := t_MI_TMSI(tmsi);
|
|
} else {
|
|
mi := tr_MI_IMSI(imsi);
|
|
}
|
|
|
|
for (i := 0; i < sizeof(bts_ids); i := i + 1) {
|
|
rx_rsl := f_exp_ipa_rx(tr_RSL_PAGING_CMD(mi), idx := {bts_ids[i], 0});
|
|
/* check channel type, paging group */
|
|
if (rx_rsl.ies[1].body.paging_group != paging_group) {
|
|
setverdict(fail, "Paging for wrong paging group");
|
|
}
|
|
if (ispresent(rsl_chneed) and
|
|
rx_rsl.ies[3].body.chan_needed.chan_needed != valueof(rsl_chneed)) {
|
|
setverdict(fail, "RSL Channel Needed != BSSMAP Channel Needed");
|
|
}
|
|
}
|
|
f_sleep(2.0);
|
|
/* do a quick check on all not-included BTSs if they received paging */
|
|
for (i := 0; i < NUM_BTS; i := i + 1) {
|
|
timer T := 0.1;
|
|
if (f_bts_in_list(i, bts_ids)) {
|
|
continue;
|
|
}
|
|
T.start;
|
|
alt {
|
|
[] IPA_RSL[i][0].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(mi))) {
|
|
setverdict(fail, "Paging on BTS ", i, " which is not part of ", bts_ids);
|
|
}
|
|
[] IPA_RSL[i][0].receive { repeat; }
|
|
[] T.timeout { }
|
|
}
|
|
}
|
|
|
|
setverdict(pass);
|
|
}
|
|
|
|
const BtsIdList c_BtsId_all := { 0, 1, 2 };
|
|
const BtsIdList c_BtsId_none := { };
|
|
const BtsIdList c_BtsId_LAC1 := { 0, 1 };
|
|
const BtsIdList c_BtsId_LAC2 := { 2 };
|
|
|
|
/* PAGING by IMSI + TMSI */
|
|
testcase TC_paging_imsi_nochan() runs on test_CT {
|
|
var BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := valueof(ts_BSSMAP_CIL_noCell);
|
|
f_pageing_helper('001010100000001'H, cid_list, c_BtsId_all, omit, omit);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* PAGING by IMSI + TMSI */
|
|
testcase TC_paging_tmsi_nochan() runs on test_CT {
|
|
var BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := valueof(ts_BSSMAP_CIL_noCell);
|
|
f_pageing_helper('001010100000001'H, cid_list, c_BtsId_all, omit, 'A1B2C301'O);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging with different "channel needed' values */
|
|
testcase TC_paging_tmsi_any() runs on test_CT {
|
|
var BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := valueof(ts_BSSMAP_CIL_noCell);
|
|
f_pageing_helper('001010100000002'H, cid_list, c_BtsId_all, RSL_CHANNEED_ANY, 'A1B2C302'O);
|
|
f_shutdown_helper();
|
|
}
|
|
testcase TC_paging_tmsi_sdcch() runs on test_CT {
|
|
var BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := valueof(ts_BSSMAP_CIL_noCell);
|
|
f_pageing_helper('001010100000003'H, cid_list, c_BtsId_all, RSL_CHANNEED_SDCCH, 'A1B2C303'O);
|
|
f_shutdown_helper();
|
|
}
|
|
testcase TC_paging_tmsi_tch_f() runs on test_CT {
|
|
var BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := valueof(ts_BSSMAP_CIL_noCell);
|
|
f_pageing_helper('001010000000004'H, cid_list, c_BtsId_all, RSL_CHANNEED_TCH_F, 'A1B2C304'O);
|
|
f_shutdown_helper();
|
|
}
|
|
testcase TC_paging_tmsi_tch_hf() runs on test_CT {
|
|
var BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := valueof(ts_BSSMAP_CIL_noCell);
|
|
f_pageing_helper('001010000000005'H, cid_list, c_BtsId_all, RSL_CHANNEED_TCH_ForH, 'A1B2C305'O);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging by CGI */
|
|
testcase TC_paging_imsi_nochan_cgi() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_CGI := { ts_BSSMAP_CI_CGI(cid.mcc, cid.mnc, cid.lac, cid.ci) } };
|
|
f_pageing_helper('001010000000006'H, cid_list, { 0 });
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging by LAC+CI */
|
|
testcase TC_paging_imsi_nochan_lac_ci() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_LAC_CI := { ts_BSSMAP_CI_LAC_CI(cid.lac, cid.ci) } };
|
|
f_pageing_helper('001010000000007'H, cid_list, { 0 });
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging by CI */
|
|
testcase TC_paging_imsi_nochan_ci() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_CI := { ts_BSSMAP_CI_CI(cid.ci) } };
|
|
f_pageing_helper('001010000000008'H, cid_list, { 0 });
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging by LAI */
|
|
testcase TC_paging_imsi_nochan_lai() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_LAI := { ts_BSSMAP_CI_LAI(cid.mcc, cid.mnc, cid.lac) } };
|
|
f_pageing_helper('001010000000009'H, cid_list, c_BtsId_LAC1);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging by LAC */
|
|
testcase TC_paging_imsi_nochan_lac() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_LAC := { ts_BSSMAP_CI_LAC(cid.lac) } };
|
|
f_pageing_helper('001010000000010'H, cid_list, c_BtsId_LAC1);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging by "all in BSS" */
|
|
testcase TC_paging_imsi_nochan_all() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_allInBSS := ''O };
|
|
f_pageing_helper('001010000000011'H, cid_list, c_BtsId_all);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging by PLMN+LAC+RNC; We do not implement this; Verify nothing is paged */
|
|
testcase TC_paging_imsi_nochan_plmn_lac_rnc() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_PLMN_LAC_RNC := { ts_BSSMAP_CI_PLMN_LAC_RNC(cid.mcc, cid.mnc, cid.lac, 12) } };
|
|
f_pageing_helper('001010000000012'H, cid_list, c_BtsId_none);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging by RNC; We do not implement this; Verify nothing is paged */
|
|
testcase TC_paging_imsi_nochan_rnc() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_RNC := { int2oct(13, 2) } };
|
|
f_pageing_helper('001010000000013'H, cid_list, c_BtsId_none);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging by LAC+RNC; We do not implement; Verify nothing is paged */
|
|
testcase TC_paging_imsi_nochan_lac_rnc() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_LAC_RNC := { ts_BSSMAP_CI_LAC_RNC(cid.lac, 14) } };
|
|
f_pageing_helper('001010000000014'H, cid_list, c_BtsId_none);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging on multiple cells (multiple entries in list): Verify all of them page */
|
|
testcase TC_paging_imsi_nochan_lacs() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_LAC := { ts_BSSMAP_CI_LAC(1), ts_BSSMAP_CI_LAC(2) } };
|
|
f_pageing_helper('001010000000015'H, cid_list, c_BtsId_all);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging on empty list: Verify none of them page */
|
|
testcase TC_paging_imsi_nochan_lacs_empty() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_LAC := { } };
|
|
f_pageing_helper('001010000000016'H, cid_list, c_BtsId_none);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Paging by CGI with unknown MCC/MNC: Verify nothing is paged. */
|
|
testcase TC_paging_imsi_nochan_cgi_unknown_cid() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
cid_list := { cIl_CGI := { ts_BSSMAP_CI_CGI(unknown_cid.mcc, unknown_cid.mnc, unknown_cid.lac, unknown_cid.ci) } };
|
|
f_pageing_helper('001010000000006'H, cid_list, c_BtsId_none);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Send paging response containing invalid (wrongly formatted) MobileIdentity IE. */
|
|
testcase TC_paging_imsi_nochan_ci_resp_invalid_mi() runs on test_CT {
|
|
var template BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
var BSSAP_N_CONNECT_ind rx_c_ind;
|
|
var DchanTuple dt;
|
|
var octetstring rr_pag_resp := '06270003535992617965720000'O;
|
|
/* { 06 27 } is { GSM48_PDISC_RR, GSM48_MT_RR_PAG_RESP }
|
|
* see 3GPP TS 44.018, table 9.1.25.1
|
|
* { 00 } or { 01 } is CKSN + Spare Half Octet, not important
|
|
* { 03 53 59 92 } is Mobile Station Classmark
|
|
* { 61 79 65 72 00 00 } is the invalid Mobile Identity IE (3GPP TS 24.008, 10.5.1.4),
|
|
* Length is 0x61 (97 in decimal).
|
|
*/
|
|
|
|
cid_list := { cIl_CI := { ts_BSSMAP_CI_CI(cid.ci) } };
|
|
f_pageing_helper('001010000000008'H, cid_list, { 0 });
|
|
|
|
/* Send CHAN RQD and wait for allocation; acknowledge it */
|
|
dt.rsl_chan_nr := f_chreq_act_ack();
|
|
dt.idx := {0, 0};
|
|
|
|
/* Send unsolicited Paging response (no matching Paging CMD stored in BSC) */
|
|
f_ipa_tx(ts_RSL_EST_IND(dt.rsl_chan_nr, valueof(ts_RslLinkID_DCCH(0)), rr_pag_resp));
|
|
|
|
/* Expevct a CR with a matching Paging response on the A-Interface */
|
|
timer T := 5.0;
|
|
T.start;
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(rr_pag_resp))) -> value rx_c_ind {
|
|
setverdict(pass);
|
|
dt.sccp_conn_id := rx_c_ind.connectionId;
|
|
BSSAP.send(ts_BSSAP_CONNECT_res(dt.sccp_conn_id));
|
|
}
|
|
[] BSSAP.receive {
|
|
setverdict(fail, "Received unexpected message on A-Interface!");
|
|
}
|
|
[] T.timeout {
|
|
setverdict(fail, "Received nothing on A-Interface!");
|
|
}
|
|
}
|
|
|
|
f_perform_clear_test_ct(dt);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Verify paging retransmission interval + count */
|
|
/* Verify paging stops after channel establishment */
|
|
/* Test behavior under paging overload */
|
|
|
|
/* Verify PCH load */
|
|
testcase TC_paging_imsi_load() runs on test_CT {
|
|
var BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
timer T := 4.0;
|
|
timer T_retrans := 1.0;
|
|
cid_list := valueof(ts_BSSMAP_CIL_noCell);
|
|
f_pageing_helper('001010123456789'H, cid_list, c_BtsId_all);
|
|
|
|
/* tell BSC there is no paging space anymore */
|
|
f_ipa_tx(ts_RSL_PAGING_LOAD_IND(0));
|
|
f_sleep(0.2);
|
|
IPA_RSL[0][0].clear;
|
|
|
|
/* Wait for 4 seconds if any more PAGING CMD are received on RSL. Normally,
|
|
* there would be 8 retransmissions during 4 seconds */
|
|
T.start;
|
|
T_retrans.start;
|
|
alt {
|
|
[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(?))) {
|
|
setverdict(fail, "Received PAGING after LOAD_IND(0)");
|
|
mtc.stop;
|
|
}
|
|
[] T_retrans.timeout {
|
|
/* re-trnsmit the zero-space LOAD IND to avoid BSC 'auto credit' */
|
|
f_ipa_tx(ts_RSL_PAGING_LOAD_IND(0));
|
|
T_retrans.start;
|
|
repeat;
|
|
}
|
|
[] T.timeout {
|
|
setverdict(pass);
|
|
}
|
|
}
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Verify Paging Counter */
|
|
testcase TC_paging_counter() runs on test_CT {
|
|
var BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
timer T := 4.0;
|
|
var integer i;
|
|
var integer paging_attempted_bsc;
|
|
var integer paging_attempted_bts[NUM_BTS];
|
|
var integer paging_expired_bsc;
|
|
var integer paging_expired_bts[NUM_BTS];
|
|
cid_list := valueof(ts_BSSMAP_CIL_noCell);
|
|
|
|
f_init();
|
|
|
|
/* read counters before paging */
|
|
paging_attempted_bsc := f_ctrl_get_ratectr_abs(IPA_CTRL, "bsc", 0, "paging:attempted");
|
|
paging_expired_bsc := f_ctrl_get_ratectr_abs(IPA_CTRL, "bsc", 0, "paging:expired");
|
|
for (i := 0; i < NUM_BTS; i := i+1) {
|
|
paging_attempted_bts[i] := f_ctrl_get_ratectr_abs(IPA_CTRL, "bts", i, "paging:attempted");
|
|
paging_expired_bts[i] := f_ctrl_get_ratectr_abs(IPA_CTRL, "bts", i, "paging:expired");
|
|
}
|
|
|
|
f_pageing_helper('001230000000001'H, cid_list, c_BtsId_all);
|
|
|
|
/* expect the attempted pages on BSC and each BTSs to have incremented by one */
|
|
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bsc", 0, "paging:attempted", paging_attempted_bsc+1);
|
|
for (i := 0; i < NUM_BTS; i := i+1) {
|
|
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bts", i, "paging:attempted",
|
|
paging_attempted_bts[i]+1);
|
|
}
|
|
|
|
/* assume that 12s later the paging on all BTSs have expired and hence incremented by 1 */
|
|
f_sleep(12.0);
|
|
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bsc", 0, "paging:expired", paging_expired_bsc+1);
|
|
for (i := 0; i < NUM_BTS; i := i+1) {
|
|
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bts", i, "paging:expired",
|
|
paging_expired_bts[i]+1);
|
|
}
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
|
|
/* Verify paging stops after A-RESET */
|
|
testcase TC_paging_imsi_a_reset() runs on test_CT {
|
|
var BSSMAP_FIELD_CellIdentificationList cid_list;
|
|
timer T := 3.0;
|
|
cid_list := valueof(ts_BSSMAP_CIL_noCell);
|
|
f_pageing_helper('001010123456789'H, cid_list, c_BtsId_all);
|
|
|
|
/* Perform a BSSMAP Reset and wait for ACK */
|
|
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap[0].sccp_addr_peer, g_bssap[0].sccp_addr_own, ts_BSSMAP_Reset(0, g_osmux_enabled_cn)));
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap[0].sccp_addr_own, g_bssap[0].sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled_cn))) { }
|
|
[] BSSAP.receive { repeat; }
|
|
}
|
|
|
|
/* Wait to avoid a possible race condition if a paging message is
|
|
* received right before the reset ACK. */
|
|
f_sleep(0.2);
|
|
|
|
/* Clear the queue, it might still contain stuff like BCCH FILLING */
|
|
for (var integer i := 0; i < sizeof(IPA_RSL); i := i+1) {
|
|
IPA_RSL[i][0].clear;
|
|
}
|
|
|
|
/* Wait for 3 seconds if any more PAGING CMD are received on RSL */
|
|
T.start;
|
|
alt {
|
|
[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(?))) {
|
|
setverdict(fail, "Received PAGING after A-RESET");
|
|
mtc.stop;
|
|
}
|
|
[] IPA_RSL[1][0].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(?))) {
|
|
setverdict(fail, "Received PAGING after A-RESET");
|
|
mtc.stop;
|
|
}
|
|
[] IPA_RSL[2][0].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(?))) {
|
|
setverdict(fail, "Received PAGING after A-RESET");
|
|
mtc.stop;
|
|
}
|
|
[] T.timeout {
|
|
setverdict(pass);
|
|
}
|
|
}
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Verify how we handle unsolicited Paging Response. In case of an unsolicit
|
|
* paging response we can not know which MSC is in charge, so we will blindly
|
|
* pick the first configured MSC. This behavior is required in order to make
|
|
* MT-CSFB calls working because in those cases the BSC can not know that the
|
|
* MSC has already paged the subscriver via SGs. So any MT-CSFB call will look
|
|
* like an unsolicited Paging Response to the MSC.
|
|
*/
|
|
testcase TC_paging_resp_unsol() runs on test_CT {
|
|
|
|
f_init(1);
|
|
timer T := 5.0;
|
|
|
|
var BSSAP_N_CONNECT_ind rx_c_ind;
|
|
var DchanTuple dt;
|
|
var PDU_ML3_MS_NW l3 := valueof(ts_PAG_RESP(ts_MI_IMSI_LV('001010008880018'H)));
|
|
var octetstring rr_pag_resp := enc_PDU_ML3_MS_NW(l3);
|
|
|
|
/* Send CHAN RQD and wait for allocation; acknowledge it */
|
|
dt.rsl_chan_nr := f_chreq_act_ack();
|
|
dt.idx := {0, 0};
|
|
|
|
/* Send unsolicited Paging response (no matching Paging CMD stored in BSC) */
|
|
f_ipa_tx(ts_RSL_EST_IND(dt.rsl_chan_nr, valueof(ts_RslLinkID_DCCH(0)), rr_pag_resp));
|
|
|
|
|
|
/* Expevct a CR with a matching Paging response on the A-Interface */
|
|
T.start;
|
|
alt {
|
|
[] BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(rr_pag_resp))) -> value rx_c_ind {
|
|
setverdict(pass);
|
|
dt.sccp_conn_id := rx_c_ind.connectionId;
|
|
BSSAP.send(ts_BSSAP_CONNECT_res(dt.sccp_conn_id));
|
|
}
|
|
[] BSSAP.receive {
|
|
setverdict(fail, "Received unexpected message on A-Interface!");
|
|
}
|
|
[] T.timeout {
|
|
setverdict(fail, "Received nothing on A-Interface!");
|
|
}
|
|
}
|
|
|
|
f_perform_clear_test_ct(dt);
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* Verify BSC can schedule N paging requests under one minute if BTS buffer is good enough */
|
|
function f_TC_paging_Nreq(integer num_subscribers, boolean send_pag_load_ind) runs on test_CT {
|
|
var ASP_RSL_Unitdata rx_rsl_ud;
|
|
var Hexstrings imsis := {};
|
|
var Booleans rx_paging_done := {};
|
|
var integer rx_paging_num := 0;
|
|
var integer i;
|
|
timer T_rx := 60.0;
|
|
timer T_load_ind := 1.0;
|
|
|
|
for (i := 0; i < num_subscribers; i := i + 1) {
|
|
imsis := imsis & {f_gen_imsi(i)};
|
|
rx_paging_done := rx_paging_done & { false };
|
|
}
|
|
|
|
f_init(1, guard_timeout := 100.0);
|
|
|
|
/* Clear the queue, it might still contain stuff like BCCH FILLING */
|
|
IPA_RSL[0][0].clear;
|
|
if (send_pag_load_ind) {
|
|
/* Tell there's plenty of space at the BTS (UINT16_MAX): */
|
|
f_ipa_tx(ts_RSL_PAGING_LOAD_IND(65535));
|
|
}
|
|
|
|
for (i := 0; i < num_subscribers; i := i + 1) {
|
|
/* Page on LAC-CI of BTS0: */
|
|
BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap[0].sccp_addr_peer, g_bssap[0].sccp_addr_own,
|
|
ts_BSSMAP_Paging(imsis[i], valueof(ts_BSSMAP_CIL_LAC_CI({ts_BSSMAP_CI_LAC_CI(1, 0)})),
|
|
omit, omit)));
|
|
}
|
|
|
|
T_rx.start;
|
|
T_load_ind.start;
|
|
alt {
|
|
[] IPA_RSL[0][0].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(?), IPAC_PROTO_RSL_TRX0)) -> value rx_rsl_ud {
|
|
var hexstring imsi := rx_rsl_ud.rsl.ies[2].body.ms_identity.mobileIdentityV.oddEvenInd_identity.imsi.digits;
|
|
var hexstring imsi_suffix := substr(imsi, lengthof(imsi)-6, 6);
|
|
var charstring imsi_str := hex2str(imsi_suffix);
|
|
var integer imsi_idx := str2int(imsi_str);
|
|
if (rx_paging_done[imsi_idx] == false) {
|
|
rx_paging_done[imsi_idx] := true;
|
|
rx_paging_num := rx_paging_num + 1;
|
|
} else {
|
|
setverdict(fail, "Retrans of ", imsi_str, " happened before Rx initial trans for all reqs. rx_paging_num=", rx_paging_num);
|
|
mtc.stop;
|
|
}
|
|
if (rx_paging_num < num_subscribers) {
|
|
repeat;
|
|
}
|
|
}
|
|
[] IPA_RSL[0][0].receive { repeat; }
|
|
[] T_load_ind.timeout {
|
|
log("[CCH Load Ind timer] received paging requests so far: ", rx_paging_num);
|
|
if (send_pag_load_ind) {
|
|
f_ipa_tx(ts_RSL_PAGING_LOAD_IND(40));
|
|
}
|
|
T_load_ind.start;
|
|
repeat;
|
|
}
|
|
[] T_rx.timeout {
|
|
setverdict(fail, "Timeout expecting paging requests, so far ", rx_paging_num);
|
|
mtc.stop;
|
|
}
|
|
}
|
|
|
|
/* Drop OML connection to have all paging requests flushed: */
|
|
f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
/* Verify BSC can schedule 500 paging requests under one minute if BTS buffer is good enough */
|
|
testcase TC_paging_500req() runs on test_CT {
|
|
f_TC_paging_Nreq(500, true);
|
|
}
|
|
/* Same as TC_paging_500req, but without sending CCCH Load Indication, which
|
|
* means BTS is always under CCH Load Threshold, aka capable of sending tons of requests.
|
|
* Since No CCCH Load Ind, BSC uses a conservative estimation of BTS load, which
|
|
* for current config yields ~8req/sec, so 480req/min maximum. */
|
|
testcase TC_paging_450req_no_paging_load_ind() runs on test_CT {
|
|
f_TC_paging_Nreq(450, false);
|
|
}
|
|
|
|
/* Test RSL link drop causes counter increment */
|
|
testcase TC_rsl_drop_counter() runs on test_CT {
|
|
var integer rsl_fail;
|
|
|
|
f_init(1);
|
|
|
|
rsl_fail := f_ctrl_get_ratectr_abs(IPA_CTRL, "bts", 0, "rsl_fail");
|
|
|
|
f_ipa_rsl_stop(bts[0][0].rsl);
|
|
|
|
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bts", 0, "rsl_fail", rsl_fail+1);
|
|
|
|
f_shutdown_helper();
|
|
}
|
|
|
|
/* TODO: Test OML link drop causes counter increment */
|
|
|
|
/* The body of TC_rsl_unknown_unit_id() and TC_oml_unknown_unit_id() tests. */
|
|
function f_ipa_unknown_unit_id(integer mp_bsc_ipa_port) runs on test_CT return boolean {
|
|
var IPA_Client client;
|
|
timer T := 10.0;
|
|
|
|
client.id := "IPA-BTS0-TRX0-RSL";
|
|
client.vc_IPA := IPA_Emulation_CT.create(client.id & "-IPA") alive;
|
|
client.ccm_pars := c_IPA_default_ccm_pars;
|
|
client.ccm_pars.name := "Osmocom TTCN-3 BTS Simulator";
|
|
client.ccm_pars.unit_id := "99/0/0"; /* value which is unknown at BTS */
|
|
|
|
f_ipa_ctrl_start_client(mp_bsc_ip, mp_bsc_ctrl_port);
|
|
|
|
f_init_mgcp(0, "VirtMGW");
|
|
|
|
/* start RSL/OML connection (XXX re-uses RSL port/protocol definitions for OML) */
|
|
map(client.vc_IPA:IPA_PORT, system:IPA);
|
|
connect(client.vc_IPA:IPA_RSL_PORT, self:IPA_RSL[0][0]);
|
|
client.vc_IPA.start(IPA_Emulation.main_client(mp_bsc_ip, mp_bsc_ipa_port, "", 10000, client.ccm_pars));
|
|
|
|