ipa: First version that emulates both MSC and BSC up to ASSIGNMENT REQ
diff --git a/ipa/BSC_MS_ConnectionHandler.ttcn b/ipa/BSC_MS_ConnectionHandler.ttcn
new file mode 100644
index 0000000..443babe
--- /dev/null
+++ b/ipa/BSC_MS_ConnectionHandler.ttcn
@@ -0,0 +1,105 @@
+module BSC_MS_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 MobileL3_Types all;
+import from MobileL3_CommonIE_Types all;
+import from L3_Templates 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 BSC_MS_ConnHdlr extends BSSAP_ConnHdlr {
+	/* SCCP Connecction Identifier for the underlying SCCP connection */
+	var integer g_sccp_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)
+runs on BSSMAP_Emulation_CT return BSSAP_ConnHdlr {
+	log("Incoming SCCP Connection on BSC ?!?");
+	self.stop;
+}
+
+/* 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 BSC_MS_BssmapOps := {
+	create_cb := refers(CreateCallback),
+	unitdata_cb := refers(UnitdataCallback)
+}
+
+
+function f_gen_cl3(hexstring imsi) return PDU_BSSAP {
+	var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV(imsi));
+	var PDU_ML3_MS_NW l3 := valueof(ts_CM_SERV_REQ('0001'B, mi));
+	var BSSMAP_IE_CellIdentifier cell_id := valueof(ts_CellID_LAC_CI(23, 42));
+	var PDU_BSSAP bssap := valueof(ts_BSSMAP_ComplL3(cell_id, enc_PDU_ML3_MS_NW(l3)));
+	return bssap;
+}
+
+/* main function processing various incoming events */
+function main(SCCP_PAR_Address sccp_addr_own, SCCP_PAR_Address sccp_addr_remote)
+runs on BSC_MS_ConnHdlr {
+	var PDU_BSSAP bssap;
+
+	log("Starting main of BSC_MS_ConnHdlr");
+
+	/* generate and send the Complete Layer3 Info */
+	bssap := f_gen_cl3('901770123456789'H);
+
+	var BSSAP_Conn_Req creq := {
+		addr_peer := sccp_addr_remote,
+		addr_own := sccp_addr_own,
+		bssap := bssap
+	}
+	BSSAP.send(creq);
+
+	while (true) {
+		alt {
+		/* new SCCP-level connection indication from BSC */
+		[] BSSAP.receive(tr_BSSMAP_AssignmentCmd) -> value bssap {
+			/* TODO: Read CIC */
+			/* respond with ASSIGNMENT COMPL */
+			BSSAP.send(ts_BSSMAP_AssignmentComplete(bssap.pdu.bssmap.assignmentRequest.circuitIdentityCode));
+			}
+		/* TODO: CLEAR REQUEST from BSS */
+		/* CLEAR COMMAND from MSC; respond with CLEAR COMPLETE) */
+		[] BSSAP.receive(tr_BSSMAP_ClearCommand) -> value bssap {
+			BSSAP.send(ts_BSSMAP_ClearComplete);
+			/* FIXME: local release? */
+			}
+
+		[] BSSAP.receive(tr_BSSAP_DTAP) -> value bssap {
+			var PDU_ML3_MS_NW l3 := dec_PDU_ML3_MS_NW(bssap.pdu.dtap);
+			log("Unhandled DTAP ", l3);
+			}
+
+		[] BSSAP.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_IND) {
+			self.stop;
+			}
+
+		[] BSSAP.receive(PDU_BSSAP:?) -> value bssap {
+			log("Received unhandled SCCP-CO: ", bssap);
+			}
+		}
+	}
+}
+
+}
diff --git a/ipa/BSC_MS_Simulation.ttcn b/ipa/BSC_MS_Simulation.ttcn
new file mode 100644
index 0000000..c33e848
--- /dev/null
+++ b/ipa/BSC_MS_Simulation.ttcn
@@ -0,0 +1,77 @@
+module BSC_MS_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 BSSMAP_Emulation all;
+
+import from BSC_MS_ConnectionHandler all;
+
+type component BSC_CT {
+	/* component references */
+	var IPA_Emulation_CT vc_IPA;
+	var SCCP_CT vc_SCCP;
+	var BSSMAP_Emulation_CT vc_BSSMAP;
+	/* test port to SCCP emulation */
+	port SCCPasp_PT SCCP;
+
+	var SCCP_PAR_Address g_sccp_addr_own;
+	var SCCP_PAR_Address g_sccp_addr_remote;
+}
+
+function main(charstring remote_ip, PortNumber remote_port,
+		charstring local_ip, PortNumber local_port,
+		MSC_SCCP_MTP3_parameters sccp_pars,
+		SCCP_PAR_Address sccp_addr_own,
+		SCCP_PAR_Address sccp_addr_remote) runs on BSC_CT
+{
+	g_sccp_addr_own := sccp_addr_own;
+	g_sccp_addr_remote := sccp_addr_remote;
+
+	/* create components */
+	vc_IPA := IPA_Emulation_CT.create;
+	vc_SCCP := SCCP_CT.create;
+	vc_BSSMAP := BSSMAP_Emulation_CT.create;
+
+	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);
+
+	vc_IPA.start(IPA_Emulation.main_client(remote_ip, remote_port, local_ip, local_port));
+	vc_SCCP.start(SCCPStart(sccp_pars));
+	vc_BSSMAP.start(BSSMAP_Emulation.main(BSC_MS_BssmapOps));
+
+	while (true) {
+		timer T := 5.0;
+		T.start;
+		T.timeout;
+		f_start_BSC_MS();
+		//vc_IPA.MTP3_SP_PORT.send(t_ASP_MTP3_TRANSFERreq_sccp('83'O, 1, 2, 0, '012345'O));
+	}
+
+	vc_IPA.done;
+	vc_BSSMAP.done;
+	vc_SCCP.done
+}
+
+function f_start_BSC_MS() runs on BSC_CT {
+	var BSC_MS_ConnHdlr vc_conn;
+
+	/* start new component */
+	vc_conn := BSC_MS_ConnHdlr.create;
+	/* connect client BSSAP port to BSSAP dispatcher */
+	connect(vc_conn:BSSAP, vc_BSSMAP:CLIENT);
+	/* start component */
+	vc_conn.start(BSC_MS_ConnectionHandler.main(g_sccp_addr_own, g_sccp_addr_remote));
+}
+
+}
diff --git a/ipa/IPA_Test.ttcn b/ipa/IPA_Test.ttcn
index 4e87fa6..c8b8205 100644
--- a/ipa/IPA_Test.ttcn
+++ b/ipa/IPA_Test.ttcn
@@ -1,48 +1,58 @@
 module IPA_Test {
 
+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 MobileL3_Types all;
-import from MobileL3_CommonIE_Types all;
-import from L3_Templates all;
+import from MSC_Simulation all;
+import from BSC_MS_Simulation all;
 
-import from BSSAP_Types all;
-import from BSSMAP_Templates all;
+const integer NUM_MSC := 1;
+const integer NUM_BSC := 1;
+
+type record BscState {
+	BSC_CT BSC,
+	MSC_SCCP_MTP3_parameters sccp_pars,
+	SCCP_PAR_Address sccp_addr_own,
+	SCCP_PAR_Address sccp_addr_peer
+}
+
+type record MscState {
+	MSC_CT MSC,
+	MSC_SCCP_MTP3_parameters sccp_pars,
+	SCCP_PAR_Address sccp_addr_own
+}
 
 type component test_CT {
-	/* component references */
-	var IPA_Emulation_CT vc_IPA;
-	var SCCP_CT vc_SCCP;
-	/* test port to SCCP emulation */
-	port SCCPasp_PT SCCP;
+	var MscState msc[NUM_MSC];
+	var BscState bsc[NUM_BSC];
 
 	var boolean g_initialized := false;
-	var octetstring g_sio;
-	var MSC_SCCP_MTP3_parameters g_sccp_pars;
-	var SCCP_PAR_Address g_sccp_addr_own, g_sccp_addr_peer;
-
-	var ConnectionId g_ipa_conn_id := -1;
+	var octetstring g_sio := '83'O;
 }
 
 modulepar {
-	PortNumber mp_local_port := 0;
-	charstring mp_local_ip := "127.0.0.1";
-	PortNumber mp_remote_port := 3002;
-	charstring mp_remote_ip := "127.0.0.1";
+	PortNumber mp_bsc_port := 49999;
+	charstring mp_bsc_ip := "127.0.0.1";
+
+	PortNumber mp_msc_port := 5000;
+	charstring mp_msc_ip := "127.0.0.1";
 
 	charstring mp_sccp_service_type := "mtp3_itu";
 
-	integer mp_own_pc := 196;
-	integer mp_own_ssn := 254;
+	integer mp_bsc_pc := 196;
+	integer mp_bsc_ssn := 254;
 
-	integer mp_peer_pc := 185;	/* 0.23.1 */
-	integer mp_peer_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 */
@@ -59,76 +69,62 @@
 	globalTitle := omit
 }
 
-
-function f_gen_cl3() return PDU_BSSAP {
-	var MobileIdentityLV mi := valueof(ts_MI_IMSI_LV('901770123456789'H));
-	var PDU_ML3_MS_NW l3 := valueof(ts_CM_SERV_REQ('0001'B, mi));
-	var BSSMAP_IE_CellIdentifier cell_id := valueof(ts_CellID_LAC_CI(23, 42));
-	var PDU_BSSAP bssap := valueof(ts_BSSMAP_ComplL3(cell_id, enc_PDU_ML3_MS_NW(l3)));
-	return bssap;
+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)
 }
 
