ts_BSSMAP_HandoReq: Hand in raw list as argument, not IE type

Also, add new ts_BSSMAP_Paging() template.
diff --git a/bsc/BSC_Tests.ttcn b/bsc/BSC_Tests.ttcn
new file mode 100644
index 0000000..4629e6e
--- /dev/null
+++ b/bsc/BSC_Tests.ttcn
@@ -0,0 +1,110 @@
+module BSC_Tests {
+
+import from Osmocom_Types all;
+
+import from IPL4asp_Types all;
+
+import from IPA_Emulation all;
+
+import from MTP3asp_Types all;
+
+import from SCCP_Types all;
+import from SCCPasp_Types all;
+import from SCCP_Emulation all;
+
+import from MSC_Simulation all;
+
+const integer NUM_MSC := 1;
+
+type record MscState {
+	MSC_CT MSC,
+	MSC_SCCP_MTP3_parameters sccp_pars,
+	SCCP_PAR_Address sccp_addr_own
+}
+
+type component test_CT {
+	var MscState msc[NUM_MSC];
+
+	var boolean g_initialized := false;
+	var octetstring g_sio := '83'O;
+}
+
+modulepar {
+	PortNumber mp_msc_port := 5000;
+	charstring mp_msc_ip := "127.0.0.1";
+
+	charstring mp_sccp_service_type := "mtp3_itu";
+
+	integer mp_bsc_pc := 196;
+	integer mp_bsc_ssn := 254;
+
+	integer mp_msc_pc := 185;	/* 0.23.1 */
+	integer mp_msc_ssn := 254;
+}
+
+/* construct a SCCP_PAR_Address with just PC + SSN and no GT */
+template (value) SCCP_PAR_Address ts_SccpAddr_PC_SSN(integer pc, integer ssn) := {
+	addressIndicator := {
+		pointCodeIndic := '1'B,
+		ssnIndicator := '1'B,
+		globalTitleIndic := '0000'B,
+		routingIndicator := '1'B
+	},
+	signPointCode := SCCP_SPC_int2bit(pc, mp_sccp_service_type, '83'O),
+	//signPointCode := SCCP_SPC_int2bit(pc, mp_sccp_service_type, g_sio),
+	subsystemNumber := ssn,
+	globalTitle := omit
+}
+
+template MTP3_Field_sio ts_sio(octetstring sio_in) := {
+	ni := substr(oct2bit(sio_in),0,2),
+	prio := substr(oct2bit(sio_in),2,2),
+	si := substr(oct2bit(sio_in),4,4)
+}
+
+template MSC_SCCP_MTP3_parameters ts_SCCP_Pars(octetstring sio, integer opc, integer dpc,
+						integer local_ssn) := {
+	sio := ts_sio(sio),
+	opc := opc,
+	dpc := dpc,
+	sls := 0,
+	sccp_serviceType := mp_sccp_service_type,
+	ssn := local_ssn
+};
+
+function f_init_MscState(inout MscState msc_st, integer opc, integer dpc, integer local_ssn, integer remote_ssn)
+runs on test_CT {
+	msc_st.sccp_pars := valueof(ts_SCCP_Pars(g_sio, opc, dpc, local_ssn));
+	msc_st.sccp_addr_own := valueof(ts_SccpAddr_PC_SSN(opc, local_ssn));
+}
+
+function f_init() runs on test_CT {
+	var integer i;
+	var charstring id;
+
+	for (i := 0; i < NUM_MSC; i := i+1) {
+		f_init_MscState(msc[i], mp_msc_pc +i, mp_bsc_pc, mp_msc_ssn, mp_bsc_ssn);
+		msc[i].MSC := MSC_CT.create;
+		id := "MSC" & int2str(i);
+		msc[i].MSC.start(MSC_Simulation.main(mp_msc_ip, mp_msc_port + i, msc[i].sccp_pars, msc[i].sccp_addr_own, id));
+	}
+
+}
+
+testcase TC_recv_dump() runs on test_CT {
+	var integer i;
+	timer T := 30.0;
+
+	f_init();
+
+	alt {
+		[] msc[0].MSC.done { }
+		[] T.timeout { setverdict(fail); }
+	}
+}
+
+control {
+	execute( TC_recv_dump() );
+}
+
+}
diff --git a/bsc/MSC_ConnectionHandler.ttcn b/bsc/MSC_ConnectionHandler.ttcn
new file mode 100644
index 0000000..6a9a57f
--- /dev/null
+++ b/bsc/MSC_ConnectionHandler.ttcn
@@ -0,0 +1,154 @@
+module MSC_ConnectionHandler {
+
+import from General_Types all;
+import from Osmocom_Types all;
+import from SCCPasp_Types all;
+import from BSSAP_Types all;
+import from BSSMAP_Emulation all;
+import from BSSMAP_Templates all;
+
+import from MGCP_Types all;
+import from MGCP_Templates all;
+import from SDP_Types all;
+
+/* this component represents a single subscriber connection at the MSC.
+ * There is a 1:1 mapping between SCCP connections and BSSAP_ConnHdlr components.
+ * We inherit all component variables, ports, functions, ... from BSSAP_ConnHdlr */
+type component MSC_ConnHdlr extends BSSAP_ConnHdlr {
+	/* SCCP Connecction Identifier for the underlying SCCP connection */
+	var integer g_sccp_conn_id;
+
+	var MSC_State g_state := MSC_STATE_NONE;
+	var MgcpEndpoint g_ep_name;
+	var MgcpCallId g_call_id;
+	var MgcpConnectionId g_mgcp_conn_id;
+}
+
+/* Callback function from general BSSMAP_Emulation whenever a new incoming
+ * SCCP connection arrivces. Must create + start a new component */
+private function CreateCallback(ASP_SCCP_N_CONNECT_ind conn_ind, charstring id)
+runs on BSSMAP_Emulation_CT return BSSAP_ConnHdlr {
+	var MSC_ConnHdlr vc_conn;
+	/* Create a new BSSAP_ConnHdlr component */
+	vc_conn := MSC_ConnHdlr.create(g_bssmap_id & "-Conn-" & int2str(conn_ind.connectionId));
+	/* connect it to the port */
+	connect(vc_conn:BSSAP, self:CLIENT);
+	/* start it */
+	vc_conn.start(MSC_ConnectionHandler.main(conn_ind.connectionId, g_next_e1_ts));
+	/* increment next E1 timeslot */
+	g_next_e1_ts := g_next_e1_ts + 1;
+	return vc_conn;
+}
+
+/* Callback function from general BSSMAP_Emulation whenever a connectionless
+ * BSSMAP message arrives.  Can retunr a PDU_BSSAP that should be sent in return */
+private function UnitdataCallback(PDU_BSSAP bssap)
+runs on BSSMAP_Emulation_CT return template PDU_BSSAP {
+	var template PDU_BSSAP resp := omit;
+
+	if (match(bssap, tr_BSSMAP_Reset)) {
+		resp := ts_BSSMAP_ResetAck;
+	}
+
+	return resp;
+}
+
+const BssmapOps MSC_BssmapOps := {
+	create_cb := refers(CreateCallback),
+	unitdata_cb := refers(UnitdataCallback)
+}
+
+type enumerated MSC_State {
+	MSC_STATE_NONE,
+	MSC_STATE_WAIT_ASS_COMPL,
+	MSC_STATE_WAIT_CRCX_ACK,
+	MSC_STATE_WAIT_MDCX_ACK,
+	MSC_STATE_WAIT_CLEAR_COMPL,
+	MSC_STATE_WAIT_DLCX_ACK
+}
+
+/* main function processing various incoming events */
+function main(integer connection_id, integer e1_timeslot) runs on MSC_ConnHdlr {
+	var MgcpResponse mgcp_rsp;
+	timer T := 5.0;
+
+	g_sccp_conn_id := connection_id;
+	g_call_id := f_mgcp_alloc_call_id();
+	g_ep_name := hex2str(int2hex(e1_timeslot, 1)) & "@mgw";
+
+	/* we just accepted an incoming SCCP connection, start guard timer */
+	T.start;
+
+	while (true) {
+		var PDU_BSSAP bssap;
+		alt {
+		/* new SCCP-level connection indication from BSC */
+		[g_state == MSC_STATE_NONE] BSSAP.receive(tr_BSSMAP_ComplL3) -> value bssap {
+			/* respond with ASSIGNMENT CMD  */
+			g_state := MSC_STATE_WAIT_ASS_COMPL;
+			BSSAP.send(ts_BSSMAP_AssignmentReq(0, e1_timeslot));
+			}
+		[g_state == MSC_STATE_WAIT_ASS_COMPL] BSSAP.receive(tr_BSSMAP_AssignmentComplete) {
+			/* FIXME: Send MGCP CRCX */
+			g_state := MSC_STATE_WAIT_CRCX_ACK;
+			var MgcpTransId trans_id := f_mgcp_alloc_tid();
+			//template SDP_Message sdp := omit;
+			BSSAP.send(ts_CRCX(trans_id, g_ep_name, "recvonly", g_call_id)); //, sdp));
+			}
+		/*
+		[] BSSAP.receive(tr_BSSMAP_AssignmentFail) {
+		}
+		*/
+
+		/* receive CRCX ACK: transmit MDCX */
+		[g_state == MSC_STATE_WAIT_CRCX_ACK] BSSAP.receive(tr_CRCX_ACK) -> value mgcp_rsp {
+			/* extract connection ID */
+			g_mgcp_conn_id := f_MgcpResp_extract_conn_id(mgcp_rsp);
+			g_state := MSC_STATE_WAIT_MDCX_ACK;
+			var MgcpTransId trans_id := f_mgcp_alloc_tid();
+			BSSAP.send(ts_MDCX(trans_id, g_ep_name, "sendrecv", g_call_id, g_mgcp_conn_id));
+			}
+
+		/* receive MDCX ACK: wait + transmit CLEAR COMMAND */
+		[g_state == MSC_STATE_WAIT_MDCX_ACK] BSSAP.receive(tr_CRCX_ACK) -> value mgcp_rsp {
+			g_state := MSC_STATE_WAIT_CLEAR_COMPL
+			BSSAP.send(ts_BSSMAP_ClearCommand(9)); /* Cause: call control */
+			}
+
+		/* CLEAR COMPLETE from BSS (response to CLEAR COMMAND) */
+		[g_state == MSC_STATE_WAIT_CLEAR_COMPL] BSSAP.receive(tr_BSSMAP_ClearComplete) {
+			/* send DLCX */
+			g_state := MSC_STATE_WAIT_DLCX_ACK;
+			var MgcpTransId trans_id := f_mgcp_alloc_tid();
+			BSSAP.send(ts_DLCX(trans_id, g_ep_name, g_call_id));
+			}
+
+		[g_state == MSC_STATE_WAIT_DLCX_ACK] BSSAP.receive(tr_DLCX_ACK) {
+			BSSAP.send(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
+			setverdict(pass);
+			self.stop;
+			}
+
+		/* TODO: CLEAR REQUEST from BSS */
+
+		[] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
+			setverdict(fail);
+			self.stop;
+			}
+
+		[] BSSAP.receive(PDU_BSSAP:?) -> value bssap {
+			log("Received unhandled SCCP-CO: ", bssap);
+			}
+
+		/* Guard timer has expired, close connection */
+		[] T.timeout {
+			BSSAP.send(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
+			setverdict(inconc);
+			self.stop;
+			}
+
+		}
+	}
+}
+
+}
diff --git a/bsc/MSC_Simulation.ttcn b/bsc/MSC_Simulation.ttcn
new file mode 100644
index 0000000..f9fb0d4
--- /dev/null
+++ b/bsc/MSC_Simulation.ttcn
@@ -0,0 +1,78 @@
+module MSC_Simulation {
+
+import from IPL4asp_Types all;
+
+import from IPA_Emulation all;
+
+import from SCCP_Types all;
+import from SCCPasp_Types all;
+import from SCCP_Emulation all;
+
+/* 
+import from MobileL3_Types all;
+import from MobileL3_CommonIE_Types all;
+import from L3_Templates all;
+
+import from BSSAP_Types all;
+import from BSSMAP_Templates all;
+*/
+import from BSSMAP_Emulation all;
+
+import from MGCP_Adapter all;
+
+import from MSC_ConnectionHandler all;
+
+type component MSC_CT {
+	/* component references */
+	var IPA_Emulation_CT vc_IPA;
+	var SCCP_CT vc_SCCP;
+	var BSSMAP_Emulation_CT vc_BSSMAP;
+	var MGCP_Adapter_CT vc_MGCP_UDP;
+	/* test port to SCCP emulation */
+	port SCCPasp_PT SCCP;
+}
+
+modulepar {
+	boolean mp_mgcp_uses_udp := false;
+}
+
+function main(charstring local_ip, PortNumber local_port,
+	      MSC_SCCP_MTP3_parameters sccp_pars,
+	      SCCP_PAR_Address sccp_addr_own, charstring id) runs on MSC_CT
+{
+	/* create components */
+	vc_IPA := IPA_Emulation_CT.create(id & "-IPA");
+	vc_SCCP := SCCP_CT.create(id & "-SCCP");
+	vc_BSSMAP := BSSMAP_Emulation_CT.create(id & "-BSSMAP");
+
+	map(vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
+
+	/* connect MTP3 service provider (IPA) to lower side of SCCP */
+	connect(vc_IPA:MTP3_SP_PORT, vc_SCCP:MTP3_SCCP_PORT);
+
+	/* connect BSSNAP dispatcher to upper side of SCCP */
+	connect(vc_BSSMAP:SCCP, vc_SCCP:SCCP_SP_PORT);
+
+	if (mp_mgcp_uses_udp == false) {
+		/* connect BSSMAP dispatcher to IPA_Emulation MGCP */
+		connect(vc_BSSMAP:MGCP, vc_IPA:IPA_MGCP_PORT);
+	} else {
+		vc_MGCP_UDP := MGCP_Adapter_CT.create(id & "-MGCP_UDP");
+		connect(vc_BSSMAP:MGCP, vc_MGCP_UDP:MGCP);
+		vc_MGCP_UDP.start(MGCP_Adapter.main());
+	}
+
+	vc_IPA.start(IPA_Emulation.main_server(local_ip, local_port));
+	vc_SCCP.start(SCCPStart(sccp_pars));
+	vc_BSSMAP.start(BSSMAP_Emulation.main(MSC_BssmapOps, id & "-BSSMAP"));
+
+	/* wait until termination of respective components */
+	vc_IPA.done;
+	vc_BSSMAP.done;
+	vc_SCCP.done;
+	if (mp_mgcp_uses_udp) {
+		vc_MGCP_UDP.done;
+	}
+}
+
+}
diff --git a/bsc/gen_links.sh b/bsc/gen_links.sh
new file mode 100755
index 0000000..7be9a2d
--- /dev/null
+++ b/bsc/gen_links.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+BASEDIR=~/projects/git
+
+gen_links() {
+	DIR=$1
+	FILES=$*
+	for f in $FILES; do
+		echo "Linking $f"
+		ln -sf $DIR/$f $f
+	done
+}
+
+#DIR=$BASEDIR/titan.TestPorts.UNIX_DOMAIN_SOCKETasp/src
+#FILES="UD_PT.cc  UD_PT.hh  UD_PortType.ttcn  UD_Types.ttcn"
+#gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src
+FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCConversion.hh TCCInterface.cc TCCInterface_ip.h SDP_EncDec.cc"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src
+FILES="Socket_API_Definitions.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.IPL4asp/src
+FILES="IPL4asp_Functions.ttcn  IPL4asp_PT.cc  IPL4asp_PT.hh IPL4asp_PortType.ttcn  IPL4asp_Types.ttcn  IPL4asp_discovery.cc IPL4asp_protocol_L234.hh"
+gen_links $DIR $FILES
+
+# required by SCCP Emulation
+DIR=../MTP3asp_CNL113337/src
+FILES="MTP3asp_PortType.ttcn  MTP3asp_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=../SCCP_CNL113341/src
+FILES="SCCP_Emulation.ttcn  SCCP_EncDec.cc  SCCP_Mapping.ttcnpp  SCCP_Types.ttcn  SCCPasp_Types.ttcn"
+gen_links $DIR $FILES
+ln -sf SCCP_Mapping.ttcnpp SCCP_Mapping.ttcn
+
+DIR=$BASEDIR/titan.ProtocolModules.BSSMAP_v11.2.0/src
+FILES="BSSAP_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolModules.MobileL3_v13.4.0/src
+FILES="MobileL3_CC_Types.ttcn MobileL3_CommonIE_Types.ttcn MobileL3_GMM_SM_Types.ttcn MobileL3_MM_Types.ttcn MobileL3_RRM_Types.ttcn MobileL3_SMS_Types.ttcn MobileL3_SS_Types.ttcn MobileL3_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolModules.SDP/src
+FILES="SDP_EncDec.cc SDP_Types.ttcn SDP_parse_.tab.c SDP_parse_.tab.h SDP_parse_parser.h SDP_parser.l
+SDP_parser.y lex.SDP_parse_.c"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolModules.RTP/src
+FILES="RTP_EncDec.cc RTP_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=../library
+FILES="General_Types.ttcn Osmocom_Types.ttcn IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcn L3_Templates.ttcn BSSMAP_Templates.ttcn BSSMAP_Emulation.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc"
+gen_links $DIR $FILES
diff --git a/bsc/regen_makefile.sh b/bsc/regen_makefile.sh
new file mode 100755
index 0000000..d94af3d
--- /dev/null
+++ b/bsc/regen_makefile.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+MAIN=BSC_Tests.ttcn
+
+FILES="*.ttcn SCCP_EncDec.cc IPA_CodecPort_CtrlFunctDef.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc RTP_EncDec.cc SDP_EncDec.cc *.c MGCP_CodecPort_CtrlFunctDef.cc"
+
+ttcn3_makefilegen -l -f $MAIN $FILES
+sed -i -e 's/# TTCN3_DIR = /TTCN3_DIR = \/usr/' Makefile
+sed -i -e 's/LDFLAGS = /LDFLAGS = -L \/usr\/lib\/titan /' Makefile
+#sed -i -e 's/TTCN3_LIB = ttcn3-parallel/TTCN3_LIB = ttcn3/' Makefile
+sed -i -e 's/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include/CPPFLAGS = -D$(PLATFORM) -I$(TTCN3_DIR)\/include -I\/usr\/include\/titan/' Makefile
diff --git a/library/BSSMAP_Templates.ttcn b/library/BSSMAP_Templates.ttcn
index bcf9738..12aabc6 100644
--- a/library/BSSMAP_Templates.ttcn
+++ b/library/BSSMAP_Templates.ttcn
@@ -184,8 +184,15 @@
 	}
 }
 
