IuPS: osmo-sgsn: add core IuPS impl, call iu_init()

Add main Iu entry points for IuPS:
* gsm0408_gprs_rcvmsg_iu()
* sgsn_ranap_iu_event()
* sgsn_ranap_rab_ass_resp()

Add main MM context management for IuPS:
* sgsn_mm_ctx_by_ue_ctx()
* sgsn_mm_ctx_alloc_iu()

Call iu_init() from sgsn_main.c.

Add asn_debug impl ("extern" from libasn1c).
Initialize asn_debug VTY command (iu_vty_init()).

osmo-sgsn build: add libiu and libasn1c, libosmo-sigtran, libosmo-ranap

Change-Id: I469ae6ca9ef254d04ee0d2d79bdd65aebcd027b5
diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c
index be7637a..4a14cf6 100644
--- a/openbsc/src/gprs/sgsn_libgtp.c
+++ b/openbsc/src/gprs/sgsn_libgtp.c
@@ -34,6 +34,8 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#include "bscconfig.h"
+
 #include <osmocom/core/talloc.h>
 #include <osmocom/core/select.h>
 #include <osmocom/core/rate_ctr.h>
@@ -48,6 +50,11 @@
 #include <openbsc/gprs_gmm.h>
 #include <openbsc/gsm_subscriber.h>
 
+#ifdef BUILD_IU
+#include <openbsc/iu.h>
+#include <osmocom/ranap/ranap_ies_defs.h>
+#endif
+
 #include <gtp.h>
 #include <pdp.h>
 
@@ -218,7 +225,10 @@
 	memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr,
 		sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
 
-	/* SGSN address for user plane */
+	/* SGSN address for user plane
+	 * Default to the control plane addr for now. If we are connected to a
+	 * hnbgw via IuPS we'll need to send a PDP context update with the
+	 * correct IP address after the RAB Assignment is complete */
 	pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr);
 	memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr,
 		sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
@@ -383,6 +393,72 @@
 	return EOF;
 }
 
+#ifdef BUILD_IU
+/* Callback for RAB assignment response */
+int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
+{
+	uint8_t rab_id;
+	bool require_pdp_update = false;
+	struct sgsn_pdp_ctx *pdp = NULL;
+	RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem;
+
+	rab_id = item->rAB_ID.buf[0];
+
+	pdp = sgsn_pdp_ctx_by_nsapi(ctx, rab_id);
+	if (!pdp) {
+		LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Response for unknown RAB/NSAPI=%u\n", rab_id);
+		return -1;
+	}
+
+	if (item->transportLayerAddress) {
+		LOGPC(DRANAP, LOGL_INFO, " Setup: (%u/%s)", rab_id, osmo_hexdump(item->transportLayerAddress->buf,
+								     item->transportLayerAddress->size));
+		switch (item->transportLayerAddress->size) {
+		case 7:
+			/* It must be IPv4 inside a X213 NSAP */
+			memcpy(pdp->lib->gsnlu.v, &item->transportLayerAddress->buf[3], 4);
+			break;
+		case 4:
+			/* It must be a raw IPv4 address */
+			memcpy(pdp->lib->gsnlu.v, item->transportLayerAddress->buf, 4);
+			break;
+		case 16:
+			/* TODO: It must be a raw IPv6 address */
+		case 19:
+			/* TODO: It must be IPv6 inside a X213 NSAP */
+		default:
+			LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Resp: Unknown "
+				"transport layer address size %u\n",
+				item->transportLayerAddress->size);
+			return -1;
+		}
+		require_pdp_update = true;
+	}
+
+	/* The TEI on the RNC side might have changed, too */
+	if (item->iuTransportAssociation &&
+	    item->iuTransportAssociation->present == RANAP_IuTransportAssociation_PR_gTP_TEI &&
+	    item->iuTransportAssociation->choice.gTP_TEI.buf &&
+	    item->iuTransportAssociation->choice.gTP_TEI.size >= 4) {
+		uint32_t tei = osmo_load32be(item->iuTransportAssociation->choice.gTP_TEI.buf);
+		LOGP(DRANAP, LOGL_DEBUG, "Updating TEID on RNC side from 0x%08x to 0x%08x\n",
+			pdp->lib->teid_own, tei);
+		pdp->lib->teid_own = tei;
+		require_pdp_update = true;
+	}
+
+	if (require_pdp_update)
+		gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0);
+
+	if (pdp->state != PDP_STATE_CR_CONF) {
+		send_act_pdp_cont_acc(pdp);
+		pdp->state = PDP_STATE_CR_CONF;
+	}
+	return 0;
+
+}
+#endif
+
 /* Confirmation of a PDP Context Delete */
 static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
 {