-function f_send_bssap_cc(PDU_BSSAP bssap) runs on test_CT {
-	var ASP_SCCP_N_CONNECT_req prim;
-	prim := valueof(t_ASP_N_CONNECT_req(g_sccp_addr_peer, g_sccp_addr_own, omit, omit,
-				    enc_PDU_BSSAP(bssap), 23, omit));
-	SCCP.send(prim);
+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_BscState(inout BscState bsc_st, integer opc, integer dpc, integer local_ssn, integer remote_ssn)
+runs on test_CT {
+	bsc_st.sccp_pars := valueof(ts_SCCP_Pars(g_sio, opc, dpc, local_ssn));
+	bsc_st.sccp_addr_own := valueof(ts_SccpAddr_PC_SSN(opc, local_ssn));
+	bsc_st.sccp_addr_peer := valueof(ts_SccpAddr_PC_SSN(dpc, remote_ssn));
 }
 
-function init_pars() runs on test_CT {
-	g_sio := '83'O;
-	g_sccp_pars := {
-		sio := {
-			ni := substr(oct2bit(g_sio),0,2),
-			prio := substr(oct2bit(g_sio),2,2),
-			si := substr(oct2bit(g_sio),4,4)
-		},
-		opc := mp_own_pc,
-		dpc := mp_peer_pc,
-		sls := 0,
-		sccp_serviceType := mp_sccp_service_type,
-		ssn := mp_own_ssn
-	};
-	g_sccp_addr_own := valueof(ts_SccpAddr_PC_SSN(mp_own_pc, mp_own_ssn));
-	g_sccp_addr_peer := valueof(ts_SccpAddr_PC_SSN(mp_peer_pc, mp_peer_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));
 }
 
-private function f_init() runs on test_CT {
-	var Result res;
+function f_init() runs on test_CT {
+	var integer i;
 
-	if (g_initialized == true) {
-		return;
+	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;
+		msc[i].MSC.start(MSC_Simulation.main(mp_msc_ip, mp_msc_port + i, msc[i].sccp_pars, msc[i].sccp_addr_own));
 	}
-	g_initialized := true;
 
-	init_pars();
+	for (i := 0; i < NUM_BSC; i := i+1) {
+		f_init_BscState(bsc[i], mp_bsc_pc +i, mp_msc_pc, mp_bsc_ssn, mp_msc_ssn);
+		bsc[i].BSC := BSC_CT.create;
+		bsc[i].BSC.start(BSC_MS_Simulation.main(mp_msc_ip, mp_msc_port, mp_bsc_ip, mp_bsc_port+i,
+							bsc[i].sccp_pars, bsc[i].sccp_addr_own,
+							bsc[i].sccp_addr_peer));
+	}
 
-	/* create components */
-	vc_IPA := IPA_Emulation_CT.create;
-	vc_SCCP := SCCP_CT.create;
-
-	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 us to upper side of SCCP */
-	connect(self:SCCP, vc_SCCP:SCCP_SP_PORT);
-
-	vc_IPA.start(IPA_Emulation.ScanEvents());
-	vc_SCCP.start(SCCPStart(g_sccp_pars));
-
-	//IPA_Emulation.f_connect(mp_remote_ip, mp_remote_port, mp_local_ip, mp_local_port);
 }
 
 testcase TC_recv_dump() runs on test_CT {
 	f_init();
 
-	var PDU_BSSAP bssap := f_gen_cl3();
-	f_send_bssap_cc(bssap);
+	//var PDU_BSSAP bssap := f_gen_cl3();
+	//f_send_bssap_cc(bssap);
 
 	while (true) {
-		SCCP.receive;
+		//SCCP.receive;
 	}
 }
 
diff --git a/ipa/MSC_ConnectionHandler.ttcn b/ipa/MSC_ConnectionHandler.ttcn
index 0d7cd20..9cec556 100644
--- a/ipa/MSC_ConnectionHandler.ttcn
+++ b/ipa/MSC_ConnectionHandler.ttcn
@@ -52,7 +52,7 @@
 /* main function processing various incoming events */
 function main(integer connection_id, integer timeslot) runs on MSC_ConnHdlr {
 	g_sccp_conn_id := connection_id;
-	g_e1_timeslot := timeslot
+	g_e1_timeslot := 1; /* FIXME */
 
 	while (true) {
 		var PDU_BSSAP bssap;
diff --git a/ipa/MSC_Simulation.ttcn b/ipa/MSC_Simulation.ttcn
new file mode 100755
index 0000000..8c94188
--- /dev/null
+++ b/ipa/MSC_Simulation.ttcn
@@ -0,0 +1,59 @@
+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 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;
+	/* test port to SCCP emulation */
+	port SCCPasp_PT SCCP;
+}
+
+function main(charstring local_ip, PortNumber local_port,
+	      MSC_SCCP_MTP3_parameters sccp_pars,
+	      SCCP_PAR_Address sccp_addr_own) runs on MSC_CT
+{
+	/* create components */
+	vc_IPA := IPA_Emulation_CT.create;
+	vc_SCCP := SCCP_CT.create;
+	vc_BSSMAP := BSSMAP_Emulation_CT.create;
+
+	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);
+
+	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));
+
+	/* wait until termination of respective components */
+	vc_IPA.done;
+	vc_BSSMAP.done;
+	vc_SCCP.done;
+}
+
+}
diff --git a/ipa/gen_links.sh b/ipa/gen_links.sh
index d9bc7a4..be11ec0 100755
--- a/ipa/gen_links.sh
+++ b/ipa/gen_links.sh
@@ -47,5 +47,5 @@
 
 
 DIR=../library
