Support forwarding RIM messages over GTPCv1 EUTRAN<->GERAN

MMEs connect over Gn interface using GTPCv1 towards the SGSN in order to
exchange RIM PDUs by using "RAN Information Relay" GTPCv1 message type.
For more info, see 3GPP TS 29.060 sec 7.5.14.1 "RAN Information Relay"

In order to support it, this commit does the following:

* Uses new libgtp APIs to rx and tx RAN Information Relay messages. The
  same "gsn" object is reused, ie. the local GTPCv1 socket address used
  for exchanging messages against GGSN is reused.
* Adds a new "sgsn_mme_ctx" struct holding information about MMEs
  allowed by the SGSN, each one containing information about the GTP
  address it uses, the in/out routing based on TAI requests, etc. The
  set of MMEs and their config can be set up using new VTY node introduced
  in this commit.
* The RIM related code in SGSN is refactored to allow forwarding from
  and to several types of addresses/interfaces.

Depends: osmo-ggsn.git Change-Id Iea3eb032ccd4aed5187baca7f7719349d76039d4
Depends: libosmocore.git Change-Id I534db7d8bc5ceb19a2a6866f07d5f5c70e456c5c
Related: SYS#5314
Change-Id: I396450b8d8b66595dab8ff7bf41cbf964bb40d93
diff --git a/include/osmocom/sgsn/Makefile.am b/include/osmocom/sgsn/Makefile.am
index 51bdee8..289f502 100644
--- a/include/osmocom/sgsn/Makefile.am
+++ b/include/osmocom/sgsn/Makefile.am
@@ -22,6 +22,7 @@
 	gprs_subscriber.h \
 	gprs_utils.h \
 	gtphub.h \
+	gtp_mme.h \
 	sgsn.h \
 	sgsn_rim.h \
 	signal.h \
diff --git a/include/osmocom/sgsn/gtp_mme.h b/include/osmocom/sgsn/gtp_mme.h
new file mode 100644
index 0000000..ceea405
--- /dev/null
+++ b/include/osmocom/sgsn/gtp_mme.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <netinet/in.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/gprs/protocol/gsm_24_301.h>
+
+struct gsn_t;
+
+struct mme_rim_route {
+	struct llist_head list; /* item in struct sgsn_mme_ctx */
+	struct osmo_eutran_tai tai;
+};
+
+struct sgsn_mme_ctx {
+	struct llist_head list; /* item in sgsn_mme_ctxts */
+	struct llist_head routes; /* list of struct mme_rim_route */
+	struct sgsn_instance *sgsn; /* backpointer */
+	char *name;
+	struct in_addr remote_addr;
+
+	/* is it the default route for outgoing message? are all incoming messages accepted? */
+	bool default_route;
+};
+struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name);
+struct sgsn_mme_ctx *sgsn_mme_ctx_find_alloc(struct sgsn_instance *sgsn, const char *name);
+void sgsn_mme_ctx_free(struct sgsn_mme_ctx *mme);
+
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_name(const struct sgsn_instance *sgsn, const char *name);
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_addr(const struct sgsn_instance *sgsn, const struct in_addr *addr);
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_route(const struct sgsn_instance *sgsn, const struct osmo_eutran_tai *tai);
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_default_route(const struct sgsn_instance *sgsn);
+
+void sgsn_mme_ctx_route_add(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);
+void sgsn_mme_ctx_route_del(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);
+
+#define LOGMME(mme, cat, level, fmt, args...) { \
+	char _buf[INET_ADDRSTRLEN]; \
+	LOGP(cat, level, "MME(%s:%s): " fmt, (mme)->name, inet_ntop(AF_INET, &(mme)->remote_addr, _buf, sizeof(_buf)), ## args); \
+	} while (0)
diff --git a/include/osmocom/sgsn/sgsn.h b/include/osmocom/sgsn/sgsn.h
index d9ef938..b686c7c 100644
--- a/include/osmocom/sgsn/sgsn.h
+++ b/include/osmocom/sgsn/sgsn.h
@@ -6,7 +6,10 @@
 #include <osmocom/core/select.h>
 #include <osmocom/crypt/gprs_cipher.h>
 #include <osmocom/gprs/gprs_ns2.h>
+#include <osmocom/gprs/gprs_bssgp.h>
+
 #include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/gtp_mme.h>
 #include <osmocom/gsm/oap_client.h>
 #include <osmocom/gsupclient/gsup_client.h>
 #include <osmocom/sgsn/common.h>
@@ -145,6 +148,8 @@
 	struct ares_addr_node *ares_servers;
 
 	struct rate_ctr_group *rate_ctrs;
+
+	struct llist_head mme_list; /* list of struct sgsn_mme_ctx */
 };
 
 extern struct sgsn_instance *sgsn;
@@ -169,6 +174,7 @@
 void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen);
 void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc);
 int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx);
+int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu);
 
 /* gprs_sndcp.c */
 
diff --git a/include/osmocom/sgsn/sgsn_rim.h b/include/osmocom/sgsn/sgsn_rim.h
index ca3660b..aa5a726 100644
--- a/include/osmocom/sgsn/sgsn_rim.h
+++ b/include/osmocom/sgsn/sgsn_rim.h
@@ -1,3 +1,6 @@
 #pragma once
 
-int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg);
+struct sgsn_mme_ctx;
+
+int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg);
+int sgsn_rim_rx_from_gtp(struct bssgp_ran_information_pdu *pdu, struct sgsn_mme_ctx *mme);
diff --git a/include/osmocom/sgsn/vty.h b/include/osmocom/sgsn/vty.h
index bd469ef..a273222 100644
--- a/include/osmocom/sgsn/vty.h
+++ b/include/osmocom/sgsn/vty.h
@@ -5,4 +5,5 @@
 enum bsc_vty_node {
 	SGSN_NODE = _LAST_OSMOVTY_NODE + 1,
 	GTPHUB_NODE,
+	MME_NODE,
 };