Merge changes I53ffe442,Ic0750bdc,Ic5499a0b,I67343f01

* changes:
  bsc: Run three virtual BTSs (2 in one lac, 1 in another)
  Add RTP_Emulation (stream source/sink) on top of RTP_CodecPort
  Add missing RTP_CodecPort_CtrlFunct TTCN and C++ files
  move RTP_CodecPort.ttcn to library
diff --git a/bsc/BSC_Tests.ttcn b/bsc/BSC_Tests.ttcn
index 926e8cc..2e48e0b 100644
--- a/bsc/BSC_Tests.ttcn
+++ b/bsc/BSC_Tests.ttcn
@@ -22,7 +22,7 @@
 
 import from RSL_Tests all;
 
-const integer NUM_BTS := 1;
+const integer NUM_BTS := 3;
 const float T3101_MAX := 12.0;
 
 
@@ -88,7 +88,7 @@
 	map(clnt.vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
 	connect(clnt.vc_IPA:IPA_RSL_PORT, self:IPA_RSL[i]);
 
-	clnt.vc_IPA.start(IPA_Emulation.main_client(bsc_host, bsc_port, "", -1, clnt.ccm_pars));
+	clnt.vc_IPA.start(IPA_Emulation.main_client(bsc_host, bsc_port, "", 10000+i, clnt.ccm_pars));
 
 	/* wait for IPA RSL link to connect and send ID ACK */
 	T.start;
@@ -606,10 +606,21 @@
 };
 private const Cell_Identity cid := { '001'H, '001'H, 1, 0 };
 
