Holger Hans Peter Freyther wrote:

hi holger,
+#define MNCC_RTP_CREATE                0x0204
+#define MNCC_RTP_CONNECT       0x0205
+#define MNCC_RTP_FREE          0x0206
Increase the version. We have a uint32_t for the version number and
it will take a while to overflow it.
i already did it. but thanks for reminding me, so i did it also for the attached patch: 0001-Complete-definitions-for-all-speech-traffic-frames-a.patch
+       RTP_PROXY, /* forward from BTS to BTS */
+       RTP_RECV_UPSTREAM, /* forward to L4 application */
+       RTP_RECV_L4, /* receive RTP frames from L4 application */
L4? is that the best name you can think off?
for signalling messages (mncc application) it makes sense. for rtp it might lead to misunderstanding i changed that in the attached patch: 0006-Adding-traffic-forwarding-via-RTP-to-remote-applicat.patch
There are already methods for "is IP based BTS", "is E1 based BTS". Couldn't
you use them here?
makes sense. i updated the patch above using this is_e1_bts() macro.
+       /* L4 uses RTP for this transaction, we send our data via RTP,
+        * otherwise we send it through MNCC interface */
+       if (msg_type == GSM_TCHF_FRAME
+        || msg_type == GSM_TCHF_FRAME_EFR
+        || msg_type == GSM_TCHH_FRAME
+        || msg_type == GSM_TCH_FRAME_AMR
+        || msg_type == GSM_BAD_FRAME) {

I have seen lchan->type checks and message type checks like these as well.
Could you create a predicate function that check mncc_is_audio_message(), or
lchan_voice_chan?
this was already done mncc_is_data_frame() check in a later patch of jolly/testing branch. i rebased my testing branch, so the patch is prior the other patches now: (see 0002-Use-helper-function-to-check-if-an-MNCC-frame-is-dat.patch).


the other patches changed a bit, due to rebase and some other improvements. i do not want to post them again, so please refer to jolly/testing branch. if wanted, i will post them.


best regards,

andreas

>From 3829e397b55f14023956a9c4c03a5563096dfcc9 Mon Sep 17 00:00:00 2001
From: Andreas Eversberg <[email protected]>
Date: Fri, 31 Jan 2014 09:02:01 +0100
Subject: [PATCH 1/9] Complete definitions for all speech traffic frames at
 MNCC interface

The new definitions are: half rate and AMR

Change of definition name for bad frame, because it applies to all types of
traffic, not only TCH/F.

Increase MNCC interface version to 4.
---
 openbsc/include/openbsc/mncc.h | 6 ++++--
 openbsc/src/libmsc/mncc.c      | 6 +++++-
 openbsc/src/libtrau/trau_mux.c | 2 +-
 openbsc/tests/trau/trau_test.c | 2 +-
 4 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index ffc247b..c61f6b8 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -95,7 +95,9 @@ struct gsm_call {
 
 #define GSM_TCHF_FRAME		0x0300
 #define GSM_TCHF_FRAME_EFR	0x0301
-#define GSM_TCHF_BAD_FRAME	0x03ff
+#define GSM_TCHH_FRAME		0x0302
+#define GSM_TCH_FRAME_AMR	0x0303
+#define GSM_BAD_FRAME		0x03ff
 
 #define MNCC_SOCKET_HELLO	0x0400
 
@@ -161,7 +163,7 @@ struct gsm_data_frame {
 	unsigned char	data[0];
 };
 
-#define MNCC_SOCK_VERSION	2
+#define MNCC_SOCK_VERSION	4
 struct gsm_mncc_hello {
 	uint32_t	msg_type;
 	uint32_t	version;
diff --git a/openbsc/src/libmsc/mncc.c b/openbsc/src/libmsc/mncc.c
index b484772..73db5f0 100644
--- a/openbsc/src/libmsc/mncc.c
+++ b/openbsc/src/libmsc/mncc.c
@@ -84,7 +84,11 @@ static struct mncc_names {
 	{"MNCC_FRAME_DROP",	0x0202},
 	{"MNCC_LCHAN_MODIFY",	0x0203},
 
-	{"GSM_TCH_FRAME",	0x0300},
+	{"GSM_TCHF_FRAME",	0x0300},
+	{"GSM_TCHF_FRAME_EFR",	0x0301},
+	{"GSM_TCHH_FRAME",	0x0302},
+	{"GSM_TCH_FRAME_AMR",	0x0303},
+	{"GSM_BAD_FRAME",	0x03ff},
 
 	{NULL, 0} };
 
diff --git a/openbsc/src/libtrau/trau_mux.c b/openbsc/src/libtrau/trau_mux.c
index 7b9bac0..fd1895f 100644
--- a/openbsc/src/libtrau/trau_mux.c
+++ b/openbsc/src/libtrau/trau_mux.c
@@ -314,7 +314,7 @@ struct msgb *trau_decode_efr(uint32_t callref,
 	return msg;
 
 bad_frame:
-	frame->msg_type = GSM_TCHF_BAD_FRAME;
+	frame->msg_type = GSM_BAD_FRAME;
 
 	return msg;
 }
diff --git a/openbsc/tests/trau/trau_test.c b/openbsc/tests/trau/trau_test.c
index f8a48db..b95f1e8 100644
--- a/openbsc/tests/trau/trau_test.c
+++ b/openbsc/tests/trau/trau_test.c
@@ -57,7 +57,7 @@ void test_trau_fr_efr(unsigned char *data)
 	msg = trau_decode_efr(1, &tf);
 	OSMO_ASSERT(msg != NULL);
 	frame = (struct gsm_data_frame *)msg->data;
-	OSMO_ASSERT(frame->msg_type == GSM_TCHF_BAD_FRAME);
+	OSMO_ASSERT(frame->msg_type == GSM_BAD_FRAME);
 	msgb_free(msg);
 }
 
-- 
1.8.1.5

>From 3216e51fa3467b6683368af7991789d0469444ea Mon Sep 17 00:00:00 2001
From: Andreas Eversberg <[email protected]>
Date: Mon, 11 Mar 2013 08:12:43 +0100
Subject: [PATCH 2/9] Use helper function to check if an MNCC frame is data
 (speech/traffic)

Rename method mncc_rcv_tchf() to mncc_rcv_data(), because the check applies
to all types of data frames, not only TCH/F data.
---
 openbsc/include/openbsc/mncc.h    |  8 ++++++++
 openbsc/src/libmsc/mncc_builtin.c | 22 ++++++++--------------
 openbsc/src/libmsc/mncc_sock.c    |  3 +--
 3 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index c61f6b8..ffac7fd 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -191,4 +191,12 @@ int mncc_sock_from_cc(struct gsm_network *net, struct msgb *msg);
 
 int mncc_sock_init(struct gsm_network *gsmnet);
 
+#define mncc_is_data_frame(msg_type) \
+	(msg_type == GSM_TCHF_FRAME \
+		|| msg_type == GSM_TCHF_FRAME_EFR \
+		|| msg_type == GSM_TCHH_FRAME \
+		|| msg_type == GSM_TCH_FRAME_AMR \
+		|| msg_type == GSM_BAD_FRAME)
+
+
 #endif
diff --git a/openbsc/src/libmsc/mncc_builtin.c b/openbsc/src/libmsc/mncc_builtin.c
index be35454..a5a463b 100644
--- a/openbsc/src/libmsc/mncc_builtin.c
+++ b/openbsc/src/libmsc/mncc_builtin.c
@@ -273,8 +273,8 @@ static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *re
 	return 0;
 }
 
-/* receiving a TCH/F frame from the BSC code */
-static int mncc_rcv_tchf(struct gsm_call *call, int msg_type,
+/* receiving a (speech) traffic frame from the BSC code */
+static int mncc_rcv_data(struct gsm_call *call, int msg_type,
 			 struct gsm_data_frame *dfr)
 {
 	struct gsm_trans *remote_trans;
@@ -339,16 +339,14 @@ int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
 		DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
 	}
 
-	switch (msg_type) {
-	case GSM_TCHF_FRAME:
-	case GSM_TCHF_FRAME_EFR:
-		break;
-	default:
-		DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
-			get_mncc_name(msg_type));
-		break;
+	if (mncc_is_data_frame(msg_type)) {
+		rc = mncc_rcv_data(call, msg_type, arg);
+		goto out_free;
 	}
 
+	DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
+		get_mncc_name(msg_type));
+
 	switch(msg_type) {
 	case MNCC_SETUP_IND:
 		rc = mncc_setup_ind(call, msg_type, arg);
@@ -408,10 +406,6 @@ int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
 			call->callref, data->cause.value);
 		rc = mncc_tx_to_cc(net, MNCC_RETRIEVE_REJ, data);
 		break;
-	case GSM_TCHF_FRAME:
-	case GSM_TCHF_FRAME_EFR:
-		rc = mncc_rcv_tchf(call, msg_type, arg);
-		break;
 	default:
 		LOGP(DMNCC, LOGL_NOTICE, "(call %x) Message unhandled\n", callref);
 		break;
diff --git a/openbsc/src/libmsc/mncc_sock.c b/openbsc/src/libmsc/mncc_sock.c
index cf4bca8..dd0a44f 100644
--- a/openbsc/src/libmsc/mncc_sock.c
+++ b/openbsc/src/libmsc/mncc_sock.c
@@ -54,8 +54,7 @@ int mncc_sock_from_cc(struct gsm_network *net, struct msgb *msg)
 	if (net->mncc_state->conn_bfd.fd < 0) {
 		LOGP(DMNCC, LOGL_ERROR, "mncc_sock receives %s for external CC app "
 			"but socket is gone\n", get_mncc_name(msg_type));
-		if (msg_type != GSM_TCHF_FRAME &&
-		    msg_type != GSM_TCHF_FRAME_EFR) {
+		if (!mncc_is_data_frame(msg_type)) {
 			/* release the request */
 			struct gsm_mncc mncc_out;
 			memset(&mncc_out, 0, sizeof(mncc_out));
-- 
1.8.1.5

>From 30cfa4df77810479031f007abb6cefab91020eb0 Mon Sep 17 00:00:00 2001
From: Andreas Eversberg <[email protected]>
Date: Mon, 16 Jan 2012 09:29:28 +0100
Subject: [PATCH 6/9] Adding traffic forwarding via RTP to remote application

Instead of forwarding traffic through MNCC interface, traffic can
be forwarded to a given RTP peer directly. A special MNCC message
is used to control the peer's destination. The traffic can still be
forwarded through MNCC interface when this special MNCC message is
not used.

It also works with E1 based BTSs.

In conjunction with LCR's "rtp-bridge" feature, the RTP traffic
can be directly exchanged with a remote SIP endpoint, so that the
traffic is not forwarded by LCR itself. This way the performance
of handling traffic only depends on OpenBSC and the remote SIP
endpoint. Also the traffic is exchanged with the SIP endpoint
without transcoding, to have maximum performance.

Increment MNCC version to 5.
---
 openbsc/include/openbsc/gsm_04_08.h    |   3 +
 openbsc/include/openbsc/mncc.h         |  12 +-
 openbsc/include/openbsc/rtp_proxy.h    |   5 +-
 openbsc/include/openbsc/transaction.h  |   2 +
 openbsc/src/ipaccess/ipaccess-config.c |   6 +
 openbsc/src/libbsc/bsc_api.c           |   1 +
 openbsc/src/libbsc/handover_logic.c    |   1 +
 openbsc/src/libmsc/gsm_04_08.c         | 199 ++++++++++++++++++++++++++-------
 openbsc/src/libmsc/mncc_sock.c         |  14 +++
 openbsc/src/libmsc/transaction.c       |   1 +
 openbsc/src/libtrau/rtp_proxy.c        |  20 +++-
 openbsc/src/libtrau/trau_mux.c         |  14 ++-
 openbsc/src/utils/bs11_config.c        |   6 +
 openbsc/tests/abis/abis_test.c         |   6 +
 openbsc/tests/gbproxy/gbproxy_test.c   |   6 +
 15 files changed, 253 insertions(+), 43 deletions(-)

diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 8df7b73..93348d1 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -6,6 +6,7 @@
 #include <osmocom/gsm/protocol/gsm_04_08.h>
 
 #include <openbsc/meas_rep.h>
+#include <openbsc/mncc.h>
 
 struct msgb;
 struct gsm_bts;
@@ -75,4 +76,6 @@ void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
 void release_security_operation(struct gsm_subscriber_connection *conn);
 void allocate_security_operation(struct gsm_subscriber_connection *conn);
 
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data);
+
 #endif
diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index ffac7fd..32a60e9 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -92,6 +92,9 @@ struct gsm_call {
 #define MNCC_FRAME_RECV		0x0201
 #define MNCC_FRAME_DROP		0x0202
 #define MNCC_LCHAN_MODIFY	0x0203
+#define MNCC_RTP_CREATE		0x0204
+#define MNCC_RTP_CONNECT	0x0205
+#define MNCC_RTP_FREE		0x0206
 
 #define GSM_TCHF_FRAME		0x0300
 #define GSM_TCHF_FRAME_EFR	0x0301
@@ -163,7 +166,7 @@ struct gsm_data_frame {
 	unsigned char	data[0];
 };
 
-#define MNCC_SOCK_VERSION	4
+#define MNCC_SOCK_VERSION	5
 struct gsm_mncc_hello {
 	uint32_t	msg_type;
 	uint32_t	version;
@@ -179,6 +182,13 @@ struct gsm_mncc_hello {
 	uint32_t	lchan_type_offset;
 };
 
+struct gsm_mncc_rtp {
+	uint32_t	msg_type;
+	uint32_t	callref;
+	uint32_t	ip;
+	uint16_t	port;
+};
+
 char *get_mncc_name(int value);
 void mncc_set_cause(struct gsm_mncc *data, int loc, int val);
 void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg);
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
index 52ffefd..a5f6a2b 100644
--- a/openbsc/include/openbsc/rtp_proxy.h
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -40,8 +40,9 @@
 
 enum rtp_rx_action {
 	RTP_NONE,
-	RTP_PROXY,
-	RTP_RECV_UPSTREAM,
+	RTP_PROXY, /* forward from BTS to BTS */
+	RTP_RECV_UPSTREAM, /* forward to application */
+	RTP_RECV_APP, /* receive RTP frames from application */
 };
 
 enum rtp_tx_action {
diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index b6c859c..db3a5cf 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -28,6 +28,7 @@ struct gsm_trans {
 
 	/* reference from MNCC or other application */
 	uint32_t callref;
+	uint32_t callref_keep; /* to remember callref, even if it is removed */
 
 	/* if traffic channel receive was requested */
 	int tch_recv;
@@ -46,6 +47,7 @@ struct gsm_trans {
 			int T308_second;	/* used to send release again */
 			struct osmo_timer_list timer;
 			struct gsm_mncc msg;	/* stores setup/disconnect/release message */
+			struct rtp_socket *rs;	/* application traffic via RTP */
 		} cc;
 		struct {
 			struct gsm411_smc_inst smc_inst;
diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c
index c42c7bb..68b9131 100644
--- a/openbsc/src/ipaccess/ipaccess-config.c
+++ b/openbsc/src/ipaccess/ipaccess-config.c
@@ -87,6 +87,12 @@ static uint8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00,
 static uint8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 };
 */
 
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+	return 0;
+}
+
 extern int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what);
 extern struct e1inp_line_ops ipaccess_e1inp_line_ops;
 
diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c
index e567038..e6629ff 100644
--- a/openbsc/src/libbsc/bsc_api.c
+++ b/openbsc/src/libbsc/bsc_api.c
@@ -31,6 +31,7 @@
 #include <openbsc/handover.h>
 #include <openbsc/debug.h>
 #include <openbsc/gsm_04_08.h>
+#include <osmocom/abis/trau_frame.h>
 #include <openbsc/trau_mux.h>
 
 #include <osmocom/gsm/protocol/gsm_08_08.h>
diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c
index 36a758b..e20d8f7 100644
--- a/openbsc/src/libbsc/handover_logic.c
+++ b/openbsc/src/libbsc/handover_logic.c
@@ -39,6 +39,7 @@
 #include <openbsc/signal.h>
 #include <osmocom/core/talloc.h>
 #include <openbsc/transaction.h>
+#include <osmocom/abis/trau_frame.h>
 #include <openbsc/trau_mux.h>
 
 struct bsc_handover {
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 76c47a5..5203b90 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -1359,8 +1359,15 @@ void _gsm48_cc_trans_free(struct gsm_trans *trans)
 	}
 	if (trans->cc.state != GSM_CSTATE_NULL)
 		new_cc_state(trans, GSM_CSTATE_NULL);
+	/* Be sure to unmap upstream traffic for our callref only. */
 	if (trans->conn)
-		trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref);
+		trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref_keep);
+
+	/* free application RTP socket */
+	if (trans->cc.rs) {
+		rtp_socket_free(trans->cc.rs);
+		trans->cc.rs = NULL;
+	}
 }
 
 static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
@@ -1478,6 +1485,7 @@ static int switch_for_handover(struct gsm_lchan *old_lchan,
 		new_rs->receive = old_rs->receive;
 		break;
 	case RTP_NONE:
+	case RTP_RECV_APP:
 		break;
 	}
 
@@ -1702,6 +1710,153 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)
 	return 0;
 }
 
