mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-ggsn.git
				synced 2025-11-04 06:03:23 +00:00 
			
		
		
		
	Compare commits
	
		
			107 Commits
		
	
	
		
			1.6.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 | ||
| 
						 | 
					55fe62f634 | ||
| 
						 | 
					4fac842826 | ||
| 
						 | 
					97f60e3dca | ||
| 
						 | 
					a727e6ed38 | ||
| 
						 | 
					3a55b89777 | ||
| 
						 | 
					9f1f747d8e | ||
| 
						 | 
					b9036af7ca | ||
| 
						 | 
					724ecc6680 | ||
| 
						 | 
					0d3bd3435f | ||
| 
						 | 
					3ed252b58e | ||
| 
						 | 
					ac802e63d7 | ||
| 
						 | 
					bc583d9763 | ||
| 
						 | 
					ade4dc191b | ||
| 
						 | 
					cd05da79e7 | ||
| 
						 | 
					5545bcea5d | ||
| 
						 | 
					c97286f839 | ||
| 
						 | 
					f471800168 | ||
| 
						 | 
					bdf0697a5a | ||
| 
						 | 
					674a912fb5 | ||
| 
						 | 
					1bf3b3d0f9 | ||
| 
						 | 
					fb9303c610 | ||
| 
						 | 
					0585769741 | ||
| 
						 | 
					9b288b788e | ||
| 
						 | 
					134ac7e7c8 | ||
| 
						 | 
					46f04343a5 | ||
| 
						 | 
					a3ca2d185b | ||
| 
						 | 
					8cbdd21867 | ||
| 
						 | 
					ae81195418 | ||
| 
						 | 
					6ee5fa939a | ||
| 
						 | 
					b6a0e3fd2e | ||
| 
						 | 
					bd2b55679e | ||
| 
						 | 
					f32c6a9095 | ||
| 
						 | 
					2eed6ec5ec | ||
| 
						 | 
					641206ad5e | ||
| 
						 | 
					bfd3119ae4 | ||
| 
						 | 
					4b9b19e998 | ||
| 
						 | 
					00e0559e17 | ||
| 
						 | 
					0b1d9dbc40 | ||
| 
						 | 
					5379273ea3 | ||
| 
						 | 
					ecef920b8f | ||
| 
						 | 
					eb9267b15e | ||
| 
						 | 
					1efb2bcd90 | ||
| 
						 | 
					878593f205 | ||
| 
						 | 
					1596463985 | ||
| 
						 | 
					9d82492e49 | ||
| 
						 | 
					303aeea8a8 | ||
| 
						 | 
					18898b4a9f | ||
| 
						 | 
					17cee2056c | ||
| 
						 | 
					67a3c833af | ||
| 
						 | 
					b1f641b5b7 | ||
| 
						 | 
					f01ce65f5b | ||
| 
						 | 
					be1cf99e9a | ||
| 
						 | 
					7710080ffd | ||
| 
						 | 
					798a81d48d | ||
| 
						 | 
					51930f7b63 | ||
| 
						 | 
					00ef1b0d6e | ||
| 
						 | 
					02a82c3c9b | ||
| 
						 | 
					349cbfcf50 | ||
| 
						 | 
					51f99ae250 | ||
| 
						 | 
					12304c0e5a | ||
| 
						 | 
					1719abb409 | ||
| 
						 | 
					3ddf4c6933 | ||
| 
						 | 
					fb2a7298e0 | ||
| 
						 | 
					568ac5ee8e | ||
| 
						 | 
					23c832bb4b | ||
| 
						 | 
					4831851ca3 | ||
| 
						 | 
					080dcfaabe | ||
| 
						 | 
					cbc07bdd82 | ||
| 
						 | 
					aedae4c971 | ||
| 
						 | 
					b36eb9d12f | ||
| 
						 | 
					8df01fad14 | ||
| 
						 | 
					c8020b959d | 
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -27,7 +27,7 @@ osmo-ggsn-*.tar*
 | 
			
		||||
# debian
 | 
			
		||||
debian/osmo-ggsn/
 | 
			
		||||
debian/*.debhelper
 | 
			
		||||
debian/libgtp1
 | 
			
		||||
debian/libgtp*/
 | 
			
		||||
debian/osmo-ggsn-dbg
 | 
			
		||||
