Compare commits

...

42 Commits

Author SHA1 Message Date
Oliver Smith
848ec697e2 Bump version: 1.10.2.1-a625 → 1.11.0
Change-Id: I1f116e1cded135f231f22ebc9b817aebf3736fc2
2023-11-28 13:07:17 +00:00
Daniel Willmann
6a2e82542d libgtp: Use gtp_cause_successful() instead of GTPCAUSE_ACC_REQ
In some cases the phone requests a PDP context type that isn't available
no the PGW/GGSN, e.g. phone requests a combined IPv4/v6 context, but
only IPv4 is supported.

In that case the GGSN can send a Create PDP Context Response with cause
"New PDP type due to network preference" or "New PDP type due to single
address bearer only". libgtp should continue handling these cause values
like the "Request Accepted" cause. Use the new gtp_cause_successful()
function for that.

Related: OS#6268
Change-Id: I7dd1e0aa185530e1e2d0402742df833c61a787a7
2023-11-24 09:48:22 +01:00
Daniel Willmann
a625bdd136 gtp: Add net GTP cause values and a function to check for success
According to the spec the upf/pgw can accept a modified pdp context from
the request e.g. if an ipv4/6 context was requested, but only ipv4 is
availiable. Introduce a function that checks all cause values that are
considered successful.

See also: 3GPP TS 29.060 Ch 7.3.2

Related: OS#6268
Change-Id: I9c3bf64537ef2223e29f8082861fa32fde26bf68
2023-11-22 12:36:49 +01:00
Pau Espin Pedrol
08bb5182a4 Bump version: 1.10.1.8-4963-dirty → 1.10.2
Change-Id: I148375902975aba0a374e4507c97f1ff67d687bc
2023-09-12 14:36:11 +02:00
Oliver Smith
4963d1c2ea lib/in46_addr: add in46a_from_gsna
Prepare to use it in gtp-kernel.c in a future patch.

Related: OS#6096
Change-Id: I3e76eb7ee89ba338f085c617662d15cffa2a62d5
2023-07-24 15:06:03 +02:00
Oliver Smith
37daa5d003 doc: running: update kernel-gtp limitations
Related: OS#6096
Change-Id: Ie4f1452ecefbe0db0e4093caa8177f1c87bd3950
2023-07-21 12:59:41 +02:00
Oliver Smith
c4c4d90b85 README: update documentation section
Change-Id: I3320dc5eb3d183a18c2bd2fe3139f729978ea2a1
2023-07-21 11:19:14 +02:00
Oliver Smith
59f1539ece systemd: depend on networking-online.target
Related: SYS#6400
Change-Id: I29e547242b2ed1cfc4750c7d7e5f8636c2e8f3dc
2023-05-26 14:10:45 +02:00
Oliver Smith
eff88c08e7 debian: set compat level to 10
Related: OS#5958
Change-Id: I4b2988fffba12cc84ff0834bb9ef0f3d9de2bcda
2023-04-25 16:48:22 +02:00
Oliver Smith
92ac7249f9 doc/manuals/chapters/configuration: fix typo
Change-Id: I0e9d2c77200c7c8b49aec669bc39ca91d5d4cf1f
2023-04-11 17:18:34 +02:00
Vadim Yanitskiy
5cf6b75dc9 tests: use -no-install libtool flag to avoid ./lt-* scripts
This option should be used for any executables which are used only
for testing, or for generating other files and are consequently never
installed.  By specifying this option, we are telling Libtool that
the executable it links will only ever be executed from where it is
built in the build tree.  Libtool is usually able to considerably
speed up the link process for such executables.

Change-Id: I2ca675e93dc5b34bb08d3b841adc115e93558137
2023-03-11 04:36:59 +07:00
Vadim Yanitskiy
4aa2e417c9 Do not hard-code -g and -O2 in CFLAGS
Let the user decide on the optimization level and debugging info.

Change-Id: I4b0b523b7dac4d67413bda37b546964262e5ea0d
2023-03-09 17:17:03 +07:00
Vadim Yanitskiy
f14c056310 Bump version: 1.10.0.4-bf69 → 1.10.1
Change-Id: Ibde9f259bccce29638d35efbd597669f5584e295
2023-02-27 22:35:47 +07:00
Vadim Yanitskiy
bf69ddbfef gtp: use OSMO_ASSERT() in gtp_new()
When using built-in static_assert() [1], gcc v12.2.1 fails:

In file included from gsn.c:27:
gsn.c: In function 'gtp_new':
gsn.c:444:54: error: expression in static assertion is not constant
  444 |         osmo_static_assert(gtp_T_defs[0].default_val != 0, first_default_val_not_zero);
      |                                                      ^

The reason is likely that gtp_T_defs[] is not const, so it cannot
be assert()ed statically.  With the current osmo_static_assert()
implementation, this assert does nothing.  One can change the
gtp_T_defs[0].default_val to 0 and the code will still compile.

Change-Id: Ia8af1736b63d501661046fe70befe5bbabc1045a
Related: [1] libosmocore.git I5ca34bc14c05e8c38c721d7df33feb1c6c41c76e
2023-02-27 17:07:26 +07:00
Vadim Yanitskiy
70a4e2e6f8 gtp/gsn.c: fix 'No newline at end of file'
git complains if it's missing, vim adds it automatically.

Change-Id: I3b4808a76da89e65b934d818e7ca280bc0651483
2023-02-27 17:07:26 +07:00
Vadim Yanitskiy
99afe979ef lib/icmpv6.h: fix struct icmpv6_{radv_hdr,opt_prefix}
Fix wrong field order in the big-endian variants.

Change-Id: Ifaa63bb5496e056805bd13b964c8b430fb11c24c
2023-02-27 17:07:05 +07:00
Oliver Smith
35066fb0b0 debian/libgtp6.shlibs: new file
List the most recent library version where new symbols where added, so
debian properly upgrades libgtp6 when upgrading osmo-sgsn from the
version that is currently in Debian to a version from the Osmocom
repositories.

Closes: OS#5318
Change-Id: Ida5dae4655c0acaeb377bc9d556a2ac333bca10a
2023-02-08 18:11:54 +01:00
Pau Espin Pedrol
55fe62f634 Bump version: 1.9.0.10-4fac-dirty → 1.10.0
Change-Id: I553fb72c577181c32005093eaf4fa986ae0e6ca8
2023-02-07 14:29:49 +01:00
Pau Espin Pedrol
4fac842826 Fix typos in comments and VTY descriptions
Change-Id: I359425152dc18d29c57047f1b10942480b7a61e5
2023-01-17 14:17:18 +01:00
arehbein
97f60e3dca osmo-ggsn: Transition to use of 'telnet_init_default'
Related: OS#5809
Change-Id: I51b7c175192759e26d1791723540841e72879b02
2022-12-23 11:13:31 +00:00
Max
a727e6ed38 ctrl: take both address and port from vty config
Change-Id: Ib31d67591657e308eebd1e6b7e23f79e6a3656e9
2022-12-17 21:14:57 +03:00
Pau Espin Pedrol
3a55b89777 gtp: Introduce VTY configurable GTP timer X3
This timer controls the amount of time a resp message transmitted by the
local gsn is to be stored in the resp queue. This is used in order to
detect duplicate requests received, since GTP states the exact same
response should be answered if a duplicate request is received.

Prior to this patch, this timer was hardcoded to 60 seconds.
This patch actually should be set, in general, to a value
equal than (T3-RESPONSE * N3-REQUESTS) values configured at
the peer, since that is the maximum period during which the local gsn
expects to receive req retransmissions from the peer.
Hence, this value must be user configurable to adapt it to the peers
connected to the GSN.

