module MSC_Tests_Iu {

/* Osmocom MSC test suite for Iu interface in TTCN-3
 * (C) 2019 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
 */

import from General_Types all;
import from Osmocom_Types all;
import from Misc_Helpers all;

import from BSC_ConnectionHandler all;
import from MSC_Tests all;

import from Osmocom_VTY_Functions all;

import from GSUP_Emulation all;
import from RAN_Emulation all;

import from RANAP_Templates all;

import from MobileL3_Types all;
import from MobileL3_CommonIE_Types all;
import from MobileL3_SMS_Types all;
import from L3_Templates all;
import from L3_Common all;

import from StatsD_Types all;
import from StatsD_CodecPort all;
import from StatsD_CodecPort_CtrlFunct all;
import from StatsD_Checker all;

testcase TC_iu_lu_imsi_reject() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_lu_imsi_reject), 1003, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_imsi_timeout_gsup() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_lu_imsi_timeout_gsup), 1004, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_imsi_auth3g_tmsi() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	f_vty_config(MSCVTY, "network", "authentication required");

	vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth3g_tmsi), 1005, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_imsi_timeout_tmsi_realloc() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	f_vty_config(MSCVTY, "network", "authentication required");

	vc_conn := f_start_handler(refers(f_tc_lu_imsi_timeout_tmsi_realloc), 1005, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_cmserv_imsi_unknown() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_cmserv_imsi_unknown), 1006, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_mo_call() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_lu_and_mo_call), 1007, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_mo_call_sccp_tiar_timeout() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;

	/* Set T(iar) in MSC 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_msc_sccp_timer_ias := 2;
	g_msc_sccp_timer_iar := 5;

	f_init(3);

	vc_conn := f_start_handler(refers(f_lu_and_mo_call_sccp_tiar_timeout), 1019, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_auth_sai_timeout() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	f_vty_config(MSCVTY, "network", "authentication required");

	vc_conn := f_start_handler(refers(f_tc_lu_auth_sai_timeout), 1008, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_auth_sai_err() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	f_vty_config(MSCVTY, "network", "authentication required");

	vc_conn := f_start_handler(refers(f_tc_lu_auth_sai_err), 1009, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

/* Test LU but RNC will send a Iu Release request in the middle */
private function f_tc_iu_lu_release_request(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
	f_init_handler(pars);

	var PDU_ML3_MS_NW l3_lu := f_build_lu_imsi(g_pars.imsi)
	var PDU_DTAP_MT dtap_mt;

	/* tell GSUP dispatcher to send this IMSI to us */
	f_create_gsup_expect(hex2str(g_pars.imsi));

	/* Send BSSAP_Conn_Req with COMPL L3 INFO to MSC */
	f_cl3_or_initial_ue(l3_lu);

	f_sleep(1.0);
	/* send release request in the middle of the LU */
	BSSAP.send(ts_RANAP_IuReleaseRequest(ts_RanapCause_om_intervention));
	alt {
	[] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_LU_Rej)) { repeat; }
	[] BSSAP.receive(tr_RANAP_IuReleaseCommand(?)) {}
	}
	BSSAP.send(ts_RANAP_IuReleaseComplete);
	alt {
	/* See https://osmocom.org/issues/2862 */
	[] BSSAP.receive(tr_RANAP_IuReleaseCommand(?)) {
			setverdict(fail, "Got a second Iu Release Command, only one expected");
			mtc.stop;
			repeat;
		}
	[] BSSAP.receive(tr_MSC_CONN_PRIM_DISC_IND) {}
	}
	setverdict(pass);
}
testcase TC_iu_lu_release_request() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_iu_lu_release_request), 1010, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_disconnect() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_lu_disconnect), 1011, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_by_imei() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_lu_by_imei), 1012, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_imsi_detach_by_imsi() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_imsi_detach_by_imsi), 1014, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_imsi_detach_by_tmsi() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_imsi_detach_by_tmsi), 1015, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_imsi_detach_by_imei() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_imsi_detach_by_imei), 1016, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_emerg_call_imei_reject() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_emerg_call_imei_reject), 1017, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_emerg_call_imsi() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_emerg_call_imsi), 1018, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_establish_and_nothing() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_establish_and_nothing), 1027, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_mo_setup_and_nothing() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_mo_setup_and_nothing), 1028, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_mo_crcx_ran_timeout() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_mo_crcx_ran_timeout), 1029, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_mo_crcx_ran_reject() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_mo_crcx_ran_reject), 1030, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_mt_crcx_ran_reject() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_mt_crcx_ran_reject), 1031, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_mt_t310() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_mt_t310), 1032, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_gsup_cancel() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_gsup_cancel), 1033, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_mo_release_timeout() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_mo_release_timeout), 1040, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_mt_call() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_lu_and_mt_call), 1142, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_mt_call_already_paging() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_lu_and_mt_call_already_paging), 1142, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_mo_sms() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_lu_and_mo_sms), 1042, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_mt_sms() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(1043, ran_idx := 2, ran_is_geran := false);
	vc_conn := f_start_handler_with_pars(refers(f_tc_lu_and_mt_sms), pars);
	vc_conn.done;
}