+type set of integer BtsIdList;
+
+private function f_bts_in_list(integer bts_id, BtsIdList bts_ids) return boolean {
+	for (var integer j := 0; j < sizeof(bts_ids); j := j + 1) {
+		if (bts_id == bts_ids[j]) {
+			return true;
+		}
+	}
+	return false;
+}
 
 /* core paging test helper function; used by most paging test cases */
 private function f_pageing_helper(hexstring imsi,
 				  template BSSMAP_FIELD_CellIdentificationList cid_list,
+				  BtsIdList bts_ids := { 0 },
 				  template RSL_ChanNeeded rsl_chneed := omit,
 				  template OCT4 tmsi := omit) runs on test_CT
 {
@@ -618,12 +629,15 @@
 	var template octetstring id_enc; /* FIXME */
 	var RSL_Message rx_rsl;
 	var integer paging_group := hex2int(imsi[lengthof(imsi)-1]);
+	var integer i;
 
 	f_init();
 	f_bssap_reset();
 
 	/* Clear the queue, it might still contain stuff like BCCH FILLING */
-	IPA_RSL[0].clear;
+	for (i := 0; i < sizeof(bts_ids); i := i + 1) {
+		IPA_RSL[bts_ids[i]].clear;
+	}
 
 	if (isvalue(rsl_chneed)) {
 		/* The values of 08.08 3.2.2.36 and 08.58 9.3.40 are luckily identical */
@@ -643,95 +657,116 @@
 	id_enc := enc_MobileIdentity(mi);
 */
 	id_enc := ?;
-	rx_rsl := f_exp_ipa_rx(0, tr_RSL_PAGING_CMD(id_enc));
-	/* check channel type, paging group */
-	if (rx_rsl.ies[1].body.paging_group != paging_group) {
-		setverdict(fail, "Paging for wrong paging group");
+	for (i := 0; i < sizeof(bts_ids); i := i + 1) {
+		rx_rsl := f_exp_ipa_rx(bts_ids[i], tr_RSL_PAGING_CMD(id_enc));
+		/* check channel type, paging group */
+		if (rx_rsl.ies[1].body.paging_group != paging_group) {
+			setverdict(fail, "Paging for wrong paging group");
+		}
+		if (ispresent(rsl_chneed) and
+		    rx_rsl.ies[3].body.chan_needed.chan_needed != valueof(rsl_chneed)) {
+			setverdict(fail, "RSL Channel Needed != BSSMAP Channel Needed");
+		}
 	}
-	if (ispresent(rsl_chneed) and
-	    rx_rsl.ies[3].body.chan_needed.chan_needed != valueof(rsl_chneed)) {
-		setverdict(fail, "RSL Channel Needed != BSSMAP Channel Needed");
+	/* do a quick check on all not-included BTSs if they received paging */
+	for (i := 0; i < NUM_BTS; i := i + 1) {
+		timer T := 0.1;
+		if (f_bts_in_list(i, bts_ids)) {
+			continue;
+		}
+		T.start;
+		alt {
+		[] IPA_RSL[i].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(id_enc))) {
+			setverdict(fail, "Paging on BTS ", i, " which is not part of ", bts_ids);
+			}
+		[] IPA_RSL[i].receive { repeat; }
+		[] T.timeout { }
+		}
 	}
 
 	setverdict(pass);
 }
 
+const BtsIdList c_BtsId_all := { 0, 1, 2 };
+const BtsIdList c_BtsId_LAC1 := { 0, 1 };
+const BtsIdList c_BtsId_LAC2 := { 2 };
+
 /* PAGING by IMSI + TMSI */
 testcase TC_paging_imsi_nochan() runs on test_CT {
 	var BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := valueof(ts_BSSMAP_CIL_noCell);
-	f_pageing_helper('001010123456789'H, cid_list);
+	f_pageing_helper('001010123456789'H, cid_list, c_BtsId_all);
 }
 
 /* PAGING by IMSI + TMSI */
 testcase TC_paging_tmsi_nochan() runs on test_CT {
 	var BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := valueof(ts_BSSMAP_CIL_noCell);
-	f_pageing_helper('001010100000001'H, cid_list, omit, 'A1B2C301'O);
+	f_pageing_helper('001010100000001'H, cid_list, c_BtsId_all, omit, 'A1B2C301'O);
 }
 
 /* Paging with different "channel needed' values */
 testcase TC_paging_tmsi_any() runs on test_CT {
 	var BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := valueof(ts_BSSMAP_CIL_noCell);
-	f_pageing_helper('001010100000002'H, cid_list, RSL_CHANNEED_ANY, 'A1B2C302'O);
+	f_pageing_helper('001010100000002'H, cid_list, c_BtsId_all, RSL_CHANNEED_ANY, 'A1B2C302'O);
 }
 testcase TC_paging_tmsi_sdcch() runs on test_CT {
 	var BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := valueof(ts_BSSMAP_CIL_noCell);
-	f_pageing_helper('001010100000003'H, cid_list, RSL_CHANNEED_SDCCH, 'A1B2C303'O);
+	f_pageing_helper('001010100000003'H, cid_list, c_BtsId_all, RSL_CHANNEED_SDCCH, 'A1B2C303'O);
 }
 testcase TC_paging_tmsi_tch_f() runs on test_CT {
 	var BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := valueof(ts_BSSMAP_CIL_noCell);
-	f_pageing_helper('001010000000004'H, cid_list, RSL_CHANNEED_TCH_F, 'A1B2C304'O);
+	f_pageing_helper('001010000000004'H, cid_list, c_BtsId_all, RSL_CHANNEED_TCH_F, 'A1B2C304'O);
 }
 testcase TC_paging_tmsi_tch_hf() runs on test_CT {
 	var BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := valueof(ts_BSSMAP_CIL_noCell);
-	f_pageing_helper('001010000000005'H, cid_list, RSL_CHANNEED_TCH_ForH, 'A1B2C305'O);
+	f_pageing_helper('001010000000005'H, cid_list, c_BtsId_all, RSL_CHANNEED_TCH_ForH, 'A1B2C305'O);
 }
 
 /* Paging by CGI */
 testcase TC_paging_imsi_nochan_cgi() runs on test_CT {
 	var template BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := { cIl_CGI := { ts_BSSMAP_CI_CGI(cid.mcc, cid.mnc, cid.lac, cid.ci) } };
-	f_pageing_helper('001010000000006'H, cid_list);
+	f_pageing_helper('001010000000006'H, cid_list, { 0 });
 }
 
 /* Paging by LAC+CI */
 testcase TC_paging_imsi_nochan_lac_ci() runs on test_CT {
 	var template BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := { cIl_LAC_CI := { ts_BSSMAP_CI_LAC_CI(cid.lac, cid.ci) } };
-	f_pageing_helper('001010000000007'H, cid_list);
+	f_pageing_helper('001010000000007'H, cid_list, { 0 });
 }
 
 /* Paging by CI */
 testcase TC_paging_imsi_nochan_ci() runs on test_CT {
 	var template BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := { cIl_CI := { ts_BSSMAP_CI_CI(cid.ci) } };
-	f_pageing_helper('001010000000008'H, cid_list);
+	f_pageing_helper('001010000000008'H, cid_list, { 0 });
 }
 
 /* Paging by LAI */
 testcase TC_paging_imsi_nochan_lai() runs on test_CT {
 	var template BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := { cIl_LAI := { ts_BSSMAP_CI_LAI(cid.mcc, cid.mnc, cid.lac) } };
-	f_pageing_helper('001010000000009'H, cid_list);
+	f_pageing_helper('001010000000009'H, cid_list, c_BtsId_LAC1);
 }
 
 /* Paging by LAC */
 testcase TC_paging_imsi_nochan_lac() runs on test_CT {
 	var template BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := { cIl_LAC := { ts_BSSMAP_CI_LAC(cid.lac) } };
-	f_pageing_helper('001010000000010'H, cid_list);
+	f_pageing_helper('001010000000010'H, cid_list, c_BtsId_LAC1);
 }
 
 /* Paging by "all in BSS" */
 testcase TC_paging_imsi_nochan_all() runs on test_CT {
 	var template BSSMAP_FIELD_CellIdentificationList cid_list;
 	cid_list := { cIl_allInBSS := ''O };
-	f_pageing_helper('001010000000011'H, cid_list);
+	f_pageing_helper('001010000000011'H, cid_list, c_BtsId_all);
 }
 
 /* Paging by PLMN+LAC+RNC */
@@ -749,7 +784,7 @@
 	var BSSMAP_FIELD_CellIdentificationList cid_list;
 	timer T := 4.0;
 	cid_list := valueof(ts_BSSMAP_CIL_noCell);
-	f_pageing_helper('001010123456789'H, cid_list);
+	f_pageing_helper('001010123456789'H, cid_list, c_BtsId_all);
 
 	/* tell BSC there is no paging space anymore */
 	f_ipa_tx(0, ts_RSL_PAGING_LOAD_IND(0));
@@ -773,7 +808,7 @@
 	var BSSMAP_FIELD_CellIdentificationList cid_list;
 	timer T := 3.0;
 	cid_list := valueof(ts_BSSMAP_CIL_noCell);
-	f_pageing_helper('001010123456789'H, cid_list);
+	f_pageing_helper('001010123456789'H, cid_list, c_BtsId_all);
 
 	/* Perform a BSSMAP Reset and wait for ACK */
 	BSSAP.send(ts_BSSAP_UNITDATA_req(g_sccp_addr_peer, g_sccp_addr_own, ts_BSSMAP_Reset(0)));
@@ -792,6 +827,14 @@
 		setverdict(fail, "Received PAGING after A-RESET");
 		self.stop;
 		}