The 60 seconds hardcoded value is therefore changed to default to our
local (T3-RESPONSE * N3-REQUESTS), since the most common scenario for
osmo-ggsn/osmo-sgsn is to run it against a peer osmo-sgsn/osmo-ggsn,
which will have the same values by default.
This way we avoid by default caching response messages for way too long,
potentially filling the queue.

Related: OS#5485
Change-Id: Ia15c1cfd201d7c43e9a1d6ceb6725ddf392d2c65
2022-11-04 11:21:25 +01:00
Pau Espin Pedrol
9f1f747d8e ggsn: Introduce tdef and make it configurable over VTY
Related: OS#5485
Change-Id: I10bc8e2e197c0e8753b23b684b5ae41025672bf7
2022-11-02 20:33:39 +01:00
Pau Espin Pedrol
b9036af7ca Use rate_ctr for gsn_t available_counters
This way they can be inspected with regular osmocom means.

Change-Id: I529305b4f824600c6e733a3c0d2c2c6673f99faf
2022-11-02 18:41:38 +01:00
Pau Espin Pedrol
724ecc6680 Split gsn_t related APIs out of gtp.{c,h}
This way we split the gsn_t object API/logic from the protocol (message
handling) code.

Change-Id: I47cebb51bf08b9fcf7f115fc8dbea5f3493d4388
2022-11-02 18:41:34 +01:00
Pau Espin Pedrol
0d3bd3435f cosmetic: gtp: Fix typo in comment
Change-Id: I54b80bba3126cb3ae534938e253721961d4e08c4
2022-11-02 13:22:17 +01:00
Max
3ed252b58e Ignore .deb build byproducts
Change-Id: Iec63ef5ea0acfc5e6621054926be15ae4754d65d
2022-08-30 19:24:48 +07:00
Max
ac802e63d7 Set working directory in systemd service file
By default systemd will execute service with root directory (or home directory for user instance) which might result in
attempts to create files in unexpected place. Let's set it to 'osmocom' subdir of state directory (/var/lib for system
instance) instead.

Related: OS#4821
Change-Id: Idffc115c21cac77f6f43356333de538ba549fc6a
2022-08-30 19:24:48 +07:00
Pau Espin Pedrol
bc583d9763 Bump version: 1.8.0.13-ade4-dirty → 1.9.0
Change-Id: Id61cbe354437233fc6baf187ea90284da6a6944b
2022-06-28 17:48:22 +02:00
Harald Welte
ade4dc191b update git URLs (git -> https; gitea)
Change-Id: I9d59b62493bcdcb1bdbfbfd0525bae2988359f27
2022-06-18 12:04:24 +02:00
Vadim Yanitskiy
cd05da79e7 tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
When using 'check_PROGRAMS', autoconf/automake generates smarter
Makefiles, so that the test programs are not being compiled during
the normal 'make all', but only during 'make check'.

Change-Id: Ia8b8dade0056c51d2dd1d814a89d1de064597344
2022-04-13 19:55:33 +03:00
Pau Espin Pedrol
5545bcea5d pco.h: Fix typo in reference to spec
Change-Id: Ic428892161123b62d25a7619128ef7325bf85500
2022-03-24 12:51:17 +01:00
Pau Espin Pedrol
c97286f839 gtp: Fix typo in comment
Change-Id: I0e38e0966081d8b37c3f816f5330b4f52f81b7fa
2022-03-07 16:22:53 +01:00
Pau Espin Pedrol
f471800168 gtp: Log retrans queue register&free entries
Change-Id: I4e12376652fc7a6a96fbdcb579dbe916c1473012
2022-03-07 16:22:53 +01:00
Pau Espin Pedrol
bdf0697a5a gtp: Specify retrans queue name & seqnum in log lines
Change-Id: I4f193d7a482ace33afd8526b5f50d2d03467d5fa
2022-03-07 12:55:07 +01:00
Pau Espin Pedrol
674a912fb5 gtp: Small log improvements in gtp_create_pdp_ind()
Drop unneeded log line, rewrite line to better fit code path.

Change-Id: Id254e04d539cc055fee8c16fb66cd897b041557e
2022-03-07 12:44:15 +01:00
Pau Espin Pedrol
1bf3b3d0f9 gtp: Log detection of rx duplicate
Change-Id: I8bc9143db6743ad4fae2fe6d6fe0417648e9eec9
2022-03-07 12:20:13 +01:00
Pau Espin Pedrol
fb9303c610 gtp: Use switch statement in gtp_create_pdp_ind()
Double if had to be changed to if-else anyway, so let's simply use a
switch statement.

Change-Id: I91e8722947e58776742521d89abef8ae7584cb25
2022-03-07 11:34:30 +01:00
Pau Espin Pedrol
0585769741 libgtp: Define retransmit QUEUE_SIZE relative to PDP_MAX (increase)
QUEUE_SIZE holds the number of pending transmitted messages
which can be handled concurrently.
Current value was 1024, same as PDP contexts (PDP_MAX). However, that
seems to be a quite low amount, which can be filled under certain
conditions, for instance if recovery procedure is triggered on the GSN
which is running full (around PDP_MAX pdp contexts created).
In this scenario, the GSN would need to send around PDP_MAX concurrent
messages (DeletePDPContextReq), which means the queue would very likely
end up being full.
Hence, let's define QUEUE_SIZE based on PDP_MAX, and set it to twice the
size to make sure it won't be filled in extreme conditions.

Change-Id: I6034b0fab2b2e5962314c2fca2f893246ce5cf4f
2022-03-01 12:39:08 +01:00
Pau Espin Pedrol
9b288b788e libgtp: Fix ggsn crash if pdp alloc array is full (PDP_MAX)
osmo-ggsn crashes when concurrent pdp context num 1024 is created, due to
the gsn->pdpa array (of size PDP_MAX, 1024) being full.
The crash happens because return code of gtp_pdp_newpdp was not checked,
and hence a pointer "pdp" pointing to a temporary not-fully-allocated
object was being passed to gsn->cb_create_context_ind() callback.

Let's avoid crashing and instead reject the PDP context.

Related: OS#5469
Change-Id: I0d94ffad97eb4fef477d981bf285bf99740592a3
2022-03-01 12:38:58 +01:00
Pau Espin Pedrol
134ac7e7c8 vty: Fix cmd 'no echo-interval' doing nothing
It was incorrectly implemented and in practice was a NOOP.

Change-Id: I5e03c4965d05871d3f2e56675da6e75af0ec18c2
2022-02-25 17:25:00 +01:00
Pau Espin Pedrol
46f04343a5 tests: in46a_test: Make coverity happy when calling in46a_from_eua
Coverity warns around that test code:
"Overrunning struct type in46_addr of 20 bytes by passing it to a
function which accesses it at byte offset 39."

That's basically because in64a_from_eua expects to be passed a 2 element
array to be filled. The second element, though, is only accessed in the
case where an IPv4v6 EUA is passed, so in the cases where the test
explicitly passes an IPv4 or IPv6 EUA it's not really an issue, hence
coverity throwing a false positive here.
Let's anyway rewrite the code to pass a 2 element array for completeness,
since it doesn't hurt and makes coverity happy.

Related: Coverity CID#249006
Change-Id: Idfc9104f48eeee6e7f11ebc5c17d4b0e4b2fe9e2
2022-02-09 09:41:46 +01:00
31 changed files with 8320 additions and 1347 deletions

4
.gitignore vendored
View File

@@ -82,3 +82,7 @@ doc/manuals/build
doc/manuals/vty/ggsn_vty_reference.xml
contrib/osmo-ggsn.spec
/debian/gtp-echo-responder-dbg/
/debian/gtp-echo-responder/
/debian/osmo-ggsn-doc/
/utils/gtp-echo-responder

View File

@@ -20,16 +20,17 @@ GIT Repository
You can clone from the official osmo-ggsn.git repository using
git clone git://git.osmocom.org/osmo-ggsn.git
git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn
There is a cgit interface at http://git.osmocom.org/osmo-ggsn/
There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn>
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
------------

