<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-hnodeb/+/26503">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">First implementation of the LLSK gtp SAPI<br><br>Change-Id: I5a6f5dfc4e508c92adb35210b4dc576d64353366<br>---<br>M configure.ac<br>M include/osmocom/hnodeb/Makefile.am<br>A include/osmocom/hnodeb/gtp.h<br>M include/osmocom/hnodeb/hnb_prim.h<br>M include/osmocom/hnodeb/hnodeb.h<br>M include/osmocom/hnodeb/llsk.h<br>M include/osmocom/hnodeb/vty.h<br>M src/osmo-hnodeb/Makefile.am<br>M src/osmo-hnodeb/debug.c<br>A src/osmo-hnodeb/gtp.c<br>M src/osmo-hnodeb/hnb.c<br>M src/osmo-hnodeb/llsk.c<br>A src/osmo-hnodeb/llsk_gtp.c<br>M src/osmo-hnodeb/main.c<br>M src/osmo-hnodeb/vty.c<br>15 files changed, 722 insertions(+), 4 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-hnodeb refs/changes/03/26503/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configure.ac b/configure.ac</span><br><span>index e96a6a1..8a34b82 100644</span><br><span>--- a/configure.ac</span><br><span>+++ b/configure.ac</span><br><span>@@ -67,6 +67,7 @@</span><br><span> PKG_CHECK_MODULES(LIBOSMORUA, libosmo-rua >= 0.8.0)</span><br><span> PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.8.0)</span><br><span> PKG_CHECK_MODULES(LIBOSMOHNBAP, libosmo-hnbap >= 0.8.0)</span><br><span style="color: hsl(120, 100%, 40%);">+PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.8.0)</span><br><span> </span><br><span> </span><br><span> dnl checks for header files</span><br><span>diff --git a/include/osmocom/hnodeb/Makefile.am b/include/osmocom/hnodeb/Makefile.am</span><br><span>index dcb3868..381cff9 100644</span><br><span>--- a/include/osmocom/hnodeb/Makefile.am</span><br><span>+++ b/include/osmocom/hnodeb/Makefile.am</span><br><span>@@ -1,4 +1,5 @@</span><br><span> noinst_HEADERS = \</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp.h \</span><br><span> hnb_shutdown_fsm.h \</span><br><span> hnb_prim.h \</span><br><span> hnbap.h \</span><br><span>diff --git a/include/osmocom/hnodeb/gtp.h b/include/osmocom/hnodeb/gtp.h</span><br><span>new file mode 100644</span><br><span>index 0000000..8af69c8</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/hnodeb/gtp.h</span><br><span>@@ -0,0 +1,32 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></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%);">+ * All Rights Reserved</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/lienses/>.</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%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int hnb_gtp_bind(struct hnb *hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+void hnb_gtp_unbind(struct hnb *hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int hnb_ue_gtp_bind(struct hnb_ue *ue, const struct osmo_sockaddr *rem_addr, uint32_t rem_tei,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr *loc_addr, uint32_t *loc_tei);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int hnb_ue_gtp_tx(struct hnb_ue *ue, void *gtpu_payload, unsigned gtpu_payload_len);</span><br><span>diff --git a/include/osmocom/hnodeb/hnb_prim.h b/include/osmocom/hnodeb/hnb_prim.h</span><br><span>index 8f9466d..fbcd07a 100644</span><br><span>--- a/include/osmocom/hnodeb/hnb_prim.h</span><br><span>+++ b/include/osmocom/hnodeb/hnb_prim.h</span><br><span>@@ -223,3 +223,71 @@</span><br><span> struct hnb_audio_conn_data_ind_param conn_data_ind;</span><br><span> } u;</span><br><span> } __attribute__ ((packed));</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%);">+ * GTP</span><br><span style="color: hsl(120, 100%, 40%);">+ ***************************/</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief HNB_GTP primitives */</span><br><span style="color: hsl(120, 100%, 40%);">+enum hnb_gtp_prim_type {</span><br><span style="color: hsl(120, 100%, 40%);">+ HNB_GTP_PRIM_CONN_ESTABLISH,</span><br><span style="color: hsl(120, 100%, 40%);">+ HNB_GTP_PRIM_CONN_RELEASE,</span><br><span style="color: hsl(120, 100%, 40%);">+ HNB_GTP_PRIM_CONN_DATA,</span><br><span style="color: hsl(120, 100%, 40%);">+ _HNB_GTP_PRIM_MAX</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%);">+/* HNB_GTP_PRIM_CONN_ESTABLISH, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_establish_req_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t remote_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t spare1;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t remote_gtpu_address_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ union u_addr remote_gtpu_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* HNB_GTP_PRIM_CONN_ESTABLISH, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_establish_cnf_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t local_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t error_code; /* 0 = success, !0 = failure */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t local_gtpu_address_type; /* enum u_addr_type */</span><br><span style="color: hsl(120, 100%, 40%);">+ union u_addr local_gtpu_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* HNB_GTP_PRIM_CONN_RELEASE, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_release_req_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t remote_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* HNB_GTP_PRIM_CONN_RELEASE, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_release_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t local_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* HNB_GTP_PRIM_CONN_DATA, DL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_data_ind_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t local_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t data_len; /* GTP-U payload length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+ char data[0]; /* GTP-U payload (aka IP packet) */</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* HNB_GTP_PRIM_CONN_DATA, UL */</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_conn_data_req_param {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t remote_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t data_len; /* GTP-U payload length in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+ char data[0]; /* GTP-U payload (aka IP packet) */</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_prim {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_prim_hdr hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ union {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_gtp_conn_establish_req_param conn_establish_req;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_gtp_conn_establish_cnf_param conn_establish_cnf;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_gtp_conn_release_req_param conn_release_req;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_gtp_conn_data_req_param conn_data_req;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_gtp_conn_data_ind_param conn_data_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+ } u;</span><br><span style="color: hsl(120, 100%, 40%);">+} __attribute__ ((packed));</span><br><span>diff --git a/include/osmocom/hnodeb/hnodeb.h b/include/osmocom/hnodeb/hnodeb.h</span><br><span>index f3bf655..1dd1027 100644</span><br><span>--- a/include/osmocom/hnodeb/hnodeb.h</span><br><span>+++ b/include/osmocom/hnodeb/hnodeb.h</span><br><span>@@ -35,6 +35,9 @@</span><br><span> #include <osmocom/gsm/protocol/gsm_23_003.h></span><br><span> #include <osmocom/netif/stream.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <gtp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <pdp.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include <osmocom/hnodeb/llsk.h></span><br><span> </span><br><span> enum {</span><br><span>@@ -45,6 +48,7 @@</span><br><span> DSCTP,</span><br><span> DLLSK,</span><br><span> DRTP,</span><br><span style="color: hsl(120, 100%, 40%);">+ DGTP,</span><br><span> };</span><br><span> extern const struct log_info hnb_log_info;</span><br><span> </span><br><span>@@ -65,6 +69,9 @@</span><br><span> struct hnb_ue_ps_ctx {</span><br><span> bool active; /* Is this chan in use? */</span><br><span> bool conn_est_cnf_pending; /* Did we send CONN_ESTABLISH_CNF to lower layers? */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t local_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t remote_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct pdp_t *pdp_lib;</span><br><span> } conn_ps;</span><br><span> };</span><br><span> struct hnb_ue *hnb_ue_alloc(struct hnb *hnb, uint32_t conn_id);</span><br><span>@@ -72,6 +79,7 @@</span><br><span> void hnb_ue_reset_chan(struct hnb_ue *ue, bool is_ps);</span><br><span> int hnb_ue_voicecall_setup(struct hnb_ue *ue, const struct osmo_sockaddr *rem_addr, struct osmo_sockaddr *loc_addr);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct hnb {</span><br><span> char *identity; /* HNB-Identity */</span><br><span> struct osmo_plmn_id plmn;</span><br><span>@@ -104,6 +112,15 @@</span><br><span> int priority;</span><br><span> } rtp;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ struct gtp {</span><br><span style="color: hsl(120, 100%, 40%);">+ char *cfg_local_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr local_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsn_t *gsn;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fd fd0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fd fd1c;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fd fd1u;</span><br><span style="color: hsl(120, 100%, 40%);">+ } gtp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> uint16_t rnc_id;</span><br><span> bool registered; /* Set to true once HnbRegisterAccept was received from Iuh. rnc_id is valid iif registered==true */</span><br><span> </span><br><span>@@ -118,6 +135,7 @@</span><br><span> struct hnb *hnb_alloc(void *tall_ctx);</span><br><span> void hnb_free(struct hnb *hnb);</span><br><span> struct hnb_ue *hnb_find_ue_by_id(const struct hnb *hnb, uint32_t conn_id);</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ue *hnb_find_ue_by_tei(const struct hnb *hnb, uint32_t tei, bool is_remote);</span><br><span> struct hnb_ue *hnb_find_ue_by_imsi(const struct hnb *hnb, char *imsi);</span><br><span> </span><br><span> extern void *tall_hnb_ctx;</span><br><span>diff --git a/include/osmocom/hnodeb/llsk.h b/include/osmocom/hnodeb/llsk.h</span><br><span>index 081ee88..a6d8a57 100644</span><br><span>--- a/include/osmocom/hnodeb/llsk.h</span><br><span>+++ b/include/osmocom/hnodeb/llsk.h</span><br><span>@@ -56,3 +56,8 @@</span><br><span> uint8_t domain,</span><br><span> const uint8_t *data,</span><br><span> uint32_t data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string hnb_gtp_prim_type_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+int llsk_rx_gtp(struct hnb *hnb, struct osmo_prim_hdr *oph);</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_gtp_prim *hnb_gtp_makeprim_conn_data_ind(uint32_t context_id, uint32_t local_tei,</span><br><span style="color: hsl(120, 100%, 40%);">+ const uint8_t *data, uint32_t data_len);</span><br><span>diff --git a/include/osmocom/hnodeb/vty.h b/include/osmocom/hnodeb/vty.h</span><br><span>index 627436d..5c11302 100644</span><br><span>--- a/include/osmocom/hnodeb/vty.h</span><br><span>+++ b/include/osmocom/hnodeb/vty.h</span><br><span>@@ -28,6 +28,7 @@</span><br><span> HNODEB_NODE = _LAST_OSMOVTY_NODE,</span><br><span> IUH_NODE,</span><br><span> LLSK_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+ GTP_NODE,</span><br><span> };</span><br><span> </span><br><span> void hnb_vty_init(void);</span><br><span>diff --git a/src/osmo-hnodeb/Makefile.am b/src/osmo-hnodeb/Makefile.am</span><br><span>index 4182814..6edbf88 100644</span><br><span>--- a/src/osmo-hnodeb/Makefile.am</span><br><span>+++ b/src/osmo-hnodeb/Makefile.am</span><br><span>@@ -19,6 +19,7 @@</span><br><span> $(LIBOSMORUA_CFLAGS) \</span><br><span> $(LIBOSMORANAP_CFLAGS) \</span><br><span> $(LIBOSMOHNBAP_CFLAGS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBGTP_CFLAGS) \</span><br><span> $(NULL)</span><br><span> </span><br><span> AM_LDFLAGS = \</span><br><span>@@ -32,12 +33,14 @@</span><br><span> osmo_hnodeb_SOURCES = \</span><br><span> main.c \</span><br><span> debug.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp.c \</span><br><span> hnbap.c \</span><br><span> hnb.c \</span><br><span> hnb_shutdown_fsm.c \</span><br><span> iuh.c \</span><br><span> llsk.c \</span><br><span> llsk_audio.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ llsk_gtp.c \</span><br><span> llsk_iuh.c \</span><br><span> ranap.c \</span><br><span> rtp.c \</span><br><span>@@ -60,4 +63,5 @@</span><br><span> $(LIBOSMORANAP_LIBS) \</span><br><span> $(LIBOSMOHNBAP_LIBS) \</span><br><span> $(LIBSCTP_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBGTP_LIBS) \</span><br><span> $(NULL)</span><br><span>diff --git a/src/osmo-hnodeb/debug.c b/src/osmo-hnodeb/debug.c</span><br><span>index 5d0dabd..f122b86 100644</span><br><span>--- a/src/osmo-hnodeb/debug.c</span><br><span>+++ b/src/osmo-hnodeb/debug.c</span><br><span>@@ -57,6 +57,11 @@</span><br><span> .color = "\033[1;32m",</span><br><span> .description = "RTP Core Network side",</span><br><span> },</span><br><span style="color: hsl(120, 100%, 40%);">+ [DRTP] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "DRTP", .loglevel = LOGL_NOTICE, .enabled = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ .color = "\033[1;30m",</span><br><span style="color: hsl(120, 100%, 40%);">+ .description = "GPRS Tunnelling Protocol",</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span> };</span><br><span> </span><br><span> const struct log_info hnb_log_info = {</span><br><span>diff --git a/src/osmo-hnodeb/gtp.c b/src/osmo-hnodeb/gtp.c</span><br><span>new file mode 100644</span><br><span>index 0000000..ef7b3f8</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-hnodeb/gtp.c</span><br><span>@@ -0,0 +1,233 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></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%);">+ * All Rights Reserved</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/lienses/>.</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%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/gtp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnodeb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/llsk.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <gtp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <pdp.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Get osa of locally bound GTP-U socket */</span><br><span style="color: hsl(120, 100%, 40%);">+int sk_get_bound_addr(int fd, struct osmo_sockaddr *osa)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ //uint16_t port;</span><br><span style="color: hsl(120, 100%, 40%);">+ socklen_t alen = sizeof(*osa);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = getsockname(fd, (struct sockaddr *)&osa->u.sa, &alen);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</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%);">+ /* Is this really needed? or getsockname already gathers the port? */</span><br><span style="color: hsl(120, 100%, 40%);">+ /*port = rtp_session_get_local_port(rs->sess);</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (osa->u.sa.sa_family) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AF_INET6:</span><br><span style="color: hsl(120, 100%, 40%);">+ osa->u.sin6.sin6_port = htons(port);</span><br><span style="color: hsl(120, 100%, 40%);">+ case AF_INET:</span><br><span style="color: hsl(120, 100%, 40%);">+ osa->u.sin.sin_port = htons(port);</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</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%);">+ return 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%);">+/* Called whenever we receive a DATA packet */</span><br><span style="color: hsl(120, 100%, 40%);">+static int hnb_gtp_cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_gtp_prim *gtp_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_ue *ue = lib->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb *hnb = ue->hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGUE(ue, DGTP, LOGL_DEBUG, "Rx GTP-U packet %p len=%u\n", packet, len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ue || !ue->conn_ps.active) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGUE(ue, DGTP, LOGL_NOTICE, "Rx GTP-U packet %p len=%u but UE conn_ps is not active!\n", packet, len);</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%);">+ LOGUE(ue, DGTP, LOGL_DEBUG, "Tx GTP-CONN_DATA.req data=%p len=%u\n", packet, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim = hnb_gtp_makeprim_conn_data_ind(ue->conn_id, ue->conn_ps.local_tei, packet, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((rc = osmo_prim_srv_send(hnb->llsk, gtp_prim->hdr.msg)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGUE(ue, DGTP, LOGL_ERROR, "Failed Tx GTP-CONN_DATA.req data=%p len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ packet, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</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 style="color: hsl(120, 100%, 40%);">+/* libgtp select loop integration */</span><br><span style="color: hsl(120, 100%, 40%);">+static int hnb_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb *hnb = fd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(what & OSMO_FD_READ))</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (fd->priv_nr) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case 0:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gtp_decaps0(hnb->gtp.gsn);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case 1:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gtp_decaps1c(hnb->gtp.gsn);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case 2:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gtp_decaps1u(hnb->gtp.gsn);</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%);">+ rc = -EINVAL;</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%);">+ return rc;</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%);">+int hnb_gtp_bind(struct hnb *hnb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsn_t *gsn;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct in_addr inaddr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = inet_pton(AF_INET, hnb->gtp.cfg_local_addr, &inaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc <= 0)</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%);">+ /* TODO: add new mode GTP_MODE_GTPU_ONLY to set up gtpu side only (and ignore statedir) */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gtp_new(&gsn, "/tmp", &inaddr, GTP_MODE_SGSN);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DGTP, LOGL_ERROR, "Failed to set up GTP socket: %s\n", strerror(-rc));</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 style="color: hsl(120, 100%, 40%);">+ rc = sk_get_bound_addr(gsn->fd1u, &hnb->gtp.local_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DGTP, LOGL_ERROR, "Failed to get GTP-U socket bound address: %s\n", strerror(-rc));</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 style="color: hsl(120, 100%, 40%);">+ osmo_fd_setup(&hnb->gtp.fd0, gsn->fd0, OSMO_FD_READ, hnb_gtp_fd_cb, hnb, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((rc = osmo_fd_register(&hnb->gtp.fd0)) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_setup(&hnb->gtp.fd1c, gsn->fd1c, OSMO_FD_READ, hnb_gtp_fd_cb, hnb, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((rc = osmo_fd_register(&hnb->gtp.fd1c)) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_setup(&hnb->gtp.fd1u, gsn->fd1u, OSMO_FD_READ, hnb_gtp_fd_cb, hnb, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((rc = osmo_fd_register(&hnb->gtp.fd1u)) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_set_cb_data_ind(gsn, hnb_gtp_cb_data_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.gsn = gsn;</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+free_ret:</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_unregister(&hnb->gtp.fd1u);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_unregister(&hnb->gtp.fd1c);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_unregister(&hnb->gtp.fd0);</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_free(gsn);</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.fd0.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.fd1c.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.fd1u.fd = -1;</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 style="color: hsl(120, 100%, 40%);">+void hnb_gtp_unbind(struct hnb *hnb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_unregister(&hnb->gtp.fd1u);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_unregister(&hnb->gtp.fd1c);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_unregister(&hnb->gtp.fd0);</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_free(hnb->gtp.gsn);</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.gsn = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.fd0.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.fd1c.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.fd1u.fd = -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%);">+int hnb_ue_gtp_bind(struct hnb_ue *ue, const struct osmo_sockaddr *rem_addr, uint32_t rem_tei,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr *loc_addr, uint32_t *loc_tei)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb *hnb = ue->hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct pdp_t *pdp;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct in_addr rem_in;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGUE(ue, DGTP, LOGL_INFO, "Creating PDP context\n");</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 (rem_addr->u.sa.sa_family != AF_INET) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGUE(ue, DGTP, LOGL_ERROR, "Failed creating PDP context: unsupported proto family %u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ rem_addr->u.sa.sa_family);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENOTSUP;</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%);">+ rem_in = rem_addr->u.sin.sin_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gtp_pdp_newpdp(hnb->gtp.gsn, &pdp, ue->conn_id, 0 /* TODO: NSAPI? */, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGUE(ue, DGTP, LOGL_ERROR, "Failed creating PDP context: %s\n", strerror(-rc));</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%);">+ pdp->priv = ue;</span><br><span style="color: hsl(120, 100%, 40%);">+ ue->conn_ps.pdp_lib = pdp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pdp->teid_gn = rem_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ pdp->version = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ pdp->hisaddr0 = rem_in;</span><br><span style="color: hsl(120, 100%, 40%);">+ pdp->hisaddr1 = rem_in;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pdp->gsnru.l = sizeof(rem_in);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(pdp->gsnru.v, &rem_in, sizeof(rem_in));</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%);">+ pdp->gsnlu.l = sizeof(hnb->gtp.local_addr.u.sin.sin_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(pdp->gsnlu.v, &hnb->gtp.local_addr.u.sin.sin_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+ sizeof(hnb->gtp.local_addr.u.sin.sin_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ *loc_addr = hnb->gtp.local_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+ //loc_addr->u.sin.sin_family = AF_INET;</span><br><span style="color: hsl(120, 100%, 40%);">+ //loc_addr->u.sin.sin_addr = hnb->gtp.gsn->gsnu;</span><br><span style="color: hsl(120, 100%, 40%);">+ //loc_addr->u.sin.sin_port = GTP1U_PORT;</span><br><span style="color: hsl(120, 100%, 40%);">+ *loc_tei = pdp->teid_own;</span><br><span style="color: hsl(120, 100%, 40%);">+ return 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%);">+int hnb_ue_gtp_tx(struct hnb_ue *ue, void *gtpu_payload, unsigned gtpu_payload_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb *hnb = ue->hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!hnb->gtp.gsn) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGUE(ue, DGTP, LOGL_ERROR, "Tx: GTP socket not bound\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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ue || !ue->conn_ps.pdp_lib) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGUE(ue, DGTP, LOGL_ERROR, "Tx: UE PDP Ctx not available\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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gtp_data_req(hnb->gtp.gsn, ue->conn_ps.pdp_lib, gtpu_payload, gtpu_payload_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-hnodeb/hnb.c b/src/osmo-hnodeb/hnb.c</span><br><span>index f8878bd..787985a 100644</span><br><span>--- a/src/osmo-hnodeb/hnb.c</span><br><span>+++ b/src/osmo-hnodeb/hnb.c</span><br><span>@@ -57,6 +57,11 @@</span><br><span> hnb->rtp.ip_dscp = -1;</span><br><span> hnb->rtp.priority = -1;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.cfg_local_addr = talloc_strdup(hnb, "0.0.0.0");</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.fd0.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.fd1c.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.fd1u.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> hnb->shutdown_fi = osmo_fsm_inst_alloc(&hnb_shutdown_fsm, hnb, hnb,</span><br><span> LOGL_INFO, NULL);</span><br><span> </span><br><span>@@ -84,6 +89,11 @@</span><br><span> osmo_prim_srv_link_free(hnb->llsk_link);</span><br><span> hnb->llsk_link = NULL;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (hnb->gtp.gsn) {</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_free(hnb->gtp.gsn);</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->gtp.gsn = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> talloc_free(hnb);</span><br><span> }</span><br><span> </span><br><span>@@ -114,6 +124,8 @@</span><br><span> void hnb_ue_reset_chan(struct hnb_ue *ue, bool is_ps)</span><br><span> {</span><br><span> if (is_ps) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ue->conn_ps.pdp_lib)</span><br><span style="color: hsl(120, 100%, 40%);">+ pdp_freepdp(ue->conn_ps.pdp_lib);</span><br><span> ue->conn_ps = (struct hnb_ue_ps_ctx){0};</span><br><span> } else {</span><br><span> if (ue->conn_cs.rtp.socket)</span><br><span>@@ -199,6 +211,22 @@</span><br><span> }</span><br><span> return NULL;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct hnb_ue *hnb_find_ue_by_tei(const struct hnb *hnb, uint32_t tei, bool is_remote)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_ue *ue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(ue, &hnb->ue_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ue->conn_ps.active)</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t ue_tei = is_remote ? ue->conn_ps.remote_tei : ue->conn_ps.local_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tei != ue_tei)</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+ return ue;</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> struct hnb_ue *hnb_find_ue_by_imsi(const struct hnb *hnb, char *imsi)</span><br><span> {</span><br><span> struct hnb_ue *ue;</span><br><span>diff --git a/src/osmo-hnodeb/llsk.c b/src/osmo-hnodeb/llsk.c</span><br><span>index 121a3a8..92e5e91 100644</span><br><span>--- a/src/osmo-hnodeb/llsk.c</span><br><span>+++ b/src/osmo-hnodeb/llsk.c</span><br><span>@@ -129,7 +129,8 @@</span><br><span> return false;</span><br><span> </span><br><span> if (hnb->llsk_valid_sapi_mask & (1 << HNB_PRIM_SAPI_IUH) &&</span><br><span style="color: hsl(0, 100%, 40%);">- hnb->llsk_valid_sapi_mask & (1 << HNB_PRIM_SAPI_AUDIO))</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->llsk_valid_sapi_mask & (1 << HNB_PRIM_SAPI_AUDIO) &&</span><br><span style="color: hsl(120, 100%, 40%);">+ hnb->llsk_valid_sapi_mask & (1 << HNB_PRIM_SAPI_GTP))</span><br><span> return true;</span><br><span> return false;</span><br><span> }</span><br><span>@@ -164,9 +165,7 @@</span><br><span> case HNB_PRIM_SAPI_IUH:</span><br><span> return llsk_rx_iuh(hnb, oph);</span><br><span> case HNB_PRIM_SAPI_GTP:</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DLLSK, LOGL_ERROR, "Rx SAPI %u not yet implemented (len=%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- oph->sap, msgb_length(oph->msg));</span><br><span style="color: hsl(0, 100%, 40%);">- return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ return llsk_rx_gtp(hnb, oph);</span><br><span> case HNB_PRIM_SAPI_AUDIO:</span><br><span> return llsk_rx_audio(hnb, oph);</span><br><span> default:</span><br><span>diff --git a/src/osmo-hnodeb/llsk_gtp.c b/src/osmo-hnodeb/llsk_gtp.c</span><br><span>new file mode 100644</span><br><span>index 0000000..f526426</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-hnodeb/llsk_gtp.c</span><br><span>@@ -0,0 +1,278 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></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%);">+ * All Rights Reserved</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/lienses/>.</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%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <arpa/inet.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnodeb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/llsk.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/hnb_prim.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/gtp.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t llsk_gtp_prim_size_tbl[4][_HNB_GTP_PRIM_MAX] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [PRIM_OP_REQUEST] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [HNB_GTP_PRIM_CONN_ESTABLISH] = sizeof(struct hnb_gtp_conn_establish_req_param),</span><br><span style="color: hsl(120, 100%, 40%);">+ [HNB_GTP_PRIM_CONN_RELEASE] = sizeof(struct hnb_gtp_conn_release_req_param),</span><br><span style="color: hsl(120, 100%, 40%);">+ [HNB_GTP_PRIM_CONN_DATA] = sizeof(struct hnb_gtp_conn_data_req_param),</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ [PRIM_OP_RESPONSE] = {},</span><br><span style="color: hsl(120, 100%, 40%);">+ [PRIM_OP_INDICATION] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [HNB_GTP_PRIM_CONN_DATA] = sizeof(struct hnb_gtp_conn_data_ind_param),</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+ [PRIM_OP_CONFIRM] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [HNB_GTP_PRIM_CONN_ESTABLISH] = sizeof(struct hnb_gtp_conn_establish_cnf_param),</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 inline size_t llsk_gtp_prim_size(enum hnb_gtp_prim_type ptype, enum osmo_prim_operation op)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t val = llsk_gtp_prim_size_tbl[op][ptype];</span><br><span style="color: hsl(120, 100%, 40%);">+ if (val == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_FATAL, "Expected prim_size != 0 for ptype=%u op=%u\n", ptype, op);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_panic("Expected prim_size != 0 for ptype=%u op=%u\n", ptype, op);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return val;</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%);">+const struct value_string hnb_gtp_prim_type_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_VALUE_STRING(HNB_GTP_PRIM_CONN_ESTABLISH),</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_VALUE_STRING(HNB_GTP_PRIM_CONN_RELEASE),</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_VALUE_STRING(HNB_GTP_PRIM_CONN_DATA),</span><br><span style="color: hsl(120, 100%, 40%);">+ { 0, 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%);">+static struct hnb_gtp_prim *hnb_gtp_prim_alloc(enum hnb_gtp_prim_type ptype, enum osmo_prim_operation op, size_t extra_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_prim_hdr *oph;</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t len = llsk_gtp_prim_size(ptype, op);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ oph = osmo_prim_msgb_alloc(HNB_PRIM_SAPI_GTP, ptype, op, sizeof(*oph) + len + extra_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!oph)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_put(oph->msg, len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return (struct hnb_gtp_prim *)oph;</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 struct hnb_gtp_prim *hnb_gtp_makeprim_conn_establish_cnf(uint32_t context_id, uint8_t error_code,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t local_tei, uint8_t local_gtpu_address_type,</span><br><span style="color: hsl(120, 100%, 40%);">+ const union u_addr *local_gtpu_addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_gtp_prim *gtp_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim = hnb_gtp_prim_alloc(HNB_GTP_PRIM_CONN_ESTABLISH, PRIM_OP_CONFIRM, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim->u.conn_establish_cnf.context_id = context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim->u.conn_establish_cnf.local_tei = local_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim->u.conn_establish_cnf.error_code = error_code;</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim->u.conn_establish_cnf.local_gtpu_address_type = local_gtpu_address_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (local_gtpu_addr)</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim->u.conn_establish_cnf.local_gtpu_addr = *local_gtpu_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return gtp_prim;</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 hnb_gtp_prim *hnb_gtp_makeprim_conn_data_ind(uint32_t context_id, uint32_t local_tei,</span><br><span style="color: hsl(120, 100%, 40%);">+ const uint8_t *data, uint32_t data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_gtp_prim *gtp_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim = hnb_gtp_prim_alloc(HNB_GTP_PRIM_CONN_DATA, PRIM_OP_INDICATION, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim->u.conn_data_ind.context_id = context_id;</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim->u.conn_data_ind.local_tei = local_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim->u.conn_data_ind.data_len = data_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (data_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_put(gtp_prim->hdr.msg, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(gtp_prim->u.conn_data_ind.data, data, data_len);</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 gtp_prim;</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 int _send_conn_establish_cnf_failed(struct hnb *hnb, uint32_t context_id, uint8_t error_code)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_gtp_prim *gtp_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Tx GTP-CONN_ESTABLISH.cnf: ctx=%u error_code=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ context_id, error_code);</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim = hnb_gtp_makeprim_conn_establish_cnf(context_id, error_code, 0, HNB_PRIM_ADDR_TYPE_UNSPEC, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((rc = osmo_prim_srv_send(hnb->llsk, gtp_prim->hdr.msg)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Failed sending GTP-CONN_ESTABLISH.cnf context_id=%u error_code=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ context_id, error_code);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</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 style="color: hsl(120, 100%, 40%);">+static int llsk_rx_gtp_conn_establish_req(struct hnb *hnb, struct hnb_gtp_conn_establish_req_param *ce_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_ue *ue;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_gtp_prim *gtp_prim;</span><br><span style="color: hsl(120, 100%, 40%);">+ int af;</span><br><span style="color: hsl(120, 100%, 40%);">+ char rem_addrstr[INET6_ADDRSTRLEN+32];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr rem_osa = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sockaddr loc_osa = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+ union u_addr loc_uaddr = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t loc_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = ll_addr2osa(ce_req->remote_gtpu_address_type, &ce_req->remote_gtpu_addr, GTP1U_PORT, &rem_osa);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_ESTABLISH.req: ctx=%u with unexpected address type %u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ce_req->context_id, ce_req->remote_gtpu_address_type);</span><br><span style="color: hsl(120, 100%, 40%);">+ return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_sockaddr_to_str_buf(rem_addrstr, sizeof(rem_addrstr), &rem_osa);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_INFO, "Rx GTP-CONN_ESTABLISH.req ctx=%u rem_tei=%u rem_addr=%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ce_req->context_id, ce_req->remote_tei, rem_addrstr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((af = ll_addr_type2af(ce_req->remote_gtpu_address_type)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_ESTABLISH.req: ctx=%u with unexpected address type %u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ce_req->context_id, ce_req->remote_gtpu_address_type);</span><br><span style="color: hsl(120, 100%, 40%);">+ return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 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%);">+ ue = hnb_find_ue_by_id(hnb, ce_req->context_id);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ue) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_ESTABLISH.req: UE not found! ctx=%u rem_addr=%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ce_req->context_id, rem_addrstr);</span><br><span style="color: hsl(120, 100%, 40%);">+ return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ue->conn_ps.active) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_ESTABLISH.req: PS chan not active! ctx=%u rem_addr=%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ce_req->context_id, rem_addrstr);</span><br><span style="color: hsl(120, 100%, 40%);">+ return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 3);</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%);">+ /* Create the socket: */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((rc = hnb_ue_gtp_bind(ue, &rem_osa, ce_req->remote_tei, &loc_osa, &loc_tei)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_ESTABLISH.req: Failed to set up gtp socket ctx=%u rem_tei=%u rem_addr=%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ce_req->context_id, ce_req->remote_tei, rem_addrstr);</span><br><span style="color: hsl(120, 100%, 40%);">+ return _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 4);</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%);">+ /* Convert resulting local address back to LLSK format: */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (osa2_ll_addr(&loc_osa, &loc_uaddr, NULL) != ce_req->remote_gtpu_address_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_ESTABLISH.req: Failed to provide proper local address ctx=%u rem_addr=%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ce_req->context_id, rem_addrstr);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = _send_conn_establish_cnf_failed(hnb, ce_req->context_id, 4);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto release_sock;</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%);">+ /* Submit successful confirmation */</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_INFO, "Tx GTP-CONN_ESTABLISH.cnf: ctx=%u error_code=0 rem_addr=%s rem_tei=%u loc_addr=%s local_tei=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ce_req->context_id, rem_addrstr, ce_req->remote_tei, osmo_sockaddr_to_str(&loc_osa), loc_tei);</span><br><span style="color: hsl(120, 100%, 40%);">+ gtp_prim = hnb_gtp_makeprim_conn_establish_cnf(ce_req->context_id, 0, loc_tei, ce_req->remote_gtpu_address_type, &loc_uaddr);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((rc = osmo_prim_srv_send(hnb->llsk, gtp_prim->hdr.msg)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Failed sending GTP-CONN_ESTABLISH.cnf context_id=%u error_code=0\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ce_req->context_id);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto release_sock;</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%);">+ ue->conn_ps.local_tei = loc_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+ ue->conn_ps.remote_tei = ce_req->remote_tei;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+release_sock: /* TODO: release socket here */</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 style="color: hsl(120, 100%, 40%);">+static int llsk_rx_gtp_conn_release_req(struct hnb *hnb, struct hnb_gtp_conn_release_req_param *rel_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_ue *ue;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_DEBUG, "Rx GTP-CONN_RELEASE.req ctx=%u\n", rel_req->context_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ue = hnb_find_ue_by_id(hnb, rel_req->context_id);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ue) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_RELEASE.req: UE not found! ctx=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ rel_req->context_id);</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%);">+ /* TODO: release GTP socket */</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 style="color: hsl(120, 100%, 40%);">+static int llsk_rx_gtp_conn_data_req(struct hnb *hnb, struct hnb_gtp_conn_data_req_param *data_req)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct hnb_ue *ue;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_DEBUG, "Rx GTP-CONN_DATA.req ctx=%u rem_tei=%u data_len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ data_req->context_id, data_req->remote_tei, data_req->data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ue = hnb_find_ue_by_id(hnb, data_req->context_id);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ue) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_DATA.req: UE not found! ctx=%u data_len=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ data_req->context_id, data_req->data_len);</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%);">+ rc = hnb_ue_gtp_tx(ue, data_req->data, data_req->data_len);</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 style="color: hsl(120, 100%, 40%);">+int llsk_rx_gtp(struct hnb *hnb, struct osmo_prim_hdr *oph)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t prim_size = llsk_gtp_prim_size(oph->primitive, oph->operation);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msgb_length(oph->msg) < prim_size) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx GTP-%s.%s with length %u < %zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ get_value_string(hnb_gtp_prim_type_names, oph->primitive),</span><br><span style="color: hsl(120, 100%, 40%);">+ get_value_string(osmo_prim_op_names, oph->operation),</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_length(oph->msg), prim_size);</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%);">+ switch (oph->operation) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case PRIM_OP_REQUEST:</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (oph->primitive) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case HNB_GTP_PRIM_CONN_ESTABLISH:</span><br><span style="color: hsl(120, 100%, 40%);">+ return llsk_rx_gtp_conn_establish_req(hnb, (struct hnb_gtp_conn_establish_req_param *)msgb_data(oph->msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ case HNB_GTP_PRIM_CONN_RELEASE:</span><br><span style="color: hsl(120, 100%, 40%);">+ return llsk_rx_gtp_conn_release_req(hnb, (struct hnb_gtp_conn_release_req_param *)msgb_data(oph->msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ case HNB_GTP_PRIM_CONN_DATA:</span><br><span style="color: hsl(120, 100%, 40%);">+ return llsk_rx_gtp_conn_data_req(hnb, (struct hnb_gtp_conn_data_req_param *)msgb_data(oph->msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx llsk-gtp unknown primitive %u (len=%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ oph->primitive, msgb_length(oph->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%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ case PRIM_OP_RESPONSE:</span><br><span style="color: hsl(120, 100%, 40%);">+ case PRIM_OP_INDICATION:</span><br><span style="color: hsl(120, 100%, 40%);">+ case PRIM_OP_CONFIRM:</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DLLSK, LOGL_ERROR, "Rx llsk-gtp unexpected primitive operation %s::%s (len=%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ get_value_string(hnb_gtp_prim_type_names, oph->primitive),</span><br><span style="color: hsl(120, 100%, 40%);">+ get_value_string(osmo_prim_op_names, oph->operation),</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_length(oph->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>diff --git a/src/osmo-hnodeb/main.c b/src/osmo-hnodeb/main.c</span><br><span>index 9af83ea..5d35c18 100644</span><br><span>--- a/src/osmo-hnodeb/main.c</span><br><span>+++ b/src/osmo-hnodeb/main.c</span><br><span>@@ -51,6 +51,7 @@</span><br><span> #include <osmocom/hnodeb/vty.h></span><br><span> #include <osmocom/hnodeb/hnodeb.h></span><br><span> #include <osmocom/hnodeb/iuh.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/hnodeb/gtp.h></span><br><span> </span><br><span> static const char * const osmohnodeb_copyright =</span><br><span> "OsmoHNodeB - Osmocom 3G Home NodeB implementation\r\n"</span><br><span>@@ -280,6 +281,12 @@</span><br><span> exit(1);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ rc = hnb_gtp_bind(g_hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ perror("Error listening on GTP port");</span><br><span style="color: hsl(120, 100%, 40%);">+ exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> rc = hnb_iuh_connect(g_hnb);</span><br><span> if (rc < 0) {</span><br><span> perror("Error connecting to Iuh port");</span><br><span>@@ -305,6 +312,8 @@</span><br><span> osmo_select_main_ctx(0);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ hnb_gtp_unbind(g_hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> log_fini();</span><br><span> </span><br><span> /**</span><br><span>diff --git a/src/osmo-hnodeb/vty.c b/src/osmo-hnodeb/vty.c</span><br><span>index 131dc6b..e84e330 100644</span><br><span>--- a/src/osmo-hnodeb/vty.c</span><br><span>+++ b/src/osmo-hnodeb/vty.c</span><br><span>@@ -51,6 +51,10 @@</span><br><span> vty->node = HNODEB_NODE;</span><br><span> vty->index = g_hnb;</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GTP_NODE:</span><br><span style="color: hsl(120, 100%, 40%);">+ vty->node = HNODEB_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+ vty->index = g_hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> case HNODEB_NODE:</span><br><span> vty->node = CONFIG_NODE;</span><br><span> vty->index = g_hnb;</span><br><span>@@ -281,6 +285,33 @@</span><br><span> return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct cmd_node gtp_node = {</span><br><span style="color: hsl(120, 100%, 40%);">+ GTP_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+ "%s(config-gtp)# ",</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%);">+#define GTP_STR "Configure the GPRS Tunnelling Protocol parameters\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_hnodeb_gtp,</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg_hnodeb_gtp_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "gtp", GTP_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(g_hnb);</span><br><span style="color: hsl(120, 100%, 40%);">+ vty->index = g_hnb;</span><br><span style="color: hsl(120, 100%, 40%);">+ vty->node = GTP_NODE;</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_hnodeb_gtp_local_ip, cfg_hnodeb_gtp_local_ip_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "local-ip " VTY_IPV4_CMD,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Configure the GTP-U bind address\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "GTP-U local IPv4 address\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_talloc_replace_string(g_hnb, &g_hnb->gtp.cfg_local_addr, argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> static int config_write_hnodeb(struct vty *vty)</span><br><span> {</span><br><span>@@ -302,6 +333,8 @@</span><br><span> vty_out(vty, " remote-port %u%s", g_hnb->iuh.remote_port, VTY_NEWLINE);</span><br><span> vty_out(vty, " ll-socket%s", VTY_NEWLINE);</span><br><span> vty_out(vty, " path %s%s", osmo_prim_srv_link_get_addr(g_hnb->llsk_link), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, " gtp%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_out(vty, " local-ip %s%s", g_hnb->gtp.cfg_local_addr, VTY_NEWLINE);</span><br><span> return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span>@@ -359,6 +392,9 @@</span><br><span> install_element(HNODEB_NODE, &cfg_hnodeb_llsk_cmd);</span><br><span> install_node(&llsk_node, NULL);</span><br><span> install_element(LLSK_NODE, &cfg_hnodeb_llsk_path_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(HNODEB_NODE, &cfg_hnodeb_gtp_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_node(>p_node, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(GTP_NODE, &cfg_hnodeb_gtp_local_ip_cmd);</span><br><span> </span><br><span> install_element_ve(&asn_dbg_cmd);</span><br><span> install_element_ve(&ranap_reset_cmd);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-hnodeb/+/26503">change 26503</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-hnodeb/+/26503"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-hnodeb </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I5a6f5dfc4e508c92adb35210b4dc576d64353366 </div>
<div style="display:none"> Gerrit-Change-Number: 26503 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>