-FILES="General_Types.ttcn Osmocom_Types.ttcn IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc L3_Templates.ttcn BSSMAP_Templates.ttcn"
+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"
 gen_links $DIR $FILES
diff --git a/library/BSSMAP_Emulation.ttcn b/library/BSSMAP_Emulation.ttcn
index bcc0e11..9e4d5c3 100644
--- a/library/BSSMAP_Emulation.ttcn
+++ b/library/BSSMAP_Emulation.ttcn
@@ -1,5 +1,6 @@
 module BSSMAP_Emulation {
 
+import from SCCP_Emulation all;
 import from SCCPasp_Types all;
 import from BSSAP_Types all;
 import from BSSMAP_Templates all;
@@ -20,10 +21,15 @@
 	MSC_CONN_PRIM_DISC_REQ
 }
 
+type record BSSAP_Conn_Req {
+	SCCP_PAR_Address	addr_peer,
+	SCCP_PAR_Address	addr_own,
+	PDU_BSSAP		bssap
+}
+
 /* port between individual per-connection components and this dispatcher */
 type port BSSAP_Conn_PT message {
-	inout PDU_BSSAP;
-	inout BSSAP_Conn_Prim;
+	inout PDU_BSSAP, BSSAP_Conn_Prim, BSSAP_Conn_Req;
 } with { extension "internal" };
 
 