View File

@@ -154,9 +154,9 @@ adl_FUNC_GETOPT_LONG
AM_INIT_AUTOMAKE([foreign])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 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(

View File

@@ -30,9 +30,9 @@ BuildRequires: pkgconfig >= 0.20
BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libgtpnl) >= 1.2.0
BuildRequires: pkgconfig(libosmocore) >= 1.5.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.5.0
BuildRequires: pkgconfig(libosmovty) >= 1.5.0
BuildRequires: pkgconfig(libosmocore) >= 1.9.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.9.0
BuildRequires: pkgconfig(libosmovty) >= 1.9.0
Obsoletes: openggsn
%{?systemd_requires}

View File

@@ -1,10 +1,13 @@
[Unit]
Description=OsmoGGSN
After=networking.service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
Restart=always
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
ExecStart=/usr/bin/osmo-ggsn -c /etc/osmocom/osmo-ggsn.cfg
RestartSec=2
RestartPreventExitStatus=1

78
debian/changelog vendored
View File

@@ -1,3 +1,81 @@
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 ]
* Set working directory in systemd service file
* Ignore .deb build byproducts
* ctrl: take both address and port from vty config
[ Pau Espin Pedrol ]
* cosmetic: gtp: Fix typo in comment
* Split gsn_t related APIs out of gtp.{c,h}
* Use rate_ctr for gsn_t available_counters
* ggsn: Introduce tdef and make it configurable over VTY
* gtp: Introduce VTY configurable GTP timer X3
* Fix typos in comments and VTY descriptions
[ arehbein ]
* osmo-ggsn: Transition to use of 'telnet_init_default'
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 14:29:48 +0100
osmo-ggsn (1.9.0) unstable; urgency=medium
[ Pau Espin Pedrol ]
* tests: in46a_test: Make coverity happy when calling in46a_from_eua
* vty: Fix cmd 'no echo-interval' doing nothing
* libgtp: Fix ggsn crash if pdp alloc array is full (PDP_MAX)
* libgtp: Define retransmit QUEUE_SIZE relative to PDP_MAX (increase)
* gtp: Use switch statement in gtp_create_pdp_ind()
* gtp: Log detection of rx duplicate
* gtp: Small log improvements in gtp_create_pdp_ind()
* gtp: Specify retrans queue name & seqnum in log lines
* gtp: Log retrans queue register&free entries
* gtp: Fix typo in comment
* pco.h: Fix typo in reference to spec
[ Vadim Yanitskiy ]
* tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
[ Harald Welte ]
* update git URLs (git -> https; gitea)
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 28 Jun 2022 17:48:22 +0200
osmo-ggsn (1.8.0) unstable; urgency=medium
[ Oliver Smith ]

2
debian/compat vendored
View File

@@ -1 +1 @@
9
10

8
debian/control vendored
View File

@@ -2,17 +2,17 @@ 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.5.0),
libosmocore-dev (>= 1.9.0),
osmo-gsm-manuals-dev,
libgtpnl-dev (>= 1.2.0)
Standards-Version: 3.9.6
Vcs-Browser: http://git.osmocom.org/osmo-ggsn/
Vcs-Git: git://git.osmocom.org/osmo-ggsn
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn
Homepage: https://projects.osmocom.org/projects/openggsn
Package: osmo-ggsn

2
debian/libgtp6.shlibs vendored Normal file
View File

@@ -0,0 +1,2 @@
# Most recent version of the package that added new symbols (OS#5318)
libgtp 6 libgtp6 (>= 1.8.0)

View File

@@ -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

View File

@@ -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

View File

@@ -2,7 +2,7 @@ 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)
osmo_ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS)

View File

@@ -6,6 +6,7 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/tdef.h>
#include <osmocom/ctrl/control_if.h>
#include "../lib/tun.h"
@@ -65,9 +66,9 @@ struct apn_ctx {
uint32_t apn_type_mask;
/* GTP-U via TUN device or in Linux kernel */
enum apn_gtpu_mode gtpu_mode;
/* administratively shut-down (true) or not (false) */
/* administratively shut down (true) or not (false) */
bool shutdown;
/* transmit G-PDU sequeence numbers (true) or not (false) */
/* transmit G-PDU sequence numbers (true) or not (false) */
bool tx_gpdu_seq;
} cfg;
@@ -127,7 +128,7 @@ struct ggsn_ctx {
char *state_dir;
/* Time between Echo requests on each SGSN */
unsigned int echo_interval;
/* administratively shut-down (true) or not (false) */
/* administratively shut down (true) or not (false) */
bool shutdown;
} cfg;
@@ -152,6 +153,7 @@ struct apn_ctx *ggsn_find_or_create_apn(struct ggsn_ctx *ggsn, const char *name)
/* ggsn_main.c */
extern struct ctrl_handle *g_ctrlh;
extern void *tall_ggsn_ctx;
extern struct osmo_tdef_group ggsn_tdef_group[];
/* ggsn.c */
extern int ggsn_start(struct ggsn_ctx *ggsn);

View File

