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/osmo-bsc/osmo_bsc_audio.c b/src/osmo-bsc/osmo_bsc_audio.c
index 1160209..b4ffa88 100644
--- a/src/osmo-bsc/osmo_bsc_audio.c
+++ b/src/osmo-bsc/osmo_bsc_audio.c
@@ -26,15 +26,57 @@
 #include <openbsc/gsm_data.h>
 #include <openbsc/debug.h>
 #include <openbsc/signal.h>
+#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/gsm/gsm0808_utils.h>
+#include <openbsc/osmo_bsc_sigtran.h>
 
 #include <arpa/inet.h>
 
+/* Generate and send assignment complete message */
+static int send_aoip_ass_compl(struct gsm_subscriber_connection *conn, struct gsm_lchan *lchan)
+{
+	struct msgb *resp;
+	struct sockaddr_storage rtp_addr;
+	struct sockaddr_in rtp_addr_in;
+	struct gsm0808_speech_codec sc;
+
+	OSMO_ASSERT(lchan->abis_ip.ass_compl.valid == true);
+
+	/* Package RTP-Address data */
+	memset(&rtp_addr_in, 0, sizeof(rtp_addr_in));
+	rtp_addr_in.sin_family = AF_INET;
+	rtp_addr_in.sin_port = htons(lchan->abis_ip.bound_port);
+	rtp_addr_in.sin_addr.s_addr = htonl(lchan->abis_ip.bound_ip);
+	memset(&rtp_addr, 0, sizeof(rtp_addr));
+	memcpy(&rtp_addr, &rtp_addr_in, sizeof(rtp_addr_in));
+
+	/* Extrapolate speech codec from speech mode */
+	gsm0808_speech_codec_from_chan_type(&sc, lchan->abis_ip.ass_compl.speech_mode);
+
+	/* Generate message */
+	resp = gsm0808_create_ass_compl(lchan->abis_ip.ass_compl.rr_cause,
+					lchan->abis_ip.ass_compl.chosen_channel,
+					lchan->abis_ip.ass_compl.encr_alg_id,
+					lchan->abis_ip.ass_compl.speech_mode,
+					&rtp_addr,
+					&sc,
+					NULL);
+
+	if (!resp) {
+		LOGP(DMSC, LOGL_ERROR, "Failed to generate assignment completed message!\n"); \
+		return -EINVAL;
+	}
+
+	return osmo_bsc_sigtran_send(conn->sccp_con, resp);
+}
+
 static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
 				 void *handler_data, void *signal_data)
 {
 	struct gsm_subscriber_connection *con;
 	struct gsm_lchan *lchan = signal_data;
 	int rc;
+	uint32_t rtp_ip;
 
 	if (subsys != SS_ABISIP)
 		return 0;
@@ -49,11 +91,19 @@
 		 * TODO: handle handover here... then the audio should go to
 		 * the old mgcp port..
 		 */
+
 		/* we can ask it to connect now */
 		LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n",
 		     con->sccp_con->rtp_port, lchan->abis_ip.conn_id);
 
-		rc = rsl_ipacc_mdcx(lchan, ntohl(INADDR_ANY),
+		/* If AoIP is in use, the rtp_ip, which has been communicated
+		 * via the A interface as connect_ip */
+		if(con->sccp_con->rtp_ip)
+			rtp_ip = con->sccp_con->rtp_ip;
+		else
+			rtp_ip = ntohl(INADDR_ANY);
+
+		rc = rsl_ipacc_mdcx(lchan, rtp_ip,
 				    con->sccp_con->rtp_port,
 				    lchan->abis_ip.rtp_payload2);
 		if (rc < 0) {
@@ -61,6 +111,24 @@
 			return rc;
 		}
 		break;
+
+	case S_ABISIP_MDCX_ACK:
+		if (con->ho_lchan) {
+			/* NOTE: When an ho_lchan exists, the MDCX is part of an
+			 * handover operation (intra-bsc). This means we will not
+			 * inform the MSC about the event, which means that no
+			 * assignment complete message is transmitted */
+			LOGP(DMSC, LOGL_INFO," RTP connection handover complete\n");
+		} else if (is_ipaccess_bts(con->bts) && con->sccp_con->rtp_ip) {
+			/* NOTE: This is only relevant on AoIP networks with
+			 * IPA based base stations. See also osmo_bsc_api.c,
+			 * function bsc_assign_compl() */
+			LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL (POSTPONED)\n");
+			if (send_aoip_ass_compl(con, lchan) != 0)
+				return -EINVAL;
+		}
+		break;
+	break;
 	}
 
 	return 0;