debian/*.log
 | 
			
		||||
debian/autoreconf.*
 | 
			
		||||
@@ -79,5 +79,10 @@ doc/manuals/generated/
 | 
			
		||||
doc/manuals/osmomsc-usermanual.xml
 | 
			
		||||
doc/manuals/common
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 tests
 | 
			
		||||
SUBDIRS = \
 | 
			
		||||
	  lib \
 | 
			
		||||
	  gtp \
 | 
			
		||||
	  ggsn \
 | 
			
		||||
	  sgsnemu \
 | 
			
		||||
	  doc \
 | 
			
		||||
	  contrib \
 | 
			
		||||
	  utils \
 | 
			
		||||
	  tests \
 | 
			
		||||
	  $(NULL)
 | 
			
		||||
 | 
			
		||||
pkgconfigdir = $(libdir)/pkgconfig
 | 
			
		||||
pkgconfig_DATA = libgtp.pc
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							@@ -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
 | 
			
		||||
------------
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								configure.ac
									
									
									
									
									
								
							@@ -9,6 +9,8 @@ AC_CONFIG_AUX_DIR([.])
 | 
			
		||||
AC_CONFIG_TESTDIR(tests)
 | 
			
		||||
AC_CANONICAL_HOST
 | 
			
		||||
 | 
			
		||||
CFLAGS="$CFLAGS -std=gnu11"
 | 
			
		||||
 | 
			
		||||
dnl kernel style compile messages
 | 
			
		||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 | 
			
		||||
 | 
			
		||||
@@ -19,7 +21,7 @@ AC_PROG_AWK
 | 
			
		||||
AC_PROG_CPP
 | 
			
		||||
LT_INIT
 | 
			
		||||
 | 
			
		||||
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang 
 | 
			
		||||
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
 | 
			
		||||
AS_CASE(["$LD"],[*clang*],
 | 
			
		||||
  [AS_CASE(["${host_os}"],
 | 
			
		||||
     [*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
 | 
			
		||||
@@ -152,9 +154,10 @@ adl_FUNC_GETOPT_LONG
 | 
			
		||||
 | 
			
		||||
AM_INIT_AUTOMAKE([foreign])
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.1.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.1.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.1.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(
 | 
			
		||||
@@ -255,8 +258,9 @@ AC_CONFIG_FILES([Makefile
 | 
			
		||||
                 lib/Makefile
 | 
			
		||||
                 intl/Makefile
 | 
			
		||||
                 po/Makefile
 | 
			
		||||
                 utils/Makefile
 | 
			
		||||
                 sgsnemu/Makefile
 | 
			
		||||
    doc/manuals/Makefile
 | 
			
		||||
                 doc/manuals/Makefile
 | 
			
		||||
                 contrib/Makefile
 | 
			
		||||
                 contrib/systemd/Makefile
 | 
			
		||||
                 contrib/osmo-ggsn.spec
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,6 @@ export PATH="$inst/bin:$PATH"
 | 
			
		||||
# Additional configure options and depends
 | 
			
		||||
CONFIG=""
 | 
			
		||||
if [ "$WITH_MANUALS" = "1" ]; then
 | 
			
		||||
	osmo-build-dep.sh osmo-gsm-manuals
 | 
			
		||||
	CONFIG="--enable-manuals"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
@@ -54,11 +53,11 @@ cd "$base"
 | 
			
		||||
autoreconf --install --force
 | 
			
		||||
./configure --enable-sanitize --enable-werror $GTP $CONFIG
 | 
			
		||||
$MAKE $PARALLEL_MAKE
 | 
			
		||||
DISTCHECK_CONFIGURE_FLAGS="$CONFIG" $MAKE distcheck
 | 
			
		||||
DISTCHECK_CONFIGURE_FLAGS="$CONFIG" $MAKE $PARALLEL_MAKE distcheck
 | 
			
		||||
 | 
			
		||||
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
 | 
			
		||||
	make -C "$base/doc/manuals" publish
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
$MAKE maintainer-clean
 | 
			
		||||
$MAKE $PARALLEL_MAKE maintainer-clean
 | 
			
		||||
osmo-clean-workspace.sh
 | 
			
		||||
 
 | 
			
		||||
@@ -29,11 +29,10 @@ BuildRequires:  pkgconfig >= 0.20
 | 
			
		||||
%if 0%{?suse_version}
 | 
			
		||||
BuildRequires:  systemd-rpm-macros
 | 
			
		||||
%endif
 | 
			
		||||
BuildRequires:  pkgconfig(libgtpnl) >= 1.0.0
 | 
			
		||||
BuildRequires:  pkgconfig(libmnl) >= 1.0.3
 | 
			
		||||
BuildRequires:  pkgconfig(libosmocore) >= 1.1.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmoctrl) >= 1.1.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmovty) >= 1.1.0
 | 
			
		||||
BuildRequires:  pkgconfig(libgtpnl) >= 1.2.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmocore) >= 1.9.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmoctrl) >= 1.9.0
 | 
			
		||||
BuildRequires:  pkgconfig(libosmovty) >= 1.9.0
 | 
			
		||||
Obsoletes:      openggsn
 | 
			
		||||
%{?systemd_requires}
 | 
			
		||||
 | 
			
		||||
@@ -62,6 +61,15 @@ libgtp implements the GPRS Tunneling Protocol between SGSN and GGSN.
 | 
			
		||||
This subpackage contains libraries and header files for developing
 | 
			
		||||
applications that want to make use of libgtp.
 | 
			
		||||
 | 
			
		||||
%package -n gtp-echo-responder
 | 
			
		||||
Summary:        Small program answering GTP ECHO Request with GTP ECHO Response
 | 
			
		||||
License:        MIT
 | 
			
		||||
Group:          System/Libraries
 | 
			
		||||
 | 
			
		||||
%description -n gtp-echo-responder
 | 
			
		||||
Small program answering GTP ECHO Request with GTP ECHO Response for both GTPCv1
 | 
			
		||||
and GTPCv2.
 | 
			
		||||
 | 
			
		||||
%prep
 | 
			
		||||
%setup -q
 | 
			
		||||
 | 
			
		||||
@@ -69,6 +77,7 @@ applications that want to make use of libgtp.
 | 
			
		||||
echo "%{version}" >.tarball-version
 | 
			
		||||
autoreconf -fi
 | 
			
		||||
%configure \
 | 
			
		||||
  --enable-gtp-linux \
 | 
			
		||||
  --disable-static \
 | 
			
		||||
  --docdir="%{_docdir}/%{name}" \
 | 
			
		||||
  --with-systemdsystemunitdir=%{_unitdir} \
 | 
			
		||||
@@ -108,7 +117,9 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
			
		||||
%{_mandir}/man8/sgsnemu.8%{?ext_man}
 | 
			
		||||
%{_unitdir}/%{name}.service
 | 
			
		||||
%dir %{_docdir}/%{name}/examples
 | 
			
		||||
%{_docdir}/%{name}/examples/osmo-ggsn-kernel-gtp.cfg
 | 
			
		||||
%{_docdir}/%{name}/examples/osmo-ggsn.cfg
 | 
			
		||||
%{_docdir}/%{name}/examples/sgsnemu.conf
 | 
			
		||||
%dir %{_sysconfdir}/osmocom
 | 
			
		||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-ggsn.cfg
 | 
			
		||||
 | 
			
		||||
@@ -120,4 +131,7 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
 | 
			
		||||
%{_libdir}/libgtp.so
 | 
			
		||||
%{_libdir}/pkgconfig/libgtp.pc
 | 
			
		||||
 | 
			
		||||
%files -n gtp-echo-responder
 | 
			
		||||
%{_bindir}/gtp-echo-responder
 | 
			
		||||
 | 
			
		||||
%changelog
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										152
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										152
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,155 @@
 | 
			
		||||
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 ]
 | 
			
		||||
  * doc/examples/Makefile.am: add sgsnemu.conf
 | 
			
		||||
  * doc/examples/osmo-ggsn-kernel-gtp.cfg: new file
 | 
			
		||||
  * doc/manuals: describe GTP-U kernel module
 | 
			
		||||
  * gitignore: add ggsn_vty_reference.xml
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * Don't install osmo-ggsn-kernel-gtp.cfg to /etc/osmocom/
 | 
			
		||||
  * Don't install sgsnemu.conf to /etc/osmocom/
 | 
			
		||||
  * ggsn: Reject PDP CTX ACT for static IP addresses
 | 
			
		||||
  * vty: Inform user that static IP addresses are not supported
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * gtp: Update teic_confirmed only on resp success
 | 
			
		||||
  * gtp: Rework parsing logic of UpdatePdpCtxResponse
 | 
			
		||||
  * ggsn: Improve logging on incoming DL data packets
 | 
			
		||||
  * gtp: Improve logging of failing pdp ctx resolution from TEI/TID
 | 
			
		||||
  * cosmetic: gtpie.c: Fix trailing whitespace
 | 
			
		||||
  * gtp: constify pointer arg
 | 
			
		||||
  * gtp: Support tx/rx RAN Information Relay message
 | 
			
		||||
  * ggsn: Log tun fd write errors
 | 
			
		||||
  * ggsn: Fix heap-use-after-free during Recovery without associated PDP
 | 
			
		||||
  * cosmetic: configure.ac: Fix tabulation in line
 | 
			
		||||
  * Introduce program gtp-echo-responder
 | 
			
		||||
  * gtp_echo_responder: report invalid chars present in node-feautres cmdline arg as error
 | 
			
		||||
 | 
			
		||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 16 Nov 2021 13:49:16 +0100
 | 
			
		||||
 | 
			
		||||
osmo-ggsn (1.7.1) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
 | 
			
		||||
  * manuals: generate vty reference xml at build time
 | 
			
		||||
 | 
			
		||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Tue, 23 Feb 2021 17:31:24 +0100
 | 
			
		||||
 | 
			
		||||
osmo-ggsn (1.7.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Vadim Yanitskiy ]
 | 
			
		||||
  * debian/control: change maintainer to the Osmocom team / mailing list
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * configure.ac: Fix trailing whitespace
 | 
			
		||||
  * doc: Update VTY reference xml file
 | 
			
		||||
  * Support setting rt-prio and cpu-affinity mask through VTY
 | 
			
		||||
  * contrib/jenkins: Enable parallel make in make distcheck
 | 
			
		||||
  * ggsn: generate coredump and exit upon SIGABRT received
 | 
			
		||||
  * tests: Explicitly drop category from log
 | 
			
		||||
  * tests: Replace deprecated API log_set_print_filename
 | 
			
		||||
 | 
			
		||||
  [ Keith ]
 | 
			
		||||
  * Fix vty PDP lookups by IMSI
 | 
			
		||||
  * Prevent Crash in show pdp-context from vty
 | 
			
		||||
  * Minor: remove code duplication
 | 
			
		||||
  * Use imsi_str2gtp() in sgsnemu
 | 
			
		||||
  * sgsnemu: relax check on length of IMSI cmdline arg.
 | 
			
		||||
  * GTP: Replace recently introduced imsi_str2gtp()
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * Use OSMO_FD_* instead of deprecated BSC_FD_*
 | 
			
		||||
  * gtp-kernel: Remove duplicate #include section
 | 
			
		||||
  * gtp-kernel: don't #include libmnl headers
 | 
			
		||||
 | 
			
		||||
  [ Oliver Smith ]
 | 
			
		||||
  * contrib/jenkins: don't build osmo-gsm-manuals
 | 
			
		||||
  * configure.ac: set -std=gnu11
 | 
			
		||||
  * apn_start: avoid segfault if missing tun-device
 | 
			
		||||
  * .gitignore: ignore debian/libgtp*
 | 
			
		||||
  * deb/rpm: build with --enable-gtp-linux
 | 
			
		||||
 | 
			
		||||
 -- Pau Espin Pedrol <pespin@espeweb.net>  Tue, 23 Feb 2021 13:34:39 +0100
 | 
			
		||||
 | 
			
		||||
osmo-ggsn (1.6.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/compat
									
									
									
									
										vendored
									
									
								
							@@ -1 +1 @@
 | 
			
		||||
9
 | 
			
		||||
10
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -1,17 +1,18 @@
 | 
			
		||||
Source: osmo-ggsn
 | 
			
		||||
Maintainer: Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
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.1.0),
 | 
			
		||||
               osmo-gsm-manuals-dev
 | 
			
		||||
               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
 | 
			
		||||
@@ -37,6 +38,12 @@ Description: library implementing the GTP protocol between SGSN and GGSN
 | 
			
		||||
 This library is part of OsmoGGSN and implements the GTP protocol between
 | 
			
		||||
 SGSN (Serving GPRS support node) and GGSN.
 | 
			
		||||
 | 
			
		||||
Package: gtp-echo-responder
 | 
			
		||||
Architecture: any
 | 
			
		||||
Depends: ${shlibs:Depends},
 | 
			
		||||
         ${misc:Depends}
 | 
			
		||||
Description: Small program answering GTP ECHO Request with GTP ECHO Response
 | 
			
		||||
 | 
			
		||||
Package: libgtp-dev
 | 
			
		||||
Architecture: any
 | 
			
		||||
Multi-Arch: same
 | 
			
		||||
@@ -62,6 +69,15 @@ Description: Debug symbols for OsmoGGSN
 | 
			
		||||
 operators as the interface between the Internet and the rest of the
 | 
			
		||||
 mobile network infrastructure.
 | 
			
		||||
 | 
			
		||||
Package: gtp-echo-responder-dbg
 | 
			
		||||
Section: debug
 | 
			
		||||
Architecture: any
 | 
			
		||||
Priority: extra
 | 
			
		||||
Depends: ${shlibs:Depends}, ${misc:Depends}, gtp-echo-responder (= ${binary:Version})
 | 
			
		||||
Multi-Arch: same
 | 
			
		||||
Description: Debug symbols for gtp-echo-responder
 | 
			
		||||
 Small program answering GTP ECHO Request with GTP ECHO Response.
 | 
			
		||||
 | 
			
		||||
Package: libgtp-dbg
 | 
			
		||||
Section: debug
 | 
			
		||||
Architecture: any
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							@@ -16,6 +16,11 @@ Files: lib/getopt.c
 | 
			
		||||
Copyright: 1987-2001 Free Software Foundation, Inc.
 | 
			
		||||
License: LGPL-2.1+
 | 
			
		||||
 | 
			
		||||
Files: utils/gtp_echo_responder.c
 | 
			
		||||
       utils/gtp_echo_responder_test.py
 | 
			
		||||
Copyright: 2021 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
			
		||||
License: MIT
 | 
			
		||||
 | 
			
		||||
Files: debian/*
 | 
			
		||||
Copyright: 2010-2017  Harald Welte <laforge@gnumonks.org>
 | 
			
		||||
           2016       Ruben Undheim <ruben.undheim@gmail.com>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								debian/gtp-echo-responder.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								debian/gtp-echo-responder.install
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
/usr/bin/gtp-echo-responder
 | 
			
		||||
							
								
								
									
										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)
 | 
			
		||||
							
								
								
									
										1
									
								
								debian/osmo-ggsn.examples
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								debian/osmo-ggsn.examples
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,3 @@
 | 
			
		||||
doc/examples/osmo-ggsn.cfg
 | 
			
		||||
doc/examples/osmo-ggsn-kernel-gtp.cfg
 | 
			
		||||
doc/examples/sgsnemu.conf
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								debian/rules
									
									
									
									
										vendored
									
									
								
							@@ -19,7 +19,10 @@ override_dh_strip:
 | 
			
		||||
	dh_strip -plibgtp6 --dbg-package=libgtp-dbg
 | 
			
		||||
 | 
			
		||||
override_dh_auto_configure:
 | 
			
		||||
	dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
 | 
			
		||||
	dh_auto_configure -- \
 | 
			
		||||
		--enable-gtp-linux \
 | 
			
		||||
		--with-systemdsystemunitdir=/lib/systemd/system \
 | 
			
		||||
		--enable-manuals
 | 
			
		||||
 | 
			
		||||
# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
 | 
			
		||||
override_dh_compress:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,13 @@
 | 
			
		||||
OSMOCONF_FILES = \
 | 
			
		||||
	osmo-ggsn.cfg \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
osmoconfdir = $(sysconfdir)/osmocom
 | 
			
		||||
osmoconf_DATA = osmo-ggsn.cfg
 | 
			
		||||
osmoconf_DATA = $(OSMOCONF_FILES)
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST = osmo-ggsn.cfg
 | 
			
		||||
EXTRA_DIST = $(OSMOCONF_FILES)
 | 
			
		||||
 | 
			
		||||
CFG_FILES = find $(srcdir) -name '*.cfg*' | sed -e 's,^$(srcdir),,'
 | 
			
		||||
CFG_FILES = find $(srcdir) -name '*.cfg' -o -name '*.conf' | sed -e 's,^$(srcdir),,'
 | 
			
		||||
 | 
			
		||||
dist-hook:
 | 
			
		||||
	for f in $$($(CFG_FILES)); do \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								doc/examples/osmo-ggsn-kernel-gtp.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								doc/examples/osmo-ggsn-kernel-gtp.cfg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
!
 | 
			
		||||
! OpenGGSN (0.94.1-adac) configuration saved from vty
 | 
			
		||||
!!
 | 
			
		||||
!
 | 
			
		||||
log stderr
 | 
			
		||||
 logging filter all 1
 | 
			
		||||
 logging color 1
 | 
			
		||||
 logging print category 0
 | 
			
		||||
 logging timestamp 0
 | 
			
		||||
 logging level ip info
 | 
			
		||||
 logging level tun info
 | 
			
		||||
 logging level ggsn info
 | 
			
		||||
 logging level sgsn notice
 | 
			
		||||
 logging level icmp6 notice
 | 
			
		||||
 logging level lglobal notice
 | 
			
		||||
 logging level llapd notice
 | 
			
		||||
 logging level linp notice
 | 
			
		||||
 logging level lmux notice
 | 
			
		||||
 logging level lmi notice
 | 
			
		||||
 logging level lmib notice
 | 
			
		||||
 logging level lsms notice
 | 
			
		||||
 logging level lctrl notice
 | 
			
		||||
 logging level lgtp info
 | 
			
		||||
 logging level lstats notice
 | 
			
		||||
 logging level lgsup notice
 | 
			
		||||
 logging level loap notice
 | 
			
		||||
 logging level lss7 notice
 | 
			
		||||
 logging level lsccp notice
 | 
			
		||||
 logging level lsua notice
 | 
			
		||||
 logging level lm3ua notice
 | 
			
		||||
 logging level lmgcp notice
 | 
			
		||||
!
 | 
			
		||||
stats interval 5
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 no login
 | 
			
		||||
!
 | 
			
		||||
ggsn ggsn0
 | 
			
		||||
 gtp state-dir /tmp
 | 
			
		||||
 gtp bind-ip 127.0.0.2
 | 
			
		||||
 apn internet
 | 
			
		||||
  gtpu-mode kernel-gtp
 | 
			
		||||
  tun-device tun4
 | 
			
		||||
  type-support v4
 | 
			
		||||
  ip prefix dynamic 172.16.222.0/24
 | 
			
		||||
  ip dns 0 8.8.8.8
 | 
			
		||||
  ip dns 1 8.8.4.4
 | 
			
		||||
  ip ifconfig 172.16.222.0/24
 | 
			
		||||
  no shutdown
 | 
			
		||||
 default-apn internet
 | 
			
		||||
 no shutdown ggsn
 | 
			
		||||
@@ -11,6 +11,12 @@ if BUILD_MANUALS
 | 
			
		||||
  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
 | 
			
		||||
 | 
			
		||||
  VTY_REFERENCE = osmoggsn-vty-reference.xml
 | 
			
		||||
 | 
			
		||||
  BUILT_REFERENCE_XML = $(builddir)/vty/ggsn_vty_reference.xml
 | 
			
		||||
  $(builddir)/vty/ggsn_vty_reference.xml: $(top_builddir)/ggsn/osmo-ggsn
 | 
			
		||||
	mkdir -p $(builddir)/vty
 | 
			
		||||
	$(top_builddir)/ggsn/osmo-ggsn --vty-ref-xml > $@
 | 
			
		||||
 | 
			
		||||
  include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
 | 
			
		||||
 | 
			
		||||
  OSMO_REPOSITORY=osmo-ggsn
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -80,3 +80,52 @@ possible to pick differing ports on the same IP address), like:
 | 
			
		||||
ggsn ggsn0
 | 
			
		||||
 gtp bind-ip 127.0.0.2
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
=== GTP-U kernel module
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
userspace in OsmoGGSN. The kernel module is included in Linux 4.7.0 and higher.
 | 
			
		||||
Notably the Debian GNU/Linux distribution has it enabled by default.
 | 
			
		||||
 | 
			
		||||
In order to use this feature, make sure that your Linux kernel was configured
 | 
			
		||||
to support it (`CONFIG_GTP=m` or `=y`). Furthermore, `osmo-ggsn` must have been
 | 
			
		||||
built with `./configure` argument `--enable-gtp-linux` (which requires libgtpnl
 | 
			
		||||
to be installed).
 | 
			
		||||
 | 
			
		||||
Load the kernel module with:
 | 
			
		||||
 | 
			
		||||
----
 | 
			
		||||
$ sudo modprobe gtp
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
Then start OsmoGGSN with a configuration file that uses `gtpu-mode kernel-gtp`.
 | 
			
		||||
 | 
			
		||||
A full example configuration is in `osmo-ggsn-kernel-gtp.cfg`.
 | 
			
		||||
 | 
			
		||||
----
 | 
			
		||||
$ sudo osmo-ggsn -c /usr/share/doc/osmo-ggsn/examples/osmo-ggsn-kernel-gtp.cfg
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
.Example: APN with kernel-gtp
 | 
			
		||||
----
 | 
			
		||||
ggsn ggsn0
 | 
			
		||||
 gtp state-dir /tmp
 | 
			
		||||
 gtp bind-ip 127.0.0.2
 | 
			
		||||
 apn internet
 | 
			
		||||
  gtpu-mode kernel-gtp
 | 
			
		||||
  tun-device tun4
 | 
			
		||||
  type-support v4
 | 
			
		||||
  ip prefix dynamic 172.16.222.0/24
 | 
			
		||||
  ip dns 0 8.8.8.8
 | 
			
		||||
  ip dns 1 8.8.4.4
 | 
			
		||||
  ip ifconfig 172.16.222.0/24
 | 
			
		||||
  no shutdown
 | 
			
		||||
----
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,8 @@ include::{srcdir}/chapters/configuration.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/control_if.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/vty_cpu_sched.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/port_numbers.adoc[]
 | 
			
		||||
 | 
			
		||||
include::./common/chapters/bibliography.adoc[]
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -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)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										76
									
								
								ggsn/ggsn.c
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								ggsn/ggsn.c
									
									
									
									
									
								
							@@ -193,8 +193,8 @@ int apn_start(struct apn_ctx *apn)
 | 
			
		||||
		}
 | 
			
		||||
		LOGPAPN(LOGL_INFO, apn, "Opened TUN device %s\n", apn->tun.tun->devname);
 | 
			
		||||
 | 
			
		||||
		/* Register with libosmcoore */
 | 
			
		||||
		osmo_fd_setup(&apn->tun.fd, apn->tun.tun->fd, BSC_FD_READ, ggsn_tun_fd_cb, apn, 0);
 | 
			
		||||
		/* 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);
 | 
			
		||||
 | 
			
		||||
		/* Set TUN library callback */
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -467,9 +462,13 @@ int create_context_ind(struct pdp_t *pdp)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME: we manually force all context requests to dynamic here! */
 | 
			
		||||
	if (pdp->eua.l > 2)
 | 
			
		||||
		pdp->eua.l = 2;
 | 
			
		||||
	/* FIXME: implement context request for static IP addresses! */
 | 
			
		||||
	if (pdp->eua.l > 2) {
 | 
			
		||||
		LOGPPDP(LOGL_ERROR, pdp, "Static IP addresses not supported: %s\n",
 | 
			
		||||
			osmo_hexdump(pdp->eua.v, pdp->eua.l));
 | 
			
		||||
		gtp_create_context_resp(gsn, pdp, GTPCAUSE_NOT_SUPPORTED);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
 | 
			
		||||
 | 
			
		||||
@@ -532,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;
 | 
			
		||||
		}
 | 
			
		||||
