mgcp_e1: finish E1 support, add E1 support from libosmoabis

Currently only the endpoint handling for E1 exists, but there is no
actual code behind it that handles the E1 traffic.

Change-Id: I6b93809b5ac7d01af55888347dd787b0bc997ae1
Related: OS#2659
diff --git a/src/libosmo-mgcp/mgcp_network.c b/src/libosmo-mgcp/mgcp_network.c
index 155ed20..e0aa42e 100644
--- a/src/libosmo-mgcp/mgcp_network.c
+++ b/src/libosmo-mgcp/mgcp_network.c
@@ -46,12 +46,11 @@
 #include <osmocom/mgcp/mgcp_codec.h>
 #include <osmocom/mgcp/debug.h>
 #include <osmocom/codec/codec.h>
-
+#include <osmocom/mgcp/mgcp_e1.h>
 
 #define RTP_SEQ_MOD		(1 << 16)
 #define RTP_MAX_DROPOUT		3000
 #define RTP_MAX_MISORDER	100
-#define RTP_BUF_SIZE		4096
 
 enum rtp_proto {
 	MGCP_PROTO_RTP,
@@ -798,6 +797,23 @@
 		     "Forwarding tapped (debug) voice data failed.\n");
 }
 
+/* Generate an RTP header if it is missing */
+static void gen_rtp_header(struct msgb *msg, struct mgcp_rtp_end *rtp_end,
+			   struct mgcp_rtp_state *state)
+{
+	struct rtp_hdr *hdr = (struct rtp_hdr *)msgb_data(msg);
+
+	if (hdr->version > 0)
+		return;
+
+	hdr->version = 2;
+	hdr->payload_type = rtp_end->codec->payload_type;
+	hdr->timestamp = osmo_htonl(get_current_ts(rtp_end->codec->rate));
+	hdr->sequence = osmo_htons(state->alt_rtp_tx_sequence);
+	hdr->ssrc = state->alt_rtp_tx_ssrc;
+}
+
+
 /*! Send RTP/RTCP data to a specified destination connection.
  *  \param[in] endp associated endpoint (for configuration, logging).
  *  \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP.
@@ -857,6 +873,11 @@
 	rtp_state = &conn_src->state;
 	dest_name = conn_dst->conn->name;
 
+	/* Ensure we have an alternative SSRC in case we need it, see also
+	 * gen_rtp_header() */
+	if (rtp_state->alt_rtp_tx_ssrc == 0)
+		rtp_state->alt_rtp_tx_ssrc = rand();
+
 	if (!rtp_end->output_enabled) {
 		rtpconn_rate_ctr_inc(conn_dst, endp, RTP_DROPPED_PACKETS_CTR);
 		LOGPENDP(endp, DRTP, LOGL_DEBUG,
@@ -870,6 +891,11 @@
 		int cont;
 		int nbytes = 0;
 		int buflen = msgb_length(msg);
+
+		/* Make sure we have a valid RTP header, in cases where no RTP
+		 * header is present, we will generate one. */
+		gen_rtp_header(msg, rtp_end, rtp_state);
+
 		do {
 			/* Run transcoder */
 			cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
@@ -938,6 +964,7 @@
 
 			rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
 			rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
+			rtp_state->alt_rtp_tx_sequence++;
 
 			nbytes += len;
 			buflen = cont;
@@ -956,6 +983,7 @@
 
 		rtpconn_rate_ctr_inc(conn_dst, endp, RTP_PACKETS_TX_CTR);
 		rtpconn_rate_ctr_add(conn_dst, endp, RTP_OCTETS_TX_CTR, len);
+		rtp_state->alt_rtp_tx_sequence++;
 
 		return len;
 	}
@@ -1236,12 +1264,24 @@
 	struct osmo_rtp_msg_ctx *mc = OSMO_RTP_MSG_CTX(msg);
 	struct mgcp_conn_rtp *conn_src = mc->conn_src;
 	struct mgcp_conn *conn = conn_src->conn;
+	struct sockaddr_in *from_addr = mc->from_addr;
 
-	/* FIXME: integrate E1 support from libsomoabis, also implement
-	 * handling for RTCP packets, which can not converted to E1. */
-	LOGPCONN(conn, DRTP, LOGL_FATAL,
-		 "cannot dispatch! E1 support is not implemented yet!\n");
-	return -1;
+	/* Check if the connection is in loopback mode, if yes, just send the
+	 * incoming data back to the origin */
+	if (conn->mode == MGCP_CONN_LOOPBACK) {
+		/* When we are in loopback mode, we loop back all incoming
+		 * packets back to their origin. We will use the originating
+		 * address data from the UDP packet header to patch the
+		 * outgoing address in connection on the fly */
+		if (conn->u.rtp.end.rtp_port == 0) {
+			conn->u.rtp.end.addr = from_addr->sin_addr;
+			conn->u.rtp.end.rtp_port = from_addr->sin_port;
+		}
+		return mgcp_send_rtp(conn_src, msg);
+	}
+
+	/* Forward to E1 */
+	return mgcp_e1_send_rtp(conn->endp, conn->u.rtp.end.codec, msg);
 }
 
 /*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
@@ -1267,8 +1307,9 @@
  *  \param[in] conn Connection that is about to be removed (ignored). */
 void mgcp_cleanup_e1_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
 {
-	LOGPCONN(conn, DRTP, LOGL_FATAL,
-		 "cannot dispatch! E1 support is not implemented yet!\n");
+	/* Cleanup tasks for E1 are the same as for regular endpoint. The
+	 * shut down of the E1 part is handled separately. */
+	mgcp_cleanup_rtp_bridge_cb(endp, conn);
 }
 
 static bool is_dummy_msg(enum rtp_proto proto, struct msgb *msg)