testcase TC_iu_lu_and_mt_sms_already_paging() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(101045, ran_idx := 2, ran_is_geran := false);
	vc_conn := f_start_handler_with_pars(refers(f_tc_lu_and_mt_sms_already_paging), pars);
	vc_conn.done;
}

testcase TC_iu_lu_and_mt_sms_paging_and_nothing() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(101843, ran_idx := 2, ran_is_geran := false);
	vc_conn := f_start_handler_with_pars(refers(f_tc_lu_and_mt_sms_paging_and_nothing), pars);
	vc_conn.done;
}

testcase TC_iu_lu_and_mt_sms_paging_repeated() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(101844, ran_idx := 2, ran_is_geran := false);
	vc_conn := f_start_handler_with_pars(refers(f_tc_lu_and_mt_sms_paging_repeated), pars);
	vc_conn.done;
}

testcase TC_iu_smpp_mo_sms() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	f_vty_config2(MSCVTY, { "smpp", "esme msc_tester"}, "default-route");
	vc_conn := f_start_handler(refers(f_tc_smpp_mo_sms), 1044, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
	f_vty_config2(MSCVTY, { "smpp", "esme msc_tester"}, "no default-route");
}

testcase TC_iu_gsup_mo_sms() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	f_vty_config(MSCVTY, "msc", "sms-over-gsup");
	vc_conn := f_start_handler(refers(f_tc_gsup_mo_sms), 1088, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}

testcase TC_iu_gsup_mo_smma() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	f_vty_config(MSCVTY, "msc", "sms-over-gsup");
	vc_conn := f_start_handler(refers(f_tc_gsup_mo_smma), 1089, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}

testcase TC_iu_gsup_mt_sms_ack() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(1090, ran_idx := 2, ran_is_geran := false);
	f_vty_config(MSCVTY, "msc", "sms-over-gsup");
	vc_conn := f_start_handler_with_pars(refers(f_tc_gsup_mt_sms_ack), pars);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}

testcase TC_iu_gsup_mt_sms_err() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(1091, ran_idx := 2, ran_is_geran := false);
	f_vty_config(MSCVTY, "msc", "sms-over-gsup");
	vc_conn := f_start_handler_with_pars(refers(f_tc_gsup_mt_sms_err), pars);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}

testcase TC_iu_gsup_mt_sms_rp_mr() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(1092, ran_idx := 2, ran_is_geran := false);
	f_vty_config(MSCVTY, "msc", "sms-over-gsup");
	vc_conn := f_start_handler_with_pars(refers(f_tc_gsup_mt_sms_rp_mr), pars);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}

