Implement AoIP, port to M3UA SIGTRAN (large addition and refactoring)

This was originally a long series of commits converging to the final result
seen in this patch. It does not make much sense to review the smaller steps'
trial and error, we need to review this entire change as a whole.

Implement AoIP in osmo-msc and osmo-bsc.

Change over to the new libosmo-sigtran API with support for proper
SCCP/M3UA/SCTP stacking, as mandated by 3GPP specifications for the IuCS and
IuPS interfaces.

From here on, a separate osmo-stp process is required for SCCP routing between
OsmoBSC / OsmoHNBGW <-> OsmoMSC / OsmoSGSN

jenkins.sh: build from libosmo-sccp and osmo-iuh master branches now for new
M3UA SIGTRAN.

Patch-by: pmaier, nhofmeyr, laforge
Change-Id: I5ae4e05ee7c57cad341ea5e86af37c1f6b0ffa77
diff --git a/src/libmsc/msc_ifaces.c b/src/libmsc/msc_ifaces.c
index 56cbd49..7d2e898 100644
--- a/src/libmsc/msc_ifaces.c
+++ b/src/libmsc/msc_ifaces.c
@@ -29,6 +29,7 @@
 #include <openbsc/mgcp.h>
 #include <openbsc/mgcpgw_client.h>
 #include <openbsc/vlr.h>
+#include <openbsc/a_iface.h>
 
 #include "../../bscconfig.h"
 