+	[] IPA_RSL[1].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(?))) {
+		setverdict(fail, "Received PAGING after A-RESET");
+		self.stop;
+		}
+	[] IPA_RSL[2].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(?))) {
+		setverdict(fail, "Received PAGING after A-RESET");
+		self.stop;
+		}
 	[] T.timeout {
 		setverdict(pass);
 		}
diff --git a/bsc/osmo-bsc.cfg b/bsc/osmo-bsc.cfg
index 488ba09..ac1553e 100644
--- a/bsc/osmo-bsc.cfg
+++ b/bsc/osmo-bsc.cfg
@@ -176,6 +176,186 @@
    timeslot 7
     phys_chan_config PDCH
     hopping enabled 0
+ bts 1
+  type sysmobts
+  band DCS1800
+  cell_identity 1
+  location_area_code 2
+  dtx uplink force
+  dtx downlink
+  base_station_id_code 63
+  ms max power 15
+  cell reselection hysteresis 4
+  rxlev access min 0
+  radio-link-timeout 32
+  channel allocator ascending
+  rach tx integer 9
+  rach max transmission 7
+  channel-descrption attach 1
+  channel-descrption bs-pa-mfrms 5
+  channel-descrption bs-ag-blks-res 1
+  early-classmark-sending forbidden
+  ip.access unit_id 1235 0
+  oml ip.access stream_id 255 line 0
+  neighbor-list mode manual-si5
+  neighbor-list add arfcn 100
+  neighbor-list add arfcn 200
+  si5 neighbor-list add arfcn 10
+  si5 neighbor-list add arfcn 20
+  codec-support fr
+  gprs mode gprs
+  gprs 11bit_rach_support_for_egprs 0
+  gprs routing area 0
+  gprs network-control-order nc0
+  gprs cell bvci 1235
+  gprs cell timer blocking-timer 3
+  gprs cell timer blocking-retries 3
+  gprs cell timer unblocking-retries 3
+  gprs cell timer reset-timer 3
+  gprs cell timer reset-retries 3
+  gprs cell timer suspend-timer 10
+  gprs cell timer suspend-retries 3
+  gprs cell timer resume-timer 10
+  gprs cell timer resume-retries 3
+  gprs cell timer capability-update-timer 10
+  gprs cell timer capability-update-retries 3
+  gprs nsei 1235
+  gprs ns timer tns-block 3
+  gprs ns timer tns-block-retries 3
+  gprs ns timer tns-reset 3
+  gprs ns timer tns-reset-retries 3
+  gprs ns timer tns-test 30
+  gprs ns timer tns-alive 3
+  gprs ns timer tns-alive-retries 10
+  gprs nsvc 0 nsvci 1235
+  gprs nsvc 0 local udp port 23000
+  gprs nsvc 0 remote udp port 23000
+  gprs nsvc 0 remote ip 192.168.100.239
+  gprs nsvc 1 nsvci 0
+  gprs nsvc 1 local udp port 0
+  gprs nsvc 1 remote udp port 0
+  gprs nsvc 1 remote ip 0.0.0.0
+  no force-combined-si
+  trx 0
+   rf_locked 0
+   arfcn 871
+   nominal power 23
+   max_power_red 20
+   rsl e1 tei 0
+   timeslot 0
+    phys_chan_config CCCH+SDCCH4
+    hopping enabled 0
+   timeslot 1
+    phys_chan_config TCH/F
+    hopping enabled 0
+   timeslot 2
+    phys_chan_config TCH/F
+    hopping enabled 0
+   timeslot 3
+    phys_chan_config TCH/F
+    hopping enabled 0
+   timeslot 4
+    phys_chan_config TCH/F
+    hopping enabled 0
+   timeslot 5
+    phys_chan_config TCH/F
+    hopping enabled 0
+   timeslot 6
+    phys_chan_config PDCH
+    hopping enabled 0
+   timeslot 7
+    phys_chan_config PDCH
+    hopping enabled 0
+ bts 2
+  type sysmobts
+  band DCS1800
+  cell_identity 1
+  location_area_code 1
+  dtx uplink force
+  dtx downlink
+  base_station_id_code 63
+  ms max power 15
+  cell reselection hysteresis 4
+  rxlev access min 0
+  radio-link-timeout 32
+  channel allocator ascending
+  rach tx integer 9
+  rach max transmission 7
+  channel-descrption attach 1
+  channel-descrption bs-pa-mfrms 5
+  channel-descrption bs-ag-blks-res 1
+  early-classmark-sending forbidden
+  ip.access unit_id 1236 0
+  oml ip.access stream_id 255 line 0
+  neighbor-list mode manual-si5
+  neighbor-list add arfcn 100
+  neighbor-list add arfcn 200
+  si5 neighbor-list add arfcn 10
+  si5 neighbor-list add arfcn 20
+  codec-support fr
+  gprs mode gprs
+  gprs 11bit_rach_support_for_egprs 0
+  gprs routing area 0
+  gprs network-control-order nc0
+  gprs cell bvci 1236
+  gprs cell timer blocking-timer 3
+  gprs cell timer blocking-retries 3
+  gprs cell timer unblocking-retries 3
+  gprs cell timer reset-timer 3
+  gprs cell timer reset-retries 3
+  gprs cell timer suspend-timer 10
+  gprs cell timer suspend-retries 3
+  gprs cell timer resume-timer 10
+  gprs cell timer resume-retries 3
+  gprs cell timer capability-update-timer 10
+  gprs cell timer capability-update-retries 3
+  gprs nsei 1236
+  gprs ns timer tns-block 3
+  gprs ns timer tns-block-retries 3
+  gprs ns timer tns-reset 3
+  gprs ns timer tns-reset-retries 3
+  gprs ns timer tns-test 30
+  gprs ns timer tns-alive 3
+  gprs ns timer tns-alive-retries 10
+  gprs nsvc 0 nsvci 1236
+  gprs nsvc 0 local udp port 23000
+  gprs nsvc 0 remote udp port 23000
+  gprs nsvc 0 remote ip 192.168.100.239
+  gprs nsvc 1 nsvci 0
+  gprs nsvc 1 local udp port 0
+  gprs nsvc 1 remote udp port 0
+  gprs nsvc 1 remote ip 0.0.0.0
+  no force-combined-si
+  trx 0
+   rf_locked 0
+   arfcn 871
+   nominal power 23
+   max_power_red 20
+   rsl e1 tei 0
+   timeslot 0
+    phys_chan_config CCCH+SDCCH4
+    hopping enabled 0
+   timeslot 1
+    phys_chan_config TCH/F
+    hopping enabled 0
+   timeslot 2
+    phys_chan_config TCH/F
+    hopping enabled 0
+   timeslot 3
+    phys_chan_config TCH/F
+    hopping enabled 0
+   timeslot 4
+    phys_chan_config TCH/F
+    hopping enabled 0
+   timeslot 5
+    phys_chan_config TCH/F
+    hopping enabled 0
+   timeslot 6
+    phys_chan_config PDCH
+    hopping enabled 0
+   timeslot 7
+    phys_chan_config PDCH
+    hopping enabled 0
 msc 0
  ip.access rtp-base 4000
  timeout-ping 20