@@ -44,6 +50,27 @@
 	var ConnectionData ConnectionTable[16];
 };
 
+private function f_conn_id_known(integer sccp_conn_id)
+runs on BSSMAP_Emulation_CT return boolean {
+	var integer i;
+	for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
+		if (ConnectionTable[i].sccp_conn_id == sccp_conn_id){
+			return true;
+		}
+	}
+	return false;
+}
+
+private function f_comp_known(BSSAP_ConnHdlr client)
+runs on BSSMAP_Emulation_CT return boolean {
+	var integer i;
+	for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
+		if (ConnectionTable[i].comp_ref == client) {
+			return true;
+		}
+	}
+	return false;
+}
 
 /* resolve component reference by connection ID */
 private function f_comp_by_conn_id(integer sccp_conn_id)
@@ -70,6 +97,17 @@
 	self.stop;
 }
 
+private function f_gen_conn_id()
+runs on BSSMAP_Emulation_CT return integer {
+	var integer conn_id;
+
+	do {
+		conn_id := float2int(rnd()*SCCP_Emulation.tsp_max_ConnectionId);
+	} while (f_conn_id_known(conn_id) == true);
+
+	return conn_id;
+}
+
 private function f_conn_table_init()
 runs on BSSMAP_Emulation_CT {
 	for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
@@ -84,6 +122,7 @@
 		if (ConnectionTable[i].sccp_conn_id == -1) {
 			ConnectionTable[i].comp_ref := comp_ref;
 			ConnectionTable[i].sccp_conn_id := sccp_conn_id;
+			log("Added conn table entry ", i, comp_ref, sccp_conn_id);
 			return;
 		}
 	}