@@ -41,13 +42,18 @@
 
 static int msc_tx(struct gsm_subscriber_connection *conn, struct msgb *msg)
 {
+	if (!conn)
+		return -EINVAL;
+	if (!msg)
+		return -EINVAL;
+
 	DEBUGP(DMSC, "msc_tx %u bytes to %s via %s\n",
 	       msg->len, vlr_subscr_name(conn->vsub),
 	       ran_type_name(conn->via_ran));
 	switch (conn->via_ran) {
 	case RAN_GERAN_A:
 		msg->dst = conn;
-		return a_tx(msg);
+		return a_iface_tx_dtap(msg);
 
 	case RAN_UTRAN_IU:
 		msg->dst = conn->iu.ue_ctx;
@@ -72,9 +78,15 @@
 /* 9.2.5 CM service accept */
 int msc_gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn)
 {
-	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACC");
-	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	struct msgb *msg;
+	struct gsm48_hdr *gh;
 
+	if (!conn)
+		return -EINVAL;
+
+	msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACC");
+
+	gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 	gh->proto_discr = GSM48_PDISC_MM;
 	gh->msg_type = GSM48_MT_MM_CM_SERV_ACC;
 
@@ -89,6 +101,10 @@
 			     enum gsm48_reject_value value)
 {
 	struct msgb *msg;
+
+	if (!conn)
+		return -EINVAL;
+
 	conn->received_cm_service_request = false;
 
 	msg = gsm48_create_mm_serv_rej(value);
@@ -104,6 +120,9 @@
 
 int msc_tx_common_id(struct gsm_subscriber_connection *conn)
 {
+	if (!conn)
+		return -EINVAL;
+
 	/* Common ID is only sent over IuCS */
 	if (conn->via_ran != RAN_UTRAN_IU) {
 		LOGP(DMM, LOGL_INFO,
@@ -118,10 +137,10 @@
 	return iu_tx_common_id(conn->iu.ue_ctx, conn->vsub->imsi);
 }
 
-#ifdef BUILD_IU
-static void iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id,
-			  uint32_t rtp_ip, uint16_t rtp_port)
+static int iu_rab_act_cs(struct ue_conn_ctx *uectx, uint8_t rab_id,
+			 uint32_t rtp_ip, uint16_t rtp_port)
 {
+#ifdef BUILD_IU
 	struct msgb *msg;
 	bool use_x213_nsap;
 	uint32_t conn_id = uectx->conn_id;
@@ -140,6 +159,11 @@
 		LOGP(DIUCS, LOGL_ERROR, "Failed to send RAB Assignment:"
 		     " conn_id=%d rab_id=%d rtp=%x:%u\n",
 		     conn_id, rab_id, rtp_ip, rtp_port);
+	return 0;
+#else
+	LOGP(DMSC, LOGL_ERROR, "Cannot send Iu RAB Assignment: built without Iu support\n");
+	return -ENOTSUP;
+#endif
 }
 
 static void mgcp_response_rab_act_cs_crcx(struct mgcp_response *r, void *priv)
@@ -165,71 +189,75 @@
 		goto rab_act_cs_error;
 	}
 
-	conn->iu.mgcp_rtp_port_cn = r->audio_port;
+	conn->rtp.port_cn = r->audio_port;
 
 	rtp_ip = mgcpgw_client_remote_addr_n(conn->network->mgcpgw.client);
-	iu_rab_act_cs(uectx, conn->iu.rab_id, rtp_ip,
-		      conn->iu.mgcp_rtp_port_ue);
-	/* use_x213_nsap == 0 for ip.access nano3G */
+
+	if (trans->conn->via_ran == RAN_UTRAN_IU) {
+		/* Assign a voice channel via RANAP on 3G */
+		if (iu_rab_act_cs(uectx, conn->iu.rab_id, rtp_ip, conn->rtp.port_subscr))
+			goto rab_act_cs_error;
+	} else if (trans->conn->via_ran == RAN_GERAN_A) {
+		/* Assign a voice channel via A on 2G */
+		if (a_iface_tx_assignment(trans))
+			goto rab_act_cs_error;
+	} else
+		goto rab_act_cs_error;
+
+	/* Respond back to MNCC (if requested) */
+	if (trans->tch_rtp_create) {
+		if (gsm48_tch_rtp_create(trans))
+			goto rab_act_cs_error;
+	}
+	return;
 
 rab_act_cs_error:
 	/* FIXME abort call, invalidate conn, ... */
+	LOGP(DMSC, LOGL_ERROR, "%s: failure during assignment\n",
+	     vlr_subscr_name(trans->vsub));
 	return;
 }
 
-static int conn_iu_rab_act_cs(struct gsm_trans *trans)
+int msc_call_assignment(struct gsm_trans *trans)
 {
-	struct gsm_subscriber_connection *conn = trans->conn;
-	struct mgcpgw_client *mgcp = conn->network->mgcpgw.client;
+	struct gsm_subscriber_connection *conn;
+	struct mgcpgw_client *mgcp;
 	struct msgb *msg;
+	uint16_t bts_base;
 
-	/* HACK. where to scope the RAB Id? At the conn / subscriber /
-	 * ue_conn_ctx? */
-	static uint8_t next_rab_id = 1;
-	conn->iu.rab_id = next_rab_id ++;
+	if (!trans)
+		return -EINVAL;
+	if (!trans->conn)
+		return -EINVAL;
 
-	conn->iu.mgcp_rtp_endpoint =
+	conn = trans->conn;
+	mgcp = conn->network->mgcpgw.client;
+
+#ifdef BUILD_IU
+	/* FIXME: HACK. where to scope the RAB Id? At the conn / subscriber / ue_conn_ctx? */
+	static uint8_t next_iu_rab_id = 1;
+	if (conn->via_ran == RAN_UTRAN_IU)
+		conn->iu.rab_id = next_iu_rab_id ++;
+#endif
+
+	conn->rtp.mgcp_rtp_endpoint =
 		mgcpgw_client_next_endpoint(conn->network->mgcpgw.client);
-	/* HACK: the addresses should be known from CRCX response
-	 * and config. */
-	conn->iu.mgcp_rtp_port_ue = 4000 + 2 * conn->iu.mgcp_rtp_endpoint;
+
+	/* This will calculate the port we assign to the BTS via AoIP
+	 * assignment command (or rab-assignment on 3G) The BTS will send
+	 * its RTP traffic to that port on the MGCPGW side. The MGCPGW only
+	 * gets the endpoint ID via the CRCX. It will do the same calculation
+	 * on his side too to get knowledge of the rtp port. */
+	bts_base = mgcp->actual.bts_base;
+	conn->rtp.port_subscr = bts_base + 2 * conn->rtp.mgcp_rtp_endpoint;
 
 	/* Establish the RTP stream first as looping back to the originator.
 	 * The MDCX will patch through to the counterpart. TODO: play a ring
 	 * tone instead. */
-	msg = mgcp_msg_crcx(mgcp, conn->iu.mgcp_rtp_endpoint, trans->callref,
-			    MGCP_CONN_LOOPBACK);
+	msg = mgcp_msg_crcx(mgcp, conn->rtp.mgcp_rtp_endpoint,
+			    conn->rtp.mgcp_rtp_endpoint, MGCP_CONN_LOOPBACK);
 	return mgcpgw_client_tx(mgcp, msg, mgcp_response_rab_act_cs_crcx, trans);
 }
-#endif
-
-int msc_call_assignment(struct gsm_trans *trans)
-{
-	struct gsm_subscriber_connection *conn = trans->conn;
-
-	switch (conn->via_ran) {
-	case RAN_GERAN_A:
-		LOGP(DMSC, LOGL_ERROR,
-		     "msc_call_assignment(): A-interface BSSMAP Assignment"
-		     " Request not yet implemented\n");
-		return -ENOTSUP;
-
-	case RAN_UTRAN_IU:
-#ifdef BUILD_IU
-		return conn_iu_rab_act_cs(trans);
-#else
-		LOGP(DMSC, LOGL_ERROR,
-		     "msc_call_assignment(): cannot send RAB Activation, built without Iu support\n");
-		return -ENOTSUP;
-#endif
-
-	default:
-		LOGP(DMSC, LOGL_ERROR,
-		     "msc_tx(): conn->via_ran invalid (%d)\n",
-		     conn->via_ran);
-		return -EINVAL;
-	}
-}
 
 static void mgcp_response_bridge_mdcx(struct mgcp_response *r, void *priv);
 
@@ -252,8 +280,8 @@
 	ip = mgcpgw_client_remote_addr_str(mgcp);
 
 	msg = mgcp_msg_mdcx(mgcp,
-			    conn1->iu.mgcp_rtp_endpoint,
-			    ip, conn2->iu.mgcp_rtp_port_cn,
+			    conn1->rtp.mgcp_rtp_endpoint,
+			    ip, conn2->rtp.port_cn,
 			    mode);
 	if (mgcpgw_client_tx(mgcp, msg, mgcp_response_bridge_mdcx, from))
 		LOGP(DMGCP, LOGL_ERROR,
@@ -302,8 +330,58 @@
 	}
 }
 