@@ -589,7 +589,7 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
 | 
			
		||||
	struct iphdr *iph = (struct iphdr *)pack;
 | 
			
		||||
	struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
 | 
			
		||||
	struct ippool_t *pool;
 | 
			
		||||
	char straddr[INET6_ADDRSTRLEN];
 | 
			
		||||
	char straddr[2][INET6_ADDRSTRLEN];
 | 
			
		||||
	uint8_t pref_offset;
 | 
			
		||||
 | 
			
		||||
	switch (iph->version) {
 | 
			
		||||
@@ -622,17 +622,41 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (ippool_getip(pool, &ipm, &dst)) {
 | 
			
		||||
		LOGTUN(LOGL_DEBUG, tun, "Received packet for APN(%s) with no PDP contex! (%s)\n",
 | 
			
		||||
			apn->cfg.name,
 | 
			
		||||
			iph->version == 4 ?
 | 
			
		||||
			inet_ntop(AF_INET, &iph->saddr, straddr, sizeof(straddr)) :
 | 
			
		||||
			inet_ntop(AF_INET6, &ip6h->ip6_src, straddr, sizeof(straddr)));
 | 
			
		||||
		LOGTUN(LOGL_DEBUG, tun, "APN(%s) Rx DL data packet for IP address outside "
 | 
			
		||||
		       "pool of managed addresses: %s <- %s\n",
 | 
			
		||||
		       apn->cfg.name,
 | 
			
		||||
		       iph->version == 4 ?
 | 
			
		||||
		         inet_ntop(AF_INET, &iph->daddr, straddr[0], sizeof(straddr[0])) :
 | 
			
		||||
		         inet_ntop(AF_INET6, &ip6h->ip6_dst, straddr[0], sizeof(straddr[0])),
 | 
			
		||||
		       iph->version == 4 ?
 | 
			
		||||
		         inet_ntop(AF_INET, &iph->saddr, straddr[1], sizeof(straddr[1])) :
 | 
			
		||||
		         inet_ntop(AF_INET6, &ip6h->ip6_src, straddr[1], sizeof(straddr[1])));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	LOGTUN(LOGL_DEBUG, tun, "Received packet for APN(%s)\n", apn->cfg.name);
 | 
			
		||||
 | 
			
		||||
	if (ipm->peer)		/* Check if a peer protocol is defined */
 | 
			
		||||
		gtp_data_req(apn->ggsn->gsn, (struct pdp_t *)ipm->peer, pack, len);
 | 
			
		||||
	if (ipm->peer)	{	/* Check if a peer protocol is defined */
 | 
			
		||||
		struct pdp_t *pdp = (struct pdp_t *)ipm->peer;
 | 
			
		||||
		LOGTUN(LOGL_DEBUG, tun, "APN(%s) Rx DL data packet for PDP(%s:%u): %s <- %s\n",
 | 
			
		||||
		       apn->cfg.name,
 | 
			
		||||
		       imsi_gtp2str(&(pdp)->imsi), (pdp)->nsapi,
 | 
			
		||||
		       iph->version == 4 ?
 | 
			
		||||
		         inet_ntop(AF_INET, &iph->daddr, straddr[0], sizeof(straddr[0])) :
 | 
			
		||||
		         inet_ntop(AF_INET6, &ip6h->ip6_dst, straddr[0], sizeof(straddr[0])),
 | 
			
		||||
		       iph->version == 4 ?
 | 
			
		||||
		         inet_ntop(AF_INET, &iph->saddr, straddr[1], sizeof(straddr[1])) :
 | 
			
		||||
		         inet_ntop(AF_INET6, &ip6h->ip6_src, straddr[1], sizeof(straddr[1])));
 | 
			
		||||
		gtp_data_req(apn->ggsn->gsn, pdp, pack, len);
 | 
			
		||||
	} else {
 | 
			
		||||
		LOGTUN(LOGL_DEBUG, tun, "APN(%s) Rx DL data packet for IP address with no "
 | 
			
		||||
		       "associated PDP Ctx: %s <- %s\n",
 | 
			
		||||
		       apn->cfg.name,
 | 
			
		||||
		       iph->version == 4 ?
 | 
			
		||||
 		         inet_ntop(AF_INET, &iph->daddr, straddr[0], sizeof(straddr[0])) :
 | 
			
		||||
 		         inet_ntop(AF_INET6, &ip6h->ip6_dst, straddr[0], sizeof(straddr[0])),
 | 
			
		||||
 		       iph->version == 4 ?
 | 
			
		||||
 		         inet_ntop(AF_INET, &iph->saddr, straddr[1], sizeof(straddr[1])) :
 | 
			
		||||
 		         inet_ntop(AF_INET6, &ip6h->ip6_src, straddr[1], sizeof(straddr[1])));
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -704,7 +728,7 @@ static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what)
 | 
			
		||||
{
 | 
			
		||||
	struct apn_ctx *apn = fd->data;
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(what & BSC_FD_READ);
 | 
			
		||||
	OSMO_ASSERT(what & OSMO_FD_READ);
 | 
			
		||||
 | 
			
		||||
	return tun_decaps(apn->tun.tun);
 | 
			
		||||
}
 | 
			
		||||
@@ -715,7 +739,7 @@ static int ggsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
 | 
			
		||||
	struct ggsn_ctx *ggsn = fd->data;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(what & BSC_FD_READ);
 | 
			
		||||
	OSMO_ASSERT(what & OSMO_FD_READ);
 | 
			
		||||
 | 
			
		||||
	switch (fd->priv_nr) {
 | 
			
		||||
	case 0:
 | 
			
		||||
@@ -809,15 +833,15 @@ int ggsn_start(struct ggsn_ctx *ggsn)
 | 
			
		||||
		ggsn->gsn->gsnu = ggsn->cfg.gtpu_addr.v4;
 | 
			
		||||
 | 
			
		||||
	/* Register File Descriptors */
 | 
			
		||||
	osmo_fd_setup(&ggsn->gtp_fd0, ggsn->gsn->fd0, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 0);
 | 
			
		||||
	osmo_fd_setup(&ggsn->gtp_fd0, ggsn->gsn->fd0, OSMO_FD_READ, ggsn_gtp_fd_cb, ggsn, 0);
 | 
			
		||||
	rc = osmo_fd_register(&ggsn->gtp_fd0);
 | 
			
		||||
	OSMO_ASSERT(rc == 0);
 | 
			
		||||
 | 
			
		||||
	osmo_fd_setup(&ggsn->gtp_fd1c, ggsn->gsn->fd1c, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 1);
 | 
			
		||||
	osmo_fd_setup(&ggsn->gtp_fd1c, ggsn->gsn->fd1c, OSMO_FD_READ, ggsn_gtp_fd_cb, ggsn, 1);
 | 
			
		||||
	rc = osmo_fd_register(&ggsn->gtp_fd1c);
 | 
			
		||||
	OSMO_ASSERT(rc == 0);
 | 
			
		||||
 | 
			
		||||
	osmo_fd_setup(&ggsn->gtp_fd1u, ggsn->gsn->fd1u, BSC_FD_READ, ggsn_gtp_fd_cb, ggsn, 2);
 | 
			
		||||
	osmo_fd_setup(&ggsn->gtp_fd1u, ggsn->gsn->fd1u, OSMO_FD_READ, ggsn_gtp_fd_cb, ggsn, 2);
 | 
			
		||||
	rc = osmo_fd_register(&ggsn->gtp_fd1u);
 | 
			
		||||
	OSMO_ASSERT(rc == 0);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								ggsn/ggsn.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								ggsn/ggsn.h
									
									
									
									
									
								
							@@ -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);
 | 
			
		||||
@@ -167,6 +169,3 @@ void ggsn_close_one_pdp(struct pdp_t *pdp);
 | 
			
		||||
	LOGP(DGGSN, level, "GGSN(%s): " fmt, (ggsn)->cfg.name, ## args)
 | 
			
		||||
 | 
			
		||||
#define LOGPPDP(level, pdp, fmt, args...) LOGPDPX(DGGSN, level, pdp, fmt, ## args)
 | 
			
		||||
 | 
			
		||||
#define LOGTUN(level, tun, fmt, args...) \
 | 
			
		||||
	LOGP(DTUN, level, "TUN(%s): " fmt, (tun)->devname, ## args)
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
@@ -45,6 +46,7 @@
 | 
			
		||||
#include <osmocom/vty/ports.h>
 | 
			
		||||
#include <osmocom/vty/command.h>
 | 
			
		||||
#include <osmocom/vty/misc.h>
 | 
			
		||||
#include <osmocom/vty/cpu_sched_vty.h>
 | 
			
		||||
 | 
			
		||||
#include "ggsn.h"
 | 
			
		||||
 | 
			
		||||
@@ -59,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)
 | 
			
		||||
{
 | 
			
		||||
@@ -70,6 +77,17 @@ static void signal_handler(int s)
 | 
			
		||||
		end = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGABRT:
 | 
			
		||||
		/* in case of abort, we want to obtain a talloc report and
 | 
			
		||||
		 * then run default SIGABRT handler, who will generate coredump
 | 
			
		||||
		 * and abort the process. abort() should do this for us after we
 | 
			
		||||
		 * return, but program wouldn't exit if an external SIGABRT is
 | 
			
		||||
		 * received.
 | 
			
		||||
		 */
 | 
			
		||||
		talloc_report(tall_vty_ctx, stderr);
 | 
			
		||||
		talloc_report_full(tall_ggsn_ctx, stderr);
 | 
			
		||||
		signal(SIGABRT, SIG_DFL);
 | 
			
		||||
		raise(SIGABRT);
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGUSR1:
 | 
			
		||||
		talloc_report(tall_vty_ctx, stderr);
 | 
			
		||||
		talloc_report_full(tall_ggsn_ctx, stderr);
 | 
			
		||||
@@ -95,17 +113,49 @@ static void print_help()
 | 
			
		||||
		"  -c --config-file	filename The config file to use\n"
 | 
			
		||||
		"  -V --version		Print the version of OsmoGGSN\n"
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
	printf("\nVTY reference generation:\n");
 | 
			
		||||
	printf("     --vty-ref-mode MODE        VTY reference generation mode (e.g. 'expert').\n");
 | 
			
		||||
	printf("     --vty-ref-xml              Generate the VTY reference XML output and exit.\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_long_options(const char *prog_name, const int long_option)
 | 
			
		||||
{
 | 
			
		||||
	static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
 | 
			
		||||
 | 
			
		||||
	switch (long_option) {
 | 
			
		||||
	case 1:
 | 
			
		||||
		vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
 | 
			
		||||
		if (vty_ref_mode < 0) {
 | 
			
		||||
			fprintf(stderr, "%s: Unknown VTY reference generation "
 | 
			
		||||
				"mode '%s'\n", prog_name, optarg);
 | 
			
		||||
			exit(2);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case 2:
 | 
			
		||||
		fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
 | 
			
		||||
			get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
 | 
			
		||||
			get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
 | 
			
		||||
		vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
 | 
			
		||||
		exit(0);
 | 
			
		||||
	default:
 | 
			
		||||
		fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
 | 
			
		||||
		exit(2);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_options(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	while (1) {
 | 
			
		||||
		int option_index = 0, c;
 | 
			
		||||
		static int long_option = 0;
 | 
			
		||||
		static struct option long_options[] = {
 | 
			
		||||
			{ "help", 0, 0, 'h' },
 | 
			
		||||
			{ "daemonize", 0, 0, 'D' },
 | 
			
		||||
			{ "config-file", 1, 0, 'c' },
 | 
			
		||||
			{ "version", 0, 0, 'V' },
 | 
			
		||||
			{ "vty-ref-mode", 1, &long_option, 1 },
 | 
			
		||||
			{ "vty-ref-xml", 0, &long_option, 2 },
 | 
			
		||||
			{ 0, 0, 0, 0 }
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
@@ -114,6 +164,9 @@ static void handle_options(int argc, char **argv)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			handle_long_options(argv[0], long_option);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'h':
 | 
			
		||||
			print_usage();
 | 
			
		||||
			print_help();
 | 
			
		||||
@@ -158,6 +211,7 @@ int main(int argc, char **argv)
 | 
			
		||||
	osmo_stats_vty_add_cmds();
 | 
			
		||||
	ggsn_vty_init();
 | 
			
		||||
	ctrl_vty_init(tall_ggsn_ctx);
 | 
			
		||||
	osmo_cpu_sched_vty_init(tall_ggsn_ctx);
 | 
			
		||||
 | 
			
		||||
	handle_options(argc, argv);
 | 
			
		||||
 | 
			
		||||
@@ -169,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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -533,9 +533,11 @@ DEFUN(cfg_apn_ip_prefix, cfg_apn_ip_prefix_cmd,
 | 
			
		||||
	struct in46_prefix *pfx;
 | 
			
		||||
 | 
			
		||||
	/* first update our parsed prefix */
 | 
			
		||||
	if (!strcmp(argv[0], "static"))
 | 
			
		||||
	if (!strcmp(argv[0], "static")) {
 | 
			
		||||
		pfx = &apn->v4.cfg.static_prefix;
 | 
			
		||||
	else
 | 
			
		||||
		vty_out(vty, "%% static IP addresses currently not yet supported%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	} else
 | 
			
		||||
		pfx = &apn->v4.cfg.dynamic_prefix;
 | 
			
		||||
	str2prefix(pfx, argv[1]);
 | 
			
		||||
 | 
			
		||||
@@ -567,9 +569,11 @@ DEFUN(cfg_apn_ipv6_prefix, cfg_apn_ipv6_prefix_cmd,
 | 
			
		||||
	struct apn_ctx *apn = (struct apn_ctx *) vty->index;
 | 
			
		||||
	struct in46_prefix *pfx;
 | 
			
		||||
 | 
			
		||||
	if (!strcmp(argv[0], "static"))
 | 
			
		||||
	if (!strcmp(argv[0], "static")) {
 | 
			
		||||
		pfx = &apn->v6.cfg.static_prefix;
 | 
			
		||||
	else
 | 
			
		||||
		vty_out(vty, "%% static IP addresses currently not yet supported%s", VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	} else
 | 
			
		||||
		pfx = &apn->v6.cfg.dynamic_prefix;
 | 
			
		||||
	str2prefix(pfx, argv[1]);
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
@@ -677,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;
 | 
			
		||||
 | 
			
		||||
@@ -694,11 +698,15 @@ 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;
 | 
			
		||||
 | 
			
		||||
	if (apn->cfg.shutdown) {
 | 
			
		||||
		if (!apn->tun.cfg.dev_name) {
 | 
			
		||||
			vty_out(vty, "%% Failed to start APN, tun-device is not configured%s", VTY_NEWLINE);
 | 
			
		||||
			return CMD_WARNING;
 | 
			
		||||
		}
 | 
			
		||||
		if (apn_start(apn) < 0) {
 | 
			
		||||
			vty_out(vty, "%% Failed to start APN, check log for details%s", VTY_NEWLINE);
 | 
			
		||||
			return CMD_WARNING;
 | 
			
		||||
@@ -788,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)
 | 
			
		||||
@@ -805,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -894,11 +900,16 @@ DEFUN(show_pdpctx_imsi, show_pdpctx_imsi_cmd,
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	imsi = strtoull(argv[1], NULL, 10);
 | 
			
		||||
	if (strlen(argv[1]) < 6 || strlen(argv[1]) > 15) {
 | 
			
		||||
		vty_out(vty, "%% Invalid IMSI '%s'%s", argv[1], VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	imsi = gtp_imsi_str2gtp(argv[1]);
 | 
			
		||||
 | 
			
		||||
	if (argc > 2) {
 | 
			
		||||
		nsapi = atoi(argv[2]);
 | 
			
		||||
		if (gtp_pdp_getimsi(ggsn->gsn, &pdp, imsi, nsapi)) {
 | 
			
		||||
		if (!gtp_pdp_getimsi(ggsn->gsn, &pdp, imsi, nsapi)) {
 | 
			
		||||
			show_one_pdp(vty, pdp);
 | 
			
		||||
			num_found++;
 | 
			
		||||
		}
 | 
			
		||||
@@ -1101,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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								ggsn/pco.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								ggsn/pco.h
									
									
									
									
									
								
							@@ -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,
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								ggsn/sgsn.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								ggsn/sgsn.c
									
									
									
									
									
								
							@@ -116,6 +116,7 @@ static unsigned int sgsn_peer_drop_all_pdp_except(struct sgsn_peer *sgsn, struct
 | 
			
		||||
{
 | 
			
		||||
	unsigned int num = 0;
 | 
			
		||||
	char buf[INET_ADDRSTRLEN];
 | 
			
		||||
	unsigned int count = llist_count(&sgsn->pdp_list);
 | 
			
		||||
 | 
			
		||||
	inet_ntop(AF_INET, &sgsn->addr, buf, sizeof(buf));
 | 
			
		||||
 | 
			
		||||
@@ -125,10 +126,17 @@ static unsigned int sgsn_peer_drop_all_pdp_except(struct sgsn_peer *sgsn, struct
 | 
			
		||||
			continue;
 | 
			
		||||
		ggsn_close_one_pdp(pdp->lib);
 | 
			
		||||
		num++;
 | 
			
		||||
		if (num == count) {
 | 
			
		||||
			/* Note: if except is NULL, all pdp contexts are freed and sgsn
 | 
			
		||||
			 * is most probably already freed at this point.
 | 
			
		||||
			 * As a result, last access to sgsn->pdp_list before exiting
 | 
			
		||||
			 * loop would access already freed memory. Avoid it by exiting
 | 
			
		||||
			 * the loop without the last check, and make sure sgsn is not
 | 
			
		||||
			 * accessed after this loop. */
 | 
			
		||||
			 break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Note: if except is NULL, all pdp contexts are freed and sgsn is
 | 
			
		||||
	   already freed at this point */
 | 
			
		||||
	LOGP(DGGSN, LOGL_INFO, "SGSN(%s) Dropped %u PDP contexts\n", buf, num);
 | 
			
		||||
 | 
			
		||||
	return num;
 | 
			
		||||
 
 | 
			
		||||
@@ -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=6:0:0
 | 
			
		||||
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) \
 | 
			
		||||
		$(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 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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										582
									
								
								gtp/gsn.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										582
									
								
								gtp/gsn.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,582 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  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;
 | 
			
		||||
}
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
	/* 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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
	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 */
 | 
			
		||||
	/* 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 (create_and_bind_socket("GTPv0", *gsn, &(*gsn)->fd0, AF_INET, listen, GTP0_PORT) < 0)
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	/* Create GTP version 1 control plane socket */
 | 
			
		||||
	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 (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)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	/* 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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										189
									
								
								gtp/gsn.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								gtp/gsn.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,189 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  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 <osmocom/gsm/gsm23003.h>
 | 
			
		||||
#include <osmocom/gsm/gsm48.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);
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
	/* 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_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 *
 | 
			
		||||
								       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_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));
 | 
			
		||||
 | 
			
		||||
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 */
 | 
			
		||||
							
								
								
									
										182
									
								
								gtp/gtp.h
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								gtp/gtp.h
									
									
									
									
									
								
							@@ -13,13 +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
 | 
			
		||||
@@ -31,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 */
 | 
			
		||||
 | 
			
		||||
@@ -58,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 */
 | 
			
		||||
@@ -85,6 +80,7 @@
 | 
			
		||||
#define GTP_FWD_SRNS         58	/* Forward SRNS Context */
 | 
			
		||||
#define GTP_FWD_RELOC_ACK    59	/* Forward Relocation Complete Acknowledge */
 | 
			
		||||
#define GTP_FWD_SRNS_ACK     60	/* Forward SRNS Context Acknowledge */
 | 
			
		||||
#define GTP_RAN_INFO_RELAY   70	/* RAN Information Relay */
 | 
			
		||||
/* 61-239 For future use. */
 | 
			
		||||
#define GTP_DATA_TRAN_REQ   240	/* Data Record Transfer Request */
 | 
			
		||||
#define GTP_DATA_TRAN_RSP   241	/* Data Record Transfer Response */
 | 
			
		||||
@@ -103,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 */
 | 
			
		||||
@@ -138,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;
 | 
			
		||||
@@ -230,104 +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_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);
 | 
			
		||||
 | 
			
		||||
@@ -343,50 +257,21 @@ extern int gtp_delete_context_req2(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
			
		||||
extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp,
 | 
			
		||||
			void *pack, unsigned len);
 | 
			
		||||
 | 
			
		||||
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_ran_info_relay_req(struct gsn_t *gsn, const struct sockaddr_in *peer,
 | 
			
		||||
				  const uint8_t *ran_container, size_t ran_container_len,
 | 
			
		||||
				  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_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_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);
 | 
			
		||||
@@ -441,5 +326,6 @@ extern int eua2ipv4(struct in_addr *dst, struct ul66_t *eua);
 | 
			
		||||
extern int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna);
 | 
			
		||||
extern int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src);
 | 
			
		||||
extern const char *imsi_gtp2str(const uint64_t *imsi);
 | 
			
		||||
extern uint64_t gtp_imsi_str2gtp(const char *str);
 | 
			
		||||
 | 
			
		||||
#endif /* !_GTP_H */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								gtp/gtpie.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								gtp/gtpie.c
									
									
									
									
									
								
							@@ -1,17 +1,17 @@
 | 
			
		||||
/* 
 | 
			
		||||
/*
 | 
			
		||||
 *  OsmoGGSN - Gateway GPRS Support Node
 | 
			
		||||
 *  Copyright (C) 2002 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.
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * gtpie.c: Contains functions to encapsulate and decapsulate GTP 
 | 
			
		||||
 * information elements 
 | 
			
		||||
 * gtpie.c: Contains functions to encapsulate and decapsulate GTP
 | 
			
		||||
 * information elements
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * Encapsulation
 | 
			
		||||
 
 | 
			
		||||
@@ -338,9 +338,7 @@ int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi)
 | 
			
		||||
 | 
			
		||||
int gtp_pdp_getimsi(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi)
 | 
			
		||||
{
 | 
			
		||||
	return gtp_pdp_tidget(gsn, pdp,
 | 
			
		||||
			  (imsi & 0x0fffffffffffffffull) +
 | 
			
		||||
			  ((uint64_t) nsapi << 60));
 | 
			
		||||
	return gtp_pdp_tidget(gsn, pdp, pdp_gettid(imsi, nsapi));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										109
									
								
								lib/gtp-kernel.c
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								lib/gtp-kernel.c
									
									
									
									
									
								
							@@ -18,7 +18,6 @@
 | 
			
		||||
 | 
			
		||||
#include <libgtpnl/gtp.h>
 | 
			
		||||
#include <libgtpnl/gtpnl.h>
 | 
			
		||||
#include <libmnl/libmnl.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
@@ -31,10 +30,6 @@
 | 
			
		||||
#include "../gtp/pdp.h"
 | 
			
		||||
#include "../gtp/gtp.h"
 | 
			
		||||
 | 
			
		||||
#include <libgtpnl/gtp.h>
 | 
			
		||||
#include <libgtpnl/gtpnl.h>
 | 
			
		||||
#include <libmnl/libmnl.h>
 | 
			
		||||
 | 
			
		||||
#include "gtp-kernel.h"
 | 
			
		||||
 | 
			
		||||
static void pdp_debug(const char *prefix, const char *devname, struct pdp_t *pdp)
 | 
			
		||||
@@ -109,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);
 | 
			
		||||
 
 | 
			
		||||
@@ -318,7 +318,14 @@ int tun_decaps(struct tun_t *this)
 | 
			
		||||
 | 
			
		||||
int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
 | 
			
		||||
{
 | 
			
		||||
	return write(tun->fd, pack, len);
 | 
			
		||||
	int rc;
 | 
			
		||||
	rc = write(tun->fd, pack, len);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		SYS_ERR(DTUN, LOGL_ERROR, errno, "TUN(%s): write() failed", tun->devname);
 | 
			
		||||
	} else if (rc < len) {
 | 
			
		||||
		LOGTUN(LOGL_ERROR, tun, "short write() %d < %u\n", rc, len);
 | 
			
		||||
	}
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int tun_runscript(struct tun_t *tun, char *script)
 | 
			
		||||
 
 | 
			
		||||
@@ -59,4 +59,7 @@ extern int tun_runscript(struct tun_t *tun, char *script);
 | 
			
		||||
int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list,
 | 
			
		||||
		     size_t prefix_size, int flags);
 | 
			
		||||
 | 
			
		||||
#define LOGTUN(level, tun, fmt, args...) \
 | 
			
		||||
	LOGP(DTUN, level, "TUN(%s): " fmt, (tun)->devname, ## args)
 | 
			
		||||
 | 
			
		||||
#endif /* !_TUN_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -492,27 +492,12 @@ static int process_options(int argc, char **argv)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* imsi                                                            */
 | 
			
		||||
	if (strlen(args_info.imsi_arg) != 15) {
 | 
			
		||||
	if (strlen(args_info.imsi_arg) < 6 || strlen(args_info.imsi_arg) > 15) {
 | 
			
		||||
		printf("Invalid IMSI\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	options.imsi = 0xf000000000000000ull;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
 | 
			
		||||
	options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
 | 
			
		||||
	options.imsi = gtp_imsi_str2gtp(args_info.imsi_arg);
 | 
			
		||||
 | 
			
		||||
	printf("IMSI is:               %s (%#08llx)\n",
 | 
			
		||||
	       args_info.imsi_arg, options.imsi);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,16 @@
 | 
			
		||||
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 \
 | 
			
		||||
	queue_test.ok \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
noinst_PROGRAMS = \
 | 
			
		||||
check_PROGRAMS = \
 | 
			
		||||
	gtpie_test \
 | 
			
		||||
	queue_test \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 
 | 
			
		||||
@@ -113,7 +113,7 @@ int main(int argc, char **argv)
 | 
			
		||||
	msgb_talloc_ctx_init(tall_ctx, 0);
 | 
			
		||||
	osmo_init_logging2(tall_ctx, &log_info);
 | 
			
		||||
	log_set_use_color(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_filename(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
 | 
			
		||||
 | 
			
		||||
	srand(time(NULL));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -223,7 +223,7 @@ int main(int argc, char **argv)
 | 
			
		||||
	msgb_talloc_ctx_init(tall_ctx, 0);
 | 
			
		||||
	osmo_init_logging2(tall_ctx, &log_info);
 | 
			
		||||
	log_set_use_color(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_filename(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
 | 
			
		||||
 | 
			
		||||
	test_queue_empty();
 | 
			
		||||
	test_queue_one();
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -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 \
 | 
			
		||||
@@ -7,7 +12,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 \
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
@@ -431,7 +431,7 @@ int main(int argc, char **argv)
 | 
			
		||||
	msgb_talloc_ctx_init(tall_ctx, 0);
 | 
			
		||||
	osmo_init_logging2(tall_ctx, &log_info);
 | 
			
		||||
	log_set_use_color(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_filename(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
 | 
			
		||||
 | 
			
		||||
	srand(time(NULL));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -131,7 +131,9 @@ int main(int argc, char **argv)
 | 
			
		||||
	msgb_talloc_ctx_init(tall_ctx, 0);
 | 
			
		||||
	osmo_init_logging2(tall_ctx, &log_info);
 | 
			
		||||
	log_set_use_color(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_filename(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
 | 
			
		||||
	log_set_print_category(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_category_hex(osmo_stderr_target, 0);
 | 
			
		||||
 | 
			
		||||
	srand(time(NULL));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								utils/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								utils/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
bin_PROGRAMS = gtp-echo-responder
 | 
			
		||||
 | 
			
		||||
gtp_echo_responder_SOURCES = gtp_echo_responder.c
 | 
			
		||||
							
								
								
									
										470
									
								
								utils/gtp_echo_responder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										470
									
								
								utils/gtp_echo_responder.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,470 @@
 | 
			
		||||
/*
 | 
			
		||||
 * MIT License
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
			
		||||
 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: MIT
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice (including the next
 | 
			
		||||
 * paragraph) shall be included in all copies or substantial portions of the
 | 
			
		||||
 * Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* For more info see:
 | 
			
		||||
 * 3GPP TS 29.060 (GTPv1 and GTPv0)
 | 
			
		||||
 * 3GPP TS 29.274 (GTPv2C)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "../config.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <sys/select.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
 | 
			
		||||
#define GTP1C_PORT	2123
 | 
			
		||||
#define GTP_MSGTYPE_ECHO_REQ	1
 | 
			
		||||
#define GTP_MSGTYPE_ECHO_RSP	2
 | 
			
		||||
#define GTP1C_IE_RECOVERY 14
 | 
			
		||||
#define GTP2C_IE_RECOVERY 3
 | 
			
		||||
#define GTP2C_IE_NODE_FEATURES 152
 | 
			
		||||
 | 
			
		||||
struct gtp1_hdr {
 | 
			
		||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 | 
			
		||||
	uint8_t pn:1, s:1, e:1, spare:1, pt:1, version:3;
 | 
			
		||||
#else
 | 
			
		||||
	uint8_t version:3, pt:1, spare:1, e:1, s:1, pn:1;
 | 
			
		||||
#endif
 | 
			
		||||
	uint8_t type;
 | 
			
		||||
	uint16_t length;
 | 
			
		||||
	uint32_t tei;
 | 
			
		||||
	uint16_t seq;
 | 
			
		||||
	uint8_t npdu;
 | 
			
		||||
	uint8_t next;
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
struct gtp2_hdr {
 | 
			
		||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 | 
			
		||||
	uint8_t reserved:3, t:1, p:1, version:3;
 | 
			
		||||
#else
 | 
			
		||||
	uint8_t version:3, p:1, t:1, reserved:1;
 | 
			
		||||
#endif
 | 
			
		||||
	uint8_t type;
 | 
			
		||||
	uint16_t length;
 | 
			
		||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 | 
			
		||||
	uint32_t reserved2:8, seq:24;
 | 
			
		||||
#else
 | 
			
		||||
	uint8_t seq:24, reserved2:1;
 | 
			
		||||
#endif
 | 
			
		||||
} __attribute__((packed));
 | 
			
		||||
 | 
			
		||||
struct gtp_echo_resp_state {
 | 
			
		||||
	struct {
 | 
			
		||||
		char laddr[INET6_ADDRSTRLEN];
 | 
			
		||||
		uint8_t recovery_ctr;
 | 
			
		||||
		uint8_t node_features;
 | 
			
		||||
	} cfg;
 | 
			
		||||
	struct sockaddr_storage laddr_gtpc;
 | 
			
		||||
	int fd_gtpc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gtp_echo_resp_state *g_st;
 | 
			
		||||
 | 
			
		||||
static void print_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf("Usage: gtp-echo-responder [-h] [-V] [-l listen_addr]\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_help(void)
 | 
			
		||||
{
 | 
			
		||||
	printf("  Some useful help...\n"
 | 
			
		||||
	       "  -h --help		This help text\n"
 | 
			
		||||
	       "  -V --version		Print the version of gtp-echo-responder\n"
 | 
			
		||||
	       "  -l --listen-addr	Listend address for GTPCv1 and GTPCv2\n"
 | 
			
		||||
	       "  -R --recovery-counter GTP Recovery Counter to transmit in GTP Echo Response message\n"
 | 
			
		||||
	       "  -n --node-features	GTPCv2 Node Features bitmask to transmit in GTP Echo Response message\n"
 | 
			
		||||
	       );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_version(void)
 | 
			
		||||
{
 | 
			
		||||
	printf("gtp-echo-responder version %s\n", PACKAGE_VERSION);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t parse_node_features_mask(const char *arg)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long res;
 | 
			
		||||
	char *end;
 | 
			
		||||
	errno = 0;
 | 
			
		||||
 | 
			
		||||
	res = strtoul(arg, &end, 0);
 | 
			
		||||
	if ((errno == ERANGE && res == ULONG_MAX) || (errno && !res) ||
 | 
			
		||||
	    arg == end || *end != '\0') {
 | 
			
		||||
		fprintf(stderr, "Failed parsing Node Features bitmask: '%s'\n", arg);
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
	if (res > 0xff) {
 | 
			
		||||
		fprintf(stderr, "Failed parsing Node Features bitmask: '%s' > 0xFF\n", arg);
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
	return (uint8_t)res;
 | 
			
		||||
}
 | 
			
		||||
static void handle_options(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	while (1) {
 | 
			
		||||
		int option_index = 0, c;
 | 
			
		||||
		static struct option long_options[] = {
 | 
			
		||||
			{ "help", 0, 0, 'h' },
 | 
			
		||||
			{ "version", 0, 0, 'V' },
 | 
			
		||||
			{ "listen-addr", 1, 0, 'l'},
 | 
			
		||||
			{ "recovery-counter", 1, 0, 'R'},
 | 
			
		||||
			{ "node-features", 1, 0, 'N'},
 | 
			
		||||
			{ 0, 0, 0, 0 }
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		c = getopt_long(argc, argv, "hVl:R:N:", long_options, &option_index);
 | 
			
		||||
		if (c == -1)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'h':
 | 
			
		||||
			print_usage();
 | 
			
		||||
			print_help();
 | 
			
		||||
			exit(0);
 | 
			
		||||
		case 'V':
 | 
			
		||||
			print_version();
 | 
			
		||||
			exit(0);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'l':
 | 
			
		||||
			strncpy(&g_st->cfg.laddr[0], optarg, sizeof(g_st->cfg.laddr));
 | 
			
		||||
			g_st->cfg.laddr[sizeof(g_st->cfg.laddr) - 1] = '\0';
 | 
			
		||||
			break;
 | 
			
		||||
		case 'R':
 | 
			
		||||
			g_st->cfg.recovery_ctr = (uint8_t)atoi(optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'N':
 | 
			
		||||
			g_st->cfg.node_features = parse_node_features_mask(optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int init_socket(void)
 | 
			
		||||
{
 | 
			
		||||
	struct in_addr addr;
 | 
			
		||||
	struct in6_addr addr6;
 | 
			
		||||
	struct sockaddr_in *saddr;
 | 
			
		||||
	struct sockaddr_in6 *saddr6;
 | 
			
		||||
	int family;
 | 
			
		||||
 | 
			
		||||
	if (inet_pton(AF_INET6, g_st->cfg.laddr, &addr6) == 1) {
 | 
			
		||||
		family = AF_INET6;
 | 
			
		||||
		saddr6 = (struct sockaddr_in6 *)&g_st->laddr_gtpc;
 | 
			
		||||
		saddr6->sin6_family = family;
 | 
			
		||||
		saddr6->sin6_port = htons(GTP1C_PORT);
 | 
			
		||||
		memcpy(&saddr6->sin6_addr, &addr6, sizeof(addr6));
 | 
			
		||||
	} else if (inet_pton(AF_INET, g_st->cfg.laddr, &addr) == 1) {
 | 
			
		||||
		family = AF_INET;
 | 
			
		||||
		saddr = (struct sockaddr_in *)&g_st->laddr_gtpc;
 | 
			
		||||
		saddr->sin_family = family;
 | 
			
		||||
		saddr->sin_port = htons(GTP1C_PORT);
 | 
			
		||||
		memcpy(&saddr->sin_addr, &addr, sizeof(addr));
 | 
			
		||||
	} else {
 | 
			
		||||
		fprintf(stderr, "Failed parsing address %s\n", g_st->cfg.laddr);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((g_st->fd_gtpc = socket(family, SOCK_DGRAM, 0)) < 0) {
 | 
			
		||||
		fprintf(stderr, "socket() failed: %s\n", strerror(errno));
 | 
			
		||||
		return -2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (bind(g_st->fd_gtpc, (struct sockaddr *)&g_st->laddr_gtpc, sizeof(g_st->laddr_gtpc)) < 0) {
 | 
			
		||||
		fprintf(stderr, "bind() failed: %s\n", strerror(errno));
 | 
			
		||||
		return -3;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *sockaddr2str(const struct sockaddr *saddr)
 | 
			
		||||
{
 | 
			
		||||
	static char _rem_addr_str[INET6_ADDRSTRLEN];
 | 
			
		||||
	struct sockaddr_in *saddr4;
 | 
			
		||||
	struct sockaddr_in6 *saddr6;
 | 
			
		||||
 | 
			
		||||
	switch (saddr->sa_family) {
 | 
			
		||||
	case AF_INET6:
 | 
			
		||||
		saddr6 = (struct sockaddr_in6 *)saddr;
 | 
			
		||||
		if (!inet_ntop(saddr6->sin6_family, &saddr6->sin6_addr, _rem_addr_str, sizeof(_rem_addr_str)))
 | 
			
		||||
			strcpy(_rem_addr_str, "unknown");
 | 
			
		||||
		return _rem_addr_str;
 | 
			
		||||
	case AF_INET:
 | 
			
		||||
		saddr4 = (struct sockaddr_in *)saddr;
 | 
			
		||||
		if (!inet_ntop(saddr4->sin_family, &saddr4->sin_addr, _rem_addr_str, sizeof(_rem_addr_str)))
 | 
			
		||||
			strcpy(_rem_addr_str, "unknown");
 | 
			
		||||
		return _rem_addr_str;
 | 
			
		||||
	default:
 | 
			
		||||
		strcpy(_rem_addr_str, "unknown-family");
 | 
			
		||||
		return _rem_addr_str;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int write_cb(int fd, const uint8_t *buf, size_t buf_len, const struct sockaddr *rem_saddr)
 | 
			
		||||
{
 | 
			
		||||
	ssize_t rc;
 | 
			
		||||
 | 
			
		||||
	rc = sendto(fd, buf, buf_len, 0, rem_saddr, sizeof(struct sockaddr_storage));
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		fprintf(stderr, "sendto() failed: %s\n", strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (rc != buf_len) {
 | 
			
		||||
		fprintf(stderr, "sendto() short write: %zd vs exp %zu\n", rc, buf_len);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gen_gtpc1_echo_rsp(uint8_t *buf, struct gtp1_hdr *echo_req)
 | 
			
		||||
{
 | 
			
		||||
	int offset = 0;
 | 
			
		||||
	struct gtp1_hdr *echo_rsp = (struct gtp1_hdr *)buf;
 | 
			
		||||
	unsigned exp_hdr_len = (echo_req->s || echo_req->pn || echo_req->e) ? 12 : 8;
 | 
			
		||||
 | 
			
		||||
	memcpy(echo_rsp, echo_req, exp_hdr_len);
 | 
			
		||||
	echo_rsp->type = GTP_MSGTYPE_ECHO_RSP;
 | 
			
		||||
	offset = exp_hdr_len;
 | 
			
		||||
	buf[offset++] = GTP1C_IE_RECOVERY;
 | 
			
		||||
	buf[offset++] = g_st->cfg.recovery_ctr;
 | 
			
		||||
 | 
			
		||||
	/* Update Length */
 | 
			
		||||
	echo_rsp->length = htons(offset - 8);
 | 
			
		||||
	return offset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gen_gtpc2_echo_rsp(uint8_t *buf, struct gtp2_hdr *echo_req)
 | 
			
		||||
{
 | 
			
		||||
	int offset = 0;
 | 
			
		||||
	struct gtp1_hdr *echo_rsp = (struct gtp1_hdr *)buf;
 | 
			
		||||
	unsigned exp_hdr_len = 8;
 | 
			
		||||
 | 
			
		||||
	memcpy(echo_rsp, echo_req, exp_hdr_len);
 | 
			
		||||
	echo_rsp->type = GTP_MSGTYPE_ECHO_RSP;
 | 
			
		||||
	offset = exp_hdr_len;
 | 
			
		||||
 | 
			
		||||
	/* 3GPP TS 29.274 sec 8.5 Recovery (Restart Counter) */
 | 
			
		||||
	buf[offset++] = GTP2C_IE_RECOVERY;
 | 
			
		||||
	buf[offset++] = 0; /* IE Length (high) */
 | 
			
		||||
	buf[offset++] = 1; /* IE Length (low) */
 | 
			
		||||
	buf[offset++] = 0; /* Spare=0 | Instance=0 (Table 7.1.1-1) */
 | 
			
		||||
	buf[offset++] = g_st->cfg.recovery_ctr;
 | 
			
		||||
 | 
			
		||||
	/* 3GPP TS 29.274 sec 8.83 Node Features */
 | 
			
		||||
	if (g_st->cfg.node_features > 0) {
 | 
			
		||||
		buf[offset++] = GTP2C_IE_NODE_FEATURES;
 | 
			
		||||
		buf[offset++] = 0; /* IE Length (high) */
 | 
			
		||||
		buf[offset++] = 1; /* IE Length (low) */
 | 
			
		||||
		buf[offset++] = 0; /* Spare=0 | Instance=0 (Table 7.1.1-1) */
 | 
			
		||||
		buf[offset++] = g_st->cfg.node_features;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Update Length */
 | 
			
		||||
	echo_rsp->length = htons(offset - 4);
 | 
			
		||||
	return offset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rx_gtpc1_echo_req(struct gtp1_hdr *echo_req, unsigned buf_len, const struct sockaddr *rem_saddr)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	const size_t tx_buf_len = buf_len + 128; /* Leave some extra room */
 | 
			
		||||
	uint8_t *tx_buf = alloca(tx_buf_len);
 | 
			
		||||
 | 
			
		||||
	printf("Rx GTPCv1_ECHO_REQ from %s, Tx GTPCv1_ECHO_RSP\n", sockaddr2str(rem_saddr));
 | 
			
		||||
 | 
			
		||||
	memset(tx_buf, 0, tx_buf_len);
 | 
			
		||||
	rc = gen_gtpc1_echo_rsp(tx_buf, echo_req);
 | 
			
		||||
	return write_cb(g_st->fd_gtpc, tx_buf, rc, rem_saddr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rx_gtpc1(struct gtp1_hdr *hdr, unsigned buf_len, const struct sockaddr *rem_saddr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned exp_hdr_len = (hdr->s || hdr->pn || hdr->e) ? 12 : 8;
 | 
			
		||||
	unsigned pdu_len;
 | 
			
		||||
 | 
			
		||||
	if (buf_len < exp_hdr_len) {
 | 
			
		||||
		fprintf(stderr, "GTPCv1 packet size smaller than header! %u < exp %u\n", buf_len, exp_hdr_len);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pdu_len = ntohs(hdr->length);
 | 
			
		||||
	if (buf_len < 8 + pdu_len) {
 | 
			
		||||
		fprintf(stderr, "GTPCv1 packet size smaller than announced! %u < exp %u\n", buf_len, 8 + pdu_len);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (hdr->pt != 1) {
 | 
			
		||||
		fprintf(stderr, "GTPCv1 Protocol Type GTP' not supported!\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (hdr->type) {
 | 
			
		||||
	case GTP_MSGTYPE_ECHO_REQ:
 | 
			
		||||
		return rx_gtpc1_echo_req(hdr, buf_len, rem_saddr);
 | 
			
		||||
	default:
 | 
			
		||||
		fprintf(stderr, "Silently ignoring unexpected packet of type %u\n", hdr->type);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rx_gtpc2_echo_req(struct gtp2_hdr *echo_req, unsigned buf_len, const struct sockaddr *rem_saddr)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	const size_t tx_buf_len = buf_len + 128; /* Leave some extra room */
 | 
			
		||||
	uint8_t *tx_buf = alloca(tx_buf_len);
 | 
			
		||||
 | 
			
		||||
	if (echo_req->t) {
 | 
			
		||||
		fprintf(stderr, "GTPCv2 ECHO message should contain T=0!\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("Rx GTPCv2_ECHO_REQ from %s, Tx GTPCv2_ECHO_RSP\n", sockaddr2str(rem_saddr));
 | 
			
		||||
 | 
			
		||||
	memset(tx_buf, 0, tx_buf_len);
 | 
			
		||||
	rc = gen_gtpc2_echo_rsp(tx_buf, echo_req);
 | 
			
		||||
	return write_cb(g_st->fd_gtpc, tx_buf, rc, rem_saddr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rx_gtpc2(struct gtp2_hdr *hdr, unsigned buf_len, const struct sockaddr *rem_saddr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned exp_hdr_len = hdr->t ? 12 : 8;
 | 
			
		||||
	unsigned pdu_len;
 | 
			
		||||
 | 
			
		||||
	if (hdr->p) {
 | 
			
		||||
		fprintf(stderr, "GTPCv2 piggybacked message not supported!\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (buf_len < exp_hdr_len) {
 | 
			
		||||
		fprintf(stderr, "GTPCv2 packet size smaller than header! %u < exp %u\n", buf_len, exp_hdr_len);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pdu_len = ntohs(hdr->length);
 | 
			
		||||
	/* 3GPP TS 29.274 sec 5.5.1: "Octets 3 to 4 represent the Message Length
 | 
			
		||||
	 * field. This field shall indicate the length of the message in octets
 | 
			
		||||
	 * excluding the mandatory part of the GTP-C header (the first 4
 | 
			
		||||
	 * octets). The TEID (if present) and the Sequence  Number shall be
 | 
			
		||||
	 * included in the length count" */
 | 
			
		||||
	if (buf_len < 4 + pdu_len) {
 | 
			
		||||
		fprintf(stderr, "GTPCv2 packet size smaller than announced! %u < exp %u\n", buf_len, 4 + pdu_len);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (hdr->type) {
 | 
			
		||||
	case GTP_MSGTYPE_ECHO_REQ:
 | 
			
		||||
		return rx_gtpc2_echo_req(hdr, buf_len, rem_saddr);
 | 
			
		||||
	default:
 | 
			
		||||
		fprintf(stderr, "Silently ignoring unexpected packet of type %u\n", hdr->type);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int read_cb(int fd)
 | 
			
		||||
{
 | 
			
		||||
	ssize_t sz;
 | 
			
		||||
	uint8_t buf[4096];
 | 
			
		||||
	struct sockaddr_storage rem_saddr;
 | 
			
		||||
	socklen_t rem_saddr_len = sizeof(rem_saddr);
 | 
			
		||||
	struct gtp1_hdr *hdr1;
 | 
			
		||||
 | 
			
		||||
	if ((sz = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&rem_saddr, &rem_saddr_len)) < 0) {
 | 
			
		||||
		fprintf(stderr, "recvfrom() failed: %s\n", strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (sz == 0) {
 | 
			
		||||
		fprintf(stderr, "recvfrom() read zero bytes!\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hdr1 = (struct gtp1_hdr *)&buf[0];
 | 
			
		||||
	switch (hdr1->version) {
 | 
			
		||||
	case 1:
 | 
			
		||||
		return rx_gtpc1(hdr1, sz, (const struct sockaddr *)&rem_saddr);
 | 
			
		||||
	case 2:
 | 
			
		||||
		return rx_gtpc2((struct gtp2_hdr *)&buf[0], sz, (const struct sockaddr *)&rem_saddr);
 | 
			
		||||
	default:
 | 
			
		||||
		fprintf(stderr, "Rx GTPv%u: not supported (flags=0x%x)\n", hdr1->version, buf[0]);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int loop(void)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	fd_set rfds;
 | 
			
		||||
	int nfds;
 | 
			
		||||
 | 
			
		||||
	while (true) {
 | 
			
		||||
		FD_ZERO(&rfds);
 | 
			
		||||
		FD_SET(g_st->fd_gtpc, &rfds);
 | 
			
		||||
		nfds = g_st->fd_gtpc + 1;
 | 
			
		||||
		rc = select(nfds, &rfds, NULL, NULL, NULL);
 | 
			
		||||
		if (rc == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (rc < 0) {
 | 
			
		||||
			fprintf(stderr, "select() failed: %s\n", strerror(errno));
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (FD_ISSET(g_st->fd_gtpc, &rfds))
 | 
			
		||||
			read_cb(g_st->fd_gtpc);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	g_st = calloc(1, sizeof(struct gtp_echo_resp_state));
 | 
			
		||||
 | 
			
		||||
	strcpy(g_st->cfg.laddr, "::");
 | 
			
		||||
 | 
			
		||||
	handle_options(argc, argv);
 | 
			
		||||
 | 
			
		||||
	printf("Listening on: %s\n", g_st->cfg.laddr);
 | 
			
		||||
 | 
			
		||||
	if (init_socket() < 0)
 | 
			
		||||
		exit(1);
 | 
			
		||||
 | 
			
		||||
	printf("Socket bound successfully, listening for requests...\n");
 | 
			
		||||
 | 
			
		||||
	if (loop() < 0)
 | 
			
		||||
		exit(1);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										111
									
								
								utils/gtp_echo_responder_test.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										111
									
								
								utils/gtp_echo_responder_test.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,111 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
# MIT License
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
			
		||||
# Author: Pau Espin Pedrol <pespin@sysmocom.de>
 | 
			
		||||
#
 | 
			
		||||
# SPDX-License-Identifier: MIT
 | 
			
		||||
#
 | 
			
		||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
# of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
# in the Software without restriction, including without limitation the rights
 | 
			
		||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
# copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
# furnished to do so, subject to the following conditions:
 | 
			
		||||
#
 | 
			
		||||
# The above copyright notice and this permission notice (including the next
 | 
			
		||||
# paragraph) shall be included in all copies or substantial portions of the
 | 
			
		||||
# Software.
 | 
			
		||||
#
 | 
			
		||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
# SOFTWARE.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import socket
 | 
			
		||||
import argparse
 | 
			
		||||
import struct
 | 
			
		||||
from ipaddress import ip_address, IPv4Address
 | 
			
		||||
 | 
			
		||||
GTP1C_PORT = 2123
 | 
			
		||||
BUF_SIZE = 4096
 | 
			
		||||
 | 
			
		||||
GTP_HDRv1_FLAG_PN = (1<<0)
 | 
			
		||||
GTP_HDRv1_FLAG_S = (1<<1)
 | 
			
		||||
GTP_HDRv1_FLAG_E = (1<<2)
 | 
			
		||||
GTP_HDRv1_PT_GTP = (1<<4)
 | 
			
		||||
GTP_HDRv1_VER_GTP1 = (1<<5)
 | 
			
		||||
 | 
			
		||||
GTP_HDRv2_FLAG_T = (1<<3)
 | 
			
		||||
GTP_HDRv2_FLAG_P = (1<<4)
 | 
			
		||||
GTP_HDRv2_VER_GTP2 = (2<<5)
 | 
			
		||||
 | 
			
		||||
def gen_gtpc_v1_hdr(flags, type, length, tei, seq=0, npdu=0, next=0):
 | 
			
		||||
    spare = 0
 | 
			
		||||
    if (flags & (GTP_HDRv1_FLAG_PN|GTP_HDRv1_FLAG_S|GTP_HDRv1_FLAG_E)):
 | 
			
		||||
        #long format
 | 
			
		||||
        length += 4
 | 
			
		||||
        d = struct.pack('!BBHIHBB', flags, type, length, tei, seq, npdu, next)
 | 
			
		||||
    else:
 | 
			
		||||
        #short format
 | 
			
		||||
        d = struct.pack('!BBHI', flags, type, length, tei)
 | 
			
		||||
    return d
 | 
			
		||||
 | 
			
		||||
def gen_gtpc_v2_hdr(flags, type, length, tei=0, seq=0):
 | 
			
		||||
    spare = 0
 | 
			
		||||
    if (flags & (GTP_HDRv2_FLAG_T)):
 | 
			
		||||
        #long format, with TEI
 | 
			
		||||
        length += 4 + 4
 | 
			
		||||
        d = struct.pack('!BBHIHBB', flags, type, length, tei, seq >> 8, seq & 0xff, spare)
 | 
			
		||||
    else:
 | 
			
		||||
        #short format
 | 
			
		||||
        length += 4
 | 
			
		||||
        d = struct.pack('!BBHHBB', flags, type, length, seq >> 8, seq & 0xff, spare)
 | 
			
		||||
    return d
 | 
			
		||||
 | 
			
		||||
def gen_gtpc_v1_echo_req(tei=0, append_flags=0, seq=0, npdu=0, next=0):
 | 
			
		||||
    return gen_gtpc_v1_hdr(GTP_HDRv1_VER_GTP1 | GTP_HDRv1_PT_GTP | append_flags, 1, 0, tei, seq, npdu, next)
 | 
			
		||||
 | 
			
		||||
def gen_gtpc_v2_echo_req(append_flags=0, seq=0, recovery=0, node_features=-1):
 | 
			
		||||
    length = 0
 | 
			
		||||
    payload = b''
 | 
			
		||||
    if (recovery > 0):
 | 
			
		||||
        recovery_ie = struct.pack('!BHBB', 3, 1, 0, recovery)
 | 
			
		||||
        payload += recovery_ie
 | 
			
		||||
        length += len(recovery_ie)
 | 
			
		||||
    if (node_features > 0):
 | 
			
		||||
        node_features_ie = struct.pack('!BHBB', 152, 1, 0, node_features)
 | 
			
		||||
        payload += node_features_ie
 | 
			
		||||
        length += len(node_features_ie)
 | 
			
		||||
    return gen_gtpc_v2_hdr(GTP_HDRv2_VER_GTP2 | append_flags, 1, length, 0, seq) + payload
 | 
			
		||||
 | 
			
		||||
def tx_rx(sk, rem_addr, tx_buf, exp_rx = True):
 | 
			
		||||
    print('Tx ECHO_REQ to %r: %r' % (repr(rem_addr), repr(tx_buf)))
 | 
			
		||||
    sk.sendto(tx_buf, rem_addr)
 | 
			
		||||
    if exp_rx:
 | 
			
		||||
        rx_buf = sk.recvfrom(BUF_SIZE)
 | 
			
		||||
        msg = "Message from Server {}".format(rx_buf)
 | 
			
		||||
        print(msg)
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    p = argparse.ArgumentParser(description='Tester for gtp-echo-recorder.')
 | 
			
		||||
    p.add_argument('-l', '--local-address', default='127.0.0.2', help="Local GTP address")
 | 
			
		||||
    p.add_argument('-r', '--remote-address', default='127.0.0.1', help="Remote GTP address")
 | 
			
		||||
    args = p.parse_args()
 | 
			
		||||
 | 
			
		||||
    print('Binding socket on %r...' % repr((args.local_address, GTP1C_PORT)))
 | 
			
		||||
    family = socket.AF_INET if type(ip_address(args.local_address)) is IPv4Address else socket.AF_INET6
 | 
			
		||||
    sk = socket.socket(family=family, type=socket.SOCK_DGRAM)
 | 
			
		||||
    sk.bind((args.local_address, GTP1C_PORT));
 | 
			
		||||
 | 
			
		||||
    rem_addr = (args.remote_address, GTP1C_PORT)
 | 
			
		||||
 | 
			
		||||
    tx_rx(sk, rem_addr, gen_gtpc_v1_echo_req())
 | 
			
		||||
    tx_rx(sk, rem_addr, gen_gtpc_v1_echo_req(1, GTP_HDRv1_FLAG_S, seq=67))
 | 
			
		||||
    tx_rx(sk, rem_addr, gen_gtpc_v2_echo_req(0, seq=300, recovery=-1, node_features=-1))
 | 
			
		||||
    tx_rx(sk, rem_addr, gen_gtpc_v2_echo_req(0, seq=20, recovery=99, node_features=-1))
 | 
			
		||||
    tx_rx(sk, rem_addr, gen_gtpc_v2_echo_req(0, seq=20, recovery=100, node_features=0xbb))
 | 
			
		||||
		Reference in New Issue
	
	Block a user