@@ -95,6 +134,8 @@
 runs on BSSMAP_Emulation_CT {
 	for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
 		if (ConnectionTable[i].sccp_conn_id == sccp_conn_id) {
+			log("Deleted conn table entry ", i,
+			    ConnectionTable[i].comp_ref, sccp_conn_id);
 			ConnectionTable[i].sccp_conn_id := -1;
 			ConnectionTable[i].comp_ref := null;
 		}
@@ -135,8 +176,10 @@
 	while (true) {
 		var ASP_SCCP_N_UNITDATA_ind ud_ind;
 		var ASP_SCCP_N_CONNECT_ind conn_ind;
+		var ASP_SCCP_N_CONNECT_cfm conn_cfm;
 		var ASP_SCCP_N_DATA_ind data_ind;
 		var ASP_SCCP_N_DISCONNECT_ind disc_ind;
+		var BSSAP_Conn_Req creq;
 		var BSSAP_ConnHdlr vc_conn;
 		var PDU_BSSAP bssap;
 
@@ -183,6 +226,12 @@
 			/* TOOD: return confirm to other side? */
 			}
 
+		/* SCCP -> Client: connection confirm for outbound connection */
+		[] SCCP.receive(ASP_SCCP_N_CONNECT_cfm:?) -> value conn_cfm {
+			/* handle user payload */
+			f_handle_userData(vc_conn, conn_cfm.userData);
+			}
+
 		/* Disconnect request client -> SCCP */
 		[] CLIENT.receive(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_REQ) -> sender vc_conn {
 			var integer conn_id := f_conn_id_by_comp(vc_conn);
@@ -191,9 +240,31 @@
 			}
 
 		/* BSSAP from client -> SCCP */
+		[] CLIENT.receive(BSSAP_Conn_Req:?) -> value creq sender vc_conn {
+			var integer conn_id;
+			/* encode + send to dispatcher */
+			var octetstring userdata := enc_PDU_BSSAP(creq.bssap);
+
+			if (f_comp_known(vc_conn) == false) {
+				/* unknown client, create new connection */
+				conn_id := f_gen_conn_id();
+
+				/* store mapping between client components and SCCP connectionId */
+				f_conn_table_add(vc_conn, conn_id);
+
+				SCCP.send(t_ASP_N_CONNECT_req(creq.addr_peer, creq.addr_own, omit, omit,
+								userdata, conn_id, omit));
+			} else {
+				/* known client, send via existing connection */
+				conn_id := f_conn_id_by_comp(vc_conn);
+				SCCP.send(t_ASP_N_DATA_req(userdata, conn_id, omit));
+			}
+
+			}
+
 		[] CLIENT.receive(PDU_BSSAP:?) -> value bssap sender vc_conn {
 			var integer conn_id := f_conn_id_by_comp(vc_conn);
-			/* encode + send to dispatcher */
+			/* encode + send it to dispatcher */
 			var octetstring userdata := enc_PDU_BSSAP(bssap);
 			SCCP.send(t_ASP_N_DATA_req(userdata, conn_id, omit));
 			}
diff --git a/library/BSSMAP_Templates.ttcn b/library/BSSMAP_Templates.ttcn
index b030072..274f42e 100644
--- a/library/BSSMAP_Templates.ttcn
+++ b/library/BSSMAP_Templates.ttcn
@@ -11,7 +11,9 @@
 	spare := '0000000'B,
 	dlci := omit,
 	lengthIndicator := 0,	/* overwritten by codec */
-	pdu := ?
+	pdu := {
+		bssmap := ?
+	}
 }
 
 template PDU_BSSAP tr_BSSAP_BSSMAP := {
@@ -24,6 +26,27 @@
 	}
 }
 