@@ -34,6 +34,7 @@
#include <osmocom/core/stats.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/tdef.h>
#include <osmocom/core/utils.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/control_cmd.h>
@@ -60,6 +61,11 @@ struct ul255_t apn;
static char *config_file = "osmo-ggsn.cfg";
struct osmo_tdef_group ggsn_tdef_group[] = {
{.name = "gtp", .tdefs = gtp_T_defs, .desc = "GTP (libgtp) timers" },
{ }
};
/* To exit gracefully. Used with GCC compilation flag -pg and gprof */
static void signal_handler(int s)
{
@@ -217,12 +223,11 @@ int main(int argc, char **argv)
exit(2);
}
rc = telnet_init_dynif(tall_ggsn_ctx, NULL, vty_get_bind_addr(), OSMO_VTY_PORT_GGSN);
rc = telnet_init_default(tall_ggsn_ctx, NULL, OSMO_VTY_PORT_GGSN);
if (rc < 0)
exit(1);
g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(),
OSMO_CTRL_PORT_GGSN, NULL);
g_ctrlh = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_GGSN, NULL);
if (!g_ctrlh) {
LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
exit(1);

View File

@@ -33,6 +33,7 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/misc.h>
#include <osmocom/vty/tdef_vty.h>
#include "../gtp/gtp.h"
#include "../gtp/pdp.h"
@@ -298,7 +299,7 @@ DEFUN(cfg_ggsn_no_default_apn, cfg_ggsn_no_default_apn_cmd,
DEFUN(cfg_ggsn_shutdown, cfg_ggsn_shutdown_cmd,
"shutdown ggsn",
"Put the GGSN in administrative shut-down\n" GGSN_STR)
"Put the GGSN in administrative shutdown\n" GGSN_STR)
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
@@ -315,7 +316,7 @@ DEFUN(cfg_ggsn_shutdown, cfg_ggsn_shutdown_cmd,
DEFUN(cfg_ggsn_no_shutdown, cfg_ggsn_no_shutdown_cmd,
"no shutdown ggsn",
NO_STR GGSN_STR "Remove the GGSN from administrative shut-down\n")
NO_STR GGSN_STR "Remove the GGSN from administrative shutdown\n")
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
@@ -343,7 +344,7 @@ static void show_one_sgsn(struct vty *vty, const struct sgsn_peer *sgsn, const c
DEFUN(cfg_ggsn_show_sgsn, cfg_ggsn_show_sgsn_cmd,
"show sgsn",
NO_STR GGSN_STR "Remove the GGSN from administrative shut-down\n")
NO_STR GGSN_STR "Remove the GGSN from administrative shutdown\n")
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
struct sgsn_peer *sgsn;
@@ -389,10 +390,9 @@ DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
NO_STR "Send an echo request to this static GGSN every interval.\n")
{
struct ggsn_ctx *ggsn = (struct ggsn_ctx *) vty->index;
int prev_interval = ggsn->cfg.echo_interval;
struct sgsn_peer *sgsn;
if (prev_interval == ggsn->cfg.echo_interval)
if (ggsn->cfg.echo_interval == 0)
return CMD_SUCCESS;
ggsn->cfg.echo_interval = 0;
@@ -681,7 +681,7 @@ DEFUN(cfg_apn_no_gpdu_seq, cfg_apn_no_gpdu_seq_cmd,
DEFUN(cfg_apn_shutdown, cfg_apn_shutdown_cmd,
"shutdown",
"Put the APN in administrative shut-down\n")
"Put the APN in administrative shutdown\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
@@ -698,7 +698,7 @@ DEFUN(cfg_apn_shutdown, cfg_apn_shutdown_cmd,
DEFUN(cfg_apn_no_shutdown, cfg_apn_no_shutdown_cmd,
"no shutdown",
NO_STR "Remove the APN from administrative shut-down\n")
NO_STR "Remove the APN from administrative shutdown\n")
{
struct apn_ctx *apn = (struct apn_ctx *) vty->index;
@@ -796,6 +796,7 @@ static int config_write_ggsn(struct vty *vty)
vty_out(vty, " gtp control-ip %s%s", in46a_ntoa(&ggsn->cfg.gtpc_addr), VTY_NEWLINE);
if (ggsn->cfg.gtpu_addr.v4.s_addr)
vty_out(vty, " gtp user-ip %s%s", in46a_ntoa(&ggsn->cfg.gtpu_addr), VTY_NEWLINE);
osmo_tdef_vty_groups_write(vty, " ");
llist_for_each_entry(apn, &ggsn->apn_list, list)
config_write_apn(vty, apn);
if (ggsn->cfg.default_apn)
@@ -813,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);
}
@@ -1114,6 +1112,8 @@ int ggsn_vty_init(void)
install_element(GGSN_NODE, &cfg_ggsn_echo_interval_cmd);
install_element(GGSN_NODE, &cfg_ggsn_no_echo_interval_cmd);
osmo_tdef_vty_groups_init(GGSN_NODE, ggsn_tdef_group);
install_node(&apn_node, NULL);
install_element(APN_NODE, &cfg_description_cmd);
install_element(APN_NODE, &cfg_no_description_cmd);

View File

@@ -4,7 +4,7 @@
#include "../gtp/pdp.h"
/* 3GPP TS 24.008 10.6.5.3 */
/* 3GPP TS 24.008 10.5.6.3 */
enum pco_protocols {
PCO_P_LCP = 0xC021,
PCO_P_PAP = 0xC023,

View File

@@ -2,14 +2,14 @@
# 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=8:0:2
LIBVERSION=9:1:3
lib_LTLIBRARIES = libgtp.la
include_HEADERS = gtp.h pdp.h gtpie.h
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)
libgtp_la_SOURCES = gtp.c gtp.h gtpie.c gtpie.h pdp.c pdp.h lookupa.c lookupa.h queue.c queue.h
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)

596
gtp/gsn.c Normal file
View File

