Get rid of libgtp for GTP-U
It doesn't make much sense to pull whole libgtp to implement only the user plan side of GTP. Let's drop it and add a minimal GTP-U implementation here. Related: SYS#5516 Change-Id: I53ad4915aaed3bc7574036e963be10514e370fe2
This commit is contained in:
parent
e4f127f1a3
commit
14cceb5dfb
|
@ -67,7 +67,6 @@ PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.5.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMORUA, libosmo-rua >= 0.8.0)
|
PKG_CHECK_MODULES(LIBOSMORUA, libosmo-rua >= 0.8.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.8.0)
|
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.8.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOHNBAP, libosmo-hnbap >= 0.8.0)
|
PKG_CHECK_MODULES(LIBOSMOHNBAP, libosmo-hnbap >= 0.8.0)
|
||||||
PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.8.0)
|
|
||||||
|
|
||||||
|
|
||||||
dnl checks for header files
|
dnl checks for header files
|
||||||
|
|
|
@ -34,7 +34,6 @@ osmo-build-dep.sh libosmo-abis
|
||||||
osmo-build-dep.sh libosmo-netif
|
osmo-build-dep.sh libosmo-netif
|
||||||
osmo-build-dep.sh libosmo-sccp
|
osmo-build-dep.sh libosmo-sccp
|
||||||
osmo-build-dep.sh libasn1c
|
osmo-build-dep.sh libasn1c
|
||||||
osmo-build-dep.sh osmo-ggsn
|
|
||||||
osmo-build-dep.sh osmo-iuh
|
osmo-build-dep.sh osmo-iuh
|
||||||
|
|
||||||
# Additional configure options and depends
|
# Additional configure options and depends
|
||||||
|
|
|
@ -47,7 +47,6 @@ BuildRequires: pkgconfig(libosmo-ranap) >= 0.8.0
|
||||||
BuildRequires: pkgconfig(libosmo-rua) >= 0.8.0
|
BuildRequires: pkgconfig(libosmo-rua) >= 0.8.0
|
||||||
BuildRequires: pkgconfig(talloc)
|
BuildRequires: pkgconfig(talloc)
|
||||||
BuildRequires: pkgconfig(libasn1c) >= 0.9.30
|
BuildRequires: pkgconfig(libasn1c) >= 0.9.30
|
||||||
BuildRequires: pkgconfig(libgtp) >= 1.8.0
|
|
||||||
%{?systemd_requires}
|
%{?systemd_requires}
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|
|
@ -13,7 +13,6 @@ Build-Depends: debhelper (>=9),
|
||||||
python3-minimal,
|
python3-minimal,
|
||||||
libtalloc-dev,
|
libtalloc-dev,
|
||||||
libasn1c-dev (>= 0.9.30),
|
libasn1c-dev (>= 0.9.30),
|
||||||
libgtp-dev (>= 1.8.0),
|
|
||||||
libsctp-dev,
|
libsctp-dev,
|
||||||
libosmocore-dev (>= 1.6.0),
|
libosmocore-dev (>= 1.6.0),
|
||||||
libosmo-sigtran-dev (>= 1.5.0),
|
libosmo-sigtran-dev (>= 1.5.0),
|
||||||
|
|
|
@ -18,9 +18,6 @@
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <gtp.h>
|
|
||||||
#include <pdp.h>
|
|
||||||
|
|
||||||
#include <osmocom/core/socket.h>
|
#include <osmocom/core/socket.h>
|
||||||
#include <osmocom/core/linuxlist.h>
|
#include <osmocom/core/linuxlist.h>
|
||||||
|
|
||||||
|
@ -38,11 +35,11 @@ struct gtp_conn {
|
||||||
struct osmo_sockaddr rem_addr;
|
struct osmo_sockaddr rem_addr;
|
||||||
uint32_t loc_tei;
|
uint32_t loc_tei;
|
||||||
uint32_t rem_tei;
|
uint32_t rem_tei;
|
||||||
struct pdp_t *pdp_lib;
|
uint16_t seq_nr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gtp_conn *gtp_conn_alloc(struct hnb_ue *ue);
|
struct gtp_conn *gtp_conn_alloc(struct hnb_ue *ue);
|
||||||
void gtp_conn_free(struct gtp_conn *conn);
|
void gtp_conn_free(struct gtp_conn *conn);
|
||||||
|
|
||||||
int gtp_conn_setup(struct gtp_conn *conn, const struct osmo_sockaddr *rem_addr, uint32_t rem_tei);
|
int gtp_conn_setup(struct gtp_conn *conn, const struct osmo_sockaddr *rem_addr, uint32_t rem_tei);
|
||||||
int gtp_conn_tx(struct gtp_conn *conn, void *gtpu_payload, unsigned gtpu_payload_len);
|
int gtp_conn_tx(struct gtp_conn *conn, const uint8_t *gtpu_payload, unsigned gtpu_payload_len);
|
||||||
|
|
|
@ -107,8 +107,7 @@ struct hnb {
|
||||||
struct gtp {
|
struct gtp {
|
||||||
char *cfg_local_addr;
|
char *cfg_local_addr;
|
||||||
struct osmo_sockaddr local_addr;
|
struct osmo_sockaddr local_addr;
|
||||||
struct gsn_t *gsn;
|
struct osmo_wqueue wq1u;
|
||||||
struct osmo_fd fd1u;
|
|
||||||
} gtp;
|
} gtp;
|
||||||
|
|
||||||
uint16_t rnc_id;
|
uint16_t rnc_id;
|
||||||
|
|
|
@ -19,7 +19,6 @@ AM_CFLAGS = \
|
||||||
$(LIBOSMORUA_CFLAGS) \
|
$(LIBOSMORUA_CFLAGS) \
|
||||||
$(LIBOSMORANAP_CFLAGS) \
|
$(LIBOSMORANAP_CFLAGS) \
|
||||||
$(LIBOSMOHNBAP_CFLAGS) \
|
$(LIBOSMOHNBAP_CFLAGS) \
|
||||||
$(LIBGTP_CFLAGS) \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
AM_LDFLAGS = \
|
AM_LDFLAGS = \
|
||||||
|
@ -63,5 +62,4 @@ osmo_hnodeb_LDADD = \
|
||||||
$(LIBOSMORANAP_LIBS) \
|
$(LIBOSMORANAP_LIBS) \
|
||||||
$(LIBOSMOHNBAP_LIBS) \
|
$(LIBOSMOHNBAP_LIBS) \
|
||||||
$(LIBSCTP_LIBS) \
|
$(LIBSCTP_LIBS) \
|
||||||
$(LIBGTP_LIBS) \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -23,11 +23,27 @@
|
||||||
#include <osmocom/hnodeb/gtp.h>
|
#include <osmocom/hnodeb/gtp.h>
|
||||||
#include <osmocom/hnodeb/hnodeb.h>
|
#include <osmocom/hnodeb/hnodeb.h>
|
||||||
#include <osmocom/hnodeb/llsk.h>
|
#include <osmocom/hnodeb/llsk.h>
|
||||||
|
#include <osmocom/core/endian.h>
|
||||||
|
|
||||||
#include <gtp.h>
|
/* 3GPP TS 29.281 */
|
||||||
#include <pdp.h>
|
struct gtp1u_hdr { /* 3GPP TS 29.281 */
|
||||||
|
#if OSMO_IS_LITTLE_ENDIAN
|
||||||
|
uint8_t pn:1, /* N-PDU Number flag */
|
||||||
|
s:1, /* Sequence number flag */
|
||||||
|
e:1, /* Extension header flag */
|
||||||
|
spare:1,
|
||||||
|
pt:1, /* Protocol Type: GTP=1, GTP'=0 */
|
||||||
|
version:3; /* Version: 1 */
|
||||||
|
#elif OSMO_IS_BIG_ENDIAN
|
||||||
|
uint8_t version:3, pt:1, spare:1, e:1, s:1, pn:1;
|
||||||
|
#endif
|
||||||
|
uint8_t msg_type;
|
||||||
|
uint16_t length;
|
||||||
|
uint32_t tei; /* 05 - 08 Tunnel Endpoint ID */
|
||||||
|
uint8_t data[0];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
static uint32_t next_gtp_conn_id = 0;
|
static uint32_t next_gtp_conn_id = 1;
|
||||||
|
|
||||||
struct gtp_conn *gtp_conn_alloc(struct hnb_ue *ue)
|
struct gtp_conn *gtp_conn_alloc(struct hnb_ue *ue)
|
||||||
{
|
{
|
||||||
|
@ -49,14 +65,231 @@ void gtp_conn_free(struct gtp_conn *conn)
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (conn->pdp_lib) {
|
|
||||||
pdp_freepdp(conn->pdp_lib);
|
|
||||||
conn->pdp_lib = NULL;
|
|
||||||
}
|
|
||||||
llist_del(&conn->list);
|
llist_del(&conn->list);
|
||||||
talloc_free(conn);
|
talloc_free(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int gtp_conn_setup(struct gtp_conn *conn, const struct osmo_sockaddr *rem_addr, uint32_t rem_tei)
|
||||||
|
{
|
||||||
|
struct hnb_ue *ue = conn->ue;
|
||||||
|
struct hnb *hnb = ue->hnb;
|
||||||
|
|
||||||
|
LOGUE(ue, DGTP, LOGL_INFO, "Creating PDP context\n");
|
||||||
|
|
||||||
|
|
||||||
|
if (rem_addr->u.sa.sa_family != AF_INET) {
|
||||||
|
LOGUE(ue, DGTP, LOGL_ERROR, "Failed creating PDP context: unsupported proto family %u\n",
|
||||||
|
rem_addr->u.sa.sa_family);
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->id = next_gtp_conn_id++; /* TODO: validate next one is not already taken due to wrap-around */
|
||||||
|
|
||||||
|
conn->loc_addr = hnb->gtp.local_addr;
|
||||||
|
conn->rem_addr = *rem_addr;
|
||||||
|
conn->rem_tei = rem_tei;
|
||||||
|
conn->loc_tei = conn->id; /* We use conn ID as local TEI */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gtp_conn_tx(struct gtp_conn *conn, const uint8_t *gtpu_payload, unsigned gtpu_payload_len)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct hnb_ue *ue;
|
||||||
|
struct hnb *hnb;
|
||||||
|
struct msgb *msg;
|
||||||
|
struct gtp1u_hdr *hdr;
|
||||||
|
struct osmo_sockaddr *sa;
|
||||||
|
const uint8_t opt_hdr_len = 4;
|
||||||
|
unsigned msg_len = sizeof(*hdr) + opt_hdr_len + gtpu_payload_len;
|
||||||
|
|
||||||
|
if (!conn) {
|
||||||
|
LOGP(DGTP, LOGL_ERROR, "Tx: GTP-U conn not available\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ue = conn->ue;
|
||||||
|
hnb = ue->hnb;
|
||||||
|
|
||||||
|
if (hnb->gtp.wq1u.bfd.fd == -1) {
|
||||||
|
LOGP(DGTP, LOGL_ERROR, "Tx: GTP-U socket not available\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gtpu_payload_len == 0) {
|
||||||
|
LOGP(DGTP, LOGL_ERROR, "Tx: GTP-U len=0\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = msgb_alloc_c(hnb, sizeof(*sa) + msg_len, "gtp-ul");
|
||||||
|
|
||||||
|
sa = (struct osmo_sockaddr *)msgb_put(msg, sizeof(*sa));
|
||||||
|
*sa = conn->rem_addr;
|
||||||
|
|
||||||
|
hdr = (struct gtp1u_hdr *)msgb_put(msg, msg_len);
|
||||||
|
hdr->pn = 0;
|
||||||
|
hdr->s = 1;
|
||||||
|
hdr->e = 0;
|
||||||
|
hdr->spare = 0;
|
||||||
|
hdr->pt = 1;
|
||||||
|
hdr->version = 1;
|
||||||
|
hdr->msg_type = 0xff;
|
||||||
|
osmo_store16be(gtpu_payload_len + opt_hdr_len, &hdr->length);
|
||||||
|
osmo_store32be(conn->rem_tei, &hdr->tei);
|
||||||
|
osmo_store16be(conn->seq_nr, &hdr->data[0]);
|
||||||
|
conn->seq_nr++;
|
||||||
|
/* byes 2 and 3 are set to 0 */
|
||||||
|
memcpy(&hdr->data[opt_hdr_len], gtpu_payload, gtpu_payload_len);
|
||||||
|
|
||||||
|
rc = osmo_wqueue_enqueue(&hnb->gtp.wq1u, msg);
|
||||||
|
if (rc < 0)
|
||||||
|
msgb_free(msg);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called whenever we receive a DATA packet */
|
||||||
|
static int hnb_gtp_rx_gtp(struct hnb *hnb, struct msgb *msg, const struct osmo_sockaddr *from)
|
||||||
|
{
|
||||||
|
struct gtp_conn *conn;
|
||||||
|
struct hnb_ue *ue;
|
||||||
|
struct gtp1u_hdr *hdr;
|
||||||
|
uint32_t tei;
|
||||||
|
struct hnb_gtp_prim *gtp_prim;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
hdr = (struct gtp1u_hdr *)msgb_data(msg);
|
||||||
|
tei = osmo_load32be(&hdr->tei);
|
||||||
|
|
||||||
|
/* The local TEI is the GTP conn_id: */
|
||||||
|
conn = hnb_find_gtp_conn_by_id(hnb, tei);
|
||||||
|
if (!conn) {
|
||||||
|
LOGP(DGTP, LOGL_NOTICE, "Tx GTP-CONN_DATA.ind len=%u with no conn!\n",
|
||||||
|
msgb_l3len(msg));
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto free_ret;
|
||||||
|
}
|
||||||
|
ue = conn->ue;
|
||||||
|
|
||||||
|
if (osmo_sockaddr_cmp(from, &conn->rem_addr)) {
|
||||||
|
LOGUE(ue, DGTP, LOGL_NOTICE, "Rx DL GTP-U loc_tei=0x%08x from unexpected addr=%s!\n",
|
||||||
|
tei, osmo_sockaddr_to_str(from));
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto free_ret;
|
||||||
|
}
|
||||||
|
ue = conn->ue;
|
||||||
|
|
||||||
|
if (!ue->conn_ps.active) {
|
||||||
|
LOGUE(ue, DGTP, LOGL_NOTICE, "Tx GTP-CONN_DATA.ind len=%u but UE conn_ps is not active!\n",
|
||||||
|
msgb_l3len(msg));
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto free_ret;
|
||||||
|
}
|
||||||
|
hnb = ue->hnb;
|
||||||
|
|
||||||
|
LOGUE(ue, DGTP, LOGL_DEBUG, "Tx GTP-CONN_DATA.ind len=%u\n", msgb_l3len(msg));
|
||||||
|
gtp_prim = hnb_gtp_makeprim_conn_data_ind(conn->id, msgb_l3(msg), msgb_l3len(msg));
|
||||||
|
if ((rc = osmo_prim_srv_send(hnb->llsk, gtp_prim->hdr.msg)) < 0) {
|
||||||
|
LOGUE(ue, DGTP, LOGL_ERROR, "Failed Tx GTP-CONN_DATA.ind len=%u\n",
|
||||||
|
msgb_l3len(msg));
|
||||||
|
}
|
||||||
|
free_ret:
|
||||||
|
msgb_free(msg);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hnb_gtp_wq_read_cb(struct osmo_fd *fd)
|
||||||
|
{
|
||||||
|
struct hnb *hnb = (struct hnb *)fd->data;
|
||||||
|
struct msgb *msg;
|
||||||
|
struct gtp1u_hdr *hdr;
|
||||||
|
int rc;
|
||||||
|
struct osmo_sockaddr peer;
|
||||||
|
socklen_t peerlen = sizeof(peer.u.sas);
|
||||||
|
unsigned int opt_hdr_len;
|
||||||
|
uint16_t pl_len;
|
||||||
|
|
||||||
|
msg = msgb_alloc_c(hnb, 4096, "gtp-dl");
|
||||||
|
|
||||||
|
rc = recvfrom(hnb->gtp.wq1u.bfd.fd, msgb_data(msg), msg->data_len, 0,
|
||||||
|
&peer.u.sa, &peerlen);
|
||||||
|
if (rc <= 0) {
|
||||||
|
LOGP(DGTP, LOGL_ERROR, "recvfrom() failed: rc = %d error = %s\n",
|
||||||
|
rc, rc ? strerror(errno) : "No error");
|
||||||
|
goto free_ret;
|
||||||
|
}
|
||||||
|
msgb_put(msg, rc);
|
||||||
|
|
||||||
|
/* Do some sanity checks: */
|
||||||
|
if (msgb_length(msg) < sizeof(*hdr)) {
|
||||||
|
LOGP(DGTP, LOGL_ERROR, "Rx GTP-U packet with size %u < %zu (header)\n",
|
||||||
|
msgb_length(msg), sizeof(*hdr));
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto free_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr = (struct gtp1u_hdr *)msgb_data(msg);
|
||||||
|
pl_len = osmo_load16be(&hdr->length);
|
||||||
|
|
||||||
|
/* Do some sanity checks: */
|
||||||
|
if (hdr->version != 1) {
|
||||||
|
LOGP(DGTP, LOGL_ERROR, "Rx GTP-U version %u != 1\n", hdr->version);
|
||||||
|
rc = -ENOTSUP;
|
||||||
|
goto free_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->e == 1) {
|
||||||
|
LOGP(DGTP, LOGL_ERROR, "Rx GTP-U with Extension Header not supported\n");
|
||||||
|
rc = -ENOTSUP;
|
||||||
|
goto free_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr->s || hdr->pn || hdr->e)
|
||||||
|
opt_hdr_len = 4;
|
||||||
|
if (hdr->pn)
|
||||||
|
opt_hdr_len = 0;
|
||||||
|
|
||||||
|
if (msgb_length(msg) < sizeof(*hdr) + opt_hdr_len) {
|
||||||
|
LOGP(DGTP, LOGL_ERROR, "Rx GTP-U packet with size %u < %zu (header + opt)\n",
|
||||||
|
msgb_length(msg), sizeof(*hdr) + opt_hdr_len);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto free_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->l3h = msgb_data(msg) + sizeof(*hdr) + opt_hdr_len;
|
||||||
|
|
||||||
|
if (pl_len < opt_hdr_len || msgb_l3len(msg) != (pl_len - opt_hdr_len)) {
|
||||||
|
LOGP(DGTP, LOGL_ERROR, "Rx GTP-U packet with payload size %u != %u (header)\n",
|
||||||
|
msgb_length(msg), pl_len - opt_hdr_len);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto free_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hnb_gtp_rx_gtp(hnb, msg, &peer);
|
||||||
|
free_ret:
|
||||||
|
msgb_free(msg);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hnb_gtp_wq_write_cb(struct osmo_fd *fd, struct msgb *msg)
|
||||||
|
{
|
||||||
|
struct hnb *hnb = (struct hnb *)fd->data;
|
||||||
|
struct osmo_sockaddr *rem_addr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rem_addr = (struct osmo_sockaddr *)msgb_data(msg);
|
||||||
|
msgb_pull(msg, sizeof(*rem_addr));
|
||||||
|
|
||||||
|
rc = sendto(hnb->gtp.wq1u.bfd.fd, msgb_data(msg), msgb_length(msg), 0,
|
||||||
|
&rem_addr->u.sa, sizeof(*rem_addr));
|
||||||
|
if (rc < 0) {
|
||||||
|
int err = errno;
|
||||||
|
LOGP(DGTP, LOGL_ERROR, "GTP1-U sendto(len=%d, to=%s) failed: Error = %s\n",
|
||||||
|
msgb_length(msg), osmo_sockaddr_to_str(rem_addr), strerror(err));
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get osa of locally bound GTP-U socket */
|
/* Get osa of locally bound GTP-U socket */
|
||||||
static int sk_get_bound_addr(int fd, struct osmo_sockaddr *osa)
|
static int sk_get_bound_addr(int fd, struct osmo_sockaddr *osa)
|
||||||
{
|
{
|
||||||
|
@ -70,173 +303,43 @@ static int sk_get_bound_addr(int fd, struct osmo_sockaddr *osa)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called whenever we receive a DATA packet */
|
|
||||||
static int hnb_gtp_cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
|
||||||
{
|
|
||||||
struct hnb_gtp_prim *gtp_prim;
|
|
||||||
struct gtp_conn *conn = lib->priv;
|
|
||||||
struct hnb_ue *ue;
|
|
||||||
struct hnb *hnb;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!conn) {
|
|
||||||
LOGP(DGTP, LOGL_NOTICE, "Tx GTP-CONN_DATA.ind data=%p len=%u with no conn!\n",
|
|
||||||
packet, len);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
ue = conn->ue;
|
|
||||||
|
|
||||||
if (!ue->conn_ps.active) {
|
|
||||||
LOGUE(ue, DGTP, LOGL_NOTICE, "Tx GTP-CONN_DATA.ind data=%p len=%u but UE conn_ps is not active!\n",
|
|
||||||
packet, len);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
hnb = ue->hnb;
|
|
||||||
|
|
||||||
LOGUE(ue, DGTP, LOGL_DEBUG, "Tx GTP-CONN_DATA.ind data=%p len=%u\n", packet, len);
|
|
||||||
gtp_prim = hnb_gtp_makeprim_conn_data_ind(conn->id, packet, len);
|
|
||||||
if ((rc = osmo_prim_srv_send(hnb->llsk, gtp_prim->hdr.msg)) < 0) {
|
|
||||||
LOGUE(ue, DGTP, LOGL_ERROR, "Failed Tx GTP-CONN_DATA.ind data=%p len=%u\n",
|
|
||||||
packet, len);
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* libgtp select loop integration */
|
|
||||||
static int hnb_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
|
|
||||||
{
|
|
||||||
struct hnb *hnb = fd->data;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!(what & OSMO_FD_READ))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch (fd->priv_nr) {
|
|
||||||
case 0:
|
|
||||||
rc = gtp_decaps1u(hnb->gtp.gsn);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rc = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hnb_gtp_bind(struct hnb *hnb)
|
int hnb_gtp_bind(struct hnb *hnb)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct gsn_t *gsn;
|
|
||||||
struct in_addr inaddr;
|
|
||||||
|
|
||||||
rc = inet_pton(AF_INET, hnb->gtp.cfg_local_addr, &inaddr);
|
OSMO_ASSERT(hnb->gtp.wq1u.bfd.fd == -1);
|
||||||
if (rc <= 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* TODO: add new mode GTP_MODE_GTPU_ONLY to set up gtpu side only (and ignore statedir) */
|
hnb->gtp.wq1u.read_cb = hnb_gtp_wq_read_cb;
|
||||||
rc = gtp_new(&gsn, "/tmp", &inaddr, GTP_MODE_SGSN);
|
hnb->gtp.wq1u.write_cb = hnb_gtp_wq_write_cb;
|
||||||
|
|
||||||
|
rc = osmo_sock_init2_ofd(&hnb->gtp.wq1u.bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
|
||||||
|
hnb->gtp.cfg_local_addr, 2152, NULL, 0, OSMO_SOCK_F_BIND);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGP(DGTP, LOGL_ERROR, "Failed to set up GTP socket: %s\n", strerror(-rc));
|
LOGP(DGTP, LOGL_ERROR, "Failed to set up GTP socket: %s\n", strerror(-rc));
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = sk_get_bound_addr(gsn->fd1u, &hnb->gtp.local_addr);
|
rc = sk_get_bound_addr(hnb->gtp.wq1u.bfd.fd, &hnb->gtp.local_addr);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGP(DGTP, LOGL_ERROR, "Failed to get GTP-U socket bound address: %s\n", strerror(-rc));
|
LOGP(DGTP, LOGL_ERROR, "Failed to get GTP-U socket bound address: %s\n", strerror(-rc));
|
||||||
goto free_ret;
|
goto free_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
osmo_fd_setup(&hnb->gtp.fd1u, gsn->fd1u, OSMO_FD_READ, hnb_gtp_fd_cb, hnb, 0);
|
|
||||||
if ((rc = osmo_fd_register(&hnb->gtp.fd1u)) < 0)
|
|
||||||
goto free_ret;
|
|
||||||
|
|
||||||
gtp_set_cb_data_ind(gsn, hnb_gtp_cb_data_ind);
|
|
||||||
|
|
||||||
hnb->gtp.gsn = gsn;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_ret:
|
free_ret:
|
||||||
gtp_free(gsn);
|
if (hnb->gtp.wq1u.bfd.fd != -1) {
|
||||||
hnb->gtp.fd1u.fd = -1;
|
close(hnb->gtp.wq1u.bfd.fd);
|
||||||
|
hnb->gtp.wq1u.bfd.fd = -1;
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hnb_gtp_unbind(struct hnb *hnb)
|
void hnb_gtp_unbind(struct hnb *hnb)
|
||||||
{
|
{
|
||||||
osmo_fd_unregister(&hnb->gtp.fd1u);
|
if (hnb->gtp.wq1u.bfd.fd != -1) {
|
||||||
gtp_free(hnb->gtp.gsn);
|
osmo_wqueue_clear(&hnb->gtp.wq1u);
|
||||||
hnb->gtp.gsn = NULL;
|
osmo_fd_unregister(&hnb->gtp.wq1u.bfd);
|
||||||
hnb->gtp.fd1u.fd = -1;
|
close(hnb->gtp.wq1u.bfd.fd);
|
||||||
}
|
hnb->gtp.wq1u.bfd.fd = -1;
|
||||||
|
}
|
||||||
int gtp_conn_setup(struct gtp_conn *conn, const struct osmo_sockaddr *rem_addr, uint32_t rem_tei)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
struct hnb_ue *ue = conn->ue;
|
|
||||||
struct hnb *hnb = ue->hnb;
|
|
||||||
struct pdp_t *pdp;
|
|
||||||
struct in_addr rem_in;
|
|
||||||
|
|
||||||
LOGUE(ue, DGTP, LOGL_INFO, "Creating PDP context\n");
|
|
||||||
|
|
||||||
|
|
||||||
if (rem_addr->u.sa.sa_family != AF_INET) {
|
|
||||||
LOGUE(ue, DGTP, LOGL_ERROR, "Failed creating PDP context: unsupported proto family %u\n",
|
|
||||||
rem_addr->u.sa.sa_family);
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->rem_addr = *rem_addr;
|
|
||||||
conn->rem_tei = rem_tei;
|
|
||||||
rem_in = rem_addr->u.sin.sin_addr;
|
|
||||||
conn->id = next_gtp_conn_id++; /* TODO: validate next one is not already taken due to wrap-around */
|
|
||||||
|
|
||||||
rc = gtp_pdp_newpdp(hnb->gtp.gsn, &pdp, conn->id, 0 /* TODO: NSAPI? */, NULL);
|
|
||||||
if (rc < 0) {
|
|
||||||
LOGUE(ue, DGTP, LOGL_ERROR, "Failed creating PDP context: %s\n", strerror(-rc));
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
pdp->priv = conn;
|
|
||||||
conn->pdp_lib = pdp;
|
|
||||||
|
|
||||||
pdp->teid_gn = rem_tei;
|
|
||||||
pdp->version = 1;
|
|
||||||
pdp->hisaddr0 = rem_in;
|
|
||||||
pdp->hisaddr1 = rem_in;
|
|
||||||
|
|
||||||
pdp->gsnru.l = sizeof(rem_in);
|
|
||||||
memcpy(pdp->gsnru.v, &rem_in, sizeof(rem_in));
|
|
||||||
|
|
||||||
|
|
||||||
pdp->gsnlu.l = sizeof(hnb->gtp.local_addr.u.sin.sin_addr);
|
|
||||||
memcpy(pdp->gsnlu.v, &hnb->gtp.local_addr.u.sin.sin_addr,
|
|
||||||
sizeof(hnb->gtp.local_addr.u.sin.sin_addr));
|
|
||||||
|
|
||||||
conn->loc_addr = hnb->gtp.local_addr;
|
|
||||||
//loc_addr->u.sin.sin_family = AF_INET;
|
|
||||||
//loc_addr->u.sin.sin_addr = hnb->gtp.gsn->gsnu;
|
|
||||||
//loc_addr->u.sin.sin_port = GTP1U_PORT;
|
|
||||||
conn->loc_tei = pdp->teid_own;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gtp_conn_tx(struct gtp_conn *conn, void *gtpu_payload, unsigned gtpu_payload_len)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
struct hnb_ue *ue;
|
|
||||||
struct hnb *hnb;
|
|
||||||
|
|
||||||
if (!conn || !conn->pdp_lib) {
|
|
||||||
LOGP(DGTP, LOGL_ERROR, "Tx: PDP Ctx not available\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ue = conn->ue;
|
|
||||||
hnb = ue->hnb;
|
|
||||||
if (!hnb->gtp.gsn) {
|
|
||||||
LOGUE(ue, DGTP, LOGL_ERROR, "Tx: GTP socket not bound\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = gtp_data_req(hnb->gtp.gsn, conn->pdp_lib, gtpu_payload, gtpu_payload_len);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,9 @@ struct hnb *hnb_alloc(void *tall_ctx)
|
||||||
hnb->rtp.priority = -1;
|
hnb->rtp.priority = -1;
|
||||||
|
|
||||||
hnb->gtp.cfg_local_addr = talloc_strdup(hnb, "0.0.0.0");
|
hnb->gtp.cfg_local_addr = talloc_strdup(hnb, "0.0.0.0");
|
||||||
hnb->gtp.fd1u.fd = -1;
|
osmo_wqueue_init(&hnb->gtp.wq1u, 1024);
|
||||||
|
hnb->gtp.wq1u.bfd.data = hnb;
|
||||||
|
hnb->gtp.wq1u.bfd.fd = -1;
|
||||||
|
|
||||||
hnb->shutdown_fi = osmo_fsm_inst_alloc(&hnb_shutdown_fsm, hnb, hnb,
|
hnb->shutdown_fi = osmo_fsm_inst_alloc(&hnb_shutdown_fsm, hnb, hnb,
|
||||||
LOGL_INFO, NULL);
|
LOGL_INFO, NULL);
|
||||||
|
@ -90,10 +92,7 @@ void hnb_free(struct hnb *hnb)
|
||||||
osmo_prim_srv_link_free(hnb->llsk_link);
|
osmo_prim_srv_link_free(hnb->llsk_link);
|
||||||
hnb->llsk_link = NULL;
|
hnb->llsk_link = NULL;
|
||||||
|
|
||||||
if (hnb->gtp.gsn) {
|
hnb_gtp_unbind(hnb);
|
||||||
gtp_free(hnb->gtp.gsn);
|
|
||||||
hnb->gtp.gsn = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
talloc_free(hnb);
|
talloc_free(hnb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ static int llsk_rx_gtp_conn_establish_req(struct hnb *hnb, struct hnb_gtp_conn_e
|
||||||
union u_addr loc_uaddr = {0};
|
union u_addr loc_uaddr = {0};
|
||||||
struct gtp_conn *conn = NULL;
|
struct gtp_conn *conn = NULL;
|
||||||
|
|
||||||
rc = ll_addr2osa(ce_req->remote_gtpu_address_type, &ce_req->remote_gtpu_addr, GTP1U_PORT, &rem_osa);
|
rc = ll_addr2osa(ce_req->remote_gtpu_address_type, &ce_req->remote_gtpu_addr, 2152, &rem_osa);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_ESTABLISH.req: ctx=%u with unexpected address type %u\n",
|
LOGP(DLLSK, LOGL_ERROR, "Rx GTP-CONN_ESTABLISH.req: ctx=%u with unexpected address type %u\n",
|
||||||
ce_req->context_id, ce_req->remote_gtpu_address_type);
|
ce_req->context_id, ce_req->remote_gtpu_address_type);
|
||||||
|
|
Loading…
Reference in New Issue