+template PDU_BSSAP ts_BSSAP_DTAP := {
+	discriminator := '1'B,
+	spare := '0000000'B,
+	dlci := omit,
+	lengthIndicator := 0,	/* overwritten by codec */
+	pdu := {
+		dtap := ?
+	}
+}
+
+template PDU_BSSAP tr_BSSAP_DTAP := {
+	discriminator := '1'B,
+	spare := '0000000'B,
+	dlci := omit,
+	lengthIndicator := ?,
+	pdu := {
+		dtap := ?
+	}
+}
+
+
 template (value) BSSMAP_IE_Cause ts_BSSMAP_IE_Cause(BssmapCause val) := {
 	elementIdentifier := '04'O,
 	lengthIndicator := 0,
@@ -238,4 +261,119 @@
 	}
 }
 
+template PDU_BSSAP tr_BSSMAP_AssignmentCmd modifies tr_BSSAP_BSSMAP := {
+	pdu := {
+		bssmap := {
+			assignmentRequest := {
+				messageType :='01'O,	/* overwritten */
+				channelType := ?,
+				layer3HeaderInfo := *,
+				priority := *,
+				circuitIdentityCode := ?,
+				downLinkDTX_Flag := *,
+				interferenceBandToBeUsed := *,
+				classmarkInformationType2 := *,
+				groupCallReference := *,
+				talkerFlag := *,
+				configurationEvolutionIndication := *,
+				lsaAccesControlSuppression := *,
+				serviceHandover := *,
+				encryptionInformation := *,
+				talkerPriority := *,
+				aoIPTransportLayer := *,
+				codecList := *,
+				callIdentifier := *,
+				kC128 := *,
+				globalCallReference := *,
+				lCLS_Configuration := *,
+				lCLS_ConnectionStatusControl := *,
+				lCLS_CorrelationNotNeeded := *
+			}
+		}
+	}
+}
+
+template (value) PDU_BSSAP ts_BSSMAP_AssignmentComplete(BSSMAP_IE_CircuitIdentityCode cic)
+modifies ts_BSSAP_BSSMAP := {
+	pdu := {
+		bssmap := {
+			assignmentComplete := {
+				messageType :='02'O,	/* overwritten */
+				circuitIdentityCode := cic,
+				cellIdentifier := omit,
+				chosenChannel := omit,
+				chosenEncryptionAlgorithm := omit,
+				circuitPool := omit,
+				speechVersion := omit,
+				lSAIdentifier := omit,
+				talkerPriority := omit,
+				aoIPTransportLayer := omit,
+				speechCodec := omit,
+				codecList := omit,
+				lCLS_BSS_Status := omit
+			}
+		}
+	}
+}
+
+template PDU_BSSAP tr_BSSMAP_AssignmentComplete modifies tr_BSSAP_BSSMAP := {
+	pdu := {
+		bssmap := {
+			assignmentComplete := {
+				messageType := '02'O,	/* overwritten */
+				circuitIdentityCode := ?,
+				cellIdentifier := *,
+				chosenChannel := *,
+				chosenEncryptionAlgorithm := *,
+				circuitPool := *,
+				speechVersion := *,
+				lSAIdentifier := *,
+				talkerPriority := *,
+				aoIPTransportLayer := *,
+				speechCodec := *,
+				codecList := *,
+				lCLS_BSS_Status := *
+			}
+		}
+	}
+}
+
+template (value) PDU_BSSAP ts_BSSMAP_ClearCommand(BssmapCause cause)
+modifies ts_BSSAP_BSSMAP := {
+	pdu := {
+		bssmap := {
+			clearCommand := {
+				messageType := '20'O,	/* overwritten */
+				layer3HeaderInfo := omit,
+				cause := ts_BSSMAP_IE_Cause(cause),
+				cSFB_Indication := omit
+			}
+		}
+	}
+}
+
+template PDU_BSSAP tr_BSSMAP_ClearCommand modifies tr_BSSAP_BSSMAP := {
+	pdu := {
+		bssmap := {
+			clearCommand := {
+				messageType := '20'O,	/* overwritten */
+				layer3HeaderInfo := *,
+				cause := ?,
+				cSFB_Indication := *
+			}
+		}
+	}
+}
+
+template (value) PDU_BSSAP ts_BSSMAP_ClearComplete
+modifies ts_BSSAP_BSSMAP := {
+	pdu := {
+		bssmap := {
+			clearComplete := {
+				messageType := '21'O	/* overwritten */
+			}
+		}
+	}
+}
+
 }
