module SGSN_Components {
/*
 * Osmocom PCU test suite in TTCN-3, components for BSSGP handlng
 * (C) 2018-2019 Harald Welte <laforge@gnumonks.org>
 * (C) 2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 * 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 BSSGP_Types all;
import from BSSGP_Emulation all;
import from NS_Types all;
import from NS_Emulation all;
import from GPRS_Context all;

modulepar {
	BssgpConfig mp_gb_cfg := {
		nsei := 1234,
		sgsn_role := true,
		bvc := {
			{
				bvci := 1234,
				cell_id := {
					ra_id := {
						lai := {
							mcc_mnc := '262F42'H, lac := 13135
						},
						rac := 0
					},
					cell_id := 20960
				},
				depth := BSSGP_DECODE_DEPTH_BSSGP,
				create_cb := refers(BSSGP_Emulation.DefaultCreateCallback)
			}
		}
	};

	NSConfiguration mp_nsconfig := {
		nsei := 2342,
		role_sgsn := true,
		handle_sns := true,
		nsvc := {
			{
				provider := {
					ip := {
						address_family := AF_INET,
						local_udp_port := 23000,
						local_ip := "127.0.0.1",
						remote_udp_port := 21000,
						remote_ip := "127.0.0.1"
					}
				},
				nsvci := 0
			},
			{
				provider := {
					ip := {
						address_family := AF_INET,
						local_udp_port := 23001,
						local_ip := "127.0.0.1",
						remote_udp_port := 21000,
						remote_ip := "127.0.0.1"
					}
				},
				nsvci := 0
			},
			{
				provider := {
					ip := {
						address_family := AF_INET,
						local_udp_port := 23002,
						local_ip := "127.0.0.1",
						remote_udp_port := 21000,
						remote_ip := "127.0.0.1"
					}
				},
				nsvci := 0
			}
		}
	};
}

/* FIXME: merge this into BSSGP_Client_CT ? */
type component bssgp_CT extends BSSGP_Client_CT {
	var NS_CT ns_component;
	var BSSGP_CT bssgp_component;
	port BSSGP_CT_PROC_PT PROC;
	port BSSGP_PT RIM;
	var boolean g_initialized := false;
}

/* FIXME: merge this into BSSGP_Client_CT ? */
function f_init_bssgp() runs on bssgp_CT {
	var MmContext mmctx := {
		imsi := '262420000000001'H,
		tlli := 'FFFFFFFF'O,
		n_u := 0
	};


	if (g_initialized == true) {
		return;
	}
	g_initialized := true;

	/* create a new NS component */
	ns_component := NS_CT.create alive;
	bssgp_component := BSSGP_CT.create alive;
	/* connect lower-end of BSSGP with BSSGP_CODEC_PORT (maps to NS_PT*/
	connect(bssgp_component:BSCP, ns_component:NS_SP);
	connect(self:PROC, bssgp_component:PROC);
	ns_component.start(NSStart(mp_nsconfig));
	bssgp_component.start(BssgpStart(mp_gb_cfg, testcasename()));

	for (var integer i := 0; i < lengthof(mp_gb_cfg.bvc); i := i+1) {
		var BSSGP_BVC_CT vc_BVC;
		/* obtain reference for BVC component (created by BssgpStart) */
		vc_BVC := f_bssgp_get_bvci_ct(mp_gb_cfg.bvc[i].bvci, PROC);
		/* connect our BSSGP port to the BSSGP Emulation */
		connect(self:BSSGP[i], vc_BVC:BSSGP_SP);
		connect(self:BSSGP_SIG[i], vc_BVC:BSSGP_SP_SIG);
		connect(self:BSSGP_PROC[i], vc_BVC:BSSGP_PROC);
		f_bssgp_client_register(mmctx.imsi, mmctx.tlli);
	}
	/* connect RIM related port */
	connect(self:RIM, bssgp_component:RIM);
	connect(self:BSSGP_GLOBAL[0], bssgp_component:GLOBAL);
}

/* Establish BSSGP connection to PCU */
function f_bssgp_establish() runs on BSSGP_Client_CT {
	timer T:= 10.0;

	T.start
	alt {
	[] BSSGP[0].receive(tr_BssgpStsInd(*, ?, BVC_S_UNBLOCKED)) { }
	[] BSSGP[0].receive { repeat; }
	[] T.timeout {
		setverdict(fail, "Timeout establishing BSSGP connection");
		mtc.stop;
		}
	}
	T.stop
	log("BSSGP successfully initialized");
}

}