@@ -0,0 +1,596 @@
/*
* OsmoGGSN - Gateway GPRS Support Node
* Copyright (C) 2002, 2003, 2004 Mondru AB.
* Copyright (C) 2010-2011, 2016-2017 Harald Welte <laforge@gnumonks.org>
* Copyright (C) 2015-2017 sysmocom - s.f.m.c. GmbH
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
*/
/*
* gtp.c: Contains all GTP functionality. Should be able to handle multiple
* tunnels in the same program.
*
* TODO:
* - Do we need to handle fragmentation?
*/
#ifdef __linux__
#define _GNU_SOURCE 1
#endif
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/rate_ctr.h>
#if defined(__FreeBSD__)
#include <sys/endian.h>
#endif
#include "../config.h"
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <arpa/inet.h>
/* #include <stdint.h> ISO C99 types */
#include "pdp.h"
#include "gtp.h"
#include "gtpie.h"
#include "queue.h"
/* Error reporting functions */
#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);
static const struct rate_ctr_desc gsn_ctr_description[] = {
[GSN_CTR_ERR_SOCKET] = { "err:socket", "Socket error" },
[GSN_CTR_ERR_READFROM] = { "err:readfrom", "readfrom() errors" },
[GSN_CTR_ERR_SENDTO] = { "err:sendto", "sendto() errors" },
[GSN_CTR_ERR_QUEUEFULL] = { "err:queuefull", "Failed to queue message because queue is full" },
[GSN_CTR_ERR_SEQ] = { "err:seq", "Sequence number out of range" },
[GSN_CTR_ERR_ADDRESS] = { "err:address", "GSN address conversion failed" },
[GSN_CTR_ERR_UNKNOWN_PDP] = { "err:unknown_pdp", "Failed looking up PDP context" },
[GSN_CTR_ERR_UNEXPECTED_CAUSE] = { "err:unexpected_cause", "Unexpected cause value received" },
[GSN_CTR_ERR_OUT_OF_PDP] = { "err:out_of_pdp", "Out of storage for PDP contexts" },
[GSN_CTR_PKT_EMPTY] = { "pkt:empty", "Empty packet received" },
[GSN_CTR_PKT_UNSUP] = { "pkt:unsupported", "Unsupported GTP version received" },
[GSN_CTR_PKT_TOOSHORT] = { "pkt:too_short", "Packet too short received" },
[GSN_CTR_PKT_UNKNOWN] = { "pkt:unknown", "Unknown packet type received" },
[GSN_CTR_PKT_UNEXPECT] = { "pkt:unexpected", "Unexpected packet type received" },
[GSN_CTR_PKT_DUPLICATE] = { "pkt:duplicate", "Duplicate or unsolicited packet received" },
[GSN_CTR_PKT_MISSING] = { "pkt:missing", "Missing IE in packet received" },
[GSN_CTR_PKT_INCORRECT] = { "pkt:incorrect", "Incorrect IE in packet received" },
[GSN_CTR_PKT_INVALID] = { "pkt:invalid", "Invalid format in packet received" },
};
static const struct rate_ctr_group_desc gsn_ctrg_desc = {
"gsn",
"GSN Statistics",
OSMO_STATS_CLASS_PEER,
ARRAY_SIZE(gsn_ctr_description),
gsn_ctr_description,
};
static unsigned int gsn_ctr_next_idx = 0;
/* Global timer definitions for GTP operation, provided for convenience. To make these user configurable, it is convenient to add
* gtp_gsn_tdefs as one of your program's osmo_tdef_group entries and call osmo_tdef_vty_init(). */
struct osmo_tdef gtp_T_defs[] = {
{ .T = GTP_GSN_TIMER_T3_RESPONSE, .default_val = 5, .unit = OSMO_TDEF_S,
.desc = "Timer T3-RESPONSE holds the maximum wait time for a response of a request message"
},
{ .T = GTP_GSN_TIMER_N3_REQUESTS, .default_val = 3, .unit = OSMO_TDEF_CUSTOM,
.desc = "Counter N3-REQUESTS holds the maximum number of attempts made by GTP to send a request message"
},
{ .T = GTP_GSN_TIMER_T3_HOLD_RESPONSE, .default_val = 5 * 3 /* (GTP_GSN_TIMER_T3_RESPONSE * GTP_GSN_TIMER_N3_REQUESTS) */, .unit = OSMO_TDEF_S,
.desc = "Time a GTP respoonse message is kept cached to re-transmit it when a duplicate request is received. Value is generally equal to (T3-RESPONSE * N3-REQUESTS) set at the peer"
},
{}
};
/* API Functions */
/* Deprecated, use gtp_pdp_newpdp() instead */
int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
uint64_t imsi, uint8_t nsapi)
{
int rc;
rc = gtp_pdp_newpdp(gsn, pdp, imsi, nsapi, NULL);
return rc;
}
int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp)
{
if (gsn->cb_delete_context)
gsn->cb_delete_context(pdp);
return pdp_freepdp(pdp);
}
/* Free pdp and all its secondary PDP contexts. Must be called on the primary PDP context. */
int gtp_freepdp_teardown(struct gsn_t *gsn, struct pdp_t *pdp)
{
int n;
struct pdp_t *secondary_pdp;
OSMO_ASSERT(!pdp->secondary);
for (n = 0; n < PDP_MAXNSAPI; n++) {
if (pdp->secondary_tei[n]) {
if (gtp_pdp_getgtp1(gsn, &secondary_pdp,
pdp->secondary_tei[n])) {
LOGP(DLGTP, LOGL_ERROR,
"Unknown secondary PDP context\n");
continue;
}
if (pdp != secondary_pdp) {
gtp_freepdp(gsn, secondary_pdp);
}
}
}
return gtp_freepdp(gsn, pdp);
}
/* gtp_gpdu */
extern int gtp_fd(struct gsn_t *gsn)
{
return gsn->fd0;
}
int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer))
{
gsn->cb_unsup_ind = cb;
return 0;
}
int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer))
{
gsn->cb_extheader_ind = cb;
return 0;
}
int gtp_set_cb_ran_info_relay_ind(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie))
{
gsn->cb_ran_info_relay_ind = cb;
return 0;
}
/* API: Initialise delete context callback */
/* Called whenever a pdp context is deleted for any reason */
int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb) (struct pdp_t * pdp))
{
gsn->cb_delete_context = cb;
return 0;
}
int gtp_set_cb_conf(struct gsn_t *gsn,
int (*cb) (int type, int cause,
struct pdp_t * pdp, void *cbp))
{
gsn->cb_conf = cb;
return 0;
}
int gtp_set_cb_recovery(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer, uint8_t recovery))
{
gsn->cb_recovery = cb;
return 0;
}
/* cb_recovery()
* pdp may be NULL if Recovery IE was received from a message independent
* of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
* local setup. In case pdp is known, caller may want to keep that pdp alive to
* handle subsequent msg cb as this specific pdp ctx is still valid according to
* specs.
*/
int gtp_set_cb_recovery2(struct gsn_t *gsn,
int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery))
{
gsn->cb_recovery2 = cb_recovery2;
return 0;
}
/* cb_recovery()
* pdp may be NULL if Recovery IE was received from a message independent
* of any PDP ctx (such as Echo Response), or because pdp ctx is unknown to the
* local setup. In case pdp is known, caller may want to keep that pdp alive to
* handle subsequent msg cb as this specific pdp ctx is still valid according to
* specs.
*/
int gtp_set_cb_recovery3(struct gsn_t *gsn,
int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer,
struct pdp_t *pdp, uint8_t recovery))
{
gsn->cb_recovery3 = cb_recovery3;
return 0;
}
int gtp_set_cb_data_ind(struct gsn_t *gsn,
int (*cb_data_ind) (struct pdp_t * pdp,
void *pack, unsigned len))
{
gsn->cb_data_ind = cb_data_ind;
return 0;
}
static int queue_timer_retrans(struct gsn_t *gsn)
{
/* Retransmit any outstanding packets */
/* Remove from queue if maxretrans exceeded */
time_t now;
struct qmsg_t *qmsg;
unsigned int t3_response, n3_requests;
now = time(NULL);
t3_response = osmo_tdef_get(gsn->tdef, GTP_GSN_TIMER_T3_RESPONSE, OSMO_TDEF_S, -1);
n3_requests = osmo_tdef_get(gsn->tdef, GTP_GSN_TIMER_N3_REQUESTS, OSMO_TDEF_CUSTOM, -1);
/* get first element in queue, as long as the timeout of that
* element has expired */
while ((!queue_getfirst(gsn->queue_req, &qmsg)) &&
(qmsg->timeout <= now)) {
if (qmsg->retrans > n3_requests) { /* Too many retrans */
LOGP(DLGTP, LOGL_NOTICE, "Retransmit req queue timeout of seq %" PRIu16 "\n",
qmsg->seq);
if (gsn->cb_conf)
gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp);
queue_freemsg(gsn->queue_req, qmsg);
} else {
LOGP(DLGTP, LOGL_INFO, "Retransmit (%d) of seq %" PRIu16 "\n",
qmsg->retrans, qmsg->seq);
if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0,
(struct sockaddr *)&qmsg->peer,
sizeof(struct sockaddr_in)) < 0) {
rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SENDTO);
LOGP(DLGTP, LOGL_ERROR,
"Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s\n",
gsn->fd0, (unsigned long)&qmsg->p,
qmsg->l, strerror(errno));
}
queue_back(gsn->queue_req, qmsg);
qmsg->timeout = now + t3_response;
qmsg->retrans++;
}
}
/* Also clean up reply timeouts */
while ((!queue_getfirst(gsn->queue_resp, &qmsg)) &&
(qmsg->timeout < now)) {
LOGP(DLGTP, LOGL_DEBUG, "Retransmit resp queue seq %"
PRIu16 " expired, removing from queue\n", qmsg->seq);
queue_freemsg(gsn->queue_resp, qmsg);
}
return 0;
}
static int queue_timer_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
{
time_t now, later, diff;
struct qmsg_t *qmsg;
timeout->tv_usec = 0;
if (queue_getfirst(gsn->queue_req, &qmsg)) {
timeout->tv_sec = 10;
} else {
now = time(NULL);
later = qmsg->timeout;
timeout->tv_sec = later - now;
if (timeout->tv_sec < 0)
timeout->tv_sec = 0; /* No negative allowed */
if (timeout->tv_sec > 10)
timeout->tv_sec = 10; /* Max sleep for 10 sec */
}
if (queue_getfirst(gsn->queue_resp, &qmsg)) {
/* already set by queue_req, do nothing */
} else { /* trigger faster if earlier timeout exists in queue_resp */
now = time(NULL);
later = qmsg->timeout;
diff = later - now;
if (diff < 0)
diff = 0;
if (diff < timeout->tv_sec)
timeout->tv_sec = diff;
}
return 0;
}
void gtp_queue_timer_start(struct gsn_t *gsn)
{
struct timeval next;
/* Retrieve next retransmission as timeval */
queue_timer_retranstimeout(gsn, &next);
/* re-schedule the timer */
osmo_timer_schedule(&gsn->queue_timer, next.tv_sec, next.tv_usec/1000);
}
/* timer callback for libgtp retransmission and ping */
static void queue_timer_cb(void *data)
{
struct gsn_t *gsn = data;
/* do all the retransmissions as needed */
queue_timer_retrans(gsn);
gtp_queue_timer_start(gsn);
}
/**
* @brief clear the request and response queue. Useful for debugging to reset "some" state.
* @param gsn The GGSN instance
*/
void gtp_clear_queues(struct gsn_t *gsn)
{
struct qmsg_t *qmsg;
LOGP(DLGTP, LOGL_INFO, "Clearing req & resp retransmit queues\n");
while (!queue_getfirst(gsn->queue_req, &qmsg)) {
queue_freemsg(gsn->queue_req, qmsg);
}
while (!queue_getfirst(gsn->queue_resp, &qmsg)) {
queue_freemsg(gsn->queue_resp, qmsg);
}
}
/* Perform restoration and recovery error handling as described in 29.060 */
static void log_restart(struct gsn_t *gsn)
{
FILE *f;
int i, rc;
int counter = 0;
char *filename;
filename = talloc_asprintf(NULL, "%s/%s", gsn->statedir, RESTART_FILE);
OSMO_ASSERT(filename);
/* We try to open file. On failure we will later try to create file */
if (!(f = fopen(filename, "r"))) {
LOGP(DLGTP, LOGL_NOTICE,
"State information file (%s) not found. Creating new file.\n",
filename);
} else {
rc = fscanf(f, "%d", &counter);
if (rc != 1) {
LOGP(DLGTP, LOGL_ERROR,
"fscanf failed to read counter value\n");
goto close_file;
}
if (fclose(f)) {
LOGP(DLGTP, LOGL_ERROR,
"fclose failed: Error = %s\n", strerror(errno));
}
}
gsn->restart_counter = (unsigned char)counter;
gsn->restart_counter++;
/* Keep the umask closely wrapped around our fopen() call in case the
* log outputs cause file creation. */
i = umask(022);
f = fopen(filename, "w");
umask(i);
if (!f) {
LOGP(DLGTP, LOGL_ERROR,
"fopen(path=%s, mode=%s) failed: Error = %s\n", filename,
"w", strerror(errno));
goto free_filename;
}
fprintf(f, "%d\n", gsn->restart_counter);
close_file:
if (fclose(f))
LOGP(DLGTP, LOGL_ERROR,
"fclose failed: Error = %s\n", strerror(errno));
free_filename:
talloc_free(filename);
}
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 */
(*gsn)->statedir = statedir;
log_restart(*gsn);
/* Initialise sequence number */
(*gsn)->seq_next = (*gsn)->restart_counter * 1024;
/* Initialize timers: */
(*gsn)->tdef = gtp_T_defs;
/* Small hack to properly reset tdef for old clients not using the tdef_group: */
OSMO_ASSERT(gtp_T_defs[0].default_val != 0);
if (gtp_T_defs[0].val == 0)
osmo_tdefs_reset((*gsn)->tdef);
/* Initialise request retransmit queue */
queue_new(&(*gsn)->queue_req);
queue_new(&(*gsn)->queue_resp);
/* Initialise pdp table */
pdp_init(*gsn);
/* Initialize internal queue timer */
osmo_timer_setup(&(*gsn)->queue_timer, queue_timer_cb, *gsn);
/* Initialize counter group: */
(*gsn)->ctrg = rate_ctr_group_alloc(NULL, &gsn_ctrg_desc, gsn_ctr_next_idx++);
/* Initialise call back functions */
(*gsn)->cb_create_context_ind = 0;
(*gsn)->cb_delete_context = 0;
(*gsn)->cb_unsup_ind = 0;
(*gsn)->cb_conf = 0;
(*gsn)->cb_data_ind = 0;
/* Store function parameters */
(*gsn)->gsnc = *listen;
(*gsn)->gsnu = *listen;
(*gsn)->mode = mode;
/* 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;
}
/* 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;
}
/* 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;
}
/* Start internal queue timer */
gtp_queue_timer_start(*gsn);
return 0;
}
int gtp_free(struct gsn_t *gsn)
{
/* Cleanup internal queue timer */
osmo_timer_del(&gsn->queue_timer);
/* Clean up retransmit queues */
queue_free(gsn->queue_req);
queue_free(gsn->queue_resp);
close(gsn->fd0);
close(gsn->fd1c);
close(gsn->fd1u);
rate_ctr_group_free(gsn->ctrg);
free(gsn);
return 0;
}
/* API: Register create context indication callback */
int gtp_set_cb_create_context_ind(struct gsn_t *gsn,
int (*cb_create_context_ind) (struct pdp_t *
pdp))
{
gsn->cb_create_context_ind = cb_create_context_ind;
return 0;
}
int gtp_retrans(struct gsn_t *gsn)
{
/* dummy API, deprecated. */
return 0;
}
int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout)
{
timeout->tv_sec = 24*60*60;
timeout->tv_usec = 0;
/* dummy API, deprecated. Return a huge timer to do nothing */
return 0;
}