diff --git a/library/IPA_Emulation.ttcn b/library/IPA_Emulation.ttcn
index 4d21bb4..ed51110 100644
--- a/library/IPA_Emulation.ttcn
+++ b/library/IPA_Emulation.ttcn
@@ -12,6 +12,11 @@
 }
 */
 
+type enumerated IpaMode {
+	IPA_MODE_CLIENT,
+	IPA_MODE_SERVER
+}
+
 type record ASP_IPA_Unitdata {
 	IpaStreamId	streamId,
 	octetstring	payload
@@ -31,6 +36,8 @@
 
 	var boolean g_initialized := false;
 	var ConnectionId g_ipa_conn_id := -1;
+
+	var IpaMode g_mode;
 }
 
 function f_connect(charstring remote_host, PortNumber remote_port,
@@ -41,6 +48,13 @@
 	g_ipa_conn_id := res.connId;
 }
 
+function f_bind(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
+	var Result res;
+	res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT, 
+						local_host, local_port, { tcp:={} });
+	g_ipa_conn_id := res.connId;
+}
+
 template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
 	sio := { '10'B, '00'B, '0011'B },
 	opc := opc,
@@ -107,6 +121,15 @@
 	u := omit
 }
 
+template PDU_IPA_CCM ts_IPA_ID_GET := {
+	msg_type := IPAC_MSGT_ID_GET,
+	u := {
+		get := {
+			{ 1, IPAC_IDTAG_UNITNAME }
+		}
+	}
+}
+
 /* receive IPA CCM message */
 private function f_ccm_rx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
 	select (ccm.msg_type) {
@@ -142,12 +165,24 @@
 	return ret;
 }
 
-function ScanEvents() runs on IPA_Emulation_CT {
+function main_client(charstring remote_host, PortNumber remote_port,
+		     charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
+	g_mode := IPA_MODE_CLIENT;
+	f_connect(remote_host, remote_port, local_host, local_port);
+	ScanEvents();
+}
+
+function main_server(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
+	g_mode := IPA_MODE_SERVER;
+	f_bind(local_host, local_port);
+	ScanEvents();
+}
+
+private function ScanEvents() runs on IPA_Emulation_CT {
 	var IPA_RecvFrom ipa_rx;
 	var ASP_IPA_Unitdata ipa_ud;
 	var ASP_MTP3_TRANSFERreq mtp_req;
-
-	f_connect("127.0.0.1", 5000, "127.0.0.1", 49999);
+	var ASP_Event asp_evt;
 
 	while (true) {
 		alt {
@@ -170,6 +205,21 @@
 			}
 		}
 
+		/* server only */
+		[] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
+			log("IPA: Connected");
+			g_ipa_conn_id := asp_evt.connOpened.connId;
+			if (g_mode == IPA_MODE_SERVER) {
+				f_ccm_tx(valueof(ts_IPA_ID_GET));
+			}
+		}
+
+		[] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
+			log("IPA: Closed");
+			g_ipa_conn_id := -1;
+			self.stop;
+		}
+
 		/* Received SCCP -> down into IPA */
 		[] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
 			var IPA_Send ipa_tx := {