+template BSSMAP_IE_CellIdentifierList ts_BSSMAP_IE_CidList(BSSMAP_FIELD_CellIdentificationList cid_list) := {
+	elementIdentifier := '1A'O,
+	lengthIndicator := 0, /* overwritten */
+	cellIdentifierDiscriminator := '0000'B, /* overwritten */
+	spare1_4 := '0000'B,
+	cellIdentificationList := cid_list
+}
 
-template PDU_BSSAP ts_BSSMAP_HandoReq(BssmapCause cause, BSSMAP_IE_CellIdentifierList cid_list)
+template PDU_BSSAP ts_BSSMAP_HandoReq(BssmapCause cause, BSSMAP_FIELD_CellIdentificationList cid_list)
 modifies ts_BSSAP_BSSMAP := {
 	pdu := {
 		bssmap := {
@@ -193,7 +200,7 @@
 				messageType := '11'O,
 				cause := ts_BSSMAP_IE_Cause(cause),
 				responseRequest := omit,
-				cellIdentifierList := cid_list,
+				cellIdentifierList := ts_BSSMAP_IE_CidList(cid_list),
 				circuitPoolList := omit,
 				currentChannelType1 := omit,
 				speechVersion := omit,
@@ -388,6 +395,40 @@
 	}
 }
 
+function f_hex_is_odd_length(hexstring digits) return bitstring {
+	if (lengthof(digits) rem 2 == 1) {
+		return '1'B;
+	} else {
+		return '0'B;
+	}
+}
+
+template BSSMAP_IE_IMSI ts_BSSMAP_Imsi(hexstring imsi_digits) := {
+	elementIdentifier := '08'O,
+	lengthIndicator := 0, /* overwritten */
+	typeOfIdentity := '001'B, /* IMSI */
+	oddEvenIndicator := f_hex_is_odd_length(imsi_digits),
+	digits := imsi_digits
+}
+
+template PDU_BSSAP ts_BSSMAP_Paging(hexstring imsi_digits, BSSMAP_FIELD_CellIdentificationList cid_list,
+					template integer tmsi := omit)
+modifies ts_BSSAP_BSSMAP := {
+	pdu := {
+		bssmap := {
+			paging := {
+				messageType := '51'O,
+				iMSI := ts_BSSMAP_Imsi(imsi_digits),
+				tMSI := omit, // FIXME: convert tmsi,
+				cellIdentifierList := ts_BSSMAP_IE_CidList(cid_list),
+				channelNeeded := omit,
+				eMLPP_Priority := omit,
+				pagingInformation := omit /* only VGCS/VBS flag */
+			}
+		}
+	}
+}
+
 
 
 }