add RTP proxy mode for ip.access

Up until now, we only supported direct RTP streams between ip.access BTS.
With this commit, the user can specify '-P' to the command line to enable
a RTP/RTCP proxy inside OpenBSC.  The nanoBTS will then send all their voice
data to OpenBSC, which will relay it to the respective destination BTS (which
can be the same BTS).

The default behaviour remains unchanged.  Without '-P' on the command line,
RTP/RTCP is exchanged directly.
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index a9f2ebd..2d3a634 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -44,6 +44,7 @@
 #include <openbsc/signal.h>
 #include <openbsc/trau_frame.h>
 #include <openbsc/trau_mux.h>
+#include <openbsc/rtp_proxy.h>
 #include <openbsc/talloc.h>
 #include <openbsc/transaction.h>
 
@@ -56,6 +57,10 @@
 
 static void *tall_locop_ctx;
 
+/* should ip.access BTS use direct RTP streams between each other (1),
+ * or should OpenBSC always act as RTP relay/proxy in between (0) ? */
+int ipacc_rtp_direct = 1;
+
 static const struct tlv_definition rsl_att_tlvdef = {
 	.def = {
 		[GSM48_IE_MOBILE_ID]	= { TLV_TYPE_TLV },
@@ -399,17 +404,6 @@
 	return 0;
 }
 
-/*
- * This will be ran by the linker when loading the DSO. We use it to
- * do system initialization, e.g. registration of signal handlers.
- */
-static __attribute__((constructor)) void on_dso_load_0408(void)
-{
-	tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
-					    "loc_updating_oper");
-	register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
-}
-
 static void to_bcd(u_int8_t *bcd, u_int16_t val)
 {
 	bcd[2] = val % 10;
@@ -1973,12 +1967,80 @@
 	return 0;
 }
 
+/* some other part of the code sends us a signal */
+static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
+				 void *handler_data, void *signal_data)
+{
+	struct gsm_lchan *lchan = signal_data;
+	struct gsm_bts_trx_ts *ts;
+	int rc;
+
+	if (subsys != SS_ABISIP)
+		return 0;
+
+	/* in case we use direct BTS-to-BTS RTP */
+	if (ipacc_rtp_direct)
+		return 0;
+
+	ts = lchan->ts;
+
+	switch (signal) {
+	case S_ABISIP_BIND_ACK:
+		/* the BTS has successfully bound a TCH to a local ip/port,
+		 * which means we can connect our UDP socket to it */
+		if (ts->abis_ip.rtp_socket) {
+			rtp_socket_free(ts->abis_ip.rtp_socket);
+			ts->abis_ip.rtp_socket = NULL;
+		}
+
+		ts->abis_ip.rtp_socket = rtp_socket_create();
+		if (!ts->abis_ip.rtp_socket)
+			goto out_err;
+
+		rc = rtp_socket_connect(ts->abis_ip.rtp_socket,
+				   ts->abis_ip.bound_ip,
+				   ts->abis_ip.bound_port);
+		if (rc < 0)
+			goto out_err;
+		break;
+	case S_ABISIP_DISC_IND:
+		/* the BTS tells us a RTP stream has been disconnected */
+		if (ts->abis_ip.rtp_socket) {
+			rtp_socket_free(ts->abis_ip.rtp_socket);
+			ts->abis_ip.rtp_socket = NULL;
+		}
+		break;
+	}
+
+	return 0;
+out_err:
+	/* FIXME: do something */
+	return 0;
+}
+
+/* bind rtp proxy to local IP/port and tell BTS to connect to it */
+static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan)
+{
+	struct gsm_bts_trx_ts *ts = lchan->ts;
+	struct rtp_socket *rs = ts->abis_ip.rtp_socket;
+	int rc;
+
+	rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
+				ntohs(rs->rtp.sin_local.sin_port),
+				ts->abis_ip.conn_id, 
+			/* FIXME: use RTP payload of bound socket, not BTS*/
+				ts->abis_ip.rtp_payload2);
+
+	return rc;
+}
+
 /* map two ipaccess RTP streams onto each other */
 static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
 {
 	struct gsm_bts *bts = lchan->ts->trx->bts;
 	struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
 	struct gsm_bts_trx_ts *ts;
+	int rc;
 
 	DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
 		bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
@@ -1992,23 +2054,38 @@
 	switch (bts->type) {
 	case GSM_BTS_TYPE_NANOBTS_900:
 	case GSM_BTS_TYPE_NANOBTS_1800:
-		ts = remote_lchan->ts;
-		rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
-				  ts->abis_ip.bound_port,
-				  lchan->ts->abis_ip.conn_id,
-				  ts->abis_ip.rtp_payload2);
-	
-		ts = lchan->ts;
-		rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
-				  ts->abis_ip.bound_port,
-				  remote_lchan->ts->abis_ip.conn_id,
-				  ts->abis_ip.rtp_payload2);
+		if (!ipacc_rtp_direct) {
+			/* connect the TCH's to our RTP proxy */
+			rc = ipacc_connect_proxy_bind(lchan);
+			if (rc < 0)
+				return rc;
+			rc = ipacc_connect_proxy_bind(remote_lchan);
+
+			/* connect them with each other */
+			rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket,
+					 remote_lchan->ts->abis_ip.rtp_socket);
+		} else {
+			/* directly connect TCH RTP streams to each other */
+			ts = remote_lchan->ts;
+			rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip,
+						ts->abis_ip.bound_port,
+						lchan->ts->abis_ip.conn_id,
+						ts->abis_ip.rtp_payload2);
+			if (rc < 0)
+				return rc;
+			ts = lchan->ts;
+			rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip,
+						ts->abis_ip.bound_port,
+						remote_lchan->ts->abis_ip.conn_id,
+						ts->abis_ip.rtp_payload2);
+		}
 		break;
 	case GSM_BTS_TYPE_BS11:
 		trau_mux_map_lchan(lchan, remote_lchan);
 		break;
 	default:
 		DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
+		rc = -EINVAL;
 		break;
 	}
 
@@ -3732,3 +3809,14 @@
 	return work;
 }
 
+/*
+ * This will be ran by the linker when loading the DSO. We use it to
+ * do system initialization, e.g. registration of signal handlers.
+ */
+static __attribute__((constructor)) void on_dso_load_0408(void)
+{
+	tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1,
+					    "loc_updating_oper");
+	register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
+	register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
+}