181
gtp/gsn.h Normal file
View File

@@ -0,0 +1,181 @@
/*
* OsmoGGSN - Gateway GPRS Support Node
* Copyright (C) 2002, 2003, 2004 Mondru AB.
*
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
*
*/
#ifndef _GSN_H
#define _GSN_H
#include <osmocom/core/utils.h>
#include <osmocom/core/defs.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/tdef.h>
#include <osmocom/core/rate_ctr.h>
#include "pdp.h"
#define GTP_MODE_GGSN 1
#define GTP_MODE_SGSN 2
#define RESTART_FILE "gsn_restart"
extern struct osmo_tdef gtp_T_defs[];
/* ***********************************************************
* Information storage for each gsn instance
*
* Normally each instance of the application corresponds to
* one instance of a gsn.
*
* In order to avoid global variables in the application, and
* also in order to allow several instances of a gsn in the same
* application this struct is provided in order to store all
* relevant information related to the gsn.
*
* Note that this does not include information storage for '
* each pdp context. This is stored in another struct.
*************************************************************/
enum gsn_rate_ctr_keys {
GSN_CTR_ERR_SOCKET,
GSN_CTR_ERR_READFROM, /* Number of readfrom errors */
GSN_CTR_ERR_SENDTO, /* Number of sendto errors */
GSN_CTR_ERR_QUEUEFULL, /* Number of times queue was full */
GSN_CTR_ERR_SEQ, /* Number of seq out of range */
GSN_CTR_ERR_ADDRESS, /* GSN address conversion failed */
GSN_CTR_ERR_UNKNOWN_PDP, /* GSN address conversion failed */
GSN_CTR_ERR_UNEXPECTED_CAUSE, /* Unexpected cause value received */
GSN_CTR_ERR_OUT_OF_PDP, /* Out of storage for PDP contexts */
GSN_CTR_PKT_EMPTY, /* Number of empty packets */
GSN_CTR_PKT_UNSUP, /* Number of unsupported version 29.60 11.1.1 */
GSN_CTR_PKT_TOOSHORT, /* Number of too short headers 29.60 11.1.2 */
GSN_CTR_PKT_UNKNOWN, /* Number of unknown messages 29.60 11.1.3 */
GSN_CTR_PKT_UNEXPECT, /* Number of unexpected messages 29.60 11.1.4 */
GSN_CTR_PKT_DUPLICATE, /* Number of duplicate or unsolicited replies */
GSN_CTR_PKT_MISSING, /* Number of missing information field messages */
GSN_CTR_PKT_INCORRECT, /* Number of incorrect information field messages */
GSN_CTR_PKT_INVALID, /* Number of invalid message format messages */
};
/* 3GPP TS 29.006 14.1, 14,2 */
enum gtp_gsn_timers {
GTP_GSN_TIMER_T3_RESPONSE = 3,
GTP_GSN_TIMER_N3_REQUESTS = 1003,
GTP_GSN_TIMER_T3_HOLD_RESPONSE = -3,
};
struct gsn_t {
/* Parameters related to the network interface */
int fd0; /* GTP0 file descriptor */
int fd1c; /* GTP1 control plane file descriptor */
int fd1u; /* GTP0 user plane file descriptor */
int mode; /* Mode of operation: GGSN or SGSN */
struct in_addr gsnc; /* IP address of this gsn for signalling */
struct in_addr gsnu; /* IP address of this gsn for user traffic */
/* Parameters related to signalling messages */
uint16_t seq_next; /* Next sequence number to use */
int seq_first; /* First packet in queue (oldest timeout) */
int seq_last; /* Last packet in queue (youngest timeout) */
unsigned char restart_counter; /* Increment on restart. Stored on disk */
char *statedir; /* Disk location for permanent storage */
void *priv; /* used by libgtp users to attach their own state) */
struct queue_t *queue_req; /* Request queue */
struct queue_t *queue_resp; /* Response queue */
struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
struct osmo_timer_list queue_timer; /* internal queue_{req,resp} timer */
/* Call back functions */
int (*cb_delete_context) (struct pdp_t *);
int (*cb_create_context_ind) (struct pdp_t *);
int (*cb_unsup_ind) (struct sockaddr_in * peer);
int (*cb_extheader_ind) (struct sockaddr_in * peer);
int (*cb_ran_info_relay_ind) (struct sockaddr_in *peer, union gtpie_member **ie);
int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp);
int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len);
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);
/* Counters */
struct rate_ctr_group *ctrg;
/* Timers: */
struct osmo_tdef *tdef;
};
/* External API functions */
extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
int mode);
extern int gtp_free(struct gsn_t *gsn);
extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
uint64_t imsi, uint8_t nsapi) OSMO_DEPRECATED("Use gtp_pdp_newpdp() instead");
extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp);
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_set_cb_create_context_ind(struct gsn_t *gsn,
int (*cb_create_context_ind) (struct
pdp_t *
pdp));
extern int gtp_set_cb_data_ind(struct gsn_t *gsn,
int (*cb_data_ind) (struct pdp_t * pdp,
void *pack, unsigned len));
extern int gtp_set_cb_delete_context(struct gsn_t *gsn,
int (*cb_delete_context) (struct pdp_t *
pdp));
/*extern int gtp_set_cb_create_context(struct gsn_t *gsn,
int (*cb_create_context) (struct pdp_t* pdp)); */
extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer));
extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer));
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_conf(struct gsn_t *gsn,
int (*cb) (int type, int cause, struct pdp_t * pdp,
void *cbp));
int gtp_set_cb_recovery(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer,
uint8_t recovery))
OSMO_DEPRECATED("Use gtp_set_cb_recovery2() instead, to obtain pdp ctx originating the recovery");
int gtp_set_cb_recovery2(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer,
struct pdp_t * pdp,
uint8_t recovery))
OSMO_DEPRECATED("Use gtp_set_cb_recovery3() instead, to obtain gsn handling the recovery");
int gtp_set_cb_recovery3(struct gsn_t *gsn,
int (*cb) (struct gsn_t * gsn, struct sockaddr_in * peer,
struct pdp_t * pdp,
uint8_t recovery));
void gtp_clear_queues(struct gsn_t *gsn);
extern int gtp_fd(struct gsn_t *gsn);
extern int gtp_retrans(struct gsn_t *gsn) OSMO_DEPRECATED("This API is a no-op, libgtp already does the job internally");
extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) OSMO_DEPRECATED("This API is a no-op and will return a 1 day timeout");
/* Internal APIs: */
void gtp_queue_timer_start(struct gsn_t *gsn);
#endif /* !_GSN_H */