+int msc_call_connect(struct gsm_trans *trans, uint16_t port, uint32_t ip)
+{
+	/* With this function we inform the MGCP-GW  where (ip/port) it
+	 * has to send its outgoing voic traffic. The receiving end will
+	 * usually be a PBX (e.g. Asterisk). The IP-Address we tell, will
+	 * not only be used to direct the traffic, it will also be used
+	 * as a filter to make sure only RTP packets from the right
+	 * remote end will reach the BSS. This is also the reason why
+	 * inbound audio will not work until this step is performed */
+
+	/* NOTE: This function is used when msc_call_bridge(), is not
+	 * applicable. This is usually the case when an external MNCC
+	 * is in use */
+
+	struct gsm_subscriber_connection *conn;
+	struct mgcpgw_client *mgcp;
+	struct msgb *msg;
+
+	if (!trans)
+		return -EINVAL;
+	if (!trans->conn)
+		return -EINVAL;
+	if (!trans->conn->network)
+		return -EINVAL;
+	if (!trans->conn->network->mgcpgw.client)
+		return -EINVAL;
+
+	mgcp = trans->conn->network->mgcpgw.client;
+
+	struct in_addr ip_addr;
+	ip_addr.s_addr = ntohl(ip);
+
+	conn = trans->conn;
+
+	msg = mgcp_msg_mdcx(mgcp,
+			    conn->rtp.mgcp_rtp_endpoint,
+			    inet_ntoa(ip_addr), port, MGCP_CONN_RECV_SEND);
+	if (mgcpgw_client_tx(mgcp, msg, NULL, trans))
+		LOGP(DMGCP, LOGL_ERROR,
+		     "Failed to send MDCX message for %s\n",
+		     vlr_subscr_name(trans->vsub));
+
+	return 0;
+}
+
 int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2)
 {
+	if (!trans1)
+		return -EINVAL;
+	if (!trans2)
+		return -EINVAL;
+
 	/* First setup as loopback and configure the counterparts' endpoints,
 	 * so that when transmission starts the originating addresses are
 	 * already known to be valid. The mgcp callback will continue. */
@@ -314,3 +392,31 @@
 
 	return 0;
 }
+
+void msc_call_release(struct gsm_trans *trans)
+{
+	struct msgb *msg;
+	struct gsm_subscriber_connection *conn;
+	struct mgcpgw_client *mgcp;
+
+	if (!trans)
+		return;
+	if (!trans->conn)
+		return;
+	if (!trans->conn->network)
+		return;
+
+	conn = trans->conn;
+	mgcp = conn->network->mgcpgw.client;
+
+	/* Send DLCX */
+	msg = mgcp_msg_dlcx(mgcp, conn->rtp.mgcp_rtp_endpoint,
+			    conn->rtp.mgcp_rtp_endpoint);
+	if (mgcpgw_client_tx(mgcp, msg, NULL, NULL))
+		LOGP(DMGCP, LOGL_ERROR,
+		     "Failed to send DLCX message for %s\n",
+		     vlr_subscr_name(trans->vsub));
+
+	/* Release endpoint id */
+	mgcpgw_client_release_endpoint(conn->rtp.mgcp_rtp_endpoint, mgcp);
+}