+static int mncc_rtp_create(struct gsm_network *net, uint32_t callref,
+	struct gsm_trans *trans, struct rtp_socket *rs,
+	struct gsm_mncc_rtp *mncc)
+{
+	/* use RTP instead of MNCC socket, for traffic
+	 * open application RTP socket */
+	if (rs) {
+		LOGP(DCC, LOGL_ERROR, "RTP already created.\n");
+		return -EIO;
+	}
+	rs = trans->cc.rs = rtp_socket_create();
+	if (!rs) {
+		LOGP(DCC, LOGL_ERROR, "RTP socket creation failed.\n");
+		/* reply with IP/port = 0 */
+		mncc->ip = 0;
+		mncc->port = 0;
+		mncc_recvmsg(net, trans, MNCC_RTP_CREATE,
+			(struct gsm_mncc *)mncc);
+		return -EIO;
+	}
+	rs->rx_action = RTP_RECV_APP;
+	rs->receive.net = net;
+	rs->receive.callref = callref;
+	/* reply with bound IP/port */
+	mncc->ip = ntohl(rs->rtp.sin_local.sin_addr.s_addr);
+	mncc->port = ntohs(rs->rtp.sin_local.sin_port);
+	mncc_recvmsg(net, trans, MNCC_RTP_CREATE, (struct gsm_mncc *)mncc);
+
+	return 0;
+}
+
+static int mncc_rtp_connect(struct gsm_network *net, struct gsm_trans *trans,
+	struct rtp_socket *rs, struct gsm_mncc_rtp *mncc)
+{
+	int rc;
+
+	if (!rs) {
+		LOGP(DCC, LOGL_ERROR, "RTP not created.\n");
+		return -EIO;
+	}
+	rc = rtp_socket_connect(trans->cc.rs, mncc->ip, mncc->port);
+	if (rc < 0) {
+		LOGP(DCC, LOGL_ERROR, "RTP socket connect failed.\n");
+		/* reply with IP/port = 0 */
+		mncc->ip = 0;
+		mncc->port = 0;
+		mncc_recvmsg(net, trans, MNCC_RTP_CONNECT,
+			(struct gsm_mncc *)mncc);
+		return -EIO;
+	}
+	/* reply with local IP/port */
+	mncc->ip = ntohl(rs->rtp.sin_local.sin_addr.s_addr);
+	mncc->port = ntohs(rs->rtp.sin_local.sin_port);
+	mncc_recvmsg(net, trans, MNCC_RTP_CONNECT, (struct gsm_mncc *)mncc);
+
+	return 0;
+}
+
+static int mncc_rtp_free(struct gsm_network *net, struct gsm_trans *trans,
+	struct rtp_socket *rs, struct gsm_mncc_rtp *mncc)
+{
+	if (!rs) {
+		LOGP(DCC, LOGL_ERROR, "RTP not created.\n");
+		return -EIO;
+	}
+	rtp_socket_free(trans->cc.rs);
+	trans->cc.rs = NULL;
+	/* reply */
+	mncc_recvmsg(net, trans, MNCC_RTP_FREE, (struct gsm_mncc *)mncc);
+
+	return 0;
+}
+
+/* handle RTP requests of application */
+static int mncc_rtp(struct gsm_network *net, uint32_t callref,
+	struct gsm_mncc_rtp *mncc)
+{
+	struct rtp_socket *rs;
+	struct gsm_trans *trans;
+	int rc = -EINVAL;
+
+	/* Find callref */
+	trans = trans_find_by_callref(net, callref);
+	if (!trans) {
+		LOGP(DCC, LOGL_ERROR, "Unknown transaction for callref=%d\n",
+			callref);
+		return -EINVAL;
+	}
+
+	rs = trans->cc.rs;
+
+	switch (mncc->msg_type) {
+	case MNCC_RTP_CREATE:
+		rc = mncc_rtp_create(net, callref, trans, rs, mncc);
+		break;
+	case MNCC_RTP_CONNECT:
+		rc = mncc_rtp_connect(net, trans, rs, mncc);
+		break;
+	case MNCC_RTP_FREE:
+		rc = mncc_rtp_free(net, trans, rs, mncc);
+		break;
+	}
+
+	return rc;
+}
+
+/* handle tch frame from application */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+	struct gsm_trans *trans;
+	struct gsm_bts *bts;
+
+	/* Find callref */
+	trans = trans_find_by_callref(net, data->callref);
+	if (!trans) {
+		LOGP(DMNCC, LOGL_ERROR, "TCH frame for non-existing trans\n");
+		return -EIO;
+	}
+	if (!trans->conn) {
+		LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n");
+		return 0;
+	}
+	if (trans->conn->lchan->type != GSM_LCHAN_TCH_F
+	 && trans->conn->lchan->type != GSM_LCHAN_TCH_H) {
+		/* This should be LOGL_ERROR or NOTICE, but
+		 * unfortuantely it happens for a couple of frames at
+		 * the beginning of every RTP connection */
+		LOGP(DMNCC, LOGL_DEBUG, "TCH frame for lchan != TCH_F/TCH_H\n");
+		return 0;
+	}
+	bts = trans->conn->lchan->ts->trx->bts;
+	if (!is_e1_bts(bts)) {
+		if (!trans->conn->lchan->abis_ip.rtp_socket) {
+			DEBUGP(DMNCC, "TCH frame to lchan without RTP connection\n");
+			return 0;
+		}
+		if (trans->conn->lchan->abis_ip.rtp_socket->receive.callref != callref) {
+			/* Drop frame, if not our callref. This happens, if
+			 * the call is on hold or retrieved by another
+			 * transaction. */
+			return 0;
+		}
+		return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, data);
+	} else
+		return trau_send_frame(trans->conn->lchan, data);
+}
+
 static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
 {
 	DEBUGP(DCC, "-> STATUS ENQ\n");
@@ -2937,7 +3092,6 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
 	int i, rc = 0;
 	struct gsm_trans *trans = NULL, *transt;
 	struct gsm_subscriber_connection *conn = NULL;
-	struct gsm_bts *bts = NULL;
 	struct gsm_mncc *data = arg, rel;
 
 	DEBUGP(DMNCC, "receive message %s\n", get_mncc_name(msg_type));
@@ -2950,46 +3104,15 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
 		return tch_recv_mncc(net, data->callref, 0);
 	case MNCC_FRAME_RECV:
 		return tch_recv_mncc(net, data->callref, 1);
+	case MNCC_RTP_CREATE:
+	case MNCC_RTP_CONNECT:
+	case MNCC_RTP_FREE:
+		return mncc_rtp(net, data->callref, (struct gsm_mncc_rtp *) arg);
 	case GSM_TCHF_FRAME:
 	case GSM_TCHF_FRAME_EFR:
 	case GSM_TCHH_FRAME:
 	case GSM_TCH_FRAME_AMR:
-		/* Find callref */
-		trans = trans_find_by_callref(net, data->callref);
-		if (!trans) {
-			LOGP(DMNCC, LOGL_ERROR, "TCH frame for non-existing trans\n");
-			return -EIO;
-		}
-		log_set_context(BSC_CTX_SUBSCR, trans->subscr);
-		if (!trans->conn) {
-			LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n");
-			return 0;
-		}
-		if (trans->conn->lchan->type != GSM_LCHAN_TCH_F
-		 && trans->conn->lchan->type != GSM_LCHAN_TCH_H) {
-			/* This should be LOGL_ERROR or NOTICE, but
-			 * unfortuantely it happens for a couple of frames at
-			 * the beginning of every RTP connection */
-			LOGP(DMNCC, LOGL_DEBUG, "TCH frame for lchan != TCH_F/TCH_H\n");
-			return 0;
-		}
-		bts = trans->conn->lchan->ts->trx->bts;
-		switch (bts->type) {
-		case GSM_BTS_TYPE_NANOBTS:
-		case GSM_BTS_TYPE_OSMO_SYSMO:
-			if (!trans->conn->lchan->abis_ip.rtp_socket) {
-				DEBUGP(DMNCC, "TCH frame to lchan without RTP connection\n");
-				return 0;
-			}
-			return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, arg);
-		case GSM_BTS_TYPE_BS11:
-		case GSM_BTS_TYPE_RBS2000:
-		case GSM_BTS_TYPE_NOKIA_SITE:
-			return trau_send_frame(trans->conn->lchan, arg);
-		default:
-			LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
-		}
-		return -EINVAL;
+		return tch_frame_down(net, data->callref, (struct gsm_data_frame *) arg);
 	}
 
 	memset(&rel, 0, sizeof(struct gsm_mncc));