755
gtp/gtp.c

File diff suppressed because it is too large Load Diff

158
gtp/gtp.h
View File

@@ -13,14 +13,10 @@
#define _GTP_H
#include <osmocom/core/utils.h>
#include <osmocom/core/defs.h>
#include <osmocom/core/timer.h>
#include "gtpie.h"
#include "pdp.h"
#define GTP_MODE_GGSN 1
#define GTP_MODE_SGSN 2
#include "gsn.h"
#define GTP0_PORT 3386
#define GTP1C_PORT 2123
@@ -32,12 +28,10 @@
#define GTP1_HEADER_SIZE_SHORT 8
#define GTP1_HEADER_SIZE_LONG 12
#define NAMESIZE 1024
#define SYSLOG_PRINTSIZE 255
#define ERRMSG_SIZE 255
#define RESTART_FILE "gsn_restart"
#define NAMESIZE 1024
/* GTP version 1 extension header type definitions. */
#define GTP_EXT_PDCP_PDU 0xC0 /* PDCP PDU Number */
@@ -109,7 +103,9 @@ static inline const char *gtp_type_name(uint8_t val)
#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 */
#define GTPCAUSE_ACC_REQ 128 /* Request accepted */
#define GTPCAUSE_129 129 /* For future use 129-176 */
#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 */
#define GTPCAUSE_131 131 /* For future use 131-176 */
#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */
#define GTPCAUSE_NON_EXIST 192 /* Non-existent */
#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */
@@ -143,6 +139,13 @@ static inline const char *gtp_type_name(uint8_t val)
#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 */
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;
struct pdp_t;
@@ -232,105 +235,13 @@ union gtp_packet {
struct gtp1_packet_long gtp1l;
} __attribute__ ((packed));
/* ***********************************************************
* Information storage for each gsn instance
*
* Normally each instance of the application corresponds to
* one instance of a gsn.
*
* In order to avoid global variables in the application, and
* also in order to allow several instances of a gsn in the same
* application this struct is provided in order to store all
* relevant information related to the gsn.
*
* Note that this does not include information storage for '
* each pdp context. This is stored in another struct.
*************************************************************/
struct gsn_t {
/* Parameters related to the network interface */
int fd0; /* GTP0 file descriptor */
int fd1c; /* GTP1 control plane file descriptor */
int fd1u; /* GTP0 user plane file descriptor */
int mode; /* Mode of operation: GGSN or SGSN */
struct in_addr gsnc; /* IP address of this gsn for signalling */
struct in_addr gsnu; /* IP address of this gsn for user traffic */
/* Parameters related to signalling messages */
uint16_t seq_next; /* Next sequence number to use */
int seq_first; /* First packet in queue (oldest timeout) */
int seq_last; /* Last packet in queue (youngest timeout) */
unsigned char restart_counter; /* Increment on restart. Stored on disk */
char *statedir; /* Disk location for permanent storage */
void *priv; /* used by libgtp users to attach their own state) */
struct queue_t *queue_req; /* Request queue */
struct queue_t *queue_resp; /* Response queue */
struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
struct osmo_timer_list queue_timer; /* internal queue_{req,resp} timer */
/* Call back functions */
int (*cb_delete_context) (struct pdp_t *);
int (*cb_create_context_ind) (struct pdp_t *);
int (*cb_unsup_ind) (struct sockaddr_in * peer);
int (*cb_extheader_ind) (struct sockaddr_in * peer);
int (*cb_ran_info_relay_ind) (struct sockaddr_in *peer, union gtpie_member **ie);
int (*cb_conf) (int type, int cause, struct pdp_t * pdp, void *cbp);
int (*cb_data_ind) (struct pdp_t * pdp, void *pack, unsigned len);
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);
/* Counters */
uint64_t err_socket; /* Number of socket errors */
uint64_t err_readfrom; /* Number of readfrom errors */
uint64_t err_sendto; /* Number of sendto errors */
uint64_t err_memcpy; /* Number of memcpy */
uint64_t err_queuefull; /* Number of times queue was full */
uint64_t err_seq; /* Number of seq out of range */
uint64_t err_address; /* GSN address conversion failed */
uint64_t err_unknownpdp; /* GSN address conversion failed */
uint64_t err_unknowntid; /* Application supplied unknown imsi+nsapi */
uint64_t err_cause; /* Unexpected cause value received */
uint64_t err_outofpdp; /* Out of storage for PDP contexts */
uint64_t empty; /* Number of empty packets */
uint64_t unsup; /* Number of unsupported version 29.60 11.1.1 */
uint64_t tooshort; /* Number of too short headers 29.60 11.1.2 */
uint64_t unknown; /* Number of unknown messages 29.60 11.1.3 */
uint64_t unexpect; /* Number of unexpected messages 29.60 11.1.4 */
uint64_t duplicate; /* Number of duplicate or unsolicited replies */
uint64_t missing; /* Number of missing information field messages */
uint64_t incorrect; /* Number of incorrect information field messages */
uint64_t invalid; /* Number of invalid message format messages */
};
/* External API functions */
extern const char *gtp_version();
extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
int mode);
extern int gtp_free(struct gsn_t *gsn);
extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
uint64_t imsi, uint8_t nsapi) OSMO_DEPRECATED("Use gtp_pdp_newpdp() instead");
extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp);
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_set_cb_create_context_ind(struct gsn_t *gsn,
int (*cb_create_context_ind) (struct
pdp_t *
pdp));
extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp,
int cause);
@@ -351,53 +262,10 @@ 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_set_cb_data_ind(struct gsn_t *gsn,
int (*cb_data_ind) (struct pdp_t * pdp,
void *pack, unsigned len));
extern int gtp_fd(struct gsn_t *gsn);
extern int gtp_decaps0(struct gsn_t *gsn);
extern int gtp_decaps1c(struct gsn_t *gsn);
extern int gtp_decaps1u(struct gsn_t *gsn);
extern int gtp_retrans(struct gsn_t *gsn) OSMO_DEPRECATED("This API is a no-op, libgtp already does the job internally");
extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) OSMO_DEPRECATED("This API is a no-op and will return a 1 day timeout");
extern int gtp_set_cb_delete_context(struct gsn_t *gsn,
int (*cb_delete_context) (struct pdp_t *
pdp));
/*extern int gtp_set_cb_create_context(struct gsn_t *gsn,
int (*cb_create_context) (struct pdp_t* pdp)); */
extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer));
extern int gtp_set_cb_extheader_ind(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer));
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_conf(struct gsn_t *gsn,
int (*cb) (int type, int cause, struct pdp_t * pdp,
void *cbp));
int gtp_set_cb_recovery(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer,
uint8_t recovery))
OSMO_DEPRECATED("Use gtp_set_cb_recovery2() instead, to obtain pdp ctx originating the recovery");
int gtp_set_cb_recovery2(struct gsn_t *gsn,
int (*cb) (struct sockaddr_in * peer,
struct pdp_t * pdp,
uint8_t recovery))
OSMO_DEPRECATED("Use gtp_set_cb_recovery3() instead, to obtain gsn handling the recovery");;
int gtp_set_cb_recovery3(struct gsn_t *gsn,
int (*cb) (struct gsn_t * gsn, struct sockaddr_in * peer,
struct pdp_t * pdp,
uint8_t recovery));
void gtp_clear_queues(struct gsn_t *gsn);
/* Internal functions (not part of the API */
/* Internal functions (not part of the API) */
extern int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp,
struct in_addr *inetaddrs);

