mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
synced 2025-11-02 21:23:23 +00:00
Compare commits
35 Commits
1.10.0
...
daniel/wip
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54fcd64fc7 | ||
|
|
6536376527 | ||
|
|
6d85d2a3dd | ||
|
|
cd970edee4 | ||
|
|
19a506b705 | ||
|
|
ea6c02ac1f | ||
|
|
ec357c5377 | ||
|
|
768d6d5be9 | ||
|
|
fa91a10498 | ||
|
|
6929391ecf | ||
|
|
9baac03927 | ||
|
|
9bd2711f39 | ||
|
|
b17fe7bfe9 | ||
|
|
0917ce4e22 | ||
|
|
2a0d37cb1d | ||
|
|
f3d541e353 | ||
|
|
8d976444b8 | ||
|
|
77734ac81b | ||
|
|
848ec697e2 | ||
|
|
6a2e82542d | ||
|
|
a625bdd136 | ||
|
|
08bb5182a4 | ||
|
|
4963d1c2ea | ||
|
|
37daa5d003 | ||
|
|
c4c4d90b85 | ||
|
|
59f1539ece | ||
|
|
eff88c08e7 | ||
|
|
92ac7249f9 | ||
|
|
5cf6b75dc9 | ||
|
|
4aa2e417c9 | ||
|
|
f14c056310 | ||
|
|
bf69ddbfef | ||
|
|
70a4e2e6f8 | ||
|
|
99afe979ef | ||
|
|
35066fb0b0 |
11
Makefile.am
11
Makefile.am
@@ -1,5 +1,14 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
SUBDIRS = lib gtp ggsn sgsnemu doc contrib utils tests
|
||||
SUBDIRS = \
|
||||
lib \
|
||||
gtp \
|
||||
ggsn \
|
||||
sgsnemu \
|
||||
doc \
|
||||
contrib \
|
||||
utils \
|
||||
tests \
|
||||
$(NULL)
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libgtp.pc
|
||||
|
||||
@@ -27,9 +27,10 @@ There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/o
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
There currently is no other documentation other than the wiki on the
|
||||
homepage. It would be great if somebody would work towards a user
|
||||
manual that can become part of the osmo-gsm-manuals project.
|
||||
The user manual and VTY reference are optionally built in PDF form
|
||||
as part of the build process. Find pre-rendered versions here:
|
||||
|
||||
https://ftp.osmocom.org/docs/osmo-ggsn/master/
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
|
||||
@@ -7,3 +7,5 @@
|
||||
# If any interfaces have been added since the last public release: c:r:a + 1.
|
||||
# If any interfaces have been removed or changed since the last public release: c:r:0.
|
||||
#library what description / commit summary line
|
||||
libgtp REMOVE remove GTP cause defines of reserved values
|
||||
libgtpnl > 1.2.5 gtp_tunnel_set_family()
|
||||
|
||||
@@ -154,9 +154,10 @@ adl_FUNC_GETOPT_LONG
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.8.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.8.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.8.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
|
||||
|
||||
AC_ARG_ENABLE(sanitize,
|
||||
[AS_HELP_STRING(
|
||||
|
||||
@@ -30,9 +30,9 @@ BuildRequires: pkgconfig >= 0.20
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%endif
|
||||
BuildRequires: pkgconfig(libgtpnl) >= 1.2.0
|
||||
BuildRequires: pkgconfig(libosmocore) >= 1.8.0
|
||||
BuildRequires: pkgconfig(libosmoctrl) >= 1.8.0
|
||||
BuildRequires: pkgconfig(libosmovty) >= 1.8.0
|
||||
BuildRequires: pkgconfig(libosmocore) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmoctrl) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmovty) >= 1.9.0
|
||||
Obsoletes: openggsn
|
||||
%{?systemd_requires}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[Unit]
|
||||
Description=OsmoGGSN
|
||||
After=networking.service
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
|
||||
35
debian/changelog
vendored
35
debian/changelog
vendored
@@ -1,3 +1,38 @@
|
||||
osmo-ggsn (1.11.0) unstable; urgency=medium
|
||||
|
||||
[ Daniel Willmann ]
|
||||
* gtp: Add net GTP cause values and a function to check for success
|
||||
|
||||
-- Oliver Smith <osmith@sysmocom.de> Tue, 28 Nov 2023 13:38:29 +0100
|
||||
|
||||
osmo-ggsn (1.10.2) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* Do not hard-code -g and -O2 in CFLAGS
|
||||
* tests: use -no-install libtool flag to avoid ./lt-* scripts
|
||||
|
||||
[ Oliver Smith ]
|
||||
* doc/manuals/chapters/configuration: fix typo
|
||||
* debian: set compat level to 10
|
||||
* systemd: depend on networking-online.target
|
||||
* README: update documentation section
|
||||
* doc: running: update kernel-gtp limitations
|
||||
* lib/in46_addr: add in46a_from_gsna
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 14:36:10 +0200
|
||||
|
||||
osmo-ggsn (1.10.1) unstable; urgency=medium
|
||||
|
||||
[ Oliver Smith ]
|
||||
* debian/libgtp6.shlibs: new file
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* lib/icmpv6.h: fix struct icmpv6_{radv_hdr,opt_prefix}
|
||||
* gtp/gsn.c: fix 'No newline at end of file'
|
||||
* gtp: use OSMO_ASSERT() in gtp_new()
|
||||
|
||||
-- Vadim Yanitskiy <vyanitskiy@sysmocom.de> Mon, 27 Feb 2023 22:35:47 +0700
|
||||
|
||||
osmo-ggsn (1.10.0) unstable; urgency=medium
|
||||
|
||||
[ Max ]
|
||||
|
||||
2
debian/compat
vendored
2
debian/compat
vendored
@@ -1 +1 @@
|
||||
9
|
||||
10
|
||||
|
||||
4
debian/control
vendored
4
debian/control
vendored
@@ -2,12 +2,12 @@ Source: osmo-ggsn
|
||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||
Section: net
|
||||
Priority: optional
|
||||
Build-Depends: debhelper (>= 9),
|
||||
Build-Depends: debhelper (>= 10),
|
||||
autotools-dev,
|
||||
pkg-config,
|
||||
libdpkg-perl, git,
|
||||
dh-autoreconf,
|
||||
libosmocore-dev (>= 1.8.0),
|
||||
libosmocore-dev (>= 1.9.0),
|
||||
osmo-gsm-manuals-dev,
|
||||
libgtpnl-dev (>= 1.2.0)
|
||||
Standards-Version: 3.9.6
|
||||
|
||||
2
debian/libgtp6.shlibs
vendored
Normal file
2
debian/libgtp6.shlibs
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Most recent version of the package that added new symbols (OS#5318)
|
||||
libgtp 6 libgtp6 (>= 1.8.0)
|
||||
@@ -101,7 +101,7 @@ OsmoGGSN(config-ggsn)# no shutdown ggsn <4>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<3> Enter the config node of the GGSN instance `ggsn0`
|
||||
<4> Take the GGSN instance out of shutdown
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ OsmoGGSN(config-ggsn)# shutdown ggsn <4>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<3> Enter the config node of the GGSN instance `ggsn0`
|
||||
<4> Shut down the GGSN instance
|
||||
|
||||
|
||||
@@ -215,8 +215,8 @@ OsmoGGSN(config-ggsn-apn)# no shutdown <5>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<4> Enter the config ndoe of the APN `internet`
|
||||
<3> Enter the config node of the GGSN instance `ggsn0`
|
||||
<4> Enter the config node of the APN `internet`
|
||||
<5> Take the APN out of shutdown
|
||||
|
||||
|
||||
@@ -237,8 +237,8 @@ OsmoGGSN(config-ggsn-apn)# shutdown <5>
|
||||
----
|
||||
<1> Change into privileged mode
|
||||
<2> Enter the interactive configuration mode
|
||||
<3> Enter the config ndoe of the GGSN instance `ggsn0`
|
||||
<4> Enter the config ndoe of the APN `internet`
|
||||
<3> Enter the config node of the GGSN instance `ggsn0`
|
||||
<4> Enter the config node of the APN `internet`
|
||||
<5> Shut down the APN
|
||||
|
||||
[[ggsn_no_root]]
|
||||
@@ -302,7 +302,7 @@ Name=apn0 <1>
|
||||
Address=192.168.7.1/24 <2>
|
||||
IPMasquerade=yes <3>
|
||||
----
|
||||
<1> The netowrk device name, which must match the one in the apn0.netdev unit file above
|
||||
<1> The network device name, which must match the one in the apn0.netdev unit file above
|
||||
<2> The local IP address configured on the device
|
||||
<3> Requesting systemd to configure IP masquerading for this interface. Depending on your needs,
|
||||
You may not want this if you have proper end-to-end routing set up, and want to have transparent
|
||||
|
||||
@@ -83,7 +83,12 @@ ggsn ggsn0
|
||||
|
||||
=== GTP-U kernel module
|
||||
|
||||
WARNING: As of writing, the kernel module does not support IPv6.
|
||||
WARNING: As of writing, IPv6 support for the kernel module has not been
|
||||
upstreamed yet (OS#1952).
|
||||
|
||||
WARNING: As of writing, it is not possible to configure multiple APNs with
|
||||
gtpu-mode kernel-gpt. This is a limitation in OsmoGGSN, not in the
|
||||
kernel module (OS#6106).
|
||||
|
||||
OsmoGGSN has support to use the Linux kernel GTP-U tunnel driver to accelerate
|
||||
the data/user plane while still implementing the control plane (GTP-C) in
|
||||
|
||||
@@ -2,7 +2,15 @@ bin_PROGRAMS = osmo-ggsn
|
||||
|
||||
AM_LDFLAGS = @EXEC_LDFLAGS@
|
||||
|
||||
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
|
||||
AM_CFLAGS = \
|
||||
-D_GNU_SOURCE \
|
||||
-fno-builtin \
|
||||
-Wall \
|
||||
-DSBINDIR='"$(sbindir)"' \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOCTRL_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
osmo_ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS)
|
||||
|
||||
|
||||
12
ggsn/ggsn.c
12
ggsn/ggsn.c
@@ -193,7 +193,7 @@ int apn_start(struct apn_ctx *apn)
|
||||
}
|
||||
LOGPAPN(LOGL_INFO, apn, "Opened TUN device %s\n", apn->tun.tun->devname);
|
||||
|
||||
/* Register with libosmcoore */
|
||||
/* Register with libosmocore */
|
||||
osmo_fd_setup(&apn->tun.fd, apn->tun.tun->fd, OSMO_FD_READ, ggsn_tun_fd_cb, apn, 0);
|
||||
osmo_fd_register(&apn->tun.fd);
|
||||
|
||||
@@ -202,11 +202,6 @@ int apn_start(struct apn_ctx *apn)
|
||||
break;
|
||||
case APN_GTPU_MODE_KERNEL_GTP:
|
||||
LOGPAPN(LOGL_INFO, apn, "Opening Kernel GTP device %s\n", apn->tun.cfg.dev_name);
|
||||
if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) {
|
||||
LOGPAPN(LOGL_ERROR, apn, "Kernel GTP currently supports only IPv4\n");
|
||||
apn_stop(apn);
|
||||
return -1;
|
||||
}
|
||||
if (gsn == NULL) {
|
||||
/* skip bringing up the APN now if the GSN is not initialized yet.
|
||||
* This happens during initial load of the config file, as the
|
||||
@@ -536,10 +531,11 @@ int create_context_ind(struct pdp_t *pdp)
|
||||
|
||||
in46a_to_eua(addr, num_addr, &pdp->eua);
|
||||
|
||||
if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP && apn_supports_ipv4(apn)) {
|
||||
/* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
|
||||
if (apn->cfg.gtpu_mode == APN_GTPU_MODE_KERNEL_GTP) {
|
||||
if (gtp_kernel_tunnel_add(pdp, apn->tun.cfg.dev_name) < 0) {
|
||||
LOGPPDP(LOGL_ERROR, pdp, "Cannot add tunnel to kernel: %s\n", strerror(errno));
|
||||
if (addrv6 && errno == EINVAL)
|
||||
LOGPPDP(LOGL_ERROR, pdp, "Maybe your kernel does not support GTP-U with IPv6 yet?\n");
|
||||
gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -814,10 +814,7 @@ static const char *print_gsnaddr(const struct ul16_t *in)
|
||||
{
|
||||
struct in46_addr in46;
|
||||
|
||||
in46.len = in->l;
|
||||
OSMO_ASSERT(in->l <= sizeof(in46.v6));
|
||||
memcpy(&in46.v6, in->v, in->l);
|
||||
|
||||
in46a_from_gsna(in, &in46);
|
||||
return in46a_ntoa(&in46);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ ret_broken:
|
||||
osmo_hexdump_nospc((const uint8_t *)pco_in, pco_in->length));
|
||||
}
|
||||
|
||||
/* Handle IP Control Protocol, RFC 1332, extensions in RFC 1877 */
|
||||
static void process_pco_element_ipcp(const struct pco_element *pco_elem, struct msgb *resp,
|
||||
const struct apn_ctx *apn, struct pdp_t *pdp)
|
||||
{
|
||||
|
||||
@@ -42,12 +42,11 @@ struct pco_element {
|
||||
uint8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* RFC 1332 */
|
||||
/* RFC 1332 IP Control Protocol options, extensions in RFC 1877 */
|
||||
enum ipcp_options {
|
||||
IPCP_OPT_IPADDR = 3,
|
||||
IPCP_OPT_PRIMARY_DNS = 129,
|
||||
IPCP_OPT_SECONDARY_DNS = 131,
|
||||
IPCP_OPT_IPADDR = 3, /* RFC 1332 3.3 */
|
||||
IPCP_OPT_PRIMARY_DNS = 129, /* RFC 1877 1.1 */
|
||||
IPCP_OPT_SECONDARY_DNS = 131, /* RFC 1877 1.2 */
|
||||
};
|
||||
|
||||
struct ipcp_option_hdr {
|
||||
|
||||
@@ -2,14 +2,34 @@
|
||||
# Please read chapter "Library interface versions" of the libtool documentation
|
||||
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
|
||||
# If major=current-age is increased, remember to update the dh_strip line in debian/rules!
|
||||
LIBVERSION=9:0:3
|
||||
LIBVERSION=9:1:3
|
||||
|
||||
lib_LTLIBRARIES = libgtp.la
|
||||
|
||||
include_HEADERS = gtp.h gsn.h pdp.h gtpie.h
|
||||
|
||||
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
|
||||
AM_CFLAGS = \
|
||||
-fno-builtin \
|
||||
-Wall \
|
||||
-DSBINDIR='"$(sbindir)"' \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
libgtp_la_SOURCES = \
|
||||
gsn.c \
|
||||
gsn.h \
|
||||
gtp.c \
|
||||
gtp.h \
|
||||
gtpie.c \
|
||||
gtpie.h \
|
||||
lookupa.c \
|
||||
lookupa.h \
|
||||
pdp.c \
|
||||
pdp.h \
|
||||
queue.c \
|
||||
queue.h \
|
||||
$(NULL)
|
||||
|
||||
libgtp_la_SOURCES = gtp.c gtp.h gsn.c gsn.h gtpie.c gtpie.h pdp.c pdp.h lookupa.c lookupa.h queue.c queue.h
|
||||
libgtp_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined
|
||||
libgtp_la_LIBADD = $(LIBOSMOCORE_LIBS)
|
||||
libgtp_la_LIBADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS)
|
||||
|
||||
134
gtp/gsn.c
134
gtp/gsn.c
@@ -67,7 +67,7 @@
|
||||
#define LOGP_WITH_ADDR(ss, level, addr, fmt, args...) \
|
||||
LOGP(ss, level, "addr(%s:%d) " fmt, \
|
||||
inet_ntoa((addr).sin_addr), htons((addr).sin_port), \
|
||||
##args);
|
||||
##args)
|
||||
|
||||
static const struct rate_ctr_desc gsn_ctr_description[] = {
|
||||
[GSN_CTR_ERR_SOCKET] = { "err:socket", "Socket error" },
|
||||
@@ -244,6 +244,12 @@ int gtp_set_cb_data_ind(struct gsn_t *gsn,
|
||||
gsn->cb_data_ind = cb_data_ind;
|
||||
return 0;
|
||||
}
|
||||
int gtp_set_cb_sgsn_context_request_ind(struct gsn_t *gsn,
|
||||
int (*cb) (struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie))
|
||||
{
|
||||
gsn->cb_sgsn_context_request_ind = cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int queue_timer_retrans(struct gsn_t *gsn)
|
||||
{
|
||||
@@ -423,11 +429,45 @@ free_filename:
|
||||
talloc_free(filename);
|
||||
}
|
||||
|
||||
static int create_and_bind_socket(const char *name, struct gsn_t *gsn, int *fd, int domain,
|
||||
const struct in_addr *listen, int port)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
int type = SOCK_DGRAM;
|
||||
int protocol = 0;
|
||||
|
||||
*fd = socket(domain, type, protocol);
|
||||
|
||||
if (*fd < 0) {
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SOCKET);
|
||||
LOGP(DLGTP, LOGL_ERROR,
|
||||
"%s socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
|
||||
name, domain, type, protocol, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = domain;
|
||||
addr.sin_addr = *listen;
|
||||
addr.sin_port = htons(port);
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
addr.sin_len = sizeof(addr);
|
||||
#endif
|
||||
|
||||
if (bind(*fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SOCKET);
|
||||
LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
|
||||
"%s bind(fd=%d) failed: Error = %s\n",
|
||||
name, *fd, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
|
||||
int mode)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
|
||||
LOGP(DLGTP, LOGL_NOTICE, "GTP: gtp_newgsn() started at %s\n", inet_ntoa(*listen));
|
||||
|
||||
*gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */
|
||||
@@ -441,7 +481,7 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
|
||||
/* Initialize timers: */
|
||||
(*gsn)->tdef = gtp_T_defs;
|
||||
/* Small hack to properly reset tdef for old clients not using the tdef_group: */
|
||||
osmo_static_assert(gtp_T_defs[0].default_val != 0, first_default_val_not_zero);
|
||||
OSMO_ASSERT(gtp_T_defs[0].default_val != 0);
|
||||
if (gtp_T_defs[0].val == 0)
|
||||
osmo_tdefs_reset((*gsn)->tdef);
|
||||
|
||||
@@ -467,89 +507,35 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
|
||||
(*gsn)->cb_data_ind = 0;
|
||||
|
||||
/* Store function parameters */
|
||||
/* Same IP for user traffic and signalling */
|
||||
(*gsn)->gsnc = *listen;
|
||||
(*gsn)->gsnu = *listen;
|
||||
(*gsn)->mode = mode;
|
||||
|
||||
(*gsn)->fd0 = -1;
|
||||
(*gsn)->fd1c = -1;
|
||||
(*gsn)->fd1u = -1;
|
||||
|
||||
/* Create GTP version 0 socket */
|
||||
if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
|
||||
LOGP(DLGTP, LOGL_ERROR,
|
||||
"GTPv0 socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
|
||||
AF_INET, SOCK_DGRAM, 0, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
|
||||
addr.sin_port = htons(GTP0_PORT);
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
addr.sin_len = sizeof(addr);
|
||||
#endif
|
||||
|
||||
if (bind((*gsn)->fd0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
|
||||
LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
|
||||
"bind(fd0=%d) failed: Error = %s\n",
|
||||
(*gsn)->fd0, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
if (create_and_bind_socket("GTPv0", *gsn, &(*gsn)->fd0, AF_INET, listen, GTP0_PORT) < 0)
|
||||
goto error;
|
||||
|
||||
/* Create GTP version 1 control plane socket */
|
||||
if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
|
||||
LOGP(DLGTP, LOGL_ERROR,
|
||||
"GTPv1 control plane socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
|
||||
AF_INET, SOCK_DGRAM, 0, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
|
||||
addr.sin_port = htons(GTP1C_PORT);
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
addr.sin_len = sizeof(addr);
|
||||
#endif
|
||||
|
||||
if (bind((*gsn)->fd1c, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
|
||||
LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
|
||||
"bind(fd1c=%d) failed: Error = %s\n",
|
||||
(*gsn)->fd1c, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
if (create_and_bind_socket("GTPv1 control plane", *gsn, &(*gsn)->fd1c, AF_INET, listen, GTP1C_PORT) < 0)
|
||||
goto error;
|
||||
|
||||
/* Create GTP version 1 user plane socket */
|
||||
if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
|
||||
LOGP(DLGTP, LOGL_ERROR,
|
||||
"GTPv1 user plane socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n",
|
||||
AF_INET, SOCK_DGRAM, 0, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr = *listen; /* Same IP for user traffic and signalling */
|
||||
addr.sin_port = htons(GTP1U_PORT);
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
addr.sin_len = sizeof(addr);
|
||||
#endif
|
||||
|
||||
if (bind((*gsn)->fd1u, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
rate_ctr_inc2((*gsn)->ctrg, GSN_CTR_ERR_SOCKET);
|
||||
LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr,
|
||||
"bind(fd1u=%d) failed: Error = %s\n",
|
||||
(*gsn)->fd1u, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
if (create_and_bind_socket("GTPv1 user plane", *gsn, &(*gsn)->fd1u, AF_INET, listen, GTP1U_PORT) < 0)
|
||||
goto error;
|
||||
|
||||
/* Start internal queue timer */
|
||||
gtp_queue_timer_start(*gsn);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
gtp_free(*gsn);
|
||||
*gsn = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gtp_free(struct gsn_t *gsn)
|
||||
@@ -593,4 +579,4 @@ int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
|
||||
timeout->tv_usec = 0;
|
||||
/* dummy API, deprecated. Return a huge timer to do nothing */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
#include <osmocom/gsm/gsm48.h>
|
||||
|
||||
#include "pdp.h"
|
||||
|
||||
@@ -107,6 +109,7 @@ struct gsn_t {
|
||||
int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery);
|
||||
int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery);
|
||||
int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery);
|
||||
int (*cb_sgsn_context_request_ind) (struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie); /* Pass RAI and TLLI/TMSI/IMSI directly */
|
||||
|
||||
/* Counters */
|
||||
struct rate_ctr_group *ctrg;
|
||||
@@ -130,6 +133,8 @@ extern int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp);
|
||||
extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
void *cbp);
|
||||
|
||||
extern int gtp_create_sgsn_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp);
|
||||
|
||||
extern int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
|
||||
int (*cb_create_context_ind) (struct
|
||||
pdp_t *
|
||||
@@ -152,6 +157,9 @@ extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
|
||||
extern int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn,
|
||||
int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie));
|
||||
|
||||
extern int gtp_set_cb_sgsn_context_request_ind(struct gsn_t *gsn,
|
||||
int (*cb) (struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie));
|
||||
|
||||
extern int gtp_set_cb_conf(struct gsn_t *gsn,
|
||||
int (*cb) (int type, int cause, struct pdp_t * pdp,
|
||||
void *cbp));
|
||||
|
||||
460
gtp/gtp.c
460
gtp/gtp.c
@@ -25,6 +25,8 @@
|
||||
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/gsm/gsm48.h>
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/endian.h>
|
||||
@@ -338,7 +340,7 @@ static uint32_t get_tei(void *pack)
|
||||
|
||||
static int gtp_req(struct gsn_t *gsn, uint8_t version, struct pdp_t *pdp,
|
||||
union gtp_packet *packet, int len,
|
||||
struct in_addr *inetaddr, void *cbp)
|
||||
const struct in_addr *inetaddr, void *cbp)
|
||||
{
|
||||
uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
|
||||
struct sockaddr_in addr;
|
||||
@@ -451,9 +453,7 @@ static int gtp_conf(struct gsn_t *gsn, uint8_t version, struct sockaddr_in *peer
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
union gtp_packet *packet, int len,
|
||||
struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
|
||||
static int gtp_resp2(struct gsn_t *gsn, union gtp_packet *packet, int len, struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid, uint16_t flow, uint32_t tei)
|
||||
{
|
||||
uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
|
||||
struct qmsg_t *qmsg;
|
||||
@@ -462,18 +462,11 @@ static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE);
|
||||
packet->gtp0.h.seq = hton16(seq);
|
||||
packet->gtp0.h.tid = htobe64(tid);
|
||||
if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
|
||||
(packet->gtp0.h.type == GTP_ERROR)))
|
||||
packet->gtp0.h.flow = hton16(pdp->flru);
|
||||
else if (pdp)
|
||||
packet->gtp0.h.flow = hton16(pdp->flrc);
|
||||
packet->gtp0.h.flow = hton16(flow);
|
||||
} else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
|
||||
packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT);
|
||||
packet->gtp1l.h.seq = hton16(seq);
|
||||
if (pdp && (fd == gsn->fd1u))
|
||||
packet->gtp1l.h.tei = hton32(pdp->teid_gn);
|
||||
else if (pdp)
|
||||
packet->gtp1l.h.tei = hton32(pdp->teic_gn);
|
||||
packet->gtp1l.h.tei = hton32(tei);
|
||||
} else {
|
||||
LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
|
||||
return -1;
|
||||
@@ -485,7 +478,7 @@ static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
}
|
||||
|
||||
if (sendto(fd, packet, len, 0,
|
||||
(struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
|
||||
(const struct sockaddr *)peer, sizeof(struct sockaddr_in)) < 0) {
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
|
||||
LOGP(DLGTP, LOGL_ERROR,
|
||||
"Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd,
|
||||
@@ -521,6 +514,32 @@ static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gtp_resp(uint8_t version, struct gsn_t *gsn, struct pdp_t *pdp,
|
||||
union gtp_packet *packet, int len,
|
||||
struct sockaddr_in *peer, int fd, uint16_t seq, uint64_t tid)
|
||||
{
|
||||
uint8_t ver = GTPHDR_F_GET_VER(packet->flags);
|
||||
uint16_t flow = 0, tei = 0;
|
||||
|
||||
if (ver == 0) { /* Version 0 */
|
||||
if (pdp && ((packet->gtp0.h.type == GTP_GPDU) ||
|
||||
(packet->gtp0.h.type == GTP_ERROR)))
|
||||
flow = pdp->flru;
|
||||
else if (pdp)
|
||||
flow = pdp->flrc;
|
||||
} else if (ver == 1 && (packet->flags & GTP1HDR_F_SEQ)) { /* Version 1 with seq */
|
||||
if (pdp && (fd == gsn->fd1u))
|
||||
tei = pdp->teid_gn;
|
||||
else if (pdp)
|
||||
tei = pdp->teic_gn;
|
||||
} else {
|
||||
LOGP(DLGTP, LOGL_ERROR, "Unknown packet flags: 0x%02x\n", packet->flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return gtp_resp2(gsn, packet, len, peer, fd, seq, tid, flow, tei);
|
||||
}
|
||||
|
||||
static int gtp_notification(struct gsn_t *gsn, uint8_t version,
|
||||
union gtp_packet *packet, int len,
|
||||
const struct sockaddr_in *peer, int fd, uint16_t seq)
|
||||
@@ -820,6 +839,395 @@ int gtp_ran_info_relay_req(struct gsn_t *gsn, const struct sockaddr_in *peer,
|
||||
return gtp_notification(gsn, 1, &packet, length, peer, gsn->fd1c, 0);
|
||||
}
|
||||
|
||||
#define GSM_MI_TYPE_TLLI 0x05
|
||||
|
||||
/* Send an SGSN Context Request for an MI */
|
||||
int gtp_sgsn_context_req(struct gsn_t *gsn, const struct in_addr *peer,
|
||||
const struct osmo_mobile_identity *mi, uint16_t tlli, uint32_t teic,
|
||||
const struct ul16_t *sgsn_addr, const struct ul255_t *rai, void *cbp)
|
||||
{
|
||||
union gtp_packet packet;
|
||||
|
||||
/* GTP 1 is the highest supported protocol */
|
||||
unsigned int length = get_default_gtp(1, GTP_SGSN_CONTEXT_REQ, &packet);
|
||||
|
||||
gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_RAI, rai->l, rai->v);
|
||||
gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, teic);
|
||||
gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, sgsn_addr->l, sgsn_addr->v);
|
||||
|
||||
switch (mi->type) {
|
||||
case GSM_MI_TYPE_IMSI:
|
||||
{
|
||||
uint64_t imsi = gtp_imsi_str2gtp(mi->imsi);
|
||||
imsi = ntoh64(imsi);
|
||||
gtpie_tv8(&packet, &length, GTP_MAX, GTPIE_IMSI, imsi);
|
||||
break;
|
||||
}
|
||||
case GSM_MI_TYPE_TLLI:
|
||||
gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TLLI, mi->tmsi);
|
||||
break;
|
||||
case GSM_MI_TYPE_TMSI:
|
||||
gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_P_TMSI, mi->tmsi);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
/* TODO: Error */
|
||||
break;
|
||||
}
|
||||
|
||||
return gtp_req(gsn, 1, NULL, &packet, length, peer, cbp);
|
||||
}
|
||||
|
||||
/* Handle an SGSN Context Request */
|
||||
static int gtp_sgsn_context_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
|
||||
void *pack, unsigned len)
|
||||
{
|
||||
/* Check if we have a context with TLLI/P-TMSI/IMSI in the RAI */
|
||||
struct osmo_mobile_identity mi = {0};
|
||||
uint64_t imsi;
|
||||
|
||||
union gtpie_member *ie[GTPIE_SIZE];
|
||||
uint32_t teic;
|
||||
uint8_t seq = get_seq(pack);
|
||||
struct ul16_t sgsn_addr;
|
||||
struct ul255_t rai = { .l = 6 };
|
||||
struct osmo_routing_area_id rai_parsed;
|
||||
|
||||
if (version != 1) {
|
||||
LOGP(DLGTP, LOGL_NOTICE,
|
||||
"SGSN Context Request expected only on GTPCv1: %u\n", version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int hlen = get_hlen(pack);
|
||||
|
||||
/* Decode information elements */
|
||||
if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Invalid message format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* RAI */
|
||||
if (gtpie_gettv0(ie, GTPIE_RAI, 0, &rai.v, 6)) {
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Missing RAI\n");
|
||||
goto missing_ie;
|
||||
}
|
||||
if (osmo_routing_area_id_decode(&rai_parsed, rai.v, 6) < 0) {
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Invalid RAI\n");
|
||||
}
|
||||
|
||||
/* TEI-C */
|
||||
if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &teic)) {
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Missing TEI-C\n");
|
||||
goto missing_ie;
|
||||
}
|
||||
|
||||
/* SGSN address for signalling (mandatory) */
|
||||
if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &sgsn_addr.l,
|
||||
&sgsn_addr.v, sizeof(sgsn_addr.v))) {
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Missing GSN Addr\n");
|
||||
goto missing_ie;
|
||||
}
|
||||
|
||||
/* Get PTMSI, TLLI or IMSI - only one IE allowed */
|
||||
if (!gtpie_gettv4(ie, GTPIE_TLLI, 0, &mi.tmsi)) {
|
||||
mi.type = GSM_MI_TYPE_TLLI;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!gtpie_gettv4(ie, GTPIE_P_TMSI, 0, &mi.tmsi)) {
|
||||
mi.type = GSM_MI_TYPE_TMSI;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!gtpie_gettv8(ie, GTPIE_IMSI, 0, &imsi)) {
|
||||
mi.type = GSM_MI_TYPE_IMSI;
|
||||
/* NOTE: gtpie_gettv8 already converts to host byte order, but imsi_gtp2str seems to prefer big endian */
|
||||
imsi = ntoh64(imsi);
|
||||
const char *imsi_str = imsi_gtp2str(&imsi);
|
||||
memcpy(mi.imsi, imsi_str, sizeof(mi.imsi));
|
||||
} else {
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Missing Identity information\n");
|
||||
goto missing_ie;
|
||||
}
|
||||
|
||||
done:
|
||||
if (gsn->cb_sgsn_context_request_ind)
|
||||
gsn->cb_sgsn_context_request_ind(gsn, peer, seq, &rai_parsed, teic, &mi, ie);
|
||||
|
||||
return 0;
|
||||
|
||||
missing_ie:
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Missing mandatory IE\n");
|
||||
/* TODO: Send response with cause */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static bool is_ext_ua(const struct pdp_t *pdp)
|
||||
{
|
||||
return pdp->eua.l > 0 && pdp->eua.v[0] == PDP_EUA_TYPE_v4v6;
|
||||
}
|
||||
|
||||
static int gtp_pdp_ctx(uint8_t *buf, unsigned int size, const struct pdp_t *pdp, uint16_t sapi)
|
||||
{
|
||||
uint32_t tmp32;
|
||||
uint16_t tmp16;
|
||||
uint8_t *ptr = buf;
|
||||
#define CHECK_SPACE_ERR(bytes) \
|
||||
if ((ptr - buf) + (bytes) > size) { \
|
||||
printf("Failed size check: %lu + %lu > %lu\n", (ptr- buf), bytes, size); \
|
||||
return -1; \
|
||||
}
|
||||
#define MEMCPY_CHK(dst, src, len) \
|
||||
CHECK_SPACE_ERR((len)) \
|
||||
memcpy((dst), (uint8_t *)(src), (len)); \
|
||||
(dst) += (len);
|
||||
|
||||
// Flags - FIXME: No ASI
|
||||
*ptr++ = (is_ext_ua(pdp) << 7) | ((!!pdp->vplmn_allow) << 6) | ((!!pdp->reorder) << 4) | (pdp->nsapi & 0x0f);
|
||||
// SAPI
|
||||
*ptr++ = sapi & 0x0f;
|
||||
|
||||
// QoS Sub
|
||||
if (pdp->qos_sub.l < 4) {
|
||||
/* Work around qos_sub never being set */
|
||||
*ptr++ = 4;
|
||||
*ptr++ = 0;
|
||||
*ptr++ = 0x23;
|
||||
*ptr++ = 0x02;
|
||||
*ptr++ = 0x00;
|
||||
} else {
|
||||
*ptr++ = pdp->qos_sub.l;
|
||||
MEMCPY_CHK(ptr, pdp->qos_sub.v, pdp->qos_sub.l);
|
||||
}
|
||||
// QoS Req
|
||||
*ptr++ = pdp->qos_req.l;
|
||||
MEMCPY_CHK(ptr, pdp->qos_req.v, pdp->qos_req.l);
|
||||
// QoS Neg
|
||||
*ptr++ = pdp->qos_neg.l;
|
||||
MEMCPY_CHK(ptr, pdp->qos_neg.v, pdp->qos_neg.l);
|
||||
|
||||
// SND
|
||||
tmp16 = osmo_htons(pdp->pdcpsndd);
|
||||
MEMCPY_CHK(ptr, &tmp16, sizeof(tmp16));
|
||||
// SNU
|
||||
tmp16 = osmo_htons(pdp->pdcpsndu);
|
||||
MEMCPY_CHK(ptr, &tmp16, sizeof(tmp16));
|
||||
// Send N-PDU
|
||||
*ptr++ = pdp->gtpsntx;
|
||||
// Recv N-PDU
|
||||
*ptr++ = pdp->gtpsnrx;
|
||||
// Uplink TEIC
|
||||
tmp32 = osmo_htonl(pdp->teic_gn);
|
||||
MEMCPY_CHK(ptr, &tmp32, sizeof(tmp32));
|
||||
// Uplink TEIDI
|
||||
tmp32 = osmo_htonl(pdp->teid_gn);
|
||||
MEMCPY_CHK(ptr, &tmp32, sizeof(tmp32));
|
||||
// PDP Ctx Id
|
||||
*ptr++ = pdp->pdp_id;
|
||||
// PDP Type Org
|
||||
*ptr++ = PDP_EUA_ORG_IETF;
|
||||
|
||||
// PDP Type No.
|
||||
// PDP Address
|
||||
switch (pdp->eua.v[1]) {
|
||||
case PDP_EUA_TYPE_v4:
|
||||
case PDP_EUA_TYPE_v4v6:
|
||||
/* v4v6 expects an IPv4 addr first followed by an IPv6 addr*/
|
||||
*ptr++ = PDP_EUA_TYPE_v4;
|
||||
if (pdp->eua.l < 6)
|
||||
return -1;
|
||||
*ptr++ = 4;
|
||||
MEMCPY_CHK(ptr, &pdp->eua.v[2], 4);
|
||||
break;
|
||||
case PDP_EUA_TYPE_v6:
|
||||
*ptr++ = PDP_EUA_TYPE_v6;
|
||||
if (pdp->eua.l < 18)
|
||||
return -1;
|
||||
*ptr++ = 16;
|
||||
MEMCPY_CHK(ptr, &pdp->eua.v[2], 16);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
//Panic
|
||||
}
|
||||
// GGSN Address Ctrl
|
||||
*ptr++ = pdp->gsnrc.l;
|
||||
MEMCPY_CHK(ptr, pdp->gsnrc.v, pdp->gsnrc.l);
|
||||
// GGSN Address User
|
||||
*ptr++ = pdp->gsnru.l;
|
||||
MEMCPY_CHK(ptr, pdp->gsnru.v, pdp->gsnru.l);
|
||||
// APN
|
||||
*ptr++ = pdp->apn_use.l;
|
||||
MEMCPY_CHK(ptr, pdp->apn_use.v, pdp->apn_use.l);
|
||||
// TransId
|
||||
*ptr++ = (pdp->ti >> 8) & 0x0f;
|
||||
*ptr++ = pdp->ti & 0xff;
|
||||
|
||||
if (is_ext_ua(pdp)) {
|
||||
*ptr++ = PDP_EUA_TYPE_v6;
|
||||
if (pdp->eua.l < 22)
|
||||
return -1;
|
||||
*ptr++ = 16;
|
||||
MEMCPY_CHK(ptr, &pdp->eua.v[6], 16);
|
||||
}
|
||||
return ptr - buf;
|
||||
#undef CHECK_SPACE_ERR
|
||||
#undef MEMCPY_CHK
|
||||
}
|
||||
|
||||
int gtp_sgsn_context_conf(struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq,
|
||||
uint32_t teic, uint8_t cause, uint64_t imsi, const struct in_addr *sgsn_addr, struct pdp_t *pdpctx, uint16_t sapi, uint8_t *mmctx, int mm_len, void *cbp)
|
||||
{
|
||||
union gtp_packet packet;
|
||||
struct ul255_t pdp;
|
||||
|
||||
/* GTP 1 is the highest supported protocol */
|
||||
unsigned int length = get_default_gtp(1, GTP_SGSN_CONTEXT_RSP, &packet);
|
||||
|
||||
// Cause - TV1
|
||||
gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
|
||||
|
||||
if (cause != GTPCAUSE_ACC_REQ)
|
||||
return gtp_resp2(gsn, &packet, length, peer, gsn->fd1c, seq, 0, 0, teic);
|
||||
|
||||
// IMSI - TV8
|
||||
gtpie_tv8(&packet, &length, GTP_MAX, GTPIE_IMSI, imsi);
|
||||
|
||||
// TEIC - TV4
|
||||
gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, pdpctx->teic_own);
|
||||
|
||||
// MM Ctx - TLV
|
||||
gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MM_CONTEXT, mm_len, mmctx);
|
||||
|
||||
// PDP Ctx - TLV
|
||||
if (pdpctx) {
|
||||
int rc = gtp_pdp_ctx(pdp.v, 255, pdpctx, sapi);
|
||||
if (rc > 0)
|
||||
gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PDP_CONTEXT, rc, pdp.v);
|
||||
}
|
||||
|
||||
// SGSN Addr Ctrl - TLV
|
||||
gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, 4, &sgsn_addr->s_addr);
|
||||
|
||||
// Alt GGSN Addr Ctrl (per PDP Ctx)
|
||||
// Alt GGSN Addr User (per PDP Ctx)
|
||||
/* The encoding for this is a bit insane */
|
||||
|
||||
return gtp_resp2(gsn, &packet, length, peer, gsn->fd1c, seq, 0, 0, teic);
|
||||
}
|
||||
|
||||
/* Handle an SGSN Context Response */
|
||||
static int gtp_sgsn_context_conf_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
|
||||
void *pack, unsigned len)
|
||||
{
|
||||
/** If cause is "Request accepted": Send ACK,
|
||||
else: Log and handle error */
|
||||
|
||||
/* Check if we have a context with TLLI/P-TMSI/IMSI in the RAI */
|
||||
|
||||
void *cbp = NULL;
|
||||
uint8_t type = 0;
|
||||
uint8_t cause;
|
||||
union gtpie_member *ie[GTPIE_SIZE];
|
||||
struct pdp_t *pdp = NULL;
|
||||
uint32_t teic;
|
||||
struct ul16_t sgsn_addr;
|
||||
|
||||
if (version != 1) {
|
||||
LOGP(DLGTP, LOGL_NOTICE,
|
||||
"SGSN Context Request expected only on GTPCv1: %u\n", version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int hlen = get_hlen(pack);
|
||||
|
||||
/* Remove packet from queue */
|
||||
if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp))
|
||||
return EOF;
|
||||
|
||||
/* Extract information elements into a pointer array */
|
||||
if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Invalid message format\n");
|
||||
if (gsn->cb_conf)
|
||||
gsn->cb_conf(type, EOF, NULL, cbp);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* Extract cause value (mandatory) */
|
||||
if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) {
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_MISSING);
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Missing mandatory information field\n");
|
||||
if (gsn->cb_conf)
|
||||
gsn->cb_conf(type, EOF, NULL, cbp);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* Check all conditional information elements */
|
||||
if (!gtp_cause_successful(cause)) {
|
||||
GTP_LOGPKG(LOGL_NOTICE, peer, pack, len,
|
||||
"SGSN Context response with cause (%u)\n", cause);
|
||||
if (gsn->cb_conf)
|
||||
gsn->cb_conf(type, cause, NULL, cbp);
|
||||
}
|
||||
|
||||
/* Gather UE context and PDP data, create pdp context */
|
||||
//gtp_pdp_newpdp(gsn, &pdp, imsi, nsapi, NULL)
|
||||
if (gsn->cb_conf)
|
||||
gsn->cb_conf(type, cause, pdp, cbp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle an SGSN Context Acknowledge */
|
||||
static int gtp_sgsn_context_ack(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
|
||||
void *pack, unsigned len)
|
||||
{
|
||||
/* If cause is != Request accepted, log error */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Handle an SGSN Context request */
|
||||
int gtp_context_request(struct gsn_t *gsn, int version, struct sockaddr_in *peer,
|
||||
void *pack, unsigned len)
|
||||
{
|
||||
union gtpie_member *ie[GTPIE_SIZE];
|
||||
|
||||
if (version != 1) {
|
||||
LOGP(DLGTP, LOGL_NOTICE,
|
||||
"SGSN Context Request expected only on GTPCv1: %u\n", version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int hlen = get_hlen(pack);
|
||||
|
||||
/* Decode information elements */
|
||||
if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) {
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_INVALID);
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Invalid message format (AN Information Relay)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (gsn->cb_ran_info_relay_ind)
|
||||
gsn->cb_ran_info_relay_ind(peer, ie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ***********************************************************
|
||||
* Session management messages
|
||||
* Messages: create, update and delete PDP context
|
||||
@@ -995,7 +1403,7 @@ int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause)
|
||||
/* Now send off a reply to the peer */
|
||||
gtp_create_pdp_resp(gsn, pdp->version, pdp, cause);
|
||||
|
||||
if (cause != GTPCAUSE_ACC_REQ)
|
||||
if (!gtp_cause_successful(cause))
|
||||
gtp_freepdp(gsn, pdp);
|
||||
|
||||
return 0;
|
||||
@@ -1011,7 +1419,7 @@ int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp,
|
||||
|
||||
gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
|
||||
|
||||
if (cause == GTPCAUSE_ACC_REQ) {
|
||||
if (gtp_cause_successful(cause)) {
|
||||
|
||||
if (version == 0)
|
||||
gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
|
||||
@@ -1445,7 +1853,7 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version,
|
||||
}
|
||||
|
||||
/* Check all conditional information elements */
|
||||
if (GTPCAUSE_ACC_REQ == cause) {
|
||||
if (gtp_cause_successful(cause)) {
|
||||
|
||||
if (version == 0) {
|
||||
if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
|
||||
@@ -1667,7 +2075,7 @@ static int gtp_update_pdp_resp(struct gsn_t *gsn, uint8_t version,
|
||||
|
||||
gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
|
||||
|
||||
if (cause == GTPCAUSE_ACC_REQ) {
|
||||
if (gtp_cause_successful(cause)) {
|
||||
|
||||
if (version == 0)
|
||||
gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0,
|
||||
@@ -1997,7 +2405,7 @@ static int gtp_update_pdp_conf(struct gsn_t *gsn, uint8_t version,
|
||||
|
||||
/* Check all conditional information elements */
|
||||
/* TODO: This does not handle GGSN-initiated update responses */
|
||||
if (cause == GTPCAUSE_ACC_REQ) {
|
||||
if (gtp_cause_successful(cause)) {
|
||||
if (version == 0) {
|
||||
if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0,
|
||||
&pdp->qos_neg0,
|
||||
@@ -2172,7 +2580,7 @@ int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
|
||||
gtp_resp(version, gsn, pdp, &packet, length, peer, fd,
|
||||
get_seq(pack), get_tid(pack));
|
||||
|
||||
if (cause == GTPCAUSE_ACC_REQ) {
|
||||
if (gtp_cause_successful(cause)) {
|
||||
if ((teardown) || (version == 0)) { /* Remove all contexts */
|
||||
gtp_freepdp_teardown(gsn, linked_pdp);
|
||||
} else {
|
||||
@@ -2198,7 +2606,6 @@ int gtp_delete_pdp_resp(struct gsn_t *gsn, int version,
|
||||
}
|
||||
}
|
||||
}
|
||||
/* if (cause == GTPCAUSE_ACC_REQ) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2350,7 +2757,7 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version,
|
||||
}
|
||||
|
||||
/* Check the cause value (again) */
|
||||
if ((GTPCAUSE_ACC_REQ != cause) && (GTPCAUSE_NON_EXIST != cause)) {
|
||||
if (!gtp_cause_successful(cause) && (GTPCAUSE_NON_EXIST != cause)) {
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_UNEXPECTED_CAUSE);
|
||||
GTP_LOGPKG(LOGL_ERROR, peer, pack, len,
|
||||
"Unexpected cause value received: %d\n", cause);
|
||||
@@ -2827,6 +3234,15 @@ int gtp_decaps1c(struct gsn_t *gsn)
|
||||
case GTP_RAN_INFO_RELAY:
|
||||
gtp_ran_info_relay_ind(gsn, version, &peer, buffer, status);
|
||||
break;
|
||||
case GTP_SGSN_CONTEXT_REQ:
|
||||
gtp_sgsn_context_ind(gsn, version, &peer, buffer, status);
|
||||
break;
|
||||
case GTP_SGSN_CONTEXT_RSP:
|
||||
gtp_sgsn_context_conf_ind(gsn, version, &peer, buffer, status);
|
||||
break;
|
||||
case GTP_SGSN_CONTEXT_ACK:
|
||||
gtp_sgsn_context_ack(gsn, version, &peer, buffer, status);
|
||||
break;
|
||||
default:
|
||||
rate_ctr_inc2(gsn->ctrg, GSN_CTR_PKT_UNKNOWN);
|
||||
GTP_LOGPKG(LOGL_ERROR, &peer, buffer, status,
|
||||
|
||||
33
gtp/gtp.h
33
gtp/gtp.h
@@ -53,7 +53,7 @@
|
||||
#define GTP_UPDATE_PDP_RSP 19 /* Update PDP Context Response */
|
||||
#define GTP_DELETE_PDP_REQ 20 /* Delete PDP Context Request */
|
||||
#define GTP_DELETE_PDP_RSP 21 /* Delete PDP Context Response */
|
||||
/* 22-25 For future use. *//* In version GTP 1 anonomous PDP context */
|
||||
/* 22-25 For future use. *//* In version GTP 1 anonomous PDP context */
|
||||
#define GTP_ERROR 26 /* Error Indication */
|
||||
#define GTP_PDU_NOT_REQ 27 /* PDU Notification Request */
|
||||
#define GTP_PDU_NOT_RSP 28 /* PDU Notification Response */
|
||||
@@ -99,19 +99,21 @@ static inline const char *gtp_type_name(uint8_t val)
|
||||
#define GTPCAUSE_NO_ID_NEEDED 3 /* No identity needed */
|
||||
#define GTPCAUSE_MS_REFUSES_X 4 /* MS refuses */
|
||||
#define GTPCAUSE_MS_NOT_RESP_X 5 /* MS is not GPRS responding */
|
||||
#define GTPCAUSE_006 6 /* For future use 6-48 */
|
||||
#define GTPCAUSE_049 49 /* Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) 49-63 */
|
||||
#define GTPCAUSE_064 64 /* For future use 64-127 */
|
||||
/* 6-48 For future use */
|
||||
/* 49-63 Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) */
|
||||
/* 64-127 For future use */
|
||||
#define GTPCAUSE_ACC_REQ 128 /* Request accepted */
|
||||
#define GTPCAUSE_129 129 /* For future use 129-176 */
|
||||
#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */
|
||||
#define GTPCAUSE_NEW_PDP_NET_PREF 129 /* New PDP type due to network preference */
|
||||
#define GTPCAUSE_NEW_PDP_ADDR_BEAR 130 /* New PDP type due to single address bearer only */
|
||||
/* 131-176 For future use */
|
||||
/* 177-191 Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) */
|
||||
#define GTPCAUSE_NON_EXIST 192 /* Non-existent */
|
||||
#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */
|
||||
#define GTPCAUSE_IMSI_NOT_KNOWN 194 /* IMSI not known */
|
||||
#define GTPCAUSE_MS_DETACHED 195 /* MS is GPRS detached */
|
||||
#define GTPCAUSE_MS_NOT_RESP 196 /* MS is not GPRS responding */
|
||||
#define GTPCAUSE_MS_REFUSES 197 /* MS refuses */
|
||||
#define GTPCAUSE_198 198 /* For future use */
|
||||
/* 198 For future use */
|
||||
#define GTPCAUSE_NO_RESOURCES 199 /* No resources available */
|
||||
#define GTPCAUSE_NOT_SUPPORTED 200 /* Service not supported */
|
||||
#define GTPCAUSE_MAN_IE_INCORRECT 201 /* Mandatory IE incorrect */
|
||||
@@ -134,8 +136,15 @@ static inline const char *gtp_type_name(uint8_t val)
|
||||
#define GTPCAUSE_SYN_ERR_FILTER 218 /* Syntactic errors in packet filter(s) */
|
||||
#define GTPCAUSE_MISSING_APN 219 /* Missing or unknown APN */
|
||||
#define GTPCAUSE_UNKNOWN_PDP 220 /* Unknown PDP address or PDP type */
|
||||
#define GTPCAUSE_221 221 /* For Future Use 221-240 */
|
||||
#define GTPCAUSE_241 241 /* Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) 241-255 */
|
||||
/* 221-240 For future use */
|
||||
/* 241-255 Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) */
|
||||
|
||||
static inline bool gtp_cause_successful(uint8_t cause)
|
||||
{
|
||||
return cause == GTPCAUSE_ACC_REQ ||
|
||||
cause == GTPCAUSE_NEW_PDP_NET_PREF ||
|
||||
cause == GTPCAUSE_NEW_PDP_ADDR_BEAR;
|
||||
}
|
||||
|
||||
struct ul66_t;
|
||||
struct ul16_t;
|
||||
@@ -253,6 +262,12 @@ extern int gtp_ran_info_relay_req(struct gsn_t *gsn, const struct sockaddr_in *p
|
||||
const uint8_t *rim_route_addr, size_t rim_route_addr_len,
|
||||
uint8_t rim_route_addr_discr);
|
||||
|
||||
extern int gtp_sgsn_context_req(struct gsn_t *gsn, const struct in_addr *peer,
|
||||
const struct osmo_mobile_identity *mi, uint16_t tlli, uint32_t teic,
|
||||
const struct ul16_t *sgsn_addr, const struct ul255_t *rai, void *cbp);
|
||||
extern int gtp_sgsn_context_conf(struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq,
|
||||
uint32_t teic, uint8_t cause, uint64_t imsi, const struct in_addr *sgsn_addr, struct pdp_t *pdpctx, uint16_t sapi, uint8_t *mmctx, int mm_len, void *cbp);
|
||||
|
||||
extern int gtp_decaps0(struct gsn_t *gsn);
|
||||
extern int gtp_decaps1c(struct gsn_t *gsn);
|
||||
extern int gtp_decaps1u(struct gsn_t *gsn);
|
||||
|
||||
@@ -1,10 +1,41 @@
|
||||
noinst_LIBRARIES = libmisc.a
|
||||
|
||||
noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h in46_addr.h netdev.h gtp-kernel.h netns.h util.h icmpv6.h checksum.h
|
||||
noinst_HEADERS = \
|
||||
checksum.h \
|
||||
gnugetopt.h \
|
||||
gtp-kernel.h \
|
||||
icmpv6.h \
|
||||
in46_addr.h \
|
||||
ippool.h \
|
||||
lookup.h \
|
||||
netdev.h \
|
||||
netns.h \
|
||||
syserr.h \
|
||||
tun.h \
|
||||
util.h \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
|
||||
AM_CFLAGS = \
|
||||
-fno-builtin \
|
||||
-Wall \
|
||||
-DSBINDIR='"$(sbindir)"' \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c in46_addr.c netdev.c netns.c util.c icmpv6.c checksum.c
|
||||
libmisc_a_SOURCES = \
|
||||
checksum.c \
|
||||
debug.c \
|
||||
getopt.c \
|
||||
getopt1.c \
|
||||
icmpv6.c \
|
||||
in46_addr.c \
|
||||
ippool.c \
|
||||
lookup.c \
|
||||
netdev.c \
|
||||
netns.c \
|
||||
tun.c \
|
||||
util.c \
|
||||
$(NULL)
|
||||
|
||||
if ENABLE_GTP_KERNEL
|
||||
AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
|
||||
|
||||
104
lib/gtp-kernel.c
104
lib/gtp-kernel.c
@@ -104,61 +104,97 @@ void gtp_kernel_stop(const char *devname)
|
||||
|
||||
int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname)
|
||||
{
|
||||
struct in_addr ms, sgsn;
|
||||
int ms_addr_count;
|
||||
struct in46_addr ms[2];
|
||||
struct in46_addr sgsn;
|
||||
struct gtp_tunnel *t;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
pdp_debug(__func__, devname, pdp);
|
||||
|
||||
t = gtp_tunnel_alloc();
|
||||
if (t == NULL)
|
||||
in46a_from_gsna(&pdp->gsnrc, &sgsn);
|
||||
|
||||
ms_addr_count = in46a_from_eua(&pdp->eua, ms);
|
||||
if (ms_addr_count < 0)
|
||||
return -1;
|
||||
|
||||
memcpy(&ms, &pdp->eua.v[2], sizeof(struct in_addr));
|
||||
memcpy(&sgsn, &pdp->gsnrc.v[0], sizeof(struct in_addr));
|
||||
for (int i = 0; i < ms_addr_count; i++) {
|
||||
t = gtp_tunnel_alloc();
|
||||
if (t == NULL)
|
||||
return -1;
|
||||
|
||||
gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
|
||||
gtp_tunnel_set_version(t, pdp->version);
|
||||
gtp_tunnel_set_ms_ip4(t, &ms);
|
||||
gtp_tunnel_set_sgsn_ip4(t, &sgsn);
|
||||
if (pdp->version == 0) {
|
||||
gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
|
||||
gtp_tunnel_set_flowid(t, pdp->flru);
|
||||
} else {
|
||||
gtp_tunnel_set_i_tei(t, pdp->teid_own);
|
||||
/* use the TEI advertised by SGSN when sending packets
|
||||
* towards the SGSN */
|
||||
gtp_tunnel_set_o_tei(t, pdp->teid_gn);
|
||||
gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
|
||||
gtp_tunnel_set_version(t, pdp->version);
|
||||
|
||||
if (in46a_to_af(&ms[i]) == AF_INET)
|
||||
gtp_tunnel_set_ms_ip4(t, &ms[i].v4);
|
||||
else {
|
||||
/* In IPv6, EUA doesn't contain the actual IP
|
||||
* addr/prefix. Set higher bits to 0 to get the 64 bit
|
||||
* netmask. */
|
||||
memset(((void *)&ms[i].v6) + 8, 0, 8);
|
||||
gtp_tunnel_set_ms_ip6(t, &ms[i].v6);
|
||||
}
|
||||
|
||||
if (in46a_to_af(&sgsn) == AF_INET)
|
||||
gtp_tunnel_set_sgsn_ip4(t, &sgsn.v4);
|
||||
else
|
||||
gtp_tunnel_set_sgsn_ip6(t, &sgsn.v6);
|
||||
|
||||
if (pdp->version == 0) {
|
||||
gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
|
||||
gtp_tunnel_set_flowid(t, pdp->flru);
|
||||
} else {
|
||||
gtp_tunnel_set_i_tei(t, pdp->teid_own);
|
||||
/* use the TEI advertised by SGSN when sending packets
|
||||
* towards the SGSN */
|
||||
gtp_tunnel_set_o_tei(t, pdp->teid_gn);
|
||||
}
|
||||
|
||||
ret = gtp_add_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
|
||||
gtp_tunnel_free(t);
|
||||
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = gtp_add_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
|
||||
gtp_tunnel_free(t);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname)
|
||||
{
|
||||
int ms_addr_count;
|
||||
struct in46_addr ms[2];
|
||||
struct gtp_tunnel *t;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
pdp_debug(__func__, devname, pdp);
|
||||
|
||||
t = gtp_tunnel_alloc();
|
||||
if (t == NULL)
|
||||
ms_addr_count = in46a_from_eua(&pdp->eua, ms);
|
||||
if (ms_addr_count < 0)
|
||||
return -1;
|
||||
|
||||
gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
|
||||
gtp_tunnel_set_version(t, pdp->version);
|
||||
if (pdp->version == 0) {
|
||||
gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
|
||||
gtp_tunnel_set_flowid(t, pdp->flru);
|
||||
} else {
|
||||
gtp_tunnel_set_i_tei(t, pdp->teid_own);
|
||||
}
|
||||
for (int i = 0; i < ms_addr_count; i++) {
|
||||
t = gtp_tunnel_alloc();
|
||||
if (t == NULL)
|
||||
return -1;
|
||||
|
||||
ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
|
||||
gtp_tunnel_free(t);
|
||||
gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
|
||||
gtp_tunnel_set_family(t, in46a_to_af(&ms[i]));
|
||||
gtp_tunnel_set_version(t, pdp->version);
|
||||
if (pdp->version == 0) {
|
||||
gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
|
||||
gtp_tunnel_set_flowid(t, pdp->flru);
|
||||
} else {
|
||||
gtp_tunnel_set_i_tei(t, pdp->teid_own);
|
||||
}
|
||||
|
||||
ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
|
||||
gtp_tunnel_free(t);
|
||||
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
14
lib/icmpv6.h
14
lib/icmpv6.h
@@ -44,10 +44,9 @@ struct icmpv6_radv_hdr {
|
||||
uint8_t res:6,
|
||||
m:1,
|
||||
o:1;
|
||||
#else
|
||||
uint8_t m:1,
|
||||
o:1,
|
||||
res:6;
|
||||
#elif OSMO_IS_BIG_ENDIAN
|
||||
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
|
||||
uint8_t o:1, m:1, res:6;
|
||||
#endif
|
||||
uint16_t router_lifetime;
|
||||
uint32_t reachable_time;
|
||||
@@ -72,10 +71,9 @@ struct icmpv6_opt_prefix {
|
||||
uint8_t res:6,
|
||||
a:1,
|
||||
l:1;
|
||||
#else
|
||||
uint8_t l:1,
|
||||
a:1,
|
||||
res:6;
|
||||
#elif OSMO_IS_BIG_ENDIAN
|
||||
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
|
||||
uint8_t l:1, a:1, res:6;
|
||||
#endif
|
||||
uint32_t valid_lifetime;
|
||||
uint32_t preferred_lifetime;
|
||||
|
||||
@@ -375,3 +375,10 @@ default_to_dyn_v4:
|
||||
dst->v4.s_addr = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void in46a_from_gsna(const struct ul16_t *in, struct in46_addr *dst)
|
||||
{
|
||||
dst->len = in->l;
|
||||
OSMO_ASSERT(in->l <= sizeof(dst->v6));
|
||||
memcpy(&dst->v6, in->v, in->l);
|
||||
}
|
||||
|
||||
@@ -39,3 +39,5 @@ static inline bool in46a_is_v6(const struct in46_addr *addr) {
|
||||
static inline bool in46a_is_v4(const struct in46_addr *addr) {
|
||||
return addr->len == sizeof(struct in_addr);
|
||||
}
|
||||
|
||||
void in46a_from_gsna(const struct ul16_t *in, struct in46_addr *dst);
|
||||
|
||||
@@ -2,12 +2,21 @@ bin_PROGRAMS = sgsnemu
|
||||
|
||||
AM_LDFLAGS = @EXEC_LDFLAGS@
|
||||
|
||||
AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
|
||||
AM_CFLAGS = \
|
||||
-D_GNU_SOURCE \
|
||||
-fno-builtin \
|
||||
-Wall \
|
||||
-DSBINDIR='"$(sbindir)"' \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
sgsnemu_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS)
|
||||
|
||||
if ENABLE_GTP_KERNEL
|
||||
AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
|
||||
AM_CFLAGS += \
|
||||
-DGTP_KERNEL \
|
||||
$(LIBGTPNL_CFLAGS) \
|
||||
$(NULL)
|
||||
sgsnemu_LDADD += $(LIBGTPNL_LIBS)
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-I$(top_srcdir)/include \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(NULL)
|
||||
AM_LDFLAGS = -no-install
|
||||
|
||||
EXTRA_DIST = \
|
||||
gtpie_test.ok \
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-I$(top_srcdir)/include \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(NULL)
|
||||
AM_LDFLAGS = -no-install
|
||||
|
||||
EXTRA_DIST = ippool_test.ok \
|
||||
ippool_test.err \
|
||||
|
||||
Reference in New Issue
Block a user