ipa: First version that emulates both MSC and BSC up to ASSIGNMENT REQ
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 := {