View File

@@ -23,7 +23,7 @@
#define QUEUE_DEBUG 0 /* Print debug information */
#define QUEUE_SIZE 1024 /* Size of retransmission queue */
#define QUEUE_SIZE (PDP_MAX*2) /* Size of retransmission queue */
#define QUEUE_HASH_SIZE 65536 /* Size of hash table (2^16) */
struct qmsg_t { /* Holder for queued packets */

View File

@@ -2,7 +2,7 @@ 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
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
AM_CFLAGS = -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' $(LIBOSMOCORE_CFLAGS)
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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -2,7 +2,7 @@ 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)
sgsnemu_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS)

View File

@@ -1,11 +1,12 @@
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS)
AM_LDFLAGS = -no-install
EXTRA_DIST = \
gtpie_test.ok \
queue_test.ok \
$(NULL)
noinst_PROGRAMS = \
check_PROGRAMS = \
gtpie_test \
queue_test \
$(NULL)

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g
AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS)
AM_LDFLAGS = -no-install
EXTRA_DIST = ippool_test.ok \
ippool_test.err \
@@ -7,7 +8,7 @@ EXTRA_DIST = ippool_test.ok \
in46a_test.ok \
in46a_v6_test.ok
noinst_PROGRAMS = ippool_test in46a_test
check_PROGRAMS = ippool_test in46a_test
ippool_test_SOURCES = \
ippool_test.c \

View File

@@ -146,7 +146,7 @@ static void test_in46a_to_eua(void)
static void test_in46a_from_eua(void)
{
struct in46_addr ia;
struct in46_addr ia[2];
struct ul66_t eua;
const uint8_t v4_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4 };
const uint8_t v4_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v4, 1,2,3,4 };
@@ -155,35 +155,35 @@ static void test_in46a_from_eua(void)
printf("Testing in46a_from_eua() with IPv4 addresses\n");
/* default: v4 unspec */
OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
OSMO_ASSERT(ia.len == 4);
OSMO_ASSERT(ia.v4.s_addr == 0);
OSMO_ASSERT(in46a_from_eua(&eua, ia) == 1);
OSMO_ASSERT(ia[0].len == 4);
OSMO_ASSERT(ia[0].v4.s_addr == 0);
/* invalid */
eua.v[0] = 0x23;
eua.v[1] = PDP_EUA_TYPE_v4;
eua.l = 6;
OSMO_ASSERT(in46a_from_eua(&eua, &ia) < 0);
OSMO_ASSERT(in46a_from_eua(&eua, ia) < 0);
/* invalid */
eua.v[0] = PDP_EUA_ORG_IETF;
eua.v[1] = 0x23;
eua.l = 6;
OSMO_ASSERT(in46a_from_eua(&eua, &ia) < 0);
OSMO_ASSERT(in46a_from_eua(&eua, ia) < 0);
/* unspecified V4 */
memcpy(eua.v, v4_unspec, sizeof(v4_unspec));
eua.l = sizeof(v4_unspec);
OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
OSMO_ASSERT(ia.len == 4);
OSMO_ASSERT(ia.v4.s_addr == 0);
OSMO_ASSERT(in46a_from_eua(&eua, ia) == 1);
OSMO_ASSERT(ia[0].len == 4);
OSMO_ASSERT(ia[0].v4.s_addr == 0);
/* specified V4 */
memcpy(eua.v, v4_spec, sizeof(v4_spec));
eua.l = sizeof(v4_spec);
OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
OSMO_ASSERT(ia.len == 4);
OSMO_ASSERT(ia.v4.s_addr == htonl(0x01020304));
OSMO_ASSERT(in46a_from_eua(&eua, ia) == 1);
OSMO_ASSERT(ia[0].len == 4);
OSMO_ASSERT(ia[0].v4.s_addr == htonl(0x01020304));
}
static void test_in46a_netmasklen(void)
@@ -318,7 +318,7 @@ static void test_in46a_to_eua_v4v6() {
static void test_in46a_from_eua_v6(void)
{
struct in46_addr ia;
struct in46_addr ia[2];
struct ul66_t eua;
const uint8_t v6_unspec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6 };
const uint8_t v6_spec[] = { PDP_EUA_ORG_IETF, PDP_EUA_TYPE_v6,
@@ -331,16 +331,16 @@ static void test_in46a_from_eua_v6(void)
/* unspecified V6 */
memcpy(eua.v, v6_unspec, sizeof(v6_unspec));
eua.l = sizeof(v6_unspec);
OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
OSMO_ASSERT(ia.len == 16);
OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia.v6));
OSMO_ASSERT(in46a_from_eua(&eua, ia) == 1);
OSMO_ASSERT(ia[0].len == 16);
OSMO_ASSERT(IN6_IS_ADDR_UNSPECIFIED(&ia[0].v6));
/* specified V6 */
memcpy(eua.v, v6_spec, sizeof(v6_spec));
eua.l = sizeof(v6_spec);
OSMO_ASSERT(in46a_from_eua(&eua, &ia) == 1);
OSMO_ASSERT(ia.len == 16);
OSMO_ASSERT(!memcmp(&ia.v6, v6_spec+2, ia.len));
OSMO_ASSERT(in46a_from_eua(&eua, ia) == 1);
OSMO_ASSERT(ia[0].len == 16);
OSMO_ASSERT(!memcmp(&ia[0].v6, v6_spec+2, ia[0].len));
}
static void test_in46a_from_eua_v4v6(void) {