testcase TC_iu_gsup_mo_mt_sms_rp_mr() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(1093, ran_idx := 2, ran_is_geran := false);
	f_vty_config(MSCVTY, "msc", "sms-over-gsup");
	vc_conn := f_start_handler_with_pars(refers(f_tc_gsup_mo_mt_sms_rp_mr), pars);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}

testcase TC_iu_gsup_mt_multi_part_sms() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(1094, ran_idx := 2, ran_is_geran := false);
	f_vty_config(MSCVTY, "msc", "sms-over-gsup");
	vc_conn := f_start_handler_with_pars(refers(f_tc_gsup_mt_multi_part_sms), pars);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}

testcase TC_iu_gsup_mt_sms_lu_delay() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(1095, ran_idx := 2, ran_is_geran := false);
	f_vty_config(MSCVTY, "msc", "sms-over-gsup");
	f_vty_config(MSCVTY, "msc", "timer utran X36 2500"); /* 2.5s */
	vc_conn := f_start_handler_with_pars(refers(f_TC_gsup_mt_sms_lu_delay), pars);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "timer utran X36 0");
	f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}

testcase TC_iu_gsup_mt_sms_paging_timeout() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(1096, ran_idx := 2, ran_is_geran := false);
	f_vty_config(MSCVTY, "msc", "sms-over-gsup");
	vc_conn := f_start_handler_with_pars(refers(f_TC_gsup_mt_sms_paging_timeout), pars);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}

testcase TC_iu_gsup_mt_sms_conn_timeout() runs on MTC_CT {
	var BSC_ConnHdlrPars pars;
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	pars := f_init_pars(1097, ran_idx := 2, ran_is_geran := false);
	f_vty_config(MSCVTY, "msc", "sms-over-gsup");
	vc_conn := f_start_handler_with_pars(refers(f_TC_gsup_mt_sms_conn_timeout), pars);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "no sms-over-gsup");
}

testcase TC_iu_lu_and_mo_ussd_single_request() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_lu_and_mo_ussd_single_request), 1046, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_mt_ussd_notification() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_lu_and_mt_ussd_notification), 1047, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_mo_ussd_during_mt_call() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_lu_and_mo_ussd_during_mt_call), 1048, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_mo_cc_iu_release() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);

	vc_conn := f_start_handler(refers(f_tc_mo_cc_bssmap_clear), 1043, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_mt_ussd_during_mt_call() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_lu_and_mt_ussd_during_mt_call), 1049, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_mo_ussd_mo_release() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_lu_and_mo_ussd_mo_release), 1050, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_ss_session_timeout() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	f_vty_config(MSCVTY, "msc", "ncss guard-timeout 3");
	vc_conn := f_start_handler(refers(f_tc_lu_and_ss_session_timeout), 1051, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
	f_vty_config(MSCVTY, "msc", "ncss guard-timeout 0");
}

testcase TC_iu_mt_ussd_for_unknown_subscr() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_mt_ussd_for_unknown_subscr), 1052,
				   ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_mo_ussd_for_unknown_trans() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_mo_ussd_for_unknown_trans), 1053,
				   ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_proc_ss_for_unknown_session() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_proc_ss_for_unknown_session), 1055,
				   ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_proc_ss_paging_fail() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_proc_ss_paging_fail), 1056,
				   ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_proc_ss_abort() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_proc_ss_abort), 1057,
				   ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

/* Verify multiple concurrent MO SS/USSD transactions
 * (one subscriber - one transaction) */
testcase TC_iu_multi_lu_and_mo_ussd() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn[16];
	var BSC_ConnHdlrPars pars;
	var integer i;

	f_init(3);

	for (i := 0; i < sizeof(vc_conn); i := i + 1) {
		pars := f_init_pars(1100 + i, ran_idx := 2, ran_is_geran := false);
		vc_conn[i] := f_start_handler_with_pars(refers(f_tc_lu_and_mo_ussd_single_request), pars);
	}

	for (i := 0; i < sizeof(vc_conn); i := i + 1) {
		vc_conn[i].done;
	}
}

