<p>pespin <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/24164">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  osmith: Looks good to me, but someone else must approve
  pespin: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Support forwarding RIM messages over GTPCv1 EUTRAN<->GERAN<br><br>MMEs connect over Gn interface using GTPCv1 towards the SGSN in order to<br>exchange RIM PDUs by using "RAN Information Relay" GTPCv1 message type.<br>For more info, see 3GPP TS 29.060 sec 7.5.14.1 "RAN Information Relay"<br><br>In order to support it, this commit does the following:<br><br>* Uses new libgtp APIs to rx and tx RAN Information Relay messages. The<br>  same "gsn" object is reused, ie. the local GTPCv1 socket address used<br>  for exchanging messages against GGSN is reused.<br>* Adds a new "sgsn_mme_ctx" struct holding information about MMEs<br>  allowed by the SGSN, each one containing information about the GTP<br>  address it uses, the in/out routing based on TAI requests, etc. The<br>  set of MMEs and their config can be set up using new VTY node introduced<br>  in this commit.<br>* The RIM related code in SGSN is refactored to allow forwarding from<br>  and to several types of addresses/interfaces.<br><br>Depends: osmo-ggsn.git Change-Id Iea3eb032ccd4aed5187baca7f7719349d76039d4<br>Depends: libosmocore.git Change-Id I534db7d8bc5ceb19a2a6866f07d5f5c70e456c5c<br>Related: SYS#5314<br>Change-Id: I396450b8d8b66595dab8ff7bf41cbf964bb40d93<br>---<br>M TODO-RELEASE<br>M doc/manuals/chapters/configuration.adoc<br>M include/osmocom/sgsn/Makefile.am<br>A include/osmocom/sgsn/gtp_mme.h<br>M include/osmocom/sgsn/sgsn.h<br>M include/osmocom/sgsn/sgsn_rim.h<br>M include/osmocom/sgsn/vty.h<br>M src/sgsn/Makefile.am<br>M src/sgsn/gprs_sgsn.c<br>A src/sgsn/gtp_mme.c<br>M src/sgsn/sgsn_libgtp.c<br>M src/sgsn/sgsn_main.c<br>M src/sgsn/sgsn_rim.c<br>M src/sgsn/sgsn_vty.c<br>M tests/osmo-sgsn_test-nodes.vty<br>M tests/sgsn/Makefile.am<br>16 files changed, 696 insertions(+), 39 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/TODO-RELEASE b/TODO-RELEASE</span><br><span>index 1c5d61f..44ee421 100644</span><br><span>--- a/TODO-RELEASE</span><br><span>+++ b/TODO-RELEASE</span><br><span>@@ -1 +1,3 @@</span><br><span> #component   what            description / commit summary line</span><br><span style="color: hsl(120, 100%, 40%);">+libosmogb > 1.5.1       bssgp_encode_rim_pdu    symbol was not exported previously</span><br><span style="color: hsl(120, 100%, 40%);">+libgtp > 1.7.1          use gtp_ran_info_relay_req(), gtp_set_cb_ran_info_relay_ind()</span><br><span>diff --git a/doc/manuals/chapters/configuration.adoc b/doc/manuals/chapters/configuration.adoc</span><br><span>index 7d3072e..c31761c 100644</span><br><span>--- a/doc/manuals/chapters/configuration.adoc</span><br><span>+++ b/doc/manuals/chapters/configuration.adoc</span><br><span>@@ -11,7 +11,8 @@</span><br><span> administrator only has to ensure that the NS and BSSGP layer identities</span><br><span> (NSEI, NSVCI, BVCI) are unique for each PCU connecting to the SGSN.</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-=== Configuring the Gp interface</span><br><span style="color: hsl(120, 100%, 40%);">+[[gp-if-ggsn]]</span><br><span style="color: hsl(120, 100%, 40%);">+=== Configuring the Gp interface (towards GGSN)</span><br><span> </span><br><span> The Gp interface is the GTP-C and GTP-U based interface between the SGSN</span><br><span> and the GGSNs.  It is implemented via UDP on well-known source and</span><br><span>@@ -67,6 +68,58 @@</span><br><span> <2> Enable the dynamic GGSN resolving mode</span><br><span> <3> Specify the IP address of a DNS server for APN resolution</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+[[gp-if-mme]]</span><br><span style="color: hsl(120, 100%, 40%);">+=== Configuring the Gp interface (towards MME)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The Gp interface also contains the GTP-C v1 based interface between the SGSN</span><br><span style="color: hsl(120, 100%, 40%);">+and the MMEs. This interface between SGSN and MMEs is used to transfer _RAN</span><br><span style="color: hsl(120, 100%, 40%);">+Information Relay_ GTP-C messages between them, which are used as containers to</span><br><span style="color: hsl(120, 100%, 40%);">+allow PCUs under the SGSN and eNodeBs under MMEs to  exchange cell information</span><br><span style="color: hsl(120, 100%, 40%);">+(RIM).</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+In the SGSN, this interface re-uses the same socket local configuration as per</span><br><span style="color: hsl(120, 100%, 40%);">+the GGSN connections (see _gtp local-ip_ VTY command in <<gp-if-ggsn>>).</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Similarly as with GGSNs, (again see <<gp-if-ggsn>>), selection of destination</span><br><span style="color: hsl(120, 100%, 40%);">+peers for the _RAN Information Relay_ message can be configured statically or</span><br><span style="color: hsl(120, 100%, 40%);">+dynamically over GRX.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+==== Static MME/TAI configuration</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+In this mode, there is a static list of MMEs and TAIs configured in</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN via the VTY / config file. One MME in the list can be configured as the</span><br><span style="color: hsl(120, 100%, 40%);">+_default route_, where all unspecified TAIs are routed too.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+This is a non-standard method outside of the 3GPP specifications for the</span><br><span style="color: hsl(120, 100%, 40%);">+SGSN, and is typically only used in private/small GPRS networks without</span><br><span style="color: hsl(120, 100%, 40%);">+any access to a GRX.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+.Example: Static MME/TAI configuration (single catch-all GGSN)</span><br><span style="color: hsl(120, 100%, 40%);">+----</span><br><span style="color: hsl(120, 100%, 40%);">+sgsn</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp local-ip 192.168.0.10 <1></span><br><span style="color: hsl(120, 100%, 40%);">+ mme test-mme0 <2></span><br><span style="color: hsl(120, 100%, 40%);">+  gtp remote-ip 192.168.0.20 <3></span><br><span style="color: hsl(120, 100%, 40%);">+  gtp ran-info-relay 262 42 3 <4></span><br><span style="color: hsl(120, 100%, 40%);">+  gtp ran-info-relay 262 42 4</span><br><span style="color: hsl(120, 100%, 40%);">+ mme test-mme1 <5></span><br><span style="color: hsl(120, 100%, 40%);">+  gtp remote-ip 192.168.0.30</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp ran-info-relay default  <6></span><br><span style="color: hsl(120, 100%, 40%);">+----</span><br><span style="color: hsl(120, 100%, 40%);">+<1> Configure the local IP address at the SGSN used for Gp/GTP</span><br><span style="color: hsl(120, 100%, 40%);">+<2> Configure an MME named "test-mme0"</span><br><span style="color: hsl(120, 100%, 40%);">+<3> Specify the remote IP address of the MME (for MME "test-mme0")</span><br><span style="color: hsl(120, 100%, 40%);">+<4> Route specified TAIs towards this MME</span><br><span style="color: hsl(120, 100%, 40%);">+<5> Configure an MME named "test-mme1"</span><br><span style="color: hsl(120, 100%, 40%);">+<6> Route all TAIs with an unspecified MME towards MM "test-mme1"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+==== Dynamic MME/TAI configuration</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Dynamic MME/TAI peer look up over GRX is not yet supported by OsmoSGSN.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> [[auth-pol]]</span><br><span> === Authorization Policy</span><br><span> </span><br><span>diff --git a/include/osmocom/sgsn/Makefile.am b/include/osmocom/sgsn/Makefile.am</span><br><span>index 51bdee8..289f502 100644</span><br><span>--- a/include/osmocom/sgsn/Makefile.am</span><br><span>+++ b/include/osmocom/sgsn/Makefile.am</span><br><span>@@ -22,6 +22,7 @@</span><br><span>       gprs_subscriber.h \</span><br><span>  gprs_utils.h \</span><br><span>       gtphub.h \</span><br><span style="color: hsl(120, 100%, 40%);">+    gtp_mme.h \</span><br><span>  sgsn.h \</span><br><span>     sgsn_rim.h \</span><br><span>         signal.h \</span><br><span>diff --git a/include/osmocom/sgsn/gtp_mme.h b/include/osmocom/sgsn/gtp_mme.h</span><br><span>new file mode 100644</span><br><span>index 0000000..ceea405</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/sgsn/gtp_mme.h</span><br><span>@@ -0,0 +1,41 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <netinet/in.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/protocol/gsm_24_301.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsn_t;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct mme_rim_route {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head list; /* item in struct sgsn_mme_ctx */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_eutran_tai tai;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct llist_head list; /* item in sgsn_mme_ctxts */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct llist_head routes; /* list of struct mme_rim_route */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct sgsn_instance *sgsn; /* backpointer */</span><br><span style="color: hsl(120, 100%, 40%);">+ char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct in_addr remote_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* is it the default route for outgoing message? are all incoming messages accepted? */</span><br><span style="color: hsl(120, 100%, 40%);">+       bool default_route;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_find_alloc(struct sgsn_instance *sgsn, const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+void sgsn_mme_ctx_free(struct sgsn_mme_ctx *mme);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_by_name(const struct sgsn_instance *sgsn, const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_by_addr(const struct sgsn_instance *sgsn, const struct in_addr *addr);</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_by_route(const struct sgsn_instance *sgsn, const struct osmo_eutran_tai *tai);</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_by_default_route(const struct sgsn_instance *sgsn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void sgsn_mme_ctx_route_add(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);</span><br><span style="color: hsl(120, 100%, 40%);">+void sgsn_mme_ctx_route_del(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOGMME(mme, cat, level, fmt, args...) { \</span><br><span style="color: hsl(120, 100%, 40%);">+     char _buf[INET_ADDRSTRLEN]; \</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(cat, level, "MME(%s:%s): " fmt, (mme)->name, inet_ntop(AF_INET, &(mme)->remote_addr, _buf, sizeof(_buf)), ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+        } while (0)</span><br><span>diff --git a/include/osmocom/sgsn/sgsn.h b/include/osmocom/sgsn/sgsn.h</span><br><span>index d9ef938..b686c7c 100644</span><br><span>--- a/include/osmocom/sgsn/sgsn.h</span><br><span>+++ b/include/osmocom/sgsn/sgsn.h</span><br><span>@@ -6,7 +6,10 @@</span><br><span> #include <osmocom/core/select.h></span><br><span> #include <osmocom/crypt/gprs_cipher.h></span><br><span> #include <osmocom/gprs/gprs_ns2.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gprs/gprs_bssgp.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include <osmocom/sgsn/gprs_sgsn.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gtp_mme.h></span><br><span> #include <osmocom/gsm/oap_client.h></span><br><span> #include <osmocom/gsupclient/gsup_client.h></span><br><span> #include <osmocom/sgsn/common.h></span><br><span>@@ -145,6 +148,8 @@</span><br><span>  struct ares_addr_node *ares_servers;</span><br><span> </span><br><span>     struct rate_ctr_group *rate_ctrs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   struct llist_head mme_list; /* list of struct sgsn_mme_ctx */</span><br><span> };</span><br><span> </span><br><span> extern struct sgsn_instance *sgsn;</span><br><span>@@ -169,6 +174,7 @@</span><br><span> void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen);</span><br><span> void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc);</span><br><span> int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx);</span><br><span style="color: hsl(120, 100%, 40%);">+int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu);</span><br><span> </span><br><span> /* gprs_sndcp.c */</span><br><span> </span><br><span>diff --git a/include/osmocom/sgsn/sgsn_rim.h b/include/osmocom/sgsn/sgsn_rim.h</span><br><span>index ca3660b..aa5a726 100644</span><br><span>--- a/include/osmocom/sgsn/sgsn_rim.h</span><br><span>+++ b/include/osmocom/sgsn/sgsn_rim.h</span><br><span>@@ -1,3 +1,6 @@</span><br><span> #pragma once</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+int sgsn_rim_rx_from_gtp(struct bssgp_ran_information_pdu *pdu, struct sgsn_mme_ctx *mme);</span><br><span>diff --git a/include/osmocom/sgsn/vty.h b/include/osmocom/sgsn/vty.h</span><br><span>index bd469ef..a273222 100644</span><br><span>--- a/include/osmocom/sgsn/vty.h</span><br><span>+++ b/include/osmocom/sgsn/vty.h</span><br><span>@@ -5,4 +5,5 @@</span><br><span> enum bsc_vty_node {</span><br><span>   SGSN_NODE = _LAST_OSMOVTY_NODE + 1,</span><br><span>  GTPHUB_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+  MME_NODE,</span><br><span> };</span><br><span>diff --git a/src/sgsn/Makefile.am b/src/sgsn/Makefile.am</span><br><span>index 8738986..9e4a342 100644</span><br><span>--- a/src/sgsn/Makefile.am</span><br><span>+++ b/src/sgsn/Makefile.am</span><br><span>@@ -53,6 +53,7 @@</span><br><span>     gprs_sndcp_pcomp.c \</span><br><span>         gprs_sndcp_vty.c \</span><br><span>   gprs_sndcp_xid.c \</span><br><span style="color: hsl(120, 100%, 40%);">+    gtp_mme.c \</span><br><span>  sgsn_main.c \</span><br><span>        sgsn_vty.c \</span><br><span>         sgsn_libgtp.c \</span><br><span>diff --git a/src/sgsn/gprs_sgsn.c b/src/sgsn/gprs_sgsn.c</span><br><span>index d4bc554..f744257 100644</span><br><span>--- a/src/sgsn/gprs_sgsn.c</span><br><span>+++ b/src/sgsn/gprs_sgsn.c</span><br><span>@@ -1042,6 +1042,8 @@</span><br><span>         inst->cfg.auth_policy = SGSN_AUTH_POLICY_CLOSED;</span><br><span>  inst->cfg.require_authentication = true; /* only applies if auth_policy is REMOTE */</span><br><span>      inst->cfg.gsup_server_port = OSMO_GSUP_PORT;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&inst->mme_list);</span><br><span>     return inst;</span><br><span> }</span><br><span> </span><br><span>diff --git a/src/sgsn/gtp_mme.c b/src/sgsn/gtp_mme.c</span><br><span>new file mode 100644</span><br><span>index 0000000..4fe804d</span><br><span>--- /dev/null</span><br><span>+++ b/src/sgsn/gtp_mme.c</span><br><span>@@ -0,0 +1,145 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* TS 29.060 ยง 7.5.14 RAN Information Management Messages */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2021 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: AGPL-3.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gtp_mme.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/sgsn.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern void *tall_sgsn_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static bool _eutran_tai_equal(const struct osmo_eutran_tai *t1, const struct osmo_eutran_tai *t2)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return  t1->mcc == t2->mcc &&</span><br><span style="color: hsl(120, 100%, 40%);">+           t1->mnc == t2->mnc &&</span><br><span style="color: hsl(120, 100%, 40%);">+           t1->mnc_3_digits == t2->mnc_3_digits &&</span><br><span style="color: hsl(120, 100%, 40%);">+         t1->tac == t2->tac;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct sgsn_mme_ctx *mme;</span><br><span style="color: hsl(120, 100%, 40%);">+     mme = talloc_zero(tall_sgsn_ctx, struct sgsn_mme_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!mme)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* if we are called from config file parse, this gsn doesn't exist yet */</span><br><span style="color: hsl(120, 100%, 40%);">+ mme->sgsn = sgsn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        mme->name = talloc_strdup(mme, name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    INIT_LLIST_HEAD(&mme->routes);</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_add_tail(&mme->list, &sgsn->mme_list);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return mme;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void sgsn_mme_ctx_free(struct sgsn_mme_ctx *mme)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mme_rim_route *rt, *rt2;</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_del(&mme->list);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry_safe(rt, rt2, &mme->routes, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               llist_del(&rt->list);</span><br><span style="color: hsl(120, 100%, 40%);">+          talloc_free(rt);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   talloc_free(mme);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_find_alloc(struct sgsn_instance *sgsn, const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sgsn_mme_ctx *mme;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   mme = sgsn_mme_ctx_by_name(sgsn, name);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!mme)</span><br><span style="color: hsl(120, 100%, 40%);">+             mme = sgsn_mme_ctx_alloc(sgsn, name);</span><br><span style="color: hsl(120, 100%, 40%);">+ return mme;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void sgsn_mme_ctx_route_add(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct mme_rim_route *rt = talloc_zero(mme, struct mme_rim_route);</span><br><span style="color: hsl(120, 100%, 40%);">+    rt->tai = *tai;</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_add_tail(&rt->list, &mme->routes);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void sgsn_mme_ctx_route_del(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct mme_rim_route *rt;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(rt, &mme->routes, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (_eutran_tai_equal(tai, &rt->tai)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        llist_del(&rt->list);</span><br><span style="color: hsl(120, 100%, 40%);">+                  talloc_free(rt);</span><br><span style="color: hsl(120, 100%, 40%);">+                      return;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_by_name(const struct sgsn_instance *sgsn, const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct sgsn_mme_ctx *mme;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(mme, &sgsn->mme_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!strcmp(name, mme->name))</span><br><span style="color: hsl(120, 100%, 40%);">+                      return mme;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_by_addr(const struct sgsn_instance *sgsn, const struct in_addr *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sgsn_mme_ctx *mme;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(mme, &sgsn->mme_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!memcmp(addr, &mme->remote_addr, sizeof(*addr)))</span><br><span style="color: hsl(120, 100%, 40%);">+                   return mme;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_by_route(const struct sgsn_instance *sgsn, const struct osmo_eutran_tai *tai)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sgsn_mme_ctx *mme;</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(mme, &sgsn->mme_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct mme_rim_route *rt;</span><br><span style="color: hsl(120, 100%, 40%);">+             llist_for_each_entry(rt, &mme->routes, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (_eutran_tai_equal(tai, &rt->tai)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                return mme;</span><br><span style="color: hsl(120, 100%, 40%);">+                   }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct sgsn_mme_ctx *sgsn_mme_ctx_by_default_route(const struct sgsn_instance *sgsn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct sgsn_mme_ctx *mme;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(mme, &sgsn->mme_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (mme->default_route)</span><br><span style="color: hsl(120, 100%, 40%);">+                    return mme;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/sgsn/sgsn_libgtp.c b/src/sgsn/sgsn_libgtp.c</span><br><span>index 8be7927..6229217 100644</span><br><span>--- a/src/sgsn/sgsn_libgtp.c</span><br><span>+++ b/src/sgsn/sgsn_libgtp.c</span><br><span>@@ -55,6 +55,8 @@</span><br><span> #include <osmocom/sgsn/gprs_ranap.h></span><br><span> #include <osmocom/sgsn/gprs_gmm_fsm.h></span><br><span> #include <osmocom/sgsn/gprs_mm_state_gb_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gtp_mme.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/sgsn_rim.h></span><br><span> </span><br><span> #include <gtp.h></span><br><span> #include <pdp.h></span><br><span>@@ -479,6 +481,43 @@</span><br><span>     gtp_echo_req(ggc->gsn, ggc->gtp_version, ggc, &ggc->remote_addr);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  char ri_src_str[64], ri_dest_str[64];</span><br><span style="color: hsl(120, 100%, 40%);">+ int ri_len;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bssgp_normal_hdr *bgph;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t ri_buf[64];</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t *ri_ptr = &ri_buf[0];</span><br><span style="color: hsl(120, 100%, 40%);">+     struct sockaddr_in sk_in = {</span><br><span style="color: hsl(120, 100%, 40%);">+          .sin_family = AF_INET,</span><br><span style="color: hsl(120, 100%, 40%);">+                .sin_port = htons(GTP1C_PORT),</span><br><span style="color: hsl(120, 100%, 40%);">+                .sin_addr = mme->remote_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  msg = bssgp_encode_rim_pdu(pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGMME(mme, DRIM, LOGL_ERROR, "Tx GTP RAN Information Relay: failed to encode pdu\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+   DEBUGP(DLBSSGP, "Tx GTP RAN Information Relay: RIM-PDU:%s, src=%s, dest=%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             bssgp_pdu_str(bgph->pdu_type),</span><br><span style="color: hsl(120, 100%, 40%);">+             bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &pdu->routing_info_src),</span><br><span style="color: hsl(120, 100%, 40%);">+         bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &pdu->routing_info_dest));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if ((ri_len = bssgp_create_rim_ri(ri_ptr, &pdu->routing_info_dest)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ri_ptr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                ri_len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = gtp_ran_info_relay_req(mme->sgsn->gsn,  &sk_in, msgb_data(msg), msgb_length(msg),</span><br><span style="color: hsl(120, 100%, 40%);">+                                  ri_ptr, ri_len, pdu->routing_info_dest.discr);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Confirmation of a PDP Context Update */</span><br><span> static int update_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)</span><br><span> {</span><br><span>@@ -648,6 +687,42 @@</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int cb_gtp_ran_info_relay_ind(struct sockaddr_in *peer, union gtpie_member **ie)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        char addrbuf[INET_ADDRSTRLEN];</span><br><span style="color: hsl(120, 100%, 40%);">+        struct sgsn_mme_ctx *mme = sgsn_mme_ctx_by_addr(sgsn, &peer->sin_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!mme) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DGTP, LOGL_NOTICE, "Rx GTP RAN Information Relay from unknown MME %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    inet_ntop(AF_INET, &peer->sin_addr, addrbuf, sizeof(addrbuf)));</span><br><span style="color: hsl(120, 100%, 40%);">+           return -ECONNREFUSED;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGMME(mme, DGTP, LOGL_INFO, "Rx GTP RAN Information Relay\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = msgb_alloc(4096, "gtpcv1_ran_info");</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bssgp_ran_information_pdu pdu;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (gtpie_gettlv(ie, GTPIE_RAN_T_CONTAIN, 0, &len, msgb_data(msg), 4096) || len <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: No Transparent Container IE found!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                goto ret_error;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put(msg, len);</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_bssgph(msg) = msg->data;</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_nsei(msg) = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (bssgp_parse_rim_pdu(&pdu, msg) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: Failed parsing Transparent Container IE!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          goto ret_error;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       return sgsn_rim_rx_from_gtp(&pdu, mme);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ret_error:</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Called whenever we receive a DATA packet */</span><br><span> static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)</span><br><span> {</span><br><span>@@ -837,6 +912,7 @@</span><br><span>       gtp_set_cb_data_ind(gsn, cb_data_ind);</span><br><span>       gtp_set_cb_unsup_ind(gsn, cb_unsup_ind);</span><br><span>     gtp_set_cb_extheader_ind(gsn, cb_extheader_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+      gtp_set_cb_ran_info_relay_ind(gsn, cb_gtp_ran_info_relay_ind);</span><br><span> </span><br><span>   return 0;</span><br><span> }</span><br><span>diff --git a/src/sgsn/sgsn_main.c b/src/sgsn/sgsn_main.c</span><br><span>index 71f2efa..af9757a 100644</span><br><span>--- a/src/sgsn/sgsn_main.c</span><br><span>+++ b/src/sgsn/sgsn_main.c</span><br><span>@@ -122,7 +122,7 @@</span><br><span>    case SAP_BSSGP_NM:</span><br><span>           break;</span><br><span>       case SAP_BSSGP_RIM:</span><br><span style="color: hsl(0, 100%, 40%);">-             return sgsn_rim_rx(bp, oph->msg);</span><br><span style="color: hsl(120, 100%, 40%);">+          return sgsn_rim_rx_from_gb(bp, oph->msg);</span><br><span>         }</span><br><span>    return 0;</span><br><span> }</span><br><span>@@ -162,15 +162,36 @@</span><br><span>       }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int sgsn_vty_go_parent(struct vty *vty)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (vty->node) {</span><br><span style="color: hsl(120, 100%, 40%);">+       case SGSN_NODE:</span><br><span style="color: hsl(120, 100%, 40%);">+               vty->node = CONFIG_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MME_NODE:</span><br><span style="color: hsl(120, 100%, 40%);">+                vty->node = SGSN_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+             vty->index = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+#if BUILD_IU</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_ss7_vty_go_parent(vty);</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+           vty->node = CONFIG_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+           vty->index = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return vty->node;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* NSI that BSSGP uses when transmitting on NS */</span><br><span> extern struct gprs_ns_inst *bssgp_nsi;</span><br><span> </span><br><span> static struct vty_app_info vty_info = {</span><br><span>      .name           = "OsmoSGSN",</span><br><span>      .version        = PACKAGE_VERSION,</span><br><span style="color: hsl(0, 100%, 40%);">-#if BUILD_IU</span><br><span style="color: hsl(0, 100%, 40%);">-  .go_parent_cb   = osmo_ss7_vty_go_parent,</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(120, 100%, 40%);">+       .go_parent_cb   = sgsn_vty_go_parent,</span><br><span> };</span><br><span> </span><br><span> static void print_help(void)</span><br><span>diff --git a/src/sgsn/sgsn_rim.c b/src/sgsn/sgsn_rim.c</span><br><span>index 71e6d98..f28ba60 100644</span><br><span>--- a/src/sgsn/sgsn_rim.c</span><br><span>+++ b/src/sgsn/sgsn_rim.c</span><br><span>@@ -11,57 +11,113 @@</span><br><span> #include <osmocom/gprs/gprs_bssgp.h></span><br><span> #include <osmocom/gprs/gprs_bssgp_rim.h></span><br><span> #include <osmocom/sgsn/sgsn_rim.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gtp_mme.h></span><br><span> #include <osmocom/sgsn/debug.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/sgsn.h></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* Find an NSEI for the destination cell, this function works only for GERAN! */</span><br><span style="color: hsl(0, 100%, 40%);">-static int find_dest_nsei_geran(struct bssgp_rim_routing_info *dest_rim_ri, uint16_t nsei)</span><br><span style="color: hsl(120, 100%, 40%);">+static int sgsn_bssgp_fwd_rim_to_geran(const struct bssgp_ran_information_pdu *pdu)</span><br><span> {</span><br><span>  struct bssgp_bvc_ctx *bvc_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_GERAN);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(dest_rim_ri->discr == BSSGP_RIM_ROUTING_INFO_GERAN);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     bvc_ctx = btsctx_by_raid_cid(&dest_rim_ri->geran.raid, dest_rim_ri->geran.cid);</span><br><span style="color: hsl(120, 100%, 40%);">+     bvc_ctx = btsctx_by_raid_cid(&pdu->routing_info_dest.geran.raid, pdu->routing_info_dest.geran.cid);</span><br><span>        if (!bvc_ctx) {</span><br><span style="color: hsl(0, 100%, 40%);">-         LOGP(DRIM, LOGL_ERROR, "BSSGP RIM (NSEI=%u) cannot find NSEI for destination cell\n", nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DRIM, LOGL_ERROR, "Unable to find NSEI for destination cell %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    bssgp_rim_ri_name(&pdu->routing_info_dest));</span><br><span>           return -EINVAL;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return bvc_ctx->nsei;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Forward PDU as it is to the correct interface */</span><br><span style="color: hsl(120, 100%, 40%);">+   return bssgp_tx_rim(pdu, bvc_ctx->nsei);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+static int sgsn_bssgp_fwd_rim_to_eutran(const struct bssgp_ran_information_pdu *pdu)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;</span><br><span style="color: hsl(0, 100%, 40%);">-  int d_nsei;</span><br><span style="color: hsl(0, 100%, 40%);">-     uint16_t nsei = msgb_nsei(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct sgsn_mme_ctx *mme;</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_EUTRAN);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      /* At the moment we only support GERAN, so we block all other network</span><br><span style="color: hsl(0, 100%, 40%);">-    * types here. */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DRIM, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-               "BSSGP RIM (NSEI=%u) only GERAN supported, destination cell is not a GERAN cell -- rejected.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-             /* At the moment we can only handle GERAN addresses, any other</span><br><span style="color: hsl(0, 100%, 40%);">-           * type of address will be consideres as an invalid address.</span><br><span style="color: hsl(0, 100%, 40%);">-             * see also: 3GPP TS 48.018, section 8c.3.1.3 */</span><br><span style="color: hsl(0, 100%, 40%);">-                return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+   mme = sgsn_mme_ctx_by_route(sgsn, &pdu->routing_info_dest.eutran.tai);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!mme) { /* See if we have a default route configured */</span><br><span style="color: hsl(120, 100%, 40%);">+           mme = sgsn_mme_ctx_by_default_route(sgsn);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!mme) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOGP(DRIM, LOGL_ERROR, "Unable to find MME for destination cell %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             bssgp_rim_ri_name(&pdu->routing_info_dest));</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span>    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return sgsn_mme_ran_info_req(mme, pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Receive a RIM PDU from BSSGP (GERAN) */</span><br><span style="color: hsl(120, 100%, 40%);">+int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    uint16_t nsei = msgb_nsei(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {</span><br><span>                LOGP(DRIM, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-               "BSSGP RIM (NSEI=%u) only GERAN supported, source cell is not a GERAN cell -- rejected.\n", nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-               /* See comment above */</span><br><span style="color: hsl(0, 100%, 40%);">-         return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+                "Rx BSSGP RIM (NSEI=%u): Expected src %s, got %s\n", nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+                  bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN),</span><br><span style="color: hsl(120, 100%, 40%);">+               bssgp_rim_routing_info_discr_str(pdu->routing_info_src.discr));</span><br><span style="color: hsl(120, 100%, 40%);">+               goto err;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   d_nsei = find_dest_nsei_geran(&pdu->routing_info_dest, nsei);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (d_nsei < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-            LOGP(DRIM, LOGL_NOTICE, "BSSGP RIM (NSEI=%u) Cell %s unknown to this sgsn\n",</span><br><span style="color: hsl(0, 100%, 40%);">-              nsei, bssgp_rim_ri_name(&pdu->routing_info_dest));</span><br><span style="color: hsl(0, 100%, 40%);">-          /* In case of an invalid destination address we respond with</span><br><span style="color: hsl(0, 100%, 40%);">-             * a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */</span><br><span style="color: hsl(0, 100%, 40%);">-            return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (pdu->routing_info_dest.discr) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case BSSGP_RIM_ROUTING_INFO_GERAN:</span><br><span style="color: hsl(120, 100%, 40%);">+            return sgsn_bssgp_fwd_rim_to_geran(pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSSGP_RIM_ROUTING_INFO_EUTRAN:</span><br><span style="color: hsl(120, 100%, 40%);">+           return sgsn_bssgp_fwd_rim_to_eutran(pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+     default:</span><br><span style="color: hsl(120, 100%, 40%);">+              /* At the moment we can only handle GERAN/EUTRAN addresses, any</span><br><span style="color: hsl(120, 100%, 40%);">+                * other type of address will be considered as an invalid</span><br><span style="color: hsl(120, 100%, 40%);">+              * address. see also: 3GPP TS 48.018, section 8c.3.1.3</span><br><span style="color: hsl(120, 100%, 40%);">+                 */</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DRIM, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "Rx BSSGP RIM (NSEI=%u): Unsupported dst %s\n", nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+               bssgp_rim_routing_info_discr_str(pdu->routing_info_dest.discr));</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Forward PDU as it is to the correct interface */</span><br><span style="color: hsl(0, 100%, 40%);">-     return bssgp_tx_rim(pdu, (uint16_t) d_nsei);</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGP(DRIM, LOGL_INFO, "Rx BSSGP RIM (NSEI=%u): for dest cell %s\n", nsei,</span><br><span style="color: hsl(120, 100%, 40%);">+        bssgp_rim_ri_name(&pdu->routing_info_dest));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+err:</span><br><span style="color: hsl(120, 100%, 40%);">+      /* In case of an invalid destination address we respond with</span><br><span style="color: hsl(120, 100%, 40%);">+   * a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */</span><br><span style="color: hsl(120, 100%, 40%);">+  bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+  return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Receive a RIM PDU from GTPvC1 (EUTRAN) */</span><br><span style="color: hsl(120, 100%, 40%);">+int sgsn_rim_rx_from_gtp(struct bssgp_ran_information_pdu *pdu, struct sgsn_mme_ctx *mme)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sgsn_mme_ctx *mme_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_EUTRAN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGMME(mme, DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected src %s, got %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_EUTRAN),</span><br><span style="color: hsl(120, 100%, 40%);">+                      bssgp_rim_routing_info_discr_str(pdu->routing_info_src.discr));</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGMME(mme, DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected dst %s, got %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN),</span><br><span style="color: hsl(120, 100%, 40%);">+                       bssgp_rim_routing_info_discr_str(pdu->routing_info_dest.discr));</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   mme_tmp = sgsn_mme_ctx_by_route(sgsn, &pdu->routing_info_src.eutran.tai);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!mme_tmp)/* See if we have a default route configured */</span><br><span style="color: hsl(120, 100%, 40%);">+          mme_tmp = sgsn_mme_ctx_by_default_route(sgsn);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (mme != mme_tmp) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: "</span><br><span style="color: hsl(120, 100%, 40%);">+                  "Source MME doesn't have RIM routing configured for TAI: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 bssgp_rim_ri_name(&pdu->routing_info_src));</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGMME(mme, DRIM, LOGL_INFO, "Rx GTP RAN Information Relay for dest cell %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+            bssgp_rim_ri_name(&pdu->routing_info_dest));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return sgsn_bssgp_fwd_rim_to_geran(pdu);</span><br><span> }</span><br><span>diff --git a/src/sgsn/sgsn_vty.c b/src/sgsn/sgsn_vty.c</span><br><span>index 042bad5..76d5202 100644</span><br><span>--- a/src/sgsn/sgsn_vty.c</span><br><span>+++ b/src/sgsn/sgsn_vty.c</span><br><span>@@ -37,6 +37,7 @@</span><br><span> #include <osmocom/gprs/gprs_ns2.h></span><br><span> #include <osmocom/sgsn/gprs_gmm.h></span><br><span> #include <osmocom/sgsn/gprs_sgsn.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sgsn/gtp_mme.h></span><br><span> #include <osmocom/sgsn/vty.h></span><br><span> #include <osmocom/gsupclient/gsup_client.h></span><br><span> </span><br><span>@@ -176,12 +177,35 @@</span><br><span>     1,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct cmd_node mme_node = {</span><br><span style="color: hsl(120, 100%, 40%);">+     MME_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+     "%s(config-sgsn-mme)# ",</span><br><span style="color: hsl(120, 100%, 40%);">+    1,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void config_write_mme(struct vty *vty, const struct sgsn_mme_ctx *mme, const char *prefix)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct mme_rim_route *rt;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vty_out(vty, "%smme %s%s", prefix, mme->name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    vty_out(vty, "%s gtp remote-ip %s%s", prefix, inet_ntoa(mme->remote_addr), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mme->default_route)</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%s gtp ran-info-relay default%s", prefix, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(rt, &mme->routes, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "%s gtp ran-info-relay %s %s %u%s", prefix,</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_mcc_name(rt->tai.mcc), osmo_mnc_name(rt->tai.mnc, rt->tai.mnc_3_digits),</span><br><span style="color: hsl(120, 100%, 40%);">+                        rt->tai.tac, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int config_write_sgsn(struct vty *vty)</span><br><span> {</span><br><span>         struct sgsn_ggsn_ctx *gctx;</span><br><span>  struct imsi_acl_entry *acl;</span><br><span>  struct apn_ctx *actx;</span><br><span>        struct ares_addr_node *server;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct sgsn_mme_ctx *mme;</span><br><span> </span><br><span>        vty_out(vty, "sgsn%s", VTY_NEWLINE);</span><br><span> </span><br><span>@@ -296,6 +320,10 @@</span><br><span>    } else</span><br><span>               vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(mme, &sgsn->mme_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             config_write_mme(vty, mme, " ");</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef BUILD_IU</span><br><span>       vty_out(vty, " cs7-instance-iu %u%s", g_cfg->iu.cs7_instance,</span><br><span>           VTY_NEWLINE);</span><br><span>@@ -1423,6 +1451,161 @@</span><br><span> }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_sgsn_mme, cfg_sgsn_mme_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+     "mme NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+ "Configure an MME peer\n"</span><br><span style="color: hsl(120, 100%, 40%);">+   "Name identifying the MME peer\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct sgsn_mme_ctx *mme;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   mme = sgsn_mme_ctx_find_alloc(sgsn, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!mme)</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ vty->node = MME_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+      vty->index = mme;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_sgsn_no_mme, cfg_sgsn_no_mme_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "no mme NAME",</span><br><span style="color: hsl(120, 100%, 40%);">+      NO_STR "Delete an MME peer configuration\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "Name identifying the MME peer\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct sgsn_mme_ctx *mme;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   mme = sgsn_mme_ctx_by_name(sgsn, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!mme) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% MME %s doesn't exist.%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   sgsn_mme_ctx_free(mme);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define GTP_STR "Configure GTP connection\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mme_remote_ip, cfg_mme_remote_ip_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+   "gtp remote-ip A.B.C.D",</span><br><span style="color: hsl(120, 100%, 40%);">+    GTP_STR "Set Remote GTP IP address\n" IP_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   inet_aton(argv[0], &mme->remote_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define RAN_INFO_STR "Configure RAN Information Relay routing\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define TAI_DOC "MCC\n" "MNC\n" "TAC\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mme_ran_info_relay_tai, cfg_mme_ran_info_relay_tai_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "gtp ran-info-relay <0-999> <0-999> <0-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+   GTP_STR RAN_INFO_STR TAI_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct sgsn_mme_ctx *mme_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_eutran_tai tai;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *mcc = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *mnc = argv[1];</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *tac = argv[2];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (osmo_mcc_from_str(mcc, &tai.mcc)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     tai.tac = atoi(tac);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (mme_tmp != mme) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 vty_out(vty, "%% Another MME %s already contains this route%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                             mme_tmp->name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             /* else: NO-OP, return */</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   sgsn_mme_ctx_route_add(mme, &tai);</span><br><span style="color: hsl(120, 100%, 40%);">+        return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mme_no_ran_info_relay_tai, cfg_mme_no_ran_info_relay_tai_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+     "no gtp ran-info-relay <0-999> <0-999> <0-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+        NO_STR GTP_STR RAN_INFO_STR TAI_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct sgsn_mme_ctx *mme_tmp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_eutran_tai tai;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *mcc = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *mnc = argv[1];</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *tac = argv[2];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (osmo_mcc_from_str(mcc, &tai.mcc)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     tai.tac = atoi(tac);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (mme_tmp != mme) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 vty_out(vty, "%% Another MME %s contains this route%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                             mme_tmp->name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             sgsn_mme_ctx_route_del(mme, &tai);</span><br><span style="color: hsl(120, 100%, 40%);">+                return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%% This route doesn't exist in current MME %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                 mme->name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+           return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mme_ran_info_relay_default, cfg_mme_ran_info_relay_default_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+     "gtp ran-info-relay default",</span><br><span style="color: hsl(120, 100%, 40%);">+       GTP_STR RAN_INFO_STR "Set as default route")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct sgsn_mme_ctx *default_mme;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (mme->default_route)</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_SUCCESS; /* NO-OP */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if ((default_mme = sgsn_mme_ctx_by_default_route(sgsn))) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%% Another MME %s is already set as default route, "</span><br><span style="color: hsl(120, 100%, 40%);">+                       "remove it before setting it here.%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      default_mme->name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   mme->default_route = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_mme_no_ran_info_relay_default, cfg_mme_no_ran_info_relay_default_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+     "no gtp ran-info-relay default",</span><br><span style="color: hsl(120, 100%, 40%);">+    NO_STR GTP_STR RAN_INFO_STR "Set as default route")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+     mme->default_route = false;</span><br><span style="color: hsl(120, 100%, 40%);">+        return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int sgsn_vty_init(struct sgsn_config *cfg)</span><br><span> {</span><br><span>  g_cfg = cfg;</span><br><span>@@ -1486,6 +1669,15 @@</span><br><span>        install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);</span><br><span>        install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    install_element(SGSN_NODE, &cfg_sgsn_mme_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_element(SGSN_NODE, &cfg_sgsn_no_mme_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_node(&mme_node, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_element(MME_NODE, &cfg_mme_remote_ip_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element(MME_NODE, &cfg_mme_ran_info_relay_default_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element(MME_NODE, &cfg_mme_no_ran_info_relay_default_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element(MME_NODE, &cfg_mme_ran_info_relay_tai_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+       install_element(MME_NODE, &cfg_mme_no_ran_info_relay_tai_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef BUILD_IU</span><br><span>      install_element(SGSN_NODE, &cfg_sgsn_cs7_instance_iu_cmd);</span><br><span>       ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);</span><br><span>diff --git a/tests/osmo-sgsn_test-nodes.vty b/tests/osmo-sgsn_test-nodes.vty</span><br><span>index 953a30e..f889541 100644</span><br><span>--- a/tests/osmo-sgsn_test-nodes.vty</span><br><span>+++ b/tests/osmo-sgsn_test-nodes.vty</span><br><span>@@ -61,3 +61,58 @@</span><br><span>   compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250></span><br><span>   compression v42bis passive</span><br><span> ...</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn)# mme test0</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# gtp remote-ip 1.2.3.4</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay 907 10 567</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay 202 12 51</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay 907 10 567</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn)# mme test1</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# gtp remote-ip 5.6.7.8</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay default</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+sgsn</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+ mme test0</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp remote-ip 1.2.3.4</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp ran-info-relay 907 10 567</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp ran-info-relay 202 12 51</span><br><span style="color: hsl(120, 100%, 40%);">+ mme test1</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp remote-ip 5.6.7.8</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp ran-info-relay default</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn)# mme test0</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay default</span><br><span style="color: hsl(120, 100%, 40%);">+% Another MME test1 is already set as default route, remove it before setting it here.</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn)# mme test1</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# no gtp ran-info-relay default</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn)# mme test0</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay default</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn-mme)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+sgsn</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+ mme test0</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp remote-ip 1.2.3.4</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp ran-info-relay default</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp ran-info-relay 907 10 567</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp ran-info-relay 202 12 51</span><br><span style="color: hsl(120, 100%, 40%);">+ mme test1</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp remote-ip 5.6.7.8</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn)# no mme test0</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+sgsn</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+ no compression v42bis</span><br><span style="color: hsl(120, 100%, 40%);">+ mme test1</span><br><span style="color: hsl(120, 100%, 40%);">+  gtp remote-ip 5.6.7.8</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoSGSN(config-sgsn)# no mme test1</span><br><span>diff --git a/tests/sgsn/Makefile.am b/tests/sgsn/Makefile.am</span><br><span>index b72c446..bdf941d 100644</span><br><span>--- a/tests/sgsn/Makefile.am</span><br><span>+++ b/tests/sgsn/Makefile.am</span><br><span>@@ -50,6 +50,7 @@</span><br><span>         $(top_builddir)/src/sgsn/gprs_gmm_fsm.o \</span><br><span>    $(top_builddir)/src/sgsn/gprs_mm_state_gb_fsm.o \</span><br><span>    $(top_builddir)/src/sgsn/gprs_sgsn.o \</span><br><span style="color: hsl(120, 100%, 40%);">+        $(top_builddir)/src/sgsn/gtp_mme.o \</span><br><span>         $(top_builddir)/src/sgsn/sgsn_vty.o \</span><br><span>        $(top_builddir)/src/sgsn/sgsn_libgtp.o \</span><br><span>     $(top_builddir)/src/sgsn/sgsn_auth.o \</span><br><span>@@ -62,6 +63,7 @@</span><br><span>         $(top_builddir)/src/sgsn/gprs_sndcp_pcomp.o \</span><br><span>         $(top_builddir)/src/sgsn/v42bis.o \</span><br><span>         $(top_builddir)/src/sgsn/gprs_sndcp_dcomp.o \</span><br><span style="color: hsl(120, 100%, 40%);">+   $(top_builddir)/src/sgsn/sgsn_rim.o \</span><br><span>        $(top_builddir)/src/gprs/gprs_utils.o \</span><br><span>      $(top_builddir)/src/gprs/gprs_llc_parse.o \</span><br><span>  $(top_builddir)/src/gprs/gprs_gb_parse.o \</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/24164">change 24164</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-sgsn/+/24164"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-sgsn </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I396450b8d8b66595dab8ff7bf41cbf964bb40d93 </div>
<div style="display:none"> Gerrit-Change-Number: 24164 </div>
<div style="display:none"> Gerrit-PatchSet: 9 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-Reviewer: osmith <osmith@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>