diff --git a/library/BSSMAP_Templates.ttcn b/library/BSSMAP_Templates.ttcn
index 22fefdd..54e3f79 100644
--- a/library/BSSMAP_Templates.ttcn
+++ b/library/BSSMAP_Templates.ttcn
@@ -449,7 +449,7 @@
 }
 
 private function f_enc_mcc_mnc(GsmMcc mcc, GsmMnc mnc) return OCT3 {
-	return hex2oct(mcc[1] & mcc[0] & mnc[0] & mnc[3] & mnc[2]);
+	return hex2oct(mcc[1] & mcc[0] & mnc[0] & mnc[2] & mnc[1]);
 }
 
 template BSSMAP_FIELD_CellIdentification_CGI ts_BSSMAP_CI_CGI(GsmMcc mcc, GsmMnc mnc, GsmLac lac, GsmCellId ci) := {
diff --git a/mgw/RTP_CodecPort.ttcn b/library/RTP_CodecPort.ttcn
similarity index 100%
rename from mgw/RTP_CodecPort.ttcn
rename to library/RTP_CodecPort.ttcn
diff --git a/library/RTP_CodecPort_CtrlFunct.ttcn b/library/RTP_CodecPort_CtrlFunct.ttcn
new file mode 100644
index 0000000..9f6cad2
--- /dev/null
+++ b/library/RTP_CodecPort_CtrlFunct.ttcn
@@ -0,0 +1,44 @@
+module RTP_CodecPort_CtrlFunct {
+
+  import from RTP_CodecPort all;
+  import from IPL4asp_Types all;
+
+  external function f_IPL4_listen(
+    inout RTP_CODEC_PT portRef,
+    in HostName locName,
+    in PortNumber locPort,
+    in ProtoTuple proto,
+    in OptionList options := {}
+  ) return Result;
+
+  external function f_IPL4_connect(
+    inout RTP_CODEC_PT portRef,
+    in HostName remName,
+    in PortNumber remPort,
+    in HostName locName,
+    in PortNumber locPort,
+    in ConnectionId connId,
+    in ProtoTuple proto,
+    in OptionList options := {}
+  ) return Result;
+
+  external function f_IPL4_close(
+    inout RTP_CODEC_PT portRef,
+    in ConnectionId id,
+    in ProtoTuple proto := { unspecified := {} }
+  ) return Result;
+
+  external function f_IPL4_setUserData(
+    inout RTP_CODEC_PT portRef,
+    in ConnectionId id,
+    in UserData userData
+  ) return Result;
+
+  external function f_IPL4_getUserData(
+    inout RTP_CODEC_PT portRef,
+    in ConnectionId id,
+    out UserData userData
+  ) return Result;
+
+}
+
diff --git a/library/RTP_CodecPort_CtrlFunctDef.cc b/library/RTP_CodecPort_CtrlFunctDef.cc
new file mode 100644
index 0000000..ce8e176
--- /dev/null
+++ b/library/RTP_CodecPort_CtrlFunctDef.cc
@@ -0,0 +1,56 @@
+#include "IPL4asp_PortType.hh"
+#include "RTP_CodecPort.hh"
+#include "IPL4asp_PT.hh"
+
+namespace RTP__CodecPort__CtrlFunct {
+
+  IPL4asp__Types::Result f__IPL4__listen(
+    RTP__CodecPort::RTP__CODEC__PT& portRef,
+    const IPL4asp__Types::HostName& locName,
+    const IPL4asp__Types::PortNumber& locPort,
+    const IPL4asp__Types::ProtoTuple& proto,
+    const IPL4asp__Types::OptionList& options)
+  {
+    return f__IPL4__PROVIDER__listen(portRef, locName, locPort, proto, options);
+  }
+  
+  IPL4asp__Types::Result f__IPL4__connect(
+    RTP__CodecPort::RTP__CODEC__PT& portRef,
+    const IPL4asp__Types::HostName& remName,
+    const IPL4asp__Types::PortNumber& remPort,
+    const IPL4asp__Types::HostName& locName,
+    const IPL4asp__Types::PortNumber& locPort,
+    const IPL4asp__Types::ConnectionId& connId,
+    const IPL4asp__Types::ProtoTuple& proto,
+    const IPL4asp__Types::OptionList& options)
+  {
+    return f__IPL4__PROVIDER__connect(portRef, remName, remPort,
+                                      locName, locPort, connId, proto, options);
+  }
+
+  IPL4asp__Types::Result f__IPL4__close(
+    RTP__CodecPort::RTP__CODEC__PT& portRef, 
+    const IPL4asp__Types::ConnectionId& connId, 
+    const IPL4asp__Types::ProtoTuple& proto)
+  {
+      return f__IPL4__PROVIDER__close(portRef, connId, proto);
+  }
+
+  IPL4asp__Types::Result f__IPL4__setUserData(
+    RTP__CodecPort::RTP__CODEC__PT& portRef,
+    const IPL4asp__Types::ConnectionId& connId,
+    const IPL4asp__Types::UserData& userData)
+  {
+    return f__IPL4__PROVIDER__setUserData(portRef, connId, userData);
+  }
+  
+  IPL4asp__Types::Result f__IPL4__getUserData(
+    RTP__CodecPort::RTP__CODEC__PT& portRef,
+    const IPL4asp__Types::ConnectionId& connId,
+    IPL4asp__Types::UserData& userData)
+  {
+    return f__IPL4__PROVIDER__getUserData(portRef, connId, userData);
+  }
+  
+}
+
diff --git a/library/RTP_Emulation.ttcn b/library/RTP_Emulation.ttcn
new file mode 100644
index 0000000..b8b1dbe
--- /dev/null
+++ b/library/RTP_Emulation.ttcn
@@ -0,0 +1,209 @@
+module RTP_Emulation {
+
+/* Functionalities that we want this module to imeplement:
+ *  * act as a RTP source that generates a RTP Stream
+ *  * act asaa RTP sink that consumes a RTP Stream
+ *
+ * for all of the above, we want to be able to 
+ *  * specify the payload type
+ *  * specify the interval / sample rate
+ *  * create drop-outs in the stream
+ *  * detect reordered or lost frames
+ *  * validate if the size of the frames matches epectations
+ *  * play back real audio (at least some tones?)
+ *  * enable/disable generation/verification of RTCP
+ */
+
+import from General_Types all;
+import from Osmocom_Types all;
+import from IPL4asp_Types all;
+import from RTP_Types all;
+import from RTP_CodecPort all;
+import from RTP_CodecPort_CtrlFunct all;
+
+type component RTP_Emulation_CT {
+	/* down-facing ports for RTP and RTCP codec ports on top of IPL4asp */
+	port RTP_CODEC_PT RTP;
+	var integer g_rtp_conn_id := -1;
+	port RTP_CODEC_PT RTCP;
+	var integer g_rtcp_conn_id := -1;
+
+	/* user-facing port for controlling the binding */
+	port RTPEM_CTRL_PT CTRL;
+
+	/* configurable by user, should be fixed */
+	var INT7b g_tx_payload_type := 0;
+	var integer g_tx_samplerate_hz := 8000;
+	var integer g_tx_duration_ms := 20;
+	var BIT32_BO_LAST g_tx_ssrc := hex2bit('DEADBEEF'H);
+
+	var HostName g_remote_host;
+	var PortNumber g_remote_port;
+	var HostName g_local_host;
+	var PortNumber g_local_port;
+
+	/* state variables, change over time */
+	var boolean g_rx_enabled := false;
+	var LIN2_BO_LAST g_tx_next_seq := 0;
+	var uint32_t g_tx_next_ts := 0;
+
+	var INT7b g_rx_payload_type := 0;
+	var LIN2_BO_LAST g_rx_last_seq;
+	var uint32_t g_rx_last_ts;
+}
+
+type enumerated RtpemMode {
+	RTPEM_MODE_NONE,
+	RTPEM_MODE_TXONLY,
+	RTPEM_MODE_RXONLY,
+	RTPEM_MODE_BIDIR
+};
+
+signature RTPEM_bind(in HostName local_host, inout PortNumber local_port);
+signature RTPEM_connect(in HostName remote_host, in PortNumber remote_port);
+signature RTPEM_mode(in RtpemMode mode);
+
+type port RTPEM_CTRL_PT procedure {
+	inout RTPEM_bind, RTPEM_connect, RTPEM_mode;
+} with { extension "internal" };
+
+template PDU_RTP ts_RTP(BIT32_BO_LAST ssrc, INT7b pt, LIN2_BO_LAST seq, uint32_t ts,
+			octetstring payload, BIT1 marker := '0'B) := {
+	version := 2,
+	padding_ind := '0'B,
+	extension_ind := '0'B,
+	CSRC_count := 0,
+	marker_bit := marker,
+	payload_type := pt,
+	sequence_number := seq,
+	time_stamp := int2bit(ts, 4),
+	SSRC_id := ssrc,
+	CSRCs := omit,
+	ext_header := omit,
+	data := payload
+}
+
+private function f_tx_rtp(octetstring payload, BIT1 marker := '0'B) runs on RTP_Emulation_CT {
+	var PDU_RTP rtp := valueof(ts_RTP(g_tx_ssrc, g_tx_payload_type, g_tx_next_seq,
+					  g_tx_next_ts, payload, marker));
+	RTP.send(t_RTP_Send(g_rtp_conn_id, RTP_messages_union:{rtp:=rtp}));
+	/* increment sequence + timestamp for next transmit */
+	g_tx_next_seq := g_tx_next_seq + 1;
+	g_tx_next_ts := g_tx_next_ts + (g_tx_samplerate_hz mod (1000 mod g_tx_duration_ms));
+}
+
+function f_main() runs on RTP_Emulation_CT
+{
+	var Result res;
+
+	timer T_transmit := 1000.0/int2float(g_tx_duration_ms);
+	var RTP_RecvFrom rx_rtp;
+	var template RTP_RecvFrom tr := {
+		connId := ?,
+		remName := ?,
+		remPort := ?,
+		locName := ?,
+		locPort := ?,
+		msg := ?
+	};
+	var template RTP_RecvFrom tr_rtp := tr;
+	var template RTP_RecvFrom tr_rtcp := tr;
+	tr_rtp.connId := g_rtp_conn_id;
+	tr_rtp.msg := { rtp := ? };
+	tr_rtp.connId := g_rtcp_conn_id;
+	tr_rtcp.msg := { rtcp := ? };
+
+	while (true) {
+	alt {
+		/* control procedures (calls) from the user */
+		[] CTRL.getcall(RTPEM_bind:{?,?}) -> param(g_local_host, g_local_port) {
+			if (g_local_port rem 2 == 1) {
+				//CTRL.raise(RTPEM_bind, "Local Port is not an even port number!");
+				log("Local Port is not an even port number!");
+				continue;
+			}
+			res := RTP_CodecPort_CtrlFunct.f_IPL4_listen(RTP, g_local_host,
+								g_local_port, {udp:={}});
+			g_rtp_conn_id := res.connId;
+			res := RTP_CodecPort_CtrlFunct.f_IPL4_listen(RTP, g_local_host,
+								g_local_port+1, {udp:={}});
+			g_rtcp_conn_id := res.connId;
+			CTRL.reply(RTPEM_bind:{g_local_host, g_local_port});
+		}
+		[] CTRL.getcall(RTPEM_connect:{?,?}) -> param (g_remote_host, g_remote_port) {
+			if (g_remote_port rem 2 == 1) {
+				//CTRL.raise(RTPEM_connect, "Remote Port is not an even number!");
+				log("Remote Port is not an even number!");
+				continue;
+			}
+			res := RTP_CodecPort_CtrlFunct.f_IPL4_connect(RTP, g_remote_host,
+								g_remote_port,
+								g_local_host, g_local_port,
+								g_rtp_conn_id, {udp:={}});
+			res := RTP_CodecPort_CtrlFunct.f_IPL4_connect(RTCP, g_remote_host,
+								g_remote_port+1,
+								g_local_host, g_local_port+1,
+								g_rtcp_conn_id, {udp:={}});
+			CTRL.reply(RTPEM_connect:{g_remote_host, g_remote_port});
+		}
+		[] CTRL.getcall(RTPEM_mode:{RTPEM_MODE_NONE}) {
+			T_transmit.stop;
+			g_rx_enabled := false;
+		}
+		[] CTRL.getcall(RTPEM_mode:{RTPEM_MODE_TXONLY}) {
+			/* start transmit timer */
+			T_transmit.start;
+			g_rx_enabled := false;
+		}
+		[] CTRL.getcall(RTPEM_mode:{RTPEM_MODE_RXONLY}) {
+
+			T_transmit.stop;
+			if (g_rx_enabled == false) {
+				/* flush queues */
+				RTP.clear;
+				RTCP.clear;
+				g_rx_enabled := true;
+			}
+		}
+		[] CTRL.getcall(RTPEM_mode:{RTPEM_MODE_BIDIR}) {
+			T_transmit.start;
+			if (g_rx_enabled == false) {
+				/* flush queues */
+				RTP.clear;
+				RTCP.clear;
+				g_rx_enabled := true;
+			}
+		}
+
+		/* simply ignore any RTTP/RTCP if receiver not enabled */
+		[g_rx_enabled==false] RTP.receive(tr_rtp) { }
+		[g_rx_enabled==false] RTCP.receive(tr_rtp) { }
+
+		/* process received RTCP/RTP if receiver enabled */
+		[g_rx_enabled] RTP.receive(tr_rtp) -> value rx_rtp {
+			log("RX RTP: ", rx_rtp);
+		}
+		[g_rx_enabled] RTCP.receive(tr_rtcp) -> value rx_rtp {
+			log("RX RTCP: ", rx_rtp);
+		}
+
+		/* transmit if timer has expired */
+		[] T_transmit.timeout {
+			/* send one RTP frame, re-start timer */
+			f_tx_rtp('01020304'O);
+			T_transmit.start;
+		}
+
+		/* fail on any unexpected messages */
+		[] RTP.receive {
+			setverdict(fail, "Received unexpected type from RTP");
+		}
+		[] RTCP.receive {
+			setverdict(fail, "Received unexpected type from RTCP");
+		}
+	}
+	}
+}
+
+
+}
diff --git a/mgw/gen_links.sh b/mgw/gen_links.sh
index 0b8195e..acdeb40 100755
--- a/mgw/gen_links.sh
+++ b/mgw/gen_links.sh
@@ -37,5 +37,5 @@
 gen_links $DIR $FILES
 
 DIR=../library
-FILES="General_Types.ttcn Osmocom_Types.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc"
+FILES="General_Types.ttcn Osmocom_Types.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc RTP_CodecPort.ttcn"
 gen_links $DIR $FILES