/* Verify multiple concurrent MT SS/USSD transactions
 * (one subscriber - one transaction) */
testcase TC_iu_multi_lu_and_mt_ussd() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn[16];
	var BSC_ConnHdlrPars pars;
	var integer i;

	f_init(3);

	for (i := 0; i < sizeof(vc_conn); i := i + 1) {
		pars := f_init_pars(1116 + i, ran_idx := 2, ran_is_geran := false,
				    gsup_sid := '200001'O & int2oct(i, 1));
		vc_conn[i] := f_start_handler_with_pars(refers(f_tc_lu_and_mt_ussd_notification), pars);
	}

	for (i := 0; i < sizeof(vc_conn); i := i + 1) {
		vc_conn[i].done;
	}
}

testcase TC_iu_lu_with_invalid_mcc_mnc() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_lu_with_invalid_mcc_mnc), 1054, ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_iu_lu_and_expire_while_paging() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	f_init(3);
	vc_conn := f_start_handler(refers(f_tc_lu_and_expire_while_paging), 1055,
				   ran_idx := 2, ran_is_geran := false);
	vc_conn.done;
}

testcase TC_stat_rnc_sctp_disconnected() runs on MTC_CT {
	var BSC_ConnHdlr vc_conn;
	var BSC_ConnHdlrPars pars;
	var charstring msc_stats_prefix := f_msc_stats_prefix();

	var StatsDExpects expect_connected := {
		{name := msc_stats_prefix & "ran_peers.total", mtype := "g", min := 3, max := 3},
		{name := msc_stats_prefix & "ran_peers.active", mtype := "g", min := 3, max := 3}
	};
	var StatsDExpects expect_disconnected := {
		{name := msc_stats_prefix & "ran_peers.total", mtype := "g", min := 3, max := 3},
		{name := msc_stats_prefix & "ran_peers.active", mtype := "g", min := 0, max := 0}
	};

	g_statd_timeout := 15.0;
	f_init(3);
	f_init_vty_stp();

	connect(self:STATSD_PROC, vc_STATSD:STATSD_PROC);
	f_statsd_reset();
	f_statsd_expect(expect_connected, wait_converge := true);
	disconnect(self:STATSD_PROC, vc_STATSD:STATSD_PROC);

	pars := f_init_pars(1, ran_idx := 2, ran_is_geran := false);
	vc_conn := f_start_handler_with_pars(refers(f_tc_lu_and_mt_sms), pars);
	vc_conn.done;

	f_logp(MSCVTY, "Shutting down MSC ASP in STP");
	f_vty_stp_msc_asp_cmd("shutdown");

	/* Wait for AS PENDING->INACTIVE transition (T(r) timeout after 2000msec): */
	connect(self:STATSD_PROC, vc_STATSD:STATSD_PROC);
	f_statsd_expect(expect_disconnected, wait_converge := true);
	disconnect(self:STATSD_PROC, vc_STATSD:STATSD_PROC);

	f_logp(MSCVTY, "Restarting MSC ASP in STP");
	f_vty_stp_msc_asp_cmd("no shutdown");

	connect(self:STATSD_PROC, vc_STATSD:STATSD_PROC);
	f_statsd_expect(expect_connected, wait_converge := true);
	disconnect(self:STATSD_PROC, vc_STATSD:STATSD_PROC);

	pars := f_init_pars(2, ran_idx := 2, ran_is_geran := false);
	vc_conn := f_start_handler_with_pars(refers(f_tc_lu_and_mt_sms), pars);
	vc_conn.done;
	setverdict(pass);
}