diff --git a/openbsc/src/libmsc/mncc_sock.c b/openbsc/src/libmsc/mncc_sock.c
index dd0a44f..adb56fc 100644
--- a/openbsc/src/libmsc/mncc_sock.c
+++ b/openbsc/src/libmsc/mncc_sock.c
@@ -37,6 +37,8 @@
 #include <openbsc/debug.h>
 #include <openbsc/mncc.h>
 #include <openbsc/gsm_data.h>
+#include <openbsc/transaction.h>
+#include <openbsc/rtp_proxy.h>
 
 struct mncc_sock_state {
 	struct gsm_network *net;
@@ -50,6 +52,18 @@ int mncc_sock_from_cc(struct gsm_network *net, struct msgb *msg)
 	struct gsm_mncc *mncc_in = (struct gsm_mncc *) msgb_data(msg);
 	int msg_type = mncc_in->msg_type;
 
+	/* application uses RTP for this transaction, we send our data via RTP,
+	 * otherwise we send it through MNCC interface */
+	if (mncc_is_data_frame(msg_type)) {
+		struct gsm_trans *trans = trans_find_by_callref(net, mncc_in->callref);
+
+		if (trans && trans->cc.rs) {
+			rtp_send_frame(trans->cc.rs, (struct gsm_data_frame *) mncc_in);
+			msgb_free(msg);
+			return 0;
+		}
+	}
+
 	/* Check if we currently have a MNCC handler connected */
 	if (net->mncc_state->conn_bfd.fd < 0) {
 		LOGP(DMNCC, LOGL_ERROR, "mncc_sock receives %s for external CC app "
diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c
index e425e67..bdd3d8e 100644
--- a/openbsc/src/libmsc/transaction.c
+++ b/openbsc/src/libmsc/transaction.c
@@ -78,6 +78,7 @@ struct gsm_trans *trans_alloc(struct gsm_subscriber *subscr,
 	trans->protocol = protocol;
 	trans->transaction_id = trans_id;
 	trans->callref = callref;
+	trans->callref_keep = callref;
 
 	llist_add_tail(&trans->entry, &subscr->net->trans_list);
 
diff --git a/openbsc/src/libtrau/rtp_proxy.c b/openbsc/src/libtrau/rtp_proxy.c
index b2ac4bb..8571a1a 100644
--- a/openbsc/src/libtrau/rtp_proxy.c
+++ b/openbsc/src/libtrau/rtp_proxy.c
@@ -471,7 +471,7 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
 		other_rss->bfd.when |= BSC_FD_WRITE;
 		break;
 
-	case RTP_RECV_UPSTREAM:
+	case RTP_RECV_UPSTREAM: /* from BTS to application */
 		if (!rs->receive.callref || !rs->receive.net) {
 			rc = -EIO;
 			goto out_free;
@@ -500,6 +500,24 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
 		trau_tx_to_mncc(rs->receive.net, new_msg);
 		break;
 
+	case RTP_RECV_APP: /* from remote application */
+		if (!rs->receive.callref || !rs->receive.net) {
+			rc = -EIO;
+			goto out_free;
+		}
+		if (rss->bfd.priv_nr != RTP_PRIV_RTP) {
+			rc = ENOTSUP;
+			goto out_free;
+		}
+		rc = rtp_decode(msg, rs->receive.callref, &new_msg);
+		if (rc < 0)
+			goto out_free;
+		msgb_free(msg);
+		tch_frame_down(rs->receive.net, rs->receive.callref,
+			(struct gsm_data_frame *) new_msg->data);
+		msgb_free(new_msg);
+		break;
+
 	case RTP_NONE: /* if socket exists, but disabled by app */
 		msgb_free(msg);
 		break;
diff --git a/openbsc/src/libtrau/trau_mux.c b/openbsc/src/libtrau/trau_mux.c
index bb513cc..15a84b0 100644
--- a/openbsc/src/libtrau/trau_mux.c
+++ b/openbsc/src/libtrau/trau_mux.c
@@ -171,7 +171,9 @@ int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
 			llist_del(&ue->list);
 			return 0;
 		}
-		if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
+		/* Only release, if no callref is given. We must ensure that
+		 * only the transaction's upstream is removed, if exists. */
+		if (ss && !callref && !memcmp(&ue->src, ss, sizeof(*ss))) {
 			llist_del(&ue->list);
 			return 0;
 		}
@@ -497,11 +499,21 @@ int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
 	uint8_t trau_bits_out[TRAU_FRAME_BITS];
 	struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
 	struct subch_mux *mx;
+	struct upqueue_entry *ue;
 	struct decoded_trau_frame tf;
 
 	mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
 	if (!mx)
 		return -EINVAL;
+	if (!(ue = lookup_trau_upqueue(dst_e1_ss))) {
+		/* Call might be on hold, so we drop frames. */
+		return 0;
+	}
+	if (ue->callref != frame->callref) {
+		/* Slot has different transaction, due to
+		 * another call. (Ours is on hold.) */
+		return 0;
+	}
 
 	switch (frame->msg_type) {
 	case GSM_TCHF_FRAME:
diff --git a/openbsc/src/utils/bs11_config.c b/openbsc/src/utils/bs11_config.c
index e8acb46..f459744 100644
--- a/openbsc/src/utils/bs11_config.c
+++ b/openbsc/src/utils/bs11_config.c
@@ -83,6 +83,12 @@ struct osmo_counter *osmo_counter_alloc(const char *name)
 	return NULL;
 }
 
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+	return 0;
+}
+
 int handle_serial_msg(struct msgb *rx_msg);
 
 /* create all objects for an initial configuration */
diff --git a/openbsc/tests/abis/abis_test.c b/openbsc/tests/abis/abis_test.c
index e7e78d2..6bb84cc 100644
--- a/openbsc/tests/abis/abis_test.c
+++ b/openbsc/tests/abis/abis_test.c
@@ -27,6 +27,12 @@
 #include <openbsc/abis_nm.h>
 #include <openbsc/debug.h>
 
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
+{
+	return 0;
+}
+
 static const uint8_t simple_config[] = {
 	/*0, 13, */
 	66, 18, 0, 3, 1, 2, 3, 19, 0, 3, 3, 4, 5,
diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c
index d32ac83..69ce58a 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.c
+++ b/openbsc/tests/gbproxy/gbproxy_test.c
@@ -34,6 +34,12 @@
 
 #define SGSN_NSEI 0x0100
 
+/* dummy function to keep rtp_proxy.c happy */
+int tch_frame_down()
+{
+	return 0;
+}
+
 struct gbproxy_config gbcfg;
 
 static int gprs_process_message(struct gprs_ns_inst *nsi, const char *text,
-- 
1.8.1.5

Reply via email to