control {
	execute( TC_iu_lu_imsi_reject() );
	execute( TC_iu_lu_imsi_timeout_gsup() );
	execute( TC_iu_lu_imsi_auth3g_tmsi() );
	execute( TC_iu_lu_imsi_timeout_tmsi_realloc() );
	execute( TC_iu_cmserv_imsi_unknown() );
	execute( TC_iu_lu_and_mo_call() );
	execute( TC_iu_lu_and_mo_call_sccp_tiar_timeout() );
	execute( TC_iu_lu_auth_sai_timeout() );
	execute( TC_iu_lu_auth_sai_err() );
	execute( TC_iu_lu_release_request() );
	execute( TC_iu_lu_disconnect() );
	execute( TC_iu_lu_by_imei() );
	execute( TC_iu_imsi_detach_by_imsi() );
	execute( TC_iu_imsi_detach_by_tmsi() );
	execute( TC_iu_imsi_detach_by_imei() );
	execute( TC_iu_emerg_call_imei_reject() );
	execute( TC_iu_emerg_call_imsi() );
	execute( TC_iu_establish_and_nothing() );
	execute( TC_iu_mo_setup_and_nothing() );
	execute( TC_iu_mo_crcx_ran_timeout() );
	execute( TC_iu_mo_crcx_ran_reject() );
	execute( TC_iu_mt_crcx_ran_reject() );
	execute( TC_iu_gsup_cancel() );
	execute( TC_iu_mo_release_timeout() );
	execute( TC_reset_two_1iu() );

	execute( TC_iu_lu_and_mt_call() );
	execute( TC_iu_lu_and_mt_call_already_paging() );

	execute( TC_iu_lu_and_mo_sms() );
	execute( TC_iu_lu_and_mt_sms() );
	execute( TC_iu_lu_and_mt_sms_already_paging() );
	execute( TC_iu_lu_and_mt_sms_paging_and_nothing() );
	execute( TC_iu_lu_and_mt_sms_paging_repeated() );
	execute( TC_iu_smpp_mo_sms() );

	execute( TC_iu_gsup_mo_sms() );
	execute( TC_iu_gsup_mo_smma() );
	execute( TC_iu_gsup_mt_sms_ack() );
	execute( TC_iu_gsup_mt_sms_err() );
	execute( TC_iu_gsup_mt_sms_rp_mr() );
	execute( TC_iu_gsup_mo_mt_sms_rp_mr() );
	execute( TC_iu_gsup_mt_multi_part_sms() );
	execute( TC_iu_gsup_mt_sms_lu_delay() );
	execute( TC_iu_gsup_mt_sms_paging_timeout() );
	execute( TC_iu_gsup_mt_sms_conn_timeout() );

	execute( TC_iu_lu_and_mo_ussd_single_request() );
	execute( TC_iu_lu_and_mt_ussd_notification() );
	execute( TC_iu_lu_and_mo_ussd_during_mt_call() );
	execute( TC_iu_lu_and_mt_ussd_during_mt_call() );
	execute( TC_iu_lu_and_mo_ussd_mo_release() );
	execute( TC_iu_lu_and_ss_session_timeout() );

	execute( TC_iu_mt_ussd_for_unknown_subscr() );
	execute( TC_iu_mo_ussd_for_unknown_trans() );
	execute( TC_iu_proc_ss_for_unknown_session() );
	execute( TC_iu_proc_ss_paging_fail() );
	execute( TC_iu_proc_ss_abort() );

	execute( TC_iu_multi_lu_and_mo_ussd() );
	execute( TC_iu_multi_lu_and_mt_ussd() );

	execute( TC_iu_lu_with_invalid_mcc_mnc() );
	execute( TC_iu_lu_and_expire_while_paging() );

	/* TODO: Iu + SGsAP related tests, e.g. paging on IuCS */

	/* Run this last: at the time of writing this test crashes the MSC */
	execute( TC_mo_cc_iu_release() );

	/* This "nightly" if can be removed once libosmo-sigtran (osmo-stp) > 2.1.0 is released.
	 * Currently released osmo-stp 2.1.0 ends up in in broken AS-ACTIVE+ASP-DOWN state when
	 * restarting the ASP after exiting the related asp node through VTY: */
	if (Misc_Helpers.f_osmo_repo_is("nightly")) {
		execute( TC_stat_rnc_sctp_disconnected() );
	}
}


}
