aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/FUNDING.yml1
-rw-r--r--.gitignore4
-rw-r--r--Makefile.am1
-rw-r--r--README17
-rw-r--r--README.md100
-rw-r--r--README.vty-tests2
-rw-r--r--TODO-RELEASE4
-rw-r--r--configure.ac47
-rwxr-xr-xcontrib/jenkins.sh7
-rw-r--r--contrib/osmo-sgsn.spec.in24
-rw-r--r--contrib/systemd/osmo-gtphub.service4
-rw-r--r--contrib/systemd/osmo-sgsn.service4
-rw-r--r--debian/changelog361
-rw-r--r--debian/compat2
-rw-r--r--debian/control25
-rw-r--r--debian/copyright8
-rw-r--r--doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg8
-rw-r--r--doc/examples/osmo-gtphub/osmo-gtphub.cfg10
-rw-r--r--doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg8
-rw-r--r--doc/examples/osmo-sgsn/osmo-sgsn.cfg8
-rw-r--r--doc/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg10
-rw-r--r--doc/manuals/chapters/configuration.adoc62
-rwxr-xr-xdoc/manuals/regen_doc.sh76
-rw-r--r--include/osmocom/Makefile.am1
-rw-r--r--include/osmocom/gtphub/Makefile.am3
-rw-r--r--include/osmocom/gtphub/gtphub.h (renamed from include/osmocom/sgsn/gtphub.h)6
-rw-r--r--include/osmocom/sgsn/Makefile.am13
-rw-r--r--include/osmocom/sgsn/apn.h20
-rw-r--r--include/osmocom/sgsn/auth.h39
-rw-r--r--include/osmocom/sgsn/crc24.h2
-rw-r--r--include/osmocom/sgsn/debug.h1
-rw-r--r--include/osmocom/sgsn/gprs_bssgp.h12
-rw-r--r--include/osmocom/sgsn/gprs_gb.h20
-rw-r--r--include/osmocom/sgsn/gprs_gmm.h13
-rw-r--r--include/osmocom/sgsn/gprs_gmm_fsm.h4
-rw-r--r--include/osmocom/sgsn/gprs_llc.h19
-rw-r--r--include/osmocom/sgsn/gprs_mm_state_gb_fsm.h5
-rw-r--r--include/osmocom/sgsn/gprs_mm_state_iu_fsm.h7
-rw-r--r--include/osmocom/sgsn/gprs_ns.h9
-rw-r--r--include/osmocom/sgsn/gprs_ranap.h4
-rw-r--r--include/osmocom/sgsn/gprs_sm.h5
-rw-r--r--include/osmocom/sgsn/gprs_sndcp.h24
-rw-r--r--include/osmocom/sgsn/gprs_subscriber.h79
-rw-r--r--include/osmocom/sgsn/gprs_utils.h4
-rw-r--r--include/osmocom/sgsn/gtp.h30
-rw-r--r--include/osmocom/sgsn/gtp_ggsn.h41
-rw-r--r--include/osmocom/sgsn/gtp_mme.h41
-rw-r--r--include/osmocom/sgsn/mmctx.h (renamed from include/osmocom/sgsn/gprs_sgsn.h)255
-rw-r--r--include/osmocom/sgsn/pdpctx.h94
-rw-r--r--include/osmocom/sgsn/sgsn.h60
-rw-r--r--include/osmocom/sgsn/sgsn_rim.h5
-rw-r--r--include/osmocom/sgsn/v42bis.h4
-rw-r--r--include/osmocom/sgsn/v42bis_private.h4
-rw-r--r--include/osmocom/sgsn/vty.h4
-rw-r--r--m4/ax_check_compile_flag.m474
-rw-r--r--src/gprs/Makefile.am1
-rw-r--r--src/gprs/crc24.c2
-rw-r--r--src/gprs/gprs_llc_parse.c4
-rw-r--r--src/gprs/gprs_utils.c63
-rw-r--r--src/gprs/sgsn_ares.c2
-rw-r--r--src/gtphub/gtphub.c57
-rw-r--r--src/gtphub/gtphub_ares.c7
-rw-r--r--src/gtphub/gtphub_main.c8
-rw-r--r--src/gtphub/gtphub_sock.c7
-rw-r--r--src/gtphub/gtphub_vty.c2
-rw-r--r--src/sgsn/Makefile.am10
-rw-r--r--src/sgsn/apn.c123
-rw-r--r--src/sgsn/gprs_bssgp.c95
-rw-r--r--src/sgsn/gprs_gmm.c200
-rw-r--r--src/sgsn/gprs_gmm_attach.c21
-rw-r--r--src/sgsn/gprs_gmm_fsm.c19
-rw-r--r--src/sgsn/gprs_llc.c61
-rw-r--r--src/sgsn/gprs_llc_vty.c17
-rw-r--r--src/sgsn/gprs_mm_state_gb_fsm.c33
-rw-r--r--src/sgsn/gprs_mm_state_iu_fsm.c72
-rw-r--r--src/sgsn/gprs_ns.c (renamed from src/sgsn/gprs_gb.c)87
-rw-r--r--src/sgsn/gprs_ranap.c23
-rw-r--r--src/sgsn/gprs_sm.c28
-rw-r--r--src/sgsn/gprs_sndcp.c218
-rw-r--r--src/sgsn/gprs_subscriber.c7
-rw-r--r--src/sgsn/gtp_ggsn.c178
-rw-r--r--src/sgsn/gtp_mme.c143
-rw-r--r--src/sgsn/mmctx.c (renamed from src/sgsn/gprs_sgsn.c)508
-rw-r--r--src/sgsn/pdpctx.c158
-rw-r--r--src/sgsn/sgsn.c215
-rw-r--r--src/sgsn/sgsn_auth.c2
-rw-r--r--src/sgsn/sgsn_cdr.c14
-rw-r--r--src/sgsn/sgsn_ctrl.c9
-rw-r--r--src/sgsn/sgsn_libgtp.c210
-rw-r--r--src/sgsn/sgsn_main.c105
-rw-r--r--src/sgsn/sgsn_rim.c122
-rw-r--r--src/sgsn/sgsn_vty.c442
-rw-r--r--src/sgsn/v42bis.c4
-rw-r--r--tests/Makefile.am16
-rw-r--r--tests/gprs/Makefile.am3
-rw-r--r--tests/gprs/gprs_test.c18
-rw-r--r--tests/gtphub/Makefile.am5
-rw-r--r--tests/gtphub/gtphub_test.c13
-rw-r--r--tests/osmo-sgsn_test-nodes.vty73
-rw-r--r--tests/sgsn/Makefile.am26
-rw-r--r--tests/sgsn/gprs_gb_parse.c (renamed from src/gprs/gprs_gb_parse.c)4
-rw-r--r--tests/sgsn/gprs_gb_parse.h (renamed from include/osmocom/sgsn/gprs_gb_parse.h)0
-rw-r--r--tests/sgsn/sgsn_test.c93
-rw-r--r--tests/slhc/Makefile.am3
-rw-r--r--tests/sndcp_xid/Makefile.am3
-rw-r--r--tests/v42bis/Makefile.am3
-rw-r--r--tests/xid/Makefile.am4
107 files changed, 3453 insertions, 1783 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000..7592debf9
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+open_collective: osmocom
diff --git a/.gitignore b/.gitignore
index 3626a5a62..010f151ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,8 +6,8 @@ debian/*.log
.deps
Makefile
Makefile.in
-bscconfig.h
-bscconfig.h.in
+config.h
+config.h.in
*.*~
*.sw?
.libs
diff --git a/Makefile.am b/Makefile.am
index 023a47050..b70eb4b5d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,6 +19,7 @@ SUBDIRS = \
BUILT_SOURCES = $(top_srcdir)/.version
EXTRA_DIST = \
.version \
+ README.md \
contrib/osmo-sgsn.spec.in \
debian \
git-version-gen \
diff --git a/README b/README
deleted file mode 100644
index a14ba3803..000000000
--- a/README
+++ /dev/null
@@ -1,17 +0,0 @@
-About OsmoSGSN
-==============
-
-OsmoSGSN originated from the OpenBSC project, as a separate program within
-openbsc.git. In 2017, OpenBSC was split in separate repositories, and hence
-OsmoSGSN was given its own separate git repository.
-
-OsmoSGSN exposes
-- GSUP towards OsmoHLR (or a MAP proxy);
-- GTP towards a GGSN (e.g. OsmoGGSN);
-- Gb towards a BSS (e.g. OsmoPCU);
-- IuPS towards an RNC or HNB-GW (e.g. OsmoHNBGW) for 3G data;
-- The Osmocom typical telnet VTY and CTRL interfaces.
-
-Find OsmoSGSN issue tracker and wiki online at
-https://osmocom.org/projects/osmosgsn
-https://osmocom.org/projects/osmosgsn/wiki
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..3143d048a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,100 @@
+osmo-sgsn - Osmocom SGSN Implementation
+=======================================
+
+This repository contains a C-language implementation of a *Serving GPRS
+Support Node (SGSN)* for 2.5/2.75G (GPRS/EDGE) and 3G (UMTS). It is part of the
+[Osmocom](https://osmocom.org/) Open Source Mobile Communications
+project.
+
+OsmoSGSN exposes
+
+ * *Gb* towards PCUs (e.g. [OsmoPCU](https://osmocom.org/projects/osmopcu/wiki/OsmoPCU)): Various GbIP flavors + Gb/FR/E1
+ * *GTP* towards a GGSN (e.g. [OsmoGGSN](https://osmocom.org/projects/openggsn/wiki))
+ * IuPS over IP towards RNCs / HNBGW (e.g. [osmo-hnbgw](https://osmocom.org/projects/osmohnbgw/wiki))
+ * The Osmocom typical telnet *VTY* and *CTRL* interfaces.
+ * The Osmocom typical *statsd* exporter.
+ * GSUP (custom MAP-like protocol) towards [osmo-hlr](https://osmocom.org/projects/osmo-hlr/wiki/OsmoHLR)
+
+OsmoSGSN implements
+
+ * GPRS mobility management
+ * GPRS session management
+
+
+Homepage
+--------
+
+You can find the OsmoSGSN homepage online at <https://osmocom.org/projects/osmosgsn/wiki>.
+
+
+GIT Repository
+--------------
+
+You can clone from the official osmo-sgsn.git repository using
+
+ git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
+
+There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn>
+
+
+Documentation
+-------------
+
+User Manuals and VTY reference manuals are [optionally] built in PDF form
+as part of the build process.
+
+Pre-rendered PDF version of the current "master" can be found at
+[User Manual](https://ftp.osmocom.org/docs/latest/osmosgsn-usermanual.pdf)
+as well as the [VTY Reference Manual](https://ftp.osmocom.org/docs/latest/osmosgsn-vty-reference.pdf)
+
+
+Forum
+-----
+
+We welcome any osmo-sgsn related discussions in the
+[Cellular Network Infratructure -> 2G/3G Core Network](https://discourse.osmocom.org/c/cni/2g-3g-cn).
+section of the osmocom discourse (web based Forum).
+
+
+Mailing List
+------------
+
+Discussions related to osmo-sgsn are happening on the
+osmocom-net-gprs@lists.osmocom.org mailing list, please see
+<https://lists.osmocom.org/postorius/lists/osmocom-net-gprs.lists.osmocom.org/> for subscription
+options and the list archive.
+
+Please observe the [Osmocom Mailing List
+Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
+when posting.
+
+
+Issue Tracker
+-------------
+
+We use the [issue tracker of the osmo-sgsn project on osmocom.org](https://osmocom.org/projects/osmosgsn/issues) for
+tracking the state of bug reports and feature requests. Feel free to submit any issues you may find, or help
+us out by resolving existing issues.
+
+
+Contributing
+------------
+
+Our coding standards are described at
+<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
+
+We us a gerrit based patch submission/review process for managing
+contributions. Please see
+<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for
+more details
+
+The current patch queue for osmo-sgsn can be seen at
+<https://gerrit.osmocom.org/#/q/project:osmo-sgsn+status:open>
+
+
+History
+-------
+
+OsmoSGSN originated from the OpenBSC project, as a separate program within
+openbsc.git. In 2017, OpenBSC was split in separate repositories, and hence
+OsmoSGSN was given its own separate git repository.
diff --git a/README.vty-tests b/README.vty-tests
index 0669ea8e8..dc34916ee 100644
--- a/README.vty-tests
+++ b/README.vty-tests
@@ -1,6 +1,6 @@
To run the configuration parsing and output (VTY) test suite, first install
- git://git.osmocom.org/python/osmo-python-tests
+ https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests
and pass the following configure options here:
diff --git a/TODO-RELEASE b/TODO-RELEASE
index 5514897b4..df983c1c4 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -1,4 +1,2 @@
#component what description / commit summary line
-manual needs common chapter cs7-config.adoc, vty_cpu_sched.adoc from osmo-gsm-manuals > 0.3.0
-configure.ac libosmocore depend on next released libosmocore after 1.4.x with hashtable support
-sgsn vty/config change the configuration of the vty config. old configuration are invalid.
+libosmocore > 1.9.0 gsup.h: Using new fields in struct osmo_gsup_pdp_info (ABI break) \ No newline at end of file
diff --git a/configure.ac b/configure.ac
index 947ecf152..ddd91ab2b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,45 +34,32 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
fi
PKG_PROG_PKG_CONFIG([0.20])
-dnl check for AX_CHECK_COMPILE_FLAG
-m4_ifdef([AX_CHECK_COMPILE_FLAG], [], [
- AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.])
- ])
-
dnl use a defined standard across all builds and don't depend on compiler default
CFLAGS="$CFLAGS -std=gnu11"
dnl checks for libraries
-AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
-AC_SUBST(LIBRARY_DL)
-
-AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
-AC_SUBST(LIBRARY_DLSYM)
-
-
-PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.4.0)
-PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.4.0)
-PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.4.0)
-PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.4.0)
-PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.4.0)
-PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0)
-PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.4.0)
-PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.0.0)
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.9.0)
+PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0)
+PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.4.0)
+PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.7.0)
+PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.11.0)
# Enable/disable 3G aka IuPS + IuCS support?
AC_ARG_ENABLE([iu], [AS_HELP_STRING([--enable-iu], [Build 3G support, aka IuPS and IuCS interfaces])],
[osmo_ac_iu="$enableval"],[osmo_ac_iu="no"])
if test "x$osmo_ac_iu" = "xyes" ; then
- PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.0.0)
+ PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.8.0)
PKG_CHECK_MODULES(LIBASN1C, libasn1c >= 0.9.30)
- PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.6.0)
+ PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 1.5.0)
AC_DEFINE(BUILD_IU, 1, [Define if we want to build IuPS and IuCS interfaces support])
fi
AM_CONDITIONAL(BUILD_IU, test "x$osmo_ac_iu" = "xyes")
AC_SUBST(osmo_ac_iu)
-
-PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.5.0)
PKG_CHECK_MODULES(LIBCARES, libcares)
dnl checks for header files
@@ -124,13 +111,6 @@ AC_SUBST(SYMBOL_VISIBILITY)
CPPFLAGS="$CPPFLAGS -Wall -Wno-trigraphs"
CFLAGS="$CFLAGS -Wall -Wno-trigraphs"
-AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
-AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
-AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"])
-AX_CHECK_COMPILE_FLAG([-Wnull-dereference], [CFLAGS="$CFLAGS -Wnull-dereference"])
-AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"])
-AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"])
-
# Coverage build taken from WebKit's configure.in
AC_MSG_CHECKING([whether to enable code coverage support])
AC_ARG_ENABLE(coverage,
@@ -181,7 +161,7 @@ if test "x$enable_ext_tests" = "xyes" ; then
fi
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
- AC_MSG_ERROR([Please install git://osmocom.org/python/osmo-python-tests to run the VTY/CTRL tests.])
+ AC_MSG_ERROR([Please install https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests to run the VTY/CTRL tests.])
fi
fi
AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
@@ -250,11 +230,12 @@ AC_MSG_RESULT([CFLAGS="$CFLAGS"])
AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
dnl Generate the output
-AM_CONFIG_HEADER(bscconfig.h)
+AM_CONFIG_HEADER(config.h)
AC_OUTPUT(
include/Makefile
include/osmocom/Makefile
+ include/osmocom/gtphub/Makefile
include/osmocom/sgsn/Makefile
src/Makefile
src/gprs/Makefile
diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh
index 2325897a9..321beef1b 100755
--- a/contrib/jenkins.sh
+++ b/contrib/jenkins.sh
@@ -37,14 +37,11 @@ osmo-build-dep.sh libosmo-netif
osmo-build-dep.sh osmo-ggsn
osmo-build-dep.sh osmo-hlr
-enable_werror=""
if [ "x$IU" = "x--enable-iu" ]; then
osmo-build-dep.sh libosmo-sccp
osmo-build-dep.sh libasn1c
#osmo-build-dep.sh asn1c aper-prefix # only needed for make regen in osmo-iuh
osmo-build-dep.sh osmo-iuh
-else
- enable_werror="--enable-werror"
fi
# Additional configure options and depends
@@ -63,12 +60,12 @@ set -x
cd "$base"
autoreconf --install --force
-./configure --enable-sanitize $enable_werror $IU --enable-external-tests $CONFIG
+./configure --enable-sanitize --enable-werror $IU --enable-external-tests $CONFIG
$MAKE $PARALLEL_MAKE
LD_LIBRARY_PATH="$inst/lib" $MAKE check \
|| cat-testlogs.sh
LD_LIBRARY_PATH="$inst/lib" \
- DISTCHECK_CONFIGURE_FLAGS="$enable_werror $IU --enable-external-tests $CONFIG" \
+ DISTCHECK_CONFIGURE_FLAGS="--enable-werror $IU --enable-external-tests $CONFIG" \
$MAKE $PARALLEL_MAKE distcheck \
|| cat-testlogs.sh
diff --git a/contrib/osmo-sgsn.spec.in b/contrib/osmo-sgsn.spec.in
index cd3b5b7bf..7ba994f73 100644
--- a/contrib/osmo-sgsn.spec.in
+++ b/contrib/osmo-sgsn.spec.in
@@ -34,20 +34,20 @@ BuildRequires: systemd-rpm-macros
%endif
BuildRequires: pkgconfig(libcares)
BuildRequires: pkgconfig(libcrypto) >= 0.9.5
-BuildRequires: pkgconfig(libgtp) >= 1.4.0
-BuildRequires: pkgconfig(libosmo-gsup-client) >= 1.0.0
-BuildRequires: pkgconfig(libosmo-netif) >= 0.4.0
-BuildRequires: pkgconfig(libosmoabis) >= 0.6.0
-BuildRequires: pkgconfig(libosmocore) >= 1.2.0
-BuildRequires: pkgconfig(libosmoctrl) >= 1.2.0
-BuildRequires: pkgconfig(libosmogb) >= 1.2.0
-BuildRequires: pkgconfig(libosmogsm) >= 1.2.0
-BuildRequires: pkgconfig(libosmovty) >= 1.2.0
+BuildRequires: pkgconfig(libgtp) >= 1.11.0
+BuildRequires: pkgconfig(libosmo-gsup-client) >= 1.7.0
+BuildRequires: pkgconfig(libosmo-netif) >= 1.4.0
+BuildRequires: pkgconfig(libosmoabis) >= 1.5.0
+BuildRequires: pkgconfig(libosmocore) >= 1.9.0
+BuildRequires: pkgconfig(libosmoctrl) >= 1.9.0
+BuildRequires: pkgconfig(libosmogb) >= 1.9.0
+BuildRequires: pkgconfig(libosmogsm) >= 1.9.0
+BuildRequires: pkgconfig(libosmovty) >= 1.9.0
%{?systemd_requires}
%if %{with_iu}
BuildRequires: pkgconfig(libasn1c)
-BuildRequires: pkgconfig(libosmo-ranap) >= 0.4.0
-BuildRequires: pkgconfig(libosmo-sigtran) >= 1.0.0
+BuildRequires: pkgconfig(libosmo-ranap) >= 1.5.0
+BuildRequires: pkgconfig(libosmo-sigtran) >= 1.8.0
%endif
%description
@@ -93,7 +93,7 @@ make %{?_smp_mflags}
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%files
-%doc AUTHORS README
+%doc AUTHORS README.md
%dir %{_docdir}/%{name}/examples
%dir %{_docdir}/%{name}/examples/osmo-sgsn
%exclude %{_docdir}/%{name}/examples/osmo-gtphub
diff --git a/contrib/systemd/osmo-gtphub.service b/contrib/systemd/osmo-gtphub.service
index 488178584..9ade246d4 100644
--- a/contrib/systemd/osmo-gtphub.service
+++ b/contrib/systemd/osmo-gtphub.service
@@ -1,9 +1,13 @@
[Unit]
Description=Osmocom GTP Hub
+After=network-online.target
+Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/osmo-gtphub -c /etc/osmocom/osmo-gtphub.cfg
+StateDirectory=osmocom
+WorkingDirectory=%S/osmocom
Restart=always
RestartSec=2
RestartPreventExitStatus=1
diff --git a/contrib/systemd/osmo-sgsn.service b/contrib/systemd/osmo-sgsn.service
index 0991c70c6..21ecbb752 100644
--- a/contrib/systemd/osmo-sgsn.service
+++ b/contrib/systemd/osmo-sgsn.service
@@ -3,9 +3,13 @@ Description=Osmocom SGSN (Serving GPRS Support Node)
Wants=osmo-hlr.service
After=osmo-hlr.service
After=osmo-hnbgw.service
+After=network-online.target
+Wants=network-online.target
[Service]
Type=simple
+StateDirectory=osmocom
+WorkingDirectory=%S/osmocom
Restart=always
ExecStart=/usr/bin/osmo-sgsn -c /etc/osmocom/osmo-sgsn.cfg
RestartSec=2
diff --git a/debian/changelog b/debian/changelog
index 2827f43b0..cb629fbdc 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,364 @@
+osmo-sgsn (1.11.1) unstable; urgency=medium
+
+ [ Philipp Maier ]
+ * sgsn_rim: forward message based on RIM ROUTING ADDRESS
+
+ [ Daniel Willmann ]
+ * sgsn_vty: Fix output in config_write_sgsn
+ * sgsn_vty: Correctly indent encryption cipher-plugin-path
+ * vty-tests: Test encryption options
+ * libgtp: Check for all successful create_pdp_conf causes
+
+ -- Oliver Smith <osmith@sysmocom.de> Tue, 28 Nov 2023 13:32:46 +0100
+
+osmo-sgsn (1.11.0) unstable; urgency=medium
+
+ [ Oliver Smith ]
+ * Run struct_endianness.py
+ * debian: set compat level to 10
+ * systemd: depend on networking-online.target
+
+ [ arehbein ]
+ * Transition to use of 'telnet_init_default'
+
+ [ Vadim Yanitskiy ]
+ * tests: use -no-install libtool flag to avoid ./lt-* scripts
+ * tests: $(BUILT_SOURCES) is not defined, depend on osmo-sgsn
+ * copyright: fix typo: sysmocom s/s.m.f.c./s.f.m.c./ GmbH
+
+ [ Pau Espin Pedrol ]
+ * gmm: Ciphering Key Sequence Number IE has half octet tag
+ * gprs_sm.c: Fix load of misaligned ptr address
+ * Write explicit role & sctp-role fields in ASP configurations
+ * gmm: Update DRX params during rx RAU REQ
+ * gmm: Add missing GSM48_IE_GMM_RX_NPDU_NUM_LIST IE in gsm48_gmm_att_tlvdef
+
+ [ Philipp Maier ]
+ * sgsn_rim: fix typo
+ * sgsn_rim: cosmetic: improve comment
+ * sgsn_rim: get rid of MME check in sgsn_rim_rx_from_gtp:
+ * sgsn_rim: do not check the origin of a RIM message
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 16:57:02 +0200
+
+osmo-sgsn (1.10.0) unstable; urgency=medium
+
+ [ Vadim Yanitskiy ]
+ * configure.ac: do not require unused dlsym/dlopen
+ * gprs_llc: fix misleading spacing in gprs_llc_rcvmsg()
+ * gprs_llc.h: use '#pragma once'
+ * llc: gprs_llc_fcs(): make the input data pointer const
+
+ [ Max ]
+ * Set working directory in systemd service file
+ * SNDCP: log more details on failure
+ * GTP: migrate from deprecated function
+ * Constify LLC/SNDCP parameters
+ * GMM: permit E_GMM_COMMON_PROC_SUCCESS in normal state
+ * ctrl: take both address and port from vty config
+
+ [ Pau Espin Pedrol ]
+ * vty: Make new libgtp tdefs configurable through VTY
+ * sndcp: Put decompress handling code into helper function
+ * Move gprs_gb_parse.[c,h] to tests/sgsn/
+ * Create new specific file for BSSGP code
+ * Move some functions gprs_gb.[c,h] -> gprs_gmm.[c,h]
+ * Rename gprs_gb.[c,h] -> gprs_ns.[c,h]
+ * Move gprs_tmr_to_secs() to tests/gprs/gprs_test.c
+ * cosmetic: gprs_llc_vty.c: Fix trailing whitespace
+ * vty: Fix wrong value_string used to print llme state
+ * Standarize lle and llme state enum & value_string
+ * Remove unused function gprs_parse_mi_tmsi()
+ * Replace gprs_str_to_apn() with libosmocore API osmo_apn_from_str()
+ * Move struct sgsn_ggsn_ctx to its own file gtp_ggsn.{c,h}
+ * gprs_subscriber: Move API declarations to correct header
+ * Move gprs_sndcp_vty_init() declaration to gprs_sndcp.h
+ * Introduce new header file sgsn/gtp.h
+ * Fix -Werror=old-style-definition
+ * Move related structs to gprs_subscriber.h
+ * Remove unneeded extern declaration from libosmocotrl
+ * Keep sgsn subsystems under struct sgsn_instance lifecycle
+ * Move global ggsn_list into struct sgsn_instance
+ * Move struct apn_ctx and APN related definitions to its own file
+ * Move struct sgsn_subscriber_pdp_data to gprs_subscriber.h
+ * sgsn.h: Drop declaration of non existing function
+ * Properly split llc->sndcp->gtp unitdata pathi through extra func call
+ * Move func defintions of funcs implemented in gprs_sndcp.c to gprs_sndcp.h
+ * sndcp: Standarize unitdata function naming
+ * Move gtp related functions to gtp.h
+ * Move global apn_list inside struct sgsn_instance
+ * gtp_{ggsn,mme}: Allocate contexts under struct sgsn_instance
+ * Move extern declarations of tall_sgsn_ctx to sgsn.h
+ * Drop extern declarations of global sgsn_instance in source files
+ * Move sgsn_pdp_ctx to its own file pdpctx.{c,h}
+ * Move global pdp_list inside struct sgsn_instance
+ * Move gtphub header to include/osmocom/gtphub/
+ * Move sgsn_ctrl_cmds_install() declaration to sgsn.h
+ * Move LOGGSUBSCRP to gprs_subscriber.h
+ * Rename bscconfig.h -> config.h
+ * gtphub.h: Remove dependency on sgsn/gprs_sgsn.h
+ * Split gprs_sgsn.{c,h} -> {auth,mmctx,sgsn}.{c,h}
+ * Move global mmctx list into struct sgsn_instance
+ * vty: Introduce encryption cipher-plugin-path command
+ * Fix extra whitespace in pdpctx_ctr_description
+
+ [ Oliver Smith ]
+ * contrib/jenkins.sh: use enable-werror with IU too
+ * sgsn_libgtp: cb_data_ind: remove mm_idle assert
+ * osmo-gtphub.cfg: fix conflict with osmo-ggsn.cfg
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 17:34:26 +0100
+
+osmo-sgsn (1.9.0) unstable; urgency=medium
+
+ [ Oliver Smith ]
+ * llme_free: clean up related sndcp
+ * treewide: remove FSF address
+
+ [ Pau Espin Pedrol ]
+ * Drop unneeded ax_check_compile_flag.m4
+ * Revert "sgsn: Handle different levels of QoS"
+
+ [ Neels Hofmeyr ]
+ * s/cipher_support_mask/gea_encryption_mask
+ * Iu: add UEA encryption
+
+ [ Vadim Yanitskiy ]
+ * tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
+
+ [ Harald Welte ]
+ * update git URLs (git -> https; gitea)
+ * README: Major update
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 29 Jun 2022 11:45:08 +0200
+
+osmo-sgsn (1.8.0) unstable; urgency=medium
+
+ [ Harald Welte ]
+ * Remove bogus DNS log category
+
+ [ Daniel Willmann ]
+ * manuals: Regenerate counters/VTY through docker
+
+ [ Vadim Yanitskiy ]
+ * main: resurrect removed 'ns' logging category as deprecated
+ * doc/manuals: update configuration.adoc to use new command syntax
+ * tests/Makefile.am: do not try removing non-existing files
+
+ [ Pau Espin Pedrol ]
+ * ranap: log ranap iu event type name instead of number
+ * gmm: log GMM msg type name instead of number
+ * gmm: Expect E_VLR_ANSWERED when in ST_IU_SECURITY_CMD
+ * gmm_fsm: Expect E_GMM_COMMON_PROC_INIT_REQ when in ST_GMM_COMMON_PROC_INIT
+ * mm_iu: Send event E_PMM_PS_CONN_ESTABLISH upon rx GMM SERVICE REQUEST
+ * mm_iu: Expect E_PMM_PS_ATTACH when in ST_PMM_IDLE
+ * gprs_gmm.c: State proper GMM prefix logging rx/tx of GMM messages
+ * mm_state_iu_fsm: T3314 expiry must lead to PMM IDLE, not PMM DETACHED
+ * Iu: Drop timer X3314
+ * gprs_ranap.c: Clean up code path releasing IU conn
+ * mm_state_{gb,iu}_fsm: Add missing license block, improve spec references
+ * mm_state_{gb,iu}_fsm: Improve naming for detach event
+ * Drop unused GBRPOXY enum field
+ * gtp: Delete ctx upon receive UpdateCtxResp with cause Non-existent
+ * Support forwarding RIM messages over GTPCv1 EUTRAN<->GERAN
+ * Use new stat item/ctr getter APIs
+
+ [ Keith ]
+ * vty: Fix optional display of pdp with mm-context
+ * VTY: Don't display 'PDP Address: invalid' for IPv4v6
+
+ [ Eric ]
+ * add support for multiple encryption algorithms and a5/4
+
+ [ Oliver Smith ]
+ * gtphub: remove llist_first, llist_last macros
+ * vty: add "page imsi"
+ * debian/control: remove dh-systemd build-depend
+ * Revert "Turn some compiler warnings into errors"
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 16 Nov 2021 17:57:50 +0100
+
+osmo-sgsn (1.7.0) unstable; urgency=medium
+
+ [ Daniel Willmann ]
+ * gprs_gmm: Check for RAT change and ensure this only happens for RAU/ATT
+ * gbproxy-usermanual: Explain BSSGP/BVC handling
+ * gbproxy: Whitespace fixes
+ * gbproxy: Add todo for BVC RESET logic
+ * gbproxy: Get the peer if paging by BVCI on SIG_BVC
+ * Let libosmocore handle VTY parent node tracking
+ * osmo-gbproxy: Free msgb in ns2 prim callback
+ * configure.ac: Require python3 for ext_tests
+ * osmo-gbproxy: Implement nsvc-state ctrl command
+ * gbproxy: Remove test testing NSVCI change
+ * gbproxy: Add NSE peer that can have multiple gbproxy_peers
+ * gbproxy: Ensure BVC0 is reset before handling PtP BVCs
+ * gbproxy: Only send paging to each matching NSE once
+ * gbproxy: Separate function to move gbproxy_peer to different nse
+ * gbproxy: Add logging macros for NSE and BVC
+ * gbproxy: Use LOG macros for NSE/BVC
+ * gbproxy: Change generic LOG messages so BVCI/NSEI fmt is consistent
+ * gbproxy: Add todos encountered while going through the code
+ * gbproxy: Add BVC log filters
+ * gbproxy: Add newline to log message
+ * gbproxy: Allow gbproxy_nse_free(NULL)
+ * gbproxy: Delete gbproxy_nse in delete-gbproxy-peer VTY command
+ * mm_state_gb_fsm: Handle implicit detach from mm_standby
+ * gbproxy: Fix bvci check in gbprox_rx_ptp_from_*
+ * osmo-gbproxy: Initialize all hash_maps
+ * gbproxy: Fix confusing log message in gbprox_relay2nse
+ * gbproxy: Add SGSN NRI configuration
+ * gbproxy: Add SGSN pooling support
+ * gbproxy: Add comments to sgsn functions
+ * gbproxy: Add config option to name an SGSN
+ * gbproxy: Add VTY command to override the node selection function
+ * Fix gbproxy_sgsn_by_tlli wraparound
+ * gbproxy: Implement TLLI cache and use it for SUSPEND/RESUME
+ * gbproxy: Increase TLLI cache timeout to 10s
+ * gbproxy: Implement IMSI cache
+ * gbproxy: Use IMSI cache to handle PAGING_PS_REJECT
+ * gbproxy: Use C-style comments
+ * gbproxy: Move helper function to a more logical place
+ * gbproxy: Remove unused variable assignment
+ * gbproxy: Fix VTY cmd name
+ * gbproxy: Define and use help string for gbproxy
+ * gbproxy: Add VTY commands to query the TLLI/IMSI cache
+ * gbproxy: Use IMSI cache for PTP paging and implement DUMMY_PAGING_PS
+ * gbproxy: Print the correct message type for dummy paging/paging reject
+ * gbproxy: Improve log messages in gbproxy_select_sgsn
+ * gbproxy: Fix radio status routing by TMSI
+ * manual/gbproxy: Update overview chapter
+ * Rename OsmoGbPROXY -> *Proxy
+ * manuals/gbproxy: Update configuration chapter
+ * manuals/gbproxy: Add osmo-bsc MSC pooling chapter from Neels as a base
+ * manuals/gbproxy: MSC -> SGSN for pooling chapter
+ * manuals/gbproxy: Move pooling to separate chapter
+
+ [ Alexander Couzens ]
+ * gprs_gmm_fsm.c: Implement RAT change between 2g and 3g
+ * gtphub: rename sgsn's oww osmo_sockaddr into sgsn_sockaddr
+ * gprs_llc: _bssgp_tx_dl_ud: ensure the LLME is valid before using it
+ * gmm: on invalid RA id reject the MS with an implicit detach
+ * gtphub_test: fix compilation error on gcc 10.2.0
+ * gtphub: fix compilation with gcc 10.2.0
+ * Port gbproxy to NS2
+ * sgsn: check for NULL of gprs_subscr_get_or_create()
+ * sgsn: Use the new NS2 api
+ * gbproxy: use ns2 vty2
+ * configure.ac: define a c standard instead of using the compilers default
+ * follow libosmocore/gprs_ns2 API changes of GPRS enums
+ * gbproxy: follow gprs_ns2 API vty changes
+ * sgsn: migrate to the new gprs_ns2_vty configuration
+ * follow libosmocore/gprs_ns2 API changes (gprs_ns2_dynamic_create_nse)
+
+ [ Neels Hofmeyr ]
+ * manual: explain IuPS, add SCCP/M3UA section from common chapters
+ * fix nullpointer: in gsm48_rx_gmm_ra_upd_req()
+ * gsup: send RAT type on LU
+ * gbproxy_test.c: fix mobile identity test data
+ * use new osmo_mobile_identity API everywhere
+
+ [ Eric ]
+ * tests: dlopen does not imply availability of dlsym..
+ * configure.ac: fix libtool issue with clang and sanitizer
+
+ [ Harald Welte ]
+ * gtphub_test: Fix compilation with gcc-10
+ * Fix memory leak when SNDCP de-fragmentation is used
+ * Treat RAU as implicit RESUME if GMM is suspended
+ * *.spec.in: Use %config(noreplace) to retain current config file
+ * Send a BVC-RESET to all persistent Gb interfaces at start-up
+ * Use osmo_fd_setup() whenever applicable
+ * Use osmo_fd_*_{disable,enable}
+ * gbproxy: Properly implement paging to LAC/RAC
+ * gbproxy: Implement paging to entire BSS area
+ * gprs_gb_parse: Add function to determine TLLI from encoded BSSGP
+ * gbproxy: Pass TLLI as LSP towards NS to facilitate load sharing
+ * gb_proxy_peer: Add some FIXMEs regarding invalid assumptions
+ * gb_proxy: More precise + readable log messages
+ * gb_proxy: Broadcast SGSN-INVOKE-TRACE and OVERLOAD
+ * gbproxy: Move BSS-side BVC-RESET processing to its own function
+ * gb_proxy: Slightly restructure processing of BSS-originated BVC-RESET
+ * gbproxy: Cosmetics: use longer lines
+ * gbproxy: Send BVC-STATUS if BSS sends us BVC-RESET without mandatory IEs
+ * gb_proxy: Use TLVP_PRES_LEN instead of TLVP_PRESENT
+ * gb_proxy: Rename gbproxy_peer to gbproxy_bvc
+ * gbproxy: Rename gbproxy_cfg.nses to gbproxy_cfg.bss_nses
+ * gbproxy: convert bss_nses from llist_head to hashtable
+ * gbproxy: convert nse->bvcs from llist_head to hashtable
+ * gbproxy: Remove patching, TLLI-tracking and SGSN2 support
+ * gb_proxy: cosmetic: Use function rather than open-coding is_sgsn
+ * gbproxy: Delete gbproxy_test
+ * gb_proxy: Introduce more validation / constraint checks
+ * gbproxy: use gbprox_relay2peer() whenever possible
+ * gb_proxy: Use osmo_tlv_prot_parse() to validate mandatory IEs
+ * gbproxy: Log FSM timeouts
+ * migrate to DLBSSGP as log sub-system for BSSGP
+ * gbproxy major rewrite for SGSN pool support
+ * gbproxy: Use "(nsei << 16) | bvci" as rate_ctr_group index
+ * gbproxy: Introduce new DOBJ log category; log object allocation/release
+ * gbproxy: Don't create an extra msgb copy for SGSN DL SIG
+ * gbproxy: Implement handling of BVC Flow Control
+ * gbproxy: Copy RA-ID from BSS side BVC to CELL and SGSN-side BVC
+ * gbproxy: (Re)allocate SGSN-side PTP BVC even if CELL already exists
+ * gbproxy: Fix segfault when receiving PAGING for unknown destination
+ * gbproxy: Add FSM related VTY commands
+ * gbproxy: Implement scaling of BVC flow control in SGSN pool
+ * gbproxy: Improve VTY state introspection
+ * gbproxy: rename vty command "show gbproxy ..." to "show gbproxy bvc ..."
+ * gbproxy: Add "show gbproxy cell ..." VTY command
+ * gbproxy: Fix build on Deiban 8
+ * gb_proxy: Don't use orphan log subsystem DPCU
+ * gbproxy: Avoid depending on any of the SGSN code
+ * main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
+ * manuals: generate vty reference xml at build time
+
+ [ Pau Espin Pedrol ]
+ * Use OSMO_FD_* instead of deprecated BSC_FD_*
+ * sgsn_libgtp: Improve ps-paging logging
+ * gprs_gmm_fsm.c: Add missing license header
+ * sgsn_libgtp: Avoid ps-paging MS on GMM Suspended state
+ * configure.ac: Fix trailing whitespace
+ * doc: Update VTY reference xml file
+ * Support setting rt-prio and cpu-affinity mask through VTY
+ * Change default SCTP conn NULL->127.0.0.1 to localhost->localhost
+ * contrib/jenkins: Enable parallel make in make distcheck
+ * Log error if pdp ctx is freed while holding an active timer
+ * Fix crash rx DeactPdpReq while waiting for DeactPdpAck after gtp side is freed
+ * sgsn_delete_pdp_ctx: Add documentation and assert assumptions
+ * process_ms_ctx_status: refactor to avoid code duplication
+ * process_ms_ctx_status: Fix crash deleting PDP Ctx if GTP side was already released
+ * gbproxy: generate coredump and exit upon SIGABRT received
+ * gtphub: generate coredump and exit upon SIGABRT received
+ * sgsn: generate coredump and exit upon SIGABRT received
+ * gmm: fix build without define PTMSI_ALLOC
+ * gmm: Introduce comment to ease addition of Network feature support IE later
+ * .gitignore: Ignore new autofoo tmp files
+ * sndcp: Fix struct bit fields on big endian
+ * Fix nsei+bvci not updated on rx UL SNDCP data
+
+ [ Oliver Smith ]
+ * contrib: import RPM spec
+ * contrib: integrate RPM spec
+ * Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
+ * contrib/jenkins: don't build osmo-gsm-manuals
+ * gbproxy: remove (moved to own repository)
+
+ [ Vadim Yanitskiy ]
+ * debian/control: change maintainer to the Osmocom team / mailing list
+ * gb_proxy_peer: sgsn can never be NULL in gbproxy_sgsn_by_nri()
+ * gb_proxy_peer: fix NULL pointer dereference in gbproxy_sgsn_alloc()
+
+ [ Keith ]
+ * Fix Radio Priority in MM Attach and PDP Context Activation
+ * VTY: Add gtp state-dir command
+
+ [ Philipp Maier ]
+ * gprs_sndcp: fix use after free
+ * sgsn_rim: Add routing for (GERAN) BSSGP RIM messages
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 23 Feb 2021 20:29:33 +0100
+
osmo-sgsn (1.6.0) unstable; urgency=medium
[ Pau Espin Pedrol ]
diff --git a/debian/compat b/debian/compat
index ec635144f..f599e28b8 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-9
+10
diff --git a/debian/control b/debian/control
index fe2f1e63f..aa594553b 100644
--- a/debian/control
+++ b/debian/control
@@ -2,9 +2,8 @@ Source: osmo-sgsn
Section: net
Priority: extra
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
-Build-Depends: debhelper (>=9),
+Build-Depends: debhelper (>= 10),
dh-autoreconf,
- dh-systemd (>= 1.5),
autotools-dev,
autoconf,
automake,
@@ -12,19 +11,19 @@ Build-Depends: debhelper (>=9),
pkg-config,
libtalloc-dev,
libc-ares-dev,
- libgtp-dev (>= 1.5.0),
- libosmocore-dev (>= 1.4.0),
- libosmo-abis-dev (>= 0.6.0),
- libosmo-netif-dev (>= 0.4.0),
- libosmo-gsup-client-dev (>= 1.0.0),
+ libgtp-dev (>= 1.11.0),
+ libosmocore-dev (>= 1.9.0),
+ libosmo-abis-dev (>= 1.5.0),
+ libosmo-netif-dev (>= 1.4.0),
+ libosmo-gsup-client-dev (>= 1.7.0),
libasn1c-dev (>= 0.9.30),
- libosmo-ranap-dev (>= 0.6.0),
- libosmo-sigtran-dev (>= 1.0.0),
- libosmo-sccp-dev (>= 1.0.0),
- osmo-gsm-manuals-dev
+ libosmo-ranap-dev (>= 1.5.0),
+ libosmo-sigtran-dev (>= 1.8.0),
+ libosmo-sccp-dev (>= 1.8.0),
+ osmo-gsm-manuals-dev (>= 1.5.0)
Standards-Version: 3.9.8
-Vcs-Git: git://git.osmocom.org/osmo-sgsn.git
-Vcs-Browser: https://git.osmocom.org/osmo-sgsn
+Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
+Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
Homepage: https://projects.osmocom.org/projects/osmo-sgsn
diff --git a/debian/copyright b/debian/copyright
index dd7b6672b..cd8d7e84c 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,6 +1,6 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: osmo-sgsn
-Source: git://git.osmocom.org/osmo-sgsn
+Source: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn
Files: .gitignore
.gitreview
@@ -33,7 +33,6 @@ Files: .gitignore
include/osmocom/sgsn/crc24.h
include/osmocom/sgsn/debug.h
include/osmocom/sgsn/gb_proxy.h
- include/osmocom/sgsn/gprs_gb_parse.h
include/osmocom/sgsn/gprs_gmm.h
include/osmocom/sgsn/gprs_llc.h
include/osmocom/sgsn/gprs_sgsn.h
@@ -53,6 +52,7 @@ Files: .gitignore
tests/gprs/gprs_test.ok
tests/gtphub/Makefile.am
tests/gtphub/gtphub_test.ok
+ tests/sgsn/gprs_gb_parse.h
tests/sgsn/Makefile.am
tests/sgsn/sgsn_test.ok
tests/slhc/Makefile.am
@@ -74,11 +74,10 @@ Files: include/osmocom/sgsn/a_reset.h
include/osmocom/sgsn/gprs_sndcp_pcomp.h
include/osmocom/sgsn/gprs_sndcp_xid.h
include/osmocom/sgsn/gprs_utils.h
- include/osmocom/sgsn/gtphub.h
+ include/osmocom/gtphub/gtphub.h
include/osmocom/sgsn/signal.h
src/gprs/gprs_llc_parse.c
src/gprs/crc24.c
- src/gprs/gprs_gb_parse.c
src/gprs/gprs_utils.c
src/gprs/sgsn_ares.c
src/gtphub/gtphub.c
@@ -103,6 +102,7 @@ Files: include/osmocom/sgsn/a_reset.h
src/sgsn/sgsn_main.c
src/sgsn/sgsn_vty.c
tests/gtphub/gtphub_test.c
+ tests/sgsn/gprs_gb_parse.c
tests/sgsn/sgsn_test.c
tests/slhc/slhc_test.c
tests/sndcp_xid/sndcp_xid_test.c
diff --git a/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg b/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
index 3913d2c3c..d4dadf901 100644
--- a/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
+++ b/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
@@ -5,6 +5,14 @@
! For the test, try to use most config commands.
!
+log stderr
+ logging color 1
+ logging print category-hex 0
+ logging print category 1
+ logging timestamp 0
+ logging print file basename last
+ logging print level 1
+
line vty
no login
diff --git a/doc/examples/osmo-gtphub/osmo-gtphub.cfg b/doc/examples/osmo-gtphub/osmo-gtphub.cfg
index 0bb63e312..da9bba59a 100644
--- a/doc/examples/osmo-gtphub/osmo-gtphub.cfg
+++ b/doc/examples/osmo-gtphub/osmo-gtphub.cfg
@@ -2,6 +2,14 @@
! Osmocom gtphub configuration
!
+log stderr
+ logging color 1
+ logging print category-hex 0
+ logging print category 1
+ logging timestamp 0
+ logging print file basename last
+ logging print level 1
+
line vty
no login
@@ -9,7 +17,7 @@ gtphub
! Local addresses to listen on and send from, each on standard ports
! 2123 and 2152. Setting these addresses is mandatory.
bind-to-sgsns 127.0.0.10
- bind-to-ggsns 127.0.0.2
+ bind-to-ggsns 127.0.0.20
! Local nonstandard ports or separate IPs:
!bind-to-sgsns ctrl 127.0.0.1 2342 user 127.0.0.1 4223
diff --git a/doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg b/doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg
index 7abe7b38e..69000b439 100644
--- a/doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg
+++ b/doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg
@@ -2,6 +2,14 @@
! Osmocom SGSN configuration
!
!
+log stderr
+ logging color 1
+ logging print category-hex 0
+ logging print category 1
+ logging timestamp 0
+ logging print file basename last
+ logging print level 1
+
line vty
no login
!
diff --git a/doc/examples/osmo-sgsn/osmo-sgsn.cfg b/doc/examples/osmo-sgsn/osmo-sgsn.cfg
index 11413c1b2..0b5ef4b19 100644
--- a/doc/examples/osmo-sgsn/osmo-sgsn.cfg
+++ b/doc/examples/osmo-sgsn/osmo-sgsn.cfg
@@ -2,6 +2,14 @@
! Osmocom SGSN configuration
!
!
+log stderr
+ logging color 1
+ logging print category-hex 0
+ logging print category 1
+ logging timestamp 0
+ logging print file basename last
+ logging print level 1
+
line vty
no login
!
diff --git a/doc/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg b/doc/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg
index fd5a20560..a7ed9cf1e 100644
--- a/doc/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg
+++ b/doc/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg
@@ -2,6 +2,14 @@
! Osmocom SGSN configuration
!
!
+log stderr
+ logging color 1
+ logging print category-hex 0
+ logging print category 1
+ logging timestamp 0
+ logging print file basename last
+ logging print level 1
+
line vty
no login
!
@@ -9,6 +17,8 @@ cs7 instance 0
point-code 0.23.4
asp asp-clnt-OsmoSGSN-A 2905 0 m3ua
remote-ip 172.18.8.200 ! where to reach the STP
+ role asp
+ sctp-role client
as as-clnt-OsmoSGSN-A m3ua
asp asp-clnt-OsmoSGSN-A
routing-key 3 0.23.4
diff --git a/doc/manuals/chapters/configuration.adoc b/doc/manuals/chapters/configuration.adoc
index 7d3072ec0..d6ddcd34a 100644
--- a/doc/manuals/chapters/configuration.adoc
+++ b/doc/manuals/chapters/configuration.adoc
@@ -11,7 +11,8 @@ explicit configuration of each PCU connecting to the SGSN. The
administrator only has to ensure that the NS and BSSGP layer identities
(NSEI, NSVCI, BVCI) are unique for each PCU connecting to the SGSN.
-=== Configuring the Gp interface
+[[gp-if-ggsn]]
+=== Configuring the Gp interface (towards GGSN)
The Gp interface is the GTP-C and GTP-U based interface between the SGSN
and the GGSNs. It is implemented via UDP on well-known source and
@@ -67,6 +68,58 @@ OsmoSGSN(config-sgsn)# grx-dns-add 1.2.3.4 <3>
<2> Enable the dynamic GGSN resolving mode
<3> Specify the IP address of a DNS server for APN resolution
+[[gp-if-mme]]
+=== Configuring the Gp interface (towards MME)
+
+The Gp interface also contains the GTP-C v1 based interface between the SGSN
+and the MMEs. This interface between SGSN and MMEs is used to transfer _RAN
+Information Relay_ GTP-C messages between them, which are used as containers to
+allow PCUs under the SGSN and eNodeBs under MMEs to exchange cell information
+(RIM).
+
+In the SGSN, this interface re-uses the same socket local configuration as per
+the GGSN connections (see _gtp local-ip_ VTY command in <<gp-if-ggsn>>).
+
+Similarly as with GGSNs, (again see <<gp-if-ggsn>>), selection of destination
+peers for the _RAN Information Relay_ message can be configured statically or
+dynamically over GRX.
+
+
+==== Static MME/TAI configuration
+
+In this mode, there is a static list of MMEs and TAIs configured in
+OsmoSGSN via the VTY / config file. One MME in the list can be configured as the
+_default route_, where all unspecified TAIs are routed too.
+
+This is a non-standard method outside of the 3GPP specifications for the
+SGSN, and is typically only used in private/small GPRS networks without
+any access to a GRX.
+
+.Example: Static MME/TAI configuration (single catch-all GGSN)
+----
+sgsn
+...
+ gtp local-ip 192.168.0.10 <1>
+ mme test-mme0 <2>
+ gtp remote-ip 192.168.0.20 <3>
+ gtp ran-info-relay 262 42 3 <4>
+ gtp ran-info-relay 262 42 4
+ mme test-mme1 <5>
+ gtp remote-ip 192.168.0.30
+ gtp ran-info-relay default <6>
+----
+<1> Configure the local IP address at the SGSN used for Gp/GTP
+<2> Configure an MME named "test-mme0"
+<3> Specify the remote IP address of the MME (for MME "test-mme0")
+<4> Route specified TAIs towards this MME
+<5> Configure an MME named "test-mme1"
+<6> Route all TAIs with an unspecified MME towards MM "test-mme1"
+
+==== Dynamic MME/TAI configuration
+
+Dynamic MME/TAI peer look up over GRX is not yet supported by OsmoSGSN.
+
+
[[auth-pol]]
=== Authorization Policy
@@ -345,16 +398,16 @@ Encryption can be enabled if the auth-policy is set to remote and the
HLR subscriber entries contain the keys of the SIM card. See
<<sgsn-ex-gsup>> on how to connect to an external HLR.
-.Example: Turn on encryption (GEA3)
+.Example: Turn on encryption (GEA3 and GEA4)
----
sgsn
- encryption GEA3
+ encryption gea 3 4
----
.Example: Turn off encryption (GEA0)
----
sgsn
- encryption GEA0
+ encryption gea 0
----
=== Configure SCCP/M3UA to accept _IuPS_ links
@@ -369,6 +422,7 @@ cs7 instance 0
point-code 0.23.4
asp asp-clnt-OsmoSGSN 2905 0 m3ua
remote-ip 127.0.0.1
+ role asp
sctp-role client
as as-clnt-OsmoSGSN m3ua
asp asp-clnt-OsmoSGSN
diff --git a/doc/manuals/regen_doc.sh b/doc/manuals/regen_doc.sh
index 9fcebb8b4..5c84a2321 100755
--- a/doc/manuals/regen_doc.sh
+++ b/doc/manuals/regen_doc.sh
@@ -1,71 +1,17 @@
-#!/bin/sh -e
+#!/bin/sh -x
-require_osmo_interact_vty() {
- if command -v osmo_interact_vty.py >/dev/null 2>&1; then
- return
- fi
- echo "ERROR: osmo_interact_vty.py not found. Are osmo-python-tests in PATH?"
+if [ -z "$DOCKER_PLAYGROUND" ]; then
+ echo "You need to set DOCKER_PLAYGROUND"
exit 1
-}
+fi
-# $1: "update_vty_reference" or "update_counters"
-# $2: output file
-# $3: port
-# $4-$n: command
-interact_vty() {
- action="$1"
- output="$2"
- port="$3"
- log="/tmp/$4.log"
- shift 3
+SCRIPT=$(realpath "$0")
+MANUAL_DIR=$(dirname "$SCRIPT")
- echo "Starting in background: $@"
- "$@" > "$log" 2>&1 &
- pid="$!"
+COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
- sleep 0.5
- if ! kill -0 "$pid" 2>/dev/null; then
- echo "ERROR: start failed!"
- cat "$log"
- exit 1
- fi
+cd "$DOCKER_PLAYGROUND/scripts" || exit 1
- case "$action" in
- "update_vty_reference")
- echo "Updating VTY reference: $output"
- osmo_interact_vty.py -X -p "$port" -H 127.0.0.1 -O "$output"
- ;;
- "update_counters")
- echo "Updating asciidoc counters: $output"
- osmo_interact_vty.py -c "enable;show asciidoc counters" -p "$port" -H 127.0.0.1 -O "$output"
- ;;
- *)
- echo "ERROR: invalid argument: $action"
- exit 1
- ;;
- esac
-
- kill "$pid"
- echo "Done (killed $1)"
- echo
-}
-
-DIR="$(cd "$(dirname "$0")"; pwd)"
-cd "$DIR"
-
-require_osmo_interact_vty
-
-interact_vty \
- "update_vty_reference" \
- "vty/sgsn_vty_reference.xml" \
- 4245 \
- osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
-
-interact_vty \
- "update_counters" \
- "chapters/counters_generated.adoc" \
- 4245 \
- osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
-
-
-echo "Done with all"
+OSMO_BSC_BRANCH=$COMMIT ./regen_doc.sh osmo-sgsn 4245 \
+ "$MANUAL_DIR/chapters/counters_generated.adoc" \
+ "$MANUAL_DIR/vty/sgsn_vty_reference.xml"
diff --git a/include/osmocom/Makefile.am b/include/osmocom/Makefile.am
index 09db97a95..f5bc76a4f 100644
--- a/include/osmocom/Makefile.am
+++ b/include/osmocom/Makefile.am
@@ -1,3 +1,4 @@
SUBDIRS = \
+ gtphub \
sgsn \
$(NULL)
diff --git a/include/osmocom/gtphub/Makefile.am b/include/osmocom/gtphub/Makefile.am
new file mode 100644
index 000000000..c61dad9d4
--- /dev/null
+++ b/include/osmocom/gtphub/Makefile.am
@@ -0,0 +1,3 @@
+noinst_HEADERS = \
+ gtphub.h \
+ $(NULL)
diff --git a/include/osmocom/sgsn/gtphub.h b/include/osmocom/gtphub/gtphub.h
index 6a439b576..dbf8469bc 100644
--- a/include/osmocom/sgsn/gtphub.h
+++ b/include/osmocom/gtphub/gtphub.h
@@ -27,9 +27,7 @@
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/rate_ctr.h>
-
-#include <osmocom/sgsn/gprs_sgsn.h>
-
+#include <osmocom/gsm/apn.h>
/* support */
@@ -428,7 +426,7 @@ struct gtphub_resolved_ggsn {
/* The APN OI, the Operator Identifier, is the combined address,
* including parts of the IMSI and APN NI, and ending with ".gprs". */
- char apn_oi_str[GSM_APN_LENGTH];
+ char apn_oi_str[APN_MAXLEN+1];
/* Which address and port we resolved that to. */
struct gtphub_peer_port *peer;
diff --git a/include/osmocom/sgsn/Makefile.am b/include/osmocom/sgsn/Makefile.am
index 51bdee8f7..aa6cd0f0f 100644
--- a/include/osmocom/sgsn/Makefile.am
+++ b/include/osmocom/sgsn/Makefile.am
@@ -1,18 +1,19 @@
noinst_HEADERS = \
+ apn.h \
+ auth.h \
common.h \
crc24.h \
debug.h \
- gprs_gb.h \
- gprs_gb_parse.h \
+ gprs_bssgp.h \
gprs_gmm.h \
gprs_gmm_fsm.h \
gprs_gmm_attach.h \
gprs_mm_state_gb_fsm.h \
gprs_mm_state_iu_fsm.h \
+ gprs_ns.h \
gprs_llc.h \
gprs_llc_xid.h \
gprs_ranap.h \
- gprs_sgsn.h \
gprs_sm.h \
gprs_sndcp_comp.h \
gprs_sndcp_dcomp.h \
@@ -21,7 +22,11 @@ noinst_HEADERS = \
gprs_sndcp_xid.h \
gprs_subscriber.h \
gprs_utils.h \
- gtphub.h \
+ gtp.h \
+ gtp_ggsn.h \
+ gtp_mme.h \
+ mmctx.h \
+ pdpctx.h \
sgsn.h \
sgsn_rim.h \
signal.h \
diff --git a/include/osmocom/sgsn/apn.h b/include/osmocom/sgsn/apn.h
new file mode 100644
index 000000000..3dc7a70ca
--- /dev/null
+++ b/include/osmocom/sgsn/apn.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <osmocom/core/linuxlist.h>
+
+struct sgsn_ggsn_ctx;
+
+#define GSM_APN_LENGTH 102
+
+struct apn_ctx {
+ struct llist_head list;
+ struct sgsn_ggsn_ctx *ggsn;
+ char *name;
+ char *imsi_prefix;
+ char *description;
+};
+
+struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix);
+void sgsn_apn_ctx_free(struct apn_ctx *actx);
+struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix);
+struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix);
diff --git a/include/osmocom/sgsn/auth.h b/include/osmocom/sgsn/auth.h
new file mode 100644
index 000000000..a46fb16bb
--- /dev/null
+++ b/include/osmocom/sgsn/auth.h
@@ -0,0 +1,39 @@
+/* MS authorization and subscriber data handling */
+#pragma once
+
+#include <osmocom/core/linuxlist.h>
+
+struct sgsn_config;
+struct sgsn_instance;
+struct sgsn_mm_ctx;
+struct gsm_auth_tuple;
+
+/* Authorization/ACL handling */
+enum sgsn_auth_state {
+ SGSN_AUTH_UNKNOWN,
+ SGSN_AUTH_AUTHENTICATE,
+ SGSN_AUTH_UMTS_RESYNC,
+ SGSN_AUTH_ACCEPTED,
+ SGSN_AUTH_REJECTED
+};
+
+extern const struct value_string *sgsn_auth_state_names;
+
+void sgsn_auth_init(struct sgsn_instance *sgsn);
+/* Request authorization */
+enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm);
+int sgsn_auth_request(struct sgsn_mm_ctx *mm);
+void sgsn_auth_update(struct sgsn_mm_ctx *mm);
+struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx,
+ unsigned key_seq);
+
+/*
+ * Authorization/ACL handling
+ */
+struct imsi_acl_entry {
+ struct llist_head list;
+ char imsi[OSMO_IMSI_BUF_SIZE];
+};
+struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, const struct sgsn_config *cfg);
+int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg);
+int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg);
diff --git a/include/osmocom/sgsn/crc24.h b/include/osmocom/sgsn/crc24.h
index 756638c03..c913eaf76 100644
--- a/include/osmocom/sgsn/crc24.h
+++ b/include/osmocom/sgsn/crc24.h
@@ -5,6 +5,6 @@
#define INIT_CRC24 0xffffff
-uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len);
+uint32_t crc24_calc(uint32_t fcs, const uint8_t *cp, unsigned int len);
#endif
diff --git a/include/osmocom/sgsn/debug.h b/include/osmocom/sgsn/debug.h
index 37e4a097d..80c5d9fc6 100644
--- a/include/osmocom/sgsn/debug.h
+++ b/include/osmocom/sgsn/debug.h
@@ -13,7 +13,6 @@ enum {
DMEAS,
DREF,
DGPRS,
- DNS,
DLLC,
DSNDCP,
DSLHC,
diff --git a/include/osmocom/sgsn/gprs_bssgp.h b/include/osmocom/sgsn/gprs_bssgp.h
new file mode 100644
index 000000000..0feaa9762
--- /dev/null
+++ b/include/osmocom/sgsn/gprs_bssgp.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <osmocom/core/msgb.h>
+
+/* Called by bssgp layer when a prim is received from lower layers. */
+int sgsn_bssgp_rx_prim(struct osmo_prim_hdr *oph);
+
+/* called by the bssgp layer to send NS PDUs */
+int sgsn_bssgp_dispatch_ns_unitdata_req_cb(void *ctx, struct msgb *msg);
+
+/* page a MS in its routing area */
+int sgsn_bssgp_page_ps_ra(struct sgsn_mm_ctx *mmctx);
diff --git a/include/osmocom/sgsn/gprs_gb.h b/include/osmocom/sgsn/gprs_gb.h
deleted file mode 100644
index 916236761..000000000
--- a/include/osmocom/sgsn/gprs_gb.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#pragma once
-
-#include <stdbool.h>
-
-#include <osmocom/core/msgb.h>
-#include <osmocom/sgsn/gprs_llc.h>
-
-int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
- bool drop_cipherable);
-/* Has to be called whenever any PDU (signaling, data, ...) has been received */
-void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg);
-
-/* page a MS in its routing area */
-int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx);
-
-/* called by the bssgp layer to send NS PDUs */
-int gprs_gb_send_cb(void *ctx, struct msgb *msg);
-
-/* called by the ns layer */
-int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
diff --git a/include/osmocom/sgsn/gprs_gmm.h b/include/osmocom/sgsn/gprs_gmm.h
index e2b17d217..71dd1fa7f 100644
--- a/include/osmocom/sgsn/gprs_gmm.h
+++ b/include/osmocom/sgsn/gprs_gmm.h
@@ -1,10 +1,14 @@
#ifndef _GPRS_GMM_H
#define _GPRS_GMM_H
+#include <stdbool.h>
+
#include <osmocom/core/msgb.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/crypt/auth.h>
-#include <stdbool.h>
+struct sgsn_mm_ctx;
+struct gprs_llc_llme;
int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
const struct osmo_auth_vector *vec,
@@ -28,6 +32,11 @@ int gprs_gmm_rx_suspend(struct gprs_ra_id *raid, uint32_t tlli);
int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
uint8_t suspend_ref);
+int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
+ bool drop_cipherable);
+/* Has to be called whenever any PDU (signaling, data, ...) has been received */
+void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg);
+
time_t gprs_max_time_to_idle(void);
int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type);
diff --git a/include/osmocom/sgsn/gprs_gmm_fsm.h b/include/osmocom/sgsn/gprs_gmm_fsm.h
index f10851e5c..2f0e81a09 100644
--- a/include/osmocom/sgsn/gprs_gmm_fsm.h
+++ b/include/osmocom/sgsn/gprs_gmm_fsm.h
@@ -1,8 +1,10 @@
#pragma once
#include <osmocom/core/fsm.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
+
+struct gprs_llc_llme;
/* 3GPP TS 24.008 § 4.1.3.3 GMM mobility management states on the network side */
enum gmm_fsm_states {
diff --git a/include/osmocom/sgsn/gprs_llc.h b/include/osmocom/sgsn/gprs_llc.h
index ce0e63c51..6f0e4922f 100644
--- a/include/osmocom/sgsn/gprs_llc.h
+++ b/include/osmocom/sgsn/gprs_llc.h
@@ -1,11 +1,16 @@
-#ifndef _GPRS_LLC_H
-#define _GPRS_LLC_H
+#pragma once
#include <stdint.h>
#include <stdbool.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+
+#include <osmocom/core/timer.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/crypt/gprs_cipher.h>
+
#include <osmocom/sgsn/gprs_llc_xid.h>
+struct sgsn_mm_ctx;
+
/* Section 4.7 LLC Layer Structure */
enum gprs_llc_sapi {
GPRS_SAPI_GMM = 1,
@@ -91,6 +96,7 @@ enum gprs_llc_lle_state {
GPRS_LLES_LOCAL_REL = 6, /* Local Release */
GPRS_LLES_TIMER_REC = 7, /* Timer Recovery */
};
+extern const struct value_string gprs_llc_lle_state_names[];
enum gprs_llc_llme_state {
GPRS_LLMS_UNASSIGNED = 1, /* No TLLI yet */
@@ -272,18 +278,15 @@ static inline int gprs_llc_is_retransmit(uint16_t nu, uint16_t vur)
}
/* LLC low level functions */
-void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme);
+void gprs_llme_copy_key(const struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme);
/* parse a GPRS LLC header, also check for invalid frames */
int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
uint8_t *llc_hdr, int len);
void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph, struct gprs_llc_lle *lle);
-int gprs_llc_fcs(uint8_t *data, unsigned int len);
+int gprs_llc_fcs(const uint8_t *data, unsigned int len);
/* LLME handling routines */
struct llist_head *gprs_llme_list(void);
struct gprs_llc_lle *gprs_lle_get_or_create(const uint32_t tlli, uint8_t sapi);
-
-
-#endif
diff --git a/include/osmocom/sgsn/gprs_mm_state_gb_fsm.h b/include/osmocom/sgsn/gprs_mm_state_gb_fsm.h
index e69e1e11c..4237c2f94 100644
--- a/include/osmocom/sgsn/gprs_mm_state_gb_fsm.h
+++ b/include/osmocom/sgsn/gprs_mm_state_gb_fsm.h
@@ -5,7 +5,7 @@
struct sgsn_mm_ctx;
-/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
+/* TS 23.060 § 6.1.1 Mobility Management States (A/Gb mode) */
enum mm_state_gb_fsm_states {
ST_MM_IDLE,
ST_MM_READY,
@@ -14,9 +14,8 @@ enum mm_state_gb_fsm_states {
enum mm_state_gb_fsm_events {
E_MM_GPRS_ATTACH,
- /* E_GPRS_DETACH, TODO: not used */
+ E_MM_GPRS_DETACH, /* MS becomes detached: due to Detach Req, RAU reject, implicit detach, etc. */
E_MM_PDU_RECEPTION,
- E_MM_IMPLICIT_DETACH, /* = E_MM_CANCEL_LOCATION */
E_MM_READY_TIMER_EXPIRY,
/* E_FORCE_TO_STANDBY, TODO: not used */
/* E_ABNSORMAL_RLC_CONDITION, TODO: not used */
diff --git a/include/osmocom/sgsn/gprs_mm_state_iu_fsm.h b/include/osmocom/sgsn/gprs_mm_state_iu_fsm.h
index 05342f9fb..6dae759b0 100644
--- a/include/osmocom/sgsn/gprs_mm_state_iu_fsm.h
+++ b/include/osmocom/sgsn/gprs_mm_state_iu_fsm.h
@@ -4,8 +4,7 @@
struct sgsn_mm_ctx;
-
-/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
+/* TS 23.060 § 6.1.2 Mobility Management States (Iu mode) */
enum mm_state_iu_fsm_states {
ST_PMM_DETACHED,
ST_PMM_CONNECTED,
@@ -14,12 +13,10 @@ enum mm_state_iu_fsm_states {
enum mm_state_iu_fsm_events {
E_PMM_PS_ATTACH,
- /* E_PS_DETACH, TODO: not used */
+ E_PMM_PS_DETACH, /* UE becomes detached: due to Detach Req, RAU reject, implicit detach, etc. */
E_PMM_PS_CONN_RELEASE,
E_PMM_PS_CONN_ESTABLISH,
- E_PMM_IMPLICIT_DETACH, /* = E_PS_ATTACH_REJECT, E_RAU_REJECT */
E_PMM_RA_UPDATE, /* = Serving RNC relocation */
- E_PMM_USER_INACTIVITY, /* when the inactivity timer runs out */
};
extern struct osmo_fsm mm_state_iu_fsm;
diff --git a/include/osmocom/sgsn/gprs_ns.h b/include/osmocom/sgsn/gprs_ns.h
new file mode 100644
index 000000000..235b118ec
--- /dev/null
+++ b/include/osmocom/sgsn/gprs_ns.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <stdbool.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/sgsn/gprs_llc.h>
+
+/* called by the ns layer */
+int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
diff --git a/include/osmocom/sgsn/gprs_ranap.h b/include/osmocom/sgsn/gprs_ranap.h
index 62fdf6f2d..68f9115d7 100644
--- a/include/osmocom/sgsn/gprs_ranap.h
+++ b/include/osmocom/sgsn/gprs_ranap.h
@@ -1,13 +1,15 @@
#pragma once
#include <osmocom/core/msgb.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
#ifdef BUILD_IU
#include <osmocom/ranap/ranap_ies_defs.h>
#include <osmocom/ranap/ranap_msg_factory.h>
#include <osmocom/ranap/iu_client.h>
+struct sgsn_mm_ctx;
+struct sgsn_pdp_ctx;
+
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx);
int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data);
int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp);
diff --git a/include/osmocom/sgsn/gprs_sm.h b/include/osmocom/sgsn/gprs_sm.h
index 55c95b89d..78bb2d8c3 100644
--- a/include/osmocom/sgsn/gprs_sm.h
+++ b/include/osmocom/sgsn/gprs_sm.h
@@ -1,7 +1,10 @@
#pragma once
#include <osmocom/core/msgb.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+
+struct sgsn_mm_ctx;
+struct sgsn_pdp_ctx;
+struct gprs_llc_llme;
int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause, bool teardown);
int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
diff --git a/include/osmocom/sgsn/gprs_sndcp.h b/include/osmocom/sgsn/gprs_sndcp.h
index d970240e4..30ea05308 100644
--- a/include/osmocom/sgsn/gprs_sndcp.h
+++ b/include/osmocom/sgsn/gprs_sndcp.h
@@ -3,6 +3,9 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/gsm48.h>
+
+struct gprs_llc_lle;
/* A fragment queue header, maintaining list of fragments for one N-PDU */
struct defrag_state {
@@ -60,6 +63,8 @@ struct gprs_sndcp_entity {
extern struct llist_head gprs_sndcp_entities;
+int gprs_sndcp_vty_init(void);
+
/* Set of SNDCP-XID negotiation (See also: TS 144 065,
* Section 6.8 XID parameter negotiation) */
int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi);
@@ -68,7 +73,7 @@ int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi);
* Section 6.8 XID parameter negotiation) */
int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication,
struct gprs_llc_xid_field *xid_field_response,
- struct gprs_llc_lle *lle);
+ const struct gprs_llc_lle *lle);
/* Process SNDCP-XID indication
* (See also: TS 144 065, Section 6.8 XID parameter negotiation) */
@@ -76,4 +81,21 @@ int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf,
struct gprs_llc_xid_field *xid_field_request,
struct gprs_llc_lle *lle);
+/* Clean up all gprs_sndcp_entities related to llme (OS#4824) */
+void gprs_sndcp_sm_deactivate_ind_by_llme(const struct gprs_llc_llme *llme);
+
+/* Called by SNDCP when it has received/re-assembled a N-PDU */
+int sndcp_sn_unitdata_ind(struct gprs_sndcp_entity *sne, struct msgb *msg,
+ uint32_t npdu_len, uint8_t *npdu);
+int sndcp_sn_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
+ void *mmcontext);
+
+/* Entry point for the SNSM-ACTIVATE.indication */
+int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
+/* Entry point for the SNSM-DEACTIVATE.indication */
+int sndcp_sm_deactivate_ind(const struct gprs_llc_lle *lle, uint8_t nsapi);
+
+int sndcp_ll_unitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
+ uint8_t *hdr, uint16_t len);
+
#endif /* INT_SNDCP_H */
diff --git a/include/osmocom/sgsn/gprs_subscriber.h b/include/osmocom/sgsn/gprs_subscriber.h
index d36db7500..0d4a5947e 100644
--- a/include/osmocom/sgsn/gprs_subscriber.h
+++ b/include/osmocom/sgsn/gprs_subscriber.h
@@ -4,10 +4,70 @@
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/socket.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
+#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
+
+#include <osmocom/sgsn/apn.h>
+
+struct sgsn_instance;
+struct sgsn_mm_ctx;
extern struct llist_head * const gprs_subscribers;
+#define GPRS_SUBSCRIBER_FIRST_CONTACT 0x00000001
+#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING (1 << 16)
+#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING (1 << 17)
+#define GPRS_SUBSCRIBER_CANCELLED (1 << 18)
+#define GPRS_SUBSCRIBER_ENABLE_PURGE (1 << 19)
+
+#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \
+ GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \
+ GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING \
+)
+
+struct gsm_auth_tuple {
+ int use_count;
+ int key_seq;
+ struct osmo_auth_vector vec;
+};
+#define GSM_KEY_SEQ_INVAL 7 /* GSM 04.08 - 10.5.1.2 */
+
+struct sgsn_subscriber_data {
+ struct sgsn_mm_ctx *mm;
+ struct gsm_auth_tuple auth_triplets[5];
+ int auth_triplets_updated;
+ struct llist_head pdp_list;
+ int error_cause;
+
+ uint8_t msisdn[9];
+ size_t msisdn_len;
+
+ uint8_t hlr[9];
+ size_t hlr_len;
+
+ uint8_t pdp_charg[2];
+ bool has_pdp_charg;
+};
+
+/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */
+/* see GSM 09.02, B.1, gprsSubscriptionData */
+struct sgsn_subscriber_pdp_data {
+ struct llist_head list;
+
+ unsigned int context_id;
+ enum gsm48_pdp_type_org pdp_type_org;
+ enum gsm48_pdp_type_nr pdp_type_nr;
+ struct osmo_sockaddr pdp_address[2];
+ char apn_str[GSM_APN_LENGTH];
+ uint8_t qos_subscribed[20];
+ size_t qos_subscribed_len;
+ uint8_t pdp_charg[2];
+ bool has_pdp_charg;
+};
+
+struct sgsn_subscriber_pdp_data *sgsn_subscriber_pdp_data_alloc(struct sgsn_subscriber_data *sdata);
+
struct gprs_subscr {
struct llist_head entry;
int use_count;
@@ -29,3 +89,22 @@ struct gprs_subscr *_gprs_subscr_put(struct gprs_subscr *gsub,
const char *file, int line);
#define gprs_subscr_get(gsub) _gprs_subscr_get(gsub, __FILE__, __LINE__)
#define gprs_subscr_put(gsub) _gprs_subscr_put(gsub, __FILE__, __LINE__)
+
+int gprs_subscr_init(struct sgsn_instance *sgi);
+int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx);
+int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx,
+ const uint8_t *auts,
+ const uint8_t *auts_rand);
+void gprs_subscr_cleanup(struct gprs_subscr *subscr);
+struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi);
+struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx);
+struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi);
+void gprs_subscr_cancel(struct gprs_subscr *subscr);
+void gprs_subscr_update(struct gprs_subscr *subscr);
+void gprs_subscr_update_auth_info(struct gprs_subscr *subscr);
+int gprs_subscr_rx_gsup_message(struct msgb *msg);
+
+#define LOGGSUBSCRP(level, subscr, fmt, args...) \
+ LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \
+ (subscr) ? (subscr)->imsi : "---", \
+ ## args)
diff --git a/include/osmocom/sgsn/gprs_utils.h b/include/osmocom/sgsn/gprs_utils.h
index eacaec7a2..1e6c8319c 100644
--- a/include/osmocom/sgsn/gprs_utils.h
+++ b/include/osmocom/sgsn/gprs_utils.h
@@ -29,15 +29,11 @@
struct msgb;
struct gprs_ra_id;
-int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str);
-
/* GSM 04.08, 10.5.7.3 GPRS Timer */
-int gprs_tmr_to_secs(uint8_t tmr);
uint8_t gprs_secs_to_tmr_floor(int secs);
int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len);
int gprs_is_mi_imsi(const uint8_t *value, size_t value_len);
-int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi);
void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi);
int gprs_ra_id_equals(const struct gprs_ra_id *id1, const struct gprs_ra_id *id2);
diff --git a/include/osmocom/sgsn/gtp.h b/include/osmocom/sgsn/gtp.h
new file mode 100644
index 000000000..2aec55333
--- /dev/null
+++ b/include/osmocom/sgsn/gtp.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gprs/gprs_bssgp_rim.h>
+
+struct gprs_ra_id;
+struct sgsn_instance;
+struct sgsn_ggsn_ctx;
+struct sgsn_pdp_ctx;
+struct sgsn_mm_ctx;
+struct sgsn_mme_ctx;
+
+int sgsn_gtp_init(struct sgsn_instance *sgi);
+
+int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu);
+
+void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc);
+struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
+ struct sgsn_mm_ctx *mmctx,
+ uint16_t nsapi,
+ struct tlv_parsed *tp);
+
+int sgsn_gtp_data_req(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
+ struct msgb *msg, uint32_t npdu_len, uint8_t *npdu);
+int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx);
+void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen);
+int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx);
diff --git a/include/osmocom/sgsn/gtp_ggsn.h b/include/osmocom/sgsn/gtp_ggsn.h
new file mode 100644
index 000000000..6afb8664a
--- /dev/null
+++ b/include/osmocom/sgsn/gtp_ggsn.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <stdint.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/gprs/protocol/gsm_24_301.h>
+
+struct gsn_t;
+struct sgsn_pdp_ctx;
+struct sgsn_instance;
+
+struct sgsn_ggsn_ctx {
+ struct llist_head list;
+ uint32_t id;
+ unsigned int gtp_version;
+ struct in_addr remote_addr;
+ int remote_restart_ctr;
+ struct gsn_t *gsn;
+ struct llist_head pdp_list; /* list of associated pdp ctx (struct sgsn_pdp_ctx*) */
+ struct osmo_timer_list echo_timer;
+ unsigned int echo_interval;
+};
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(struct sgsn_instance *sgsn, uint32_t id);
+void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(struct sgsn_instance *sgsn, uint32_t id);
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct sgsn_instance *sgsn, struct in_addr *addr);
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(struct sgsn_instance *sgsn, uint32_t id);
+void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx);
+int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except);
+int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn);
+void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
+void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
+void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc);
+
+#define LOGGGSN(ggc, level, fmt, args...) { \
+ char _buf[INET_ADDRSTRLEN]; \
+ LOGP(DGTP, level, "GGSN(%" PRIu32 ":%s): " fmt, (ggc)->id, inet_ntop(AF_INET, &(ggc)->remote_addr, _buf, sizeof(_buf)), ## args); \
+ } while (0)
diff --git a/include/osmocom/sgsn/gtp_mme.h b/include/osmocom/sgsn/gtp_mme.h
new file mode 100644
index 000000000..ceea4051b
--- /dev/null
+++ b/include/osmocom/sgsn/gtp_mme.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <netinet/in.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/gprs/protocol/gsm_24_301.h>
+
+struct gsn_t;
+
+struct mme_rim_route {
+ struct llist_head list; /* item in struct sgsn_mme_ctx */
+ struct osmo_eutran_tai tai;
+};
+
+struct sgsn_mme_ctx {
+ struct llist_head list; /* item in sgsn_mme_ctxts */
+ struct llist_head routes; /* list of struct mme_rim_route */
+ struct sgsn_instance *sgsn; /* backpointer */
+ char *name;
+ struct in_addr remote_addr;
+
+ /* is it the default route for outgoing message? are all incoming messages accepted? */
+ bool default_route;
+};
+struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name);
+struct sgsn_mme_ctx *sgsn_mme_ctx_find_alloc(struct sgsn_instance *sgsn, const char *name);
+void sgsn_mme_ctx_free(struct sgsn_mme_ctx *mme);
+
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_name(const struct sgsn_instance *sgsn, const char *name);
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_addr(const struct sgsn_instance *sgsn, const struct in_addr *addr);
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_route(const struct sgsn_instance *sgsn, const struct osmo_eutran_tai *tai);
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_default_route(const struct sgsn_instance *sgsn);
+
+void sgsn_mme_ctx_route_add(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);
+void sgsn_mme_ctx_route_del(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);
+
+#define LOGMME(mme, cat, level, fmt, args...) { \
+ char _buf[INET_ADDRSTRLEN]; \
+ LOGP(cat, level, "MME(%s:%s): " fmt, (mme)->name, inet_ntop(AF_INET, &(mme)->remote_addr, _buf, sizeof(_buf)), ## args); \
+ } while (0)
diff --git a/include/osmocom/sgsn/gprs_sgsn.h b/include/osmocom/sgsn/mmctx.h
index 289e0c474..c19f599c5 100644
--- a/include/osmocom/sgsn/gprs_sgsn.h
+++ b/include/osmocom/sgsn/mmctx.h
@@ -1,5 +1,4 @@
-#ifndef _GPRS_SGSN_H
-#define _GPRS_SGSN_H
+#pragma once
#include <stdint.h>
#include <netinet/in.h>
@@ -14,12 +13,17 @@
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/crypt/auth.h>
+#include <osmocom/sgsn/apn.h>
+#include <osmocom/sgsn/auth.h>
+#include <osmocom/sgsn/gprs_subscriber.h>
+
#define GSM_EXTENSION_LENGTH 15
-#define GSM_APN_LENGTH 102
struct gprs_llc_lle;
struct ctrl_handle;
struct gprs_subscr;
+struct sgsn_ggsn_ctx;
+struct sgsn_pdp_ctx;
enum gsm48_gsm_cause;
@@ -37,13 +41,6 @@ enum gprs_mm_ctr {
GMM_CTR_RA_UPDATE,
};
-enum gprs_pdp_ctx {
- PDP_CTR_PKTS_UDATA_IN,
- PDP_CTR_PKTS_UDATA_OUT,
- PDP_CTR_BYTES_UDATA_IN,
- PDP_CTR_BYTES_UDATA_OUT,
-};
-
enum gprs_t3350_mode {
GMM_T3350_MODE_NONE,
GMM_T3350_MODE_ATT,
@@ -51,17 +48,6 @@ enum gprs_t3350_mode {
GMM_T3350_MODE_PTMSI_REALL,
};
-/* Authorization/ACL handling */
-enum sgsn_auth_state {
- SGSN_AUTH_UNKNOWN,
- SGSN_AUTH_AUTHENTICATE,
- SGSN_AUTH_UMTS_RESYNC,
- SGSN_AUTH_ACCEPTED,
- SGSN_AUTH_REJECTED
-};
-
-#define MS_RADIO_ACCESS_CAPA
-
enum sgsn_ggsn_lookup_state {
SGSN_GGSN_2DIGIT,
SGSN_GGSN_3DIGIT,
@@ -104,13 +90,6 @@ struct service_info {
struct ranap_ue_conn_ctx;
-struct gsm_auth_tuple {
- int use_count;
- int key_seq;
- struct osmo_auth_vector vec;
-};
-#define GSM_KEY_SEQ_INVAL 7 /* GSM 04.08 - 10.5.1.2 */
-
/* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */
/* Extended by 3GPP TS 23.060, Table 6: SGSN MM and PDP Contexts */
struct sgsn_mm_ctx {
@@ -175,6 +154,7 @@ struct sgsn_mm_ctx {
/* Iu: CK, IK, KSI */
/* CKSN */
enum gprs_ciph_algo ciph_algo;
+ uint8_t ue_cipher_mask;
/* Auth & Ciphering Request reference from 3GPP TS 24.008 § 10.5.5.19: */
uint8_t ac_ref_nr_used;
@@ -294,64 +274,6 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
enum gsm48_gsm_cause *gsm_cause,
char *apn_str);
-enum pdp_ctx_state {
- PDP_STATE_NONE,
- PDP_STATE_CR_REQ,
- PDP_STATE_CR_CONF,
-
- /* 04.08 / Figure 6.2 / 6.1.2.2 */
- PDP_STATE_INACT_PEND,
- PDP_STATE_INACTIVE = PDP_STATE_NONE,
-};
-
-enum pdp_type {
- PDP_TYPE_NONE,
- PDP_TYPE_ETSI_PPP,
- PDP_TYPE_IANA_IPv4,
- PDP_TYPE_IANA_IPv6,
-};
-
-struct sgsn_pdp_ctx {
- struct llist_head list; /* list_head for mmctx->pdp_list */
- struct llist_head g_list; /* list_head for global list */
- struct sgsn_mm_ctx *mm; /* back pointer to MM CTX */
- int destroy_ggsn; /* destroy it on destruction */
- struct sgsn_ggsn_ctx *ggsn; /* which GGSN serves this PDP */
- struct llist_head ggsn_list; /* list_head for ggsn->pdp_list */
- struct rate_ctr_group *ctrg;
-
- //unsigned int id;
- struct pdp_t *lib; /* pointer to libgtp PDP ctx */
- enum pdp_ctx_state state;
- enum pdp_type type;
- uint32_t address;
- char *apn_subscribed;
- //char *apn_used;
- uint16_t nsapi; /* SNDCP */
- uint16_t sapi; /* LLC */
- uint8_t ti; /* transaction identifier */
- int vplmn_allowed;
- uint32_t qos_profile_subscr;
- //uint32_t qos_profile_req;
- //uint32_t qos_profile_neg;
- uint8_t radio_prio;
- //uint32_t charging_id;
-
- struct osmo_timer_list timer;
- unsigned int T; /* Txxxx number */
- unsigned int num_T_exp; /* number of consecutive T expirations */
-
- struct osmo_timer_list cdr_timer; /* CDR record wird timer */
- struct timespec cdr_start; /* The start of the CDR */
- uint64_t cdr_bytes_in;
- uint64_t cdr_bytes_out;
- uint32_t cdr_charging_id;
-};
-
-#define LOGPDPCTXP(level, pdp, fmt, args...) \
- LOGP(DGPRS, level, "PDP(%s/%u) " \
- fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args)
-
/* look up PDP context by MM context and NSAPI */
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
uint8_t nsapi);
@@ -359,168 +281,7 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
uint8_t tid);
-struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
- struct sgsn_ggsn_ctx *ggsn,
- uint8_t nsapi);
-void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp);
-void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp);
-
-
-struct sgsn_ggsn_ctx {
- struct llist_head list;
- uint32_t id;
- unsigned int gtp_version;
- struct in_addr remote_addr;
- int remote_restart_ctr;
- struct gsn_t *gsn;
- struct llist_head pdp_list; /* list of associated pdp ctx (struct sgsn_pdp_ctx*) */
- struct osmo_timer_list echo_timer;
- unsigned int echo_interval;
-};
-struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id);
-void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
-struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id);
-struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr);
-struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id);
-void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx);
-int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except);
-int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn);
-void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
-void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
-void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc);
-
-#define LOGGGSN(ggc, level, fmt, args...) { \
- char _buf[INET_ADDRSTRLEN]; \
- LOGP(DGTP, level, "GGSN(%" PRIu32 ":%s): " fmt, (ggc)->id, inet_ntop(AF_INET, &(ggc)->remote_addr, _buf, sizeof(_buf)), ## args); \
- } while (0)
-
-struct apn_ctx {
- struct llist_head list;
- struct sgsn_ggsn_ctx *ggsn;
- char *name;
- char *imsi_prefix;
- char *description;
-};
-
-struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix);
-void sgsn_apn_ctx_free(struct apn_ctx *actx);
-struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix);
-struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix);
-
-extern struct llist_head sgsn_mm_ctxts;
-extern struct llist_head sgsn_ggsn_ctxts;
-extern struct llist_head sgsn_apn_ctxts;
-extern struct llist_head sgsn_pdp_ctxts;
-
uint32_t sgsn_alloc_ptmsi(void);
-struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx);
-void sgsn_inst_init(struct sgsn_instance *sgsn);
-
-char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len);
-
-/*
- * ctrl interface related work
- */
-int sgsn_ctrl_cmds_install(void);
-
-/*
- * Authorization/ACL handling
- */
-struct imsi_acl_entry {
- struct llist_head list;
- char imsi[OSMO_IMSI_BUF_SIZE];
-};
-
-/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */
-/* see GSM 09.02, B.1, gprsSubscriptionData */
-struct sgsn_subscriber_pdp_data {
- struct llist_head list;
-
- unsigned int context_id;
- uint16_t pdp_type;
- char apn_str[GSM_APN_LENGTH];
- uint8_t qos_subscribed[20];
- size_t qos_subscribed_len;
- uint8_t pdp_charg[2];
- bool has_pdp_charg;
-};
-
-struct sgsn_subscriber_data {
- struct sgsn_mm_ctx *mm;
- struct gsm_auth_tuple auth_triplets[5];
- int auth_triplets_updated;
- struct llist_head pdp_list;
- int error_cause;
-
- uint8_t msisdn[9];
- size_t msisdn_len;
-
- uint8_t hlr[9];
- size_t hlr_len;
-
- uint8_t pdp_charg[2];
- bool has_pdp_charg;
-};
-
-#define SGSN_ERROR_CAUSE_NONE (-1)
-
-#define LOGGSUBSCRP(level, subscr, fmt, args...) \
- LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \
- (subscr) ? (subscr)->imsi : "---", \
- ## args)
-
-struct sgsn_config;
-struct sgsn_instance;
-extern const struct value_string *sgsn_auth_state_names;
-
-void sgsn_auth_init(struct sgsn_instance *sgsn);
-struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, const struct sgsn_config *cfg);
-int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg);
-int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg);
-/* Request authorization */
-int sgsn_auth_request(struct sgsn_mm_ctx *mm);
-enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm);
-void sgsn_auth_update(struct sgsn_mm_ctx *mm);
-struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx,
- unsigned key_seq);
-
-/*
- * GPRS subscriber data
- */
-#define GPRS_SUBSCRIBER_FIRST_CONTACT 0x00000001
-#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING (1 << 16)
-#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING (1 << 17)
-#define GPRS_SUBSCRIBER_CANCELLED (1 << 18)
-#define GPRS_SUBSCRIBER_ENABLE_PURGE (1 << 19)
-
-#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \
- GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \
- GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING \
-)
-
-int gprs_subscr_init(struct sgsn_instance *sgi);
-int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx);
-int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx,
- const uint8_t *auts,
- const uint8_t *auts_rand);
-int gprs_subscr_auth_sync(struct gprs_subscr *subscr,
- const uint8_t *auts, const uint8_t *auts_rand);
-void gprs_subscr_cleanup(struct gprs_subscr *subscr);
-struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi);
-struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx( struct sgsn_mm_ctx *mmctx);
-struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi);
-void gprs_subscr_cancel(struct gprs_subscr *subscr);
-void gprs_subscr_update(struct gprs_subscr *subscr);
-void gprs_subscr_update_auth_info(struct gprs_subscr *subscr);
-int gprs_subscr_rx_gsup_message(struct msgb *msg);
/* Called on subscriber data updates */
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx);
-
-int gprs_sndcp_vty_init(void);
-struct sgsn_instance;
-int sgsn_gtp_init(struct sgsn_instance *sgi);
-
-void sgsn_rate_ctr_init();
-
-#endif /* _GPRS_SGSN_H */
diff --git a/include/osmocom/sgsn/pdpctx.h b/include/osmocom/sgsn/pdpctx.h
new file mode 100644
index 000000000..255a77d3f
--- /dev/null
+++ b/include/osmocom/sgsn/pdpctx.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#include <stdint.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#include <osmocom/core/timer.h>
+#include <osmocom/core/rate_ctr.h>
+
+#include <osmocom/gsm/gsm48.h>
+
+#include <osmocom/crypt/gprs_cipher.h>
+#include <osmocom/gsm/protocol/gsm_23_003.h>
+#include <osmocom/crypt/auth.h>
+
+#include <osmocom/sgsn/apn.h>
+#include <osmocom/sgsn/gprs_subscriber.h>
+
+struct sgsn_mm_ctx;
+struct sgsn_ggsn_ctx;
+
+enum gprs_pdp_ctx {
+ PDP_CTR_PKTS_UDATA_IN,
+ PDP_CTR_PKTS_UDATA_OUT,
+ PDP_CTR_BYTES_UDATA_IN,
+ PDP_CTR_BYTES_UDATA_OUT,
+};
+
+enum pdp_ctx_state {
+ PDP_STATE_NONE,
+ PDP_STATE_CR_REQ,
+ PDP_STATE_CR_CONF,
+
+ /* 04.08 / Figure 6.2 / 6.1.2.2 */
+ PDP_STATE_INACT_PEND,
+ PDP_STATE_INACTIVE = PDP_STATE_NONE,
+};
+
+enum pdp_type {
+ PDP_TYPE_NONE,
+ PDP_TYPE_ETSI_PPP,
+ PDP_TYPE_IANA_IPv4,
+ PDP_TYPE_IANA_IPv6,
+};
+
+struct sgsn_pdp_ctx {
+ struct llist_head list; /* list_head for mmctx->pdp_list */
+ struct llist_head g_list; /* list_head for global list */
+ struct sgsn_mm_ctx *mm; /* back pointer to MM CTX */
+ int destroy_ggsn; /* destroy it on destruction */
+ struct sgsn_ggsn_ctx *ggsn; /* which GGSN serves this PDP */
+ struct llist_head ggsn_list; /* list_head for ggsn->pdp_list */
+ struct rate_ctr_group *ctrg;
+
+ //unsigned int id;
+ struct pdp_t *lib; /* pointer to libgtp PDP ctx */
+ enum pdp_ctx_state state;
+ enum pdp_type type;
+ uint32_t address;
+ char *apn_subscribed;
+ //char *apn_used;
+ uint16_t nsapi; /* SNDCP */
+ uint16_t sapi; /* LLC */
+ uint8_t ti; /* transaction identifier */
+ int vplmn_allowed;
+ uint32_t qos_profile_subscr;
+ //uint32_t qos_profile_req;
+ //uint32_t qos_profile_neg;
+ uint8_t radio_prio;
+ //uint32_t charging_id;
+
+ struct osmo_timer_list timer;
+ unsigned int T; /* Txxxx number */
+ unsigned int num_T_exp; /* number of consecutive T expirations */
+
+ struct osmo_timer_list cdr_timer; /* CDR record wird timer */
+ struct timespec cdr_start; /* The start of the CDR */
+ uint64_t cdr_bytes_in;
+ uint64_t cdr_bytes_out;
+ uint32_t cdr_charging_id;
+};
+
+#define LOGPDPCTXP(level, pdp, fmt, args...) \
+ LOGP(DGPRS, level, "PDP(%s/%u) " \
+ fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args)
+
+struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
+ struct sgsn_ggsn_ctx *ggsn,
+ uint8_t nsapi);
+void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp);
+void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp);
+
+char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6);
+
diff --git a/include/osmocom/sgsn/sgsn.h b/include/osmocom/sgsn/sgsn.h
index d9ef938f5..6e93178af 100644
--- a/include/osmocom/sgsn/sgsn.h
+++ b/include/osmocom/sgsn/sgsn.h
@@ -6,12 +6,15 @@
#include <osmocom/core/select.h>
#include <osmocom/crypt/gprs_cipher.h>
#include <osmocom/gprs/gprs_ns2.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/gprs/gprs_bssgp.h>
+
+#include <osmocom/sgsn/auth.h>
+#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/gsm/oap_client.h>
#include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/sgsn/common.h>
-#include "../../bscconfig.h"
+#include "../../config.h"
#if BUILD_IU
#include <osmocom/ranap/iu_client.h>
@@ -22,6 +25,8 @@
struct hostent;
+#define SGSN_ERROR_CAUSE_NONE (-1)
+
enum sgsn_auth_policy {
SGSN_AUTH_POLICY_OPEN,
SGSN_AUTH_POLICY_CLOSED,
@@ -72,8 +77,10 @@ struct sgsn_config {
/* misc */
struct gprs_ns2_inst *nsi;
+ char *crypt_cipher_plugin_path;
enum sgsn_auth_policy auth_policy;
- enum gprs_ciph_algo cipher;
+ uint8_t gea_encryption_mask;
+ uint8_t uea_encryption_mask;
struct llist_head imsi_acl;
struct sockaddr_in gsup_server_addr;
@@ -89,6 +96,7 @@ struct sgsn_config {
/* Timer defintions */
struct osmo_tdef *T_defs;
+ struct osmo_tdef *T_defs_gtp;
int dynamic_lookup;
@@ -145,9 +153,23 @@ struct sgsn_instance {
struct ares_addr_node *ares_servers;
struct rate_ctr_group *rate_ctrs;
+
+ struct llist_head apn_list; /* list of struct sgsn_apn_ctx */
+ struct llist_head ggsn_list; /* list of struct sgsn_ggsn_ctx */
+ struct llist_head mme_list; /* list of struct sgsn_mme_ctx */
+ struct llist_head mm_list; /* list of struct sgsn_mm_ctx */
+ struct llist_head pdp_list; /* list of struct sgsn_pdp_ctx */
+
+ struct ctrl_handle *ctrlh;
};
extern struct sgsn_instance *sgsn;
+extern void *tall_sgsn_ctx;
+
+/*
+ * ctrl interface related work (sgsn_ctrl.c)
+ */
+int sgsn_ctrl_cmds_install(void);
/* sgsn_vty.c */
@@ -156,39 +178,13 @@ int sgsn_parse_config(const char *config_file);
char *sgsn_gtp_ntoa(struct ul16_t *ul);
/* sgsn.c */
-
-/* Main input function for Gb proxy */
-int sgsn_rcvmsg(struct msgb *msg, struct gprs_ns2_vc *nsvc, uint16_t ns_bvci);
-
-/* sgsn_libgtp.c */
-struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
- struct sgsn_mm_ctx *mmctx,
- uint16_t nsapi,
- struct tlv_parsed *tp);
-int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx);
-void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen);
-void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc);
-int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx);
-
-/* gprs_sndcp.c */
-
-/* Entry point for the SNSM-ACTIVATE.indication */
-int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
-/* Entry point for the SNSM-DEACTIVATE.indication */
-int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
-/* Called by SNDCP when it has received/re-assembled a N-PDU */
-int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
- struct msgb *msg, uint32_t npdu_len, uint8_t *npdu);
-int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
- void *mmcontext);
-int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
- uint8_t *hdr, uint16_t len);
-
-
+struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx);
+int sgsn_inst_init(struct sgsn_instance *sgsn);
/*
* CDR related functionality
*/
int sgsn_cdr_init(struct sgsn_instance *sgsn);
+void sgsn_cdr_release(struct sgsn_instance *sgsn);
/*
diff --git a/include/osmocom/sgsn/sgsn_rim.h b/include/osmocom/sgsn/sgsn_rim.h
index ca3660bd3..fc87b468e 100644
--- a/include/osmocom/sgsn/sgsn_rim.h
+++ b/include/osmocom/sgsn/sgsn_rim.h
@@ -1,3 +1,6 @@
#pragma once
-int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg);
+struct sgsn_mme_ctx;
+
+int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg);
+int sgsn_rim_rx_from_gtp(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address);
diff --git a/include/osmocom/sgsn/v42bis.h b/include/osmocom/sgsn/v42bis.h
index b64c43e69..d782981b0 100644
--- a/include/osmocom/sgsn/v42bis.h
+++ b/include/osmocom/sgsn/v42bis.h
@@ -17,10 +17,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*! \page v42bis_page V.42bis modem data compression
diff --git a/include/osmocom/sgsn/v42bis_private.h b/include/osmocom/sgsn/v42bis_private.h
index c6b675a1b..cc7e63448 100644
--- a/include/osmocom/sgsn/v42bis_private.h
+++ b/include/osmocom/sgsn/v42bis_private.h
@@ -17,10 +17,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#if !defined(_SPANDSP_PRIVATE_V42BIS_H_)
diff --git a/include/osmocom/sgsn/vty.h b/include/osmocom/sgsn/vty.h
index d2e3d9a73..a2732224c 100644
--- a/include/osmocom/sgsn/vty.h
+++ b/include/osmocom/sgsn/vty.h
@@ -3,7 +3,7 @@
#include <osmocom/vty/command.h>
enum bsc_vty_node {
- GBPROXY_NODE = _LAST_OSMOVTY_NODE + 1,
- SGSN_NODE,
+ SGSN_NODE = _LAST_OSMOVTY_NODE + 1,
GTPHUB_NODE,
+ MME_NODE,
};
diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4
deleted file mode 100644
index ca3639715..000000000
--- a/m4/ax_check_compile_flag.m4
+++ /dev/null
@@ -1,74 +0,0 @@
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
-#
-# DESCRIPTION
-#
-# Check whether the given FLAG works with the current language's compiler
-# or gives an error. (Warnings, however, are ignored)
-#
-# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
-# success/failure.
-#
-# If EXTRA-FLAGS is defined, it is added to the current language's default
-# flags (e.g. CFLAGS) when the check is done. The check is thus made with
-# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
-# force the compiler to issue an error when a bad flag is given.
-#
-# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
-#
-# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
-# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
-# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation, either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 4
-
-AC_DEFUN([AX_CHECK_COMPILE_FLAG],
-[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
-AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
-AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
- ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
- _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
- AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
- [AS_VAR_SET(CACHEVAR,[yes])],
- [AS_VAR_SET(CACHEVAR,[no])])
- _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
-AS_VAR_IF(CACHEVAR,yes,
- [m4_default([$2], :)],
- [m4_default([$3], :)])
-AS_VAR_POPDEF([CACHEVAR])dnl
-])dnl AX_CHECK_COMPILE_FLAGS
diff --git a/src/gprs/Makefile.am b/src/gprs/Makefile.am
index 170ded8fc..1533dc070 100644
--- a/src/gprs/Makefile.am
+++ b/src/gprs/Makefile.am
@@ -29,7 +29,6 @@ endif
noinst_LTLIBRARIES = libcommon.la
libcommon_la_SOURCES = \
- gprs_gb_parse.c \
gprs_llc_parse.c \
crc24.c \
gprs_utils.c \
diff --git a/src/gprs/crc24.c b/src/gprs/crc24.c
index da269b375..d47d4ff82 100644
--- a/src/gprs/crc24.c
+++ b/src/gprs/crc24.c
@@ -59,7 +59,7 @@ static const uint32_t tbl_crc24[256] = {
#define INIT_CRC24 0xffffff
-uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len)
+uint32_t crc24_calc(uint32_t fcs, const uint8_t *cp, unsigned int len)
{
while (len--)
fcs = (fcs >> 8) ^ tbl_crc24[(fcs ^ *cp++) & 0xff];
diff --git a/src/gprs/gprs_llc_parse.c b/src/gprs/gprs_llc_parse.c
index 1d97004e0..d099cdaf3 100644
--- a/src/gprs/gprs_llc_parse.c
+++ b/src/gprs/gprs_llc_parse.c
@@ -29,7 +29,7 @@
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/sgsn/debug.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/crc24.h>
@@ -55,7 +55,7 @@ static const struct value_string llc_cmd_strs[] = {
#define N202 4
#define CRC24_LENGTH 3
-int gprs_llc_fcs(uint8_t *data, unsigned int len)
+int gprs_llc_fcs(const uint8_t *data, unsigned int len)
{
uint32_t fcs_calc;
diff --git a/src/gprs/gprs_utils.c b/src/gprs/gprs_utils.c
index 632718aa9..46028c63c 100644
--- a/src/gprs/gprs_utils.c
+++ b/src/gprs/gprs_utils.c
@@ -30,56 +30,6 @@
#include <string.h>
-int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str)
-{
- uint8_t *last_len_field;
- int len;
-
- /* Can we even write the length field to the output? */
- if (max_len == 0)
- return -1;
-
- /* Remember where we need to put the length once we know it */
- last_len_field = apn_enc;
- len = 1;
- apn_enc += 1;
-
- while (str[0]) {
- if (len >= max_len)
- return -1;
-
- if (str[0] == '.') {
- *last_len_field = (apn_enc - last_len_field) - 1;
- last_len_field = apn_enc;
- } else {
- *apn_enc = str[0];
- }
- apn_enc += 1;
- str += 1;
- len += 1;
- }
-
- *last_len_field = (apn_enc - last_len_field) - 1;
-
- return len;
-}
-
-/* GSM 04.08, 10.5.7.3 GPRS Timer */
-int gprs_tmr_to_secs(uint8_t tmr)
-{
- switch (tmr & GPRS_TMR_UNIT_MASK) {
- case GPRS_TMR_2SECONDS:
- return 2 * (tmr & GPRS_TMR_FACT_MASK);
- default:
- case GPRS_TMR_MINUTE:
- return 60 * (tmr & GPRS_TMR_FACT_MASK);
- case GPRS_TMR_6MINUTE:
- return 360 * (tmr & GPRS_TMR_FACT_MASK);
- case GPRS_TMR_DEACTIVATED:
- return -1;
- }
-}
-
/* This functions returns a tmr value such that
* - f is monotonic
* - f(s) <= s
@@ -132,19 +82,6 @@ int gprs_is_mi_imsi(const uint8_t *value, size_t value_len)
return 1;
}
-int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi)
-{
- uint32_t tmsi_be;
-
- if (!gprs_is_mi_tmsi(value, value_len))
- return 0;
-
- memcpy(&tmsi_be, value + 1, sizeof(tmsi_be));
-
- *tmsi = ntohl(tmsi_be);
- return 1;
-}
-
void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi)
{
uint32_t tmsi_be;
diff --git a/src/gprs/sgsn_ares.c b/src/gprs/sgsn_ares.c
index 87314f117..81ab83540 100644
--- a/src/gprs/sgsn_ares.c
+++ b/src/gprs/sgsn_ares.c
@@ -24,8 +24,6 @@
#include <netdb.h>
-extern void *tall_sgsn_ctx;
-
struct cares_event_fd {
struct llist_head head;
struct osmo_fd fd;
diff --git a/src/gtphub/gtphub.c b/src/gtphub/gtphub.c
index c24652e07..937e6a4ff 100644
--- a/src/gtphub/gtphub.c
+++ b/src/gtphub/gtphub.c
@@ -32,7 +32,7 @@
#include <gtp.h>
#include <gtpie.h>
-#include <osmocom/sgsn/gtphub.h>
+#include <osmocom/gtphub/gtphub.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_utils.h>
@@ -59,15 +59,6 @@ void *osmo_gtphub_ctx;
/* TODO move this to osmocom/core/select.h ? */
typedef int (*osmo_fd_cb_t)(struct osmo_fd *fd, unsigned int what);
-/* TODO move this to osmocom/core/linuxlist.h ? */
-#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next)
-#define llist_first(head, type, entry) \
- llist_entry(__llist_first(head), type, entry)
-
-#define __llist_last(head) (((head)->next == (head)) ? NULL : (head)->prev)
-#define llist_last(head, type, entry) \
- llist_entry(__llist_last(head), type, entry)
-
/* TODO move GTP header stuff to openggsn/gtp/ ? See gtp_decaps*() */
enum gtp_rc {
@@ -484,7 +475,7 @@ static int get_ie_imsi_str(union gtpie_member *ie[], int i,
* present but cannot be decoded. */
static int get_ie_apn_str(union gtpie_member *ie[], const char **apn_str)
{
- static char apn_buf[GSM_APN_LENGTH];
+ static char apn_buf[APN_MAXLEN+1];
unsigned int len;
if (gtpie_gettlv(ie, GTPIE_APN, 0,
&len, apn_buf, sizeof(apn_buf)) != 0)
@@ -613,7 +604,7 @@ void expiry_add(struct expiry *exq, struct expiring_item *item, time_t now)
OSMO_ASSERT(llist_empty(&exq->items)
|| (item->expiry
- >= llist_last(&exq->items, struct expiring_item, entry)->expiry));
+ >= llist_last_entry(&exq->items, struct expiring_item, entry)->expiry));
/* Add/move to the tail to always sort by expiry, ascending. */
llist_del(&item->entry);
@@ -980,7 +971,7 @@ static inline void set_tei(struct gtp_packet_desc *p, uint32_t tei)
static void gtphub_mapping_del_cb(struct expiring_item *expi);
-static struct nr_mapping *gtphub_mapping_new()
+static struct nr_mapping *gtphub_mapping_new(void)
{
struct nr_mapping *nrm;
nrm = talloc_zero(osmo_gtphub_ctx, struct nr_mapping);
@@ -1004,7 +995,7 @@ static const char *gtphub_tunnel_side_str(struct gtphub_tunnel *tun,
char *pos = buf;
int left = sizeof(buf);
int l;
-
+
struct gtphub_tunnel_endpoint *c, *u;
c = &tun->endpoint[side_idx][GTPH_PLANE_CTRL];
u = &tun->endpoint[side_idx][GTPH_PLANE_USER];
@@ -1113,7 +1104,7 @@ static void gtphub_tunnel_del_cb(struct expiring_item *expi)
/* rate counter index for hubs: [7; 10] */
#define CTR_IDX_HUB(s, p) CTR_IDX(s, p, 3, 2)
-static struct gtphub_tunnel *gtphub_tunnel_new()
+static struct gtphub_tunnel *gtphub_tunnel_new(void)
{
struct gtphub_tunnel *tun;
tun = talloc_zero(osmo_gtphub_ctx, struct gtphub_tunnel);
@@ -1142,9 +1133,7 @@ static const char *gtphub_peer_strb(struct gtphub_peer *peer, char *buf,
if (llist_empty(&peer->addresses))
return "(addressless)";
- struct gtphub_peer_addr *a = llist_first(&peer->addresses,
- struct gtphub_peer_addr,
- entry);
+ struct gtphub_peer_addr *a = llist_first_entry_or_null(&peer->addresses, struct gtphub_peer_addr, entry);
return gsn_addr_to_strb(&a->addr, buf, buflen);
}
@@ -2125,7 +2114,7 @@ int gtphub_handle_buf(struct gtphub *hub,
struct gtphub_bind *from_bind = &hub->to_gsns[side_idx][plane_idx];
struct gtphub_bind *to_bind = &hub->to_gsns[other_side_idx(side_idx)][plane_idx];
- rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_IN],
+ rate_ctr_add(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_BYTES_IN),
received);
struct gtp_packet_desc p;
@@ -2147,7 +2136,7 @@ int gtphub_handle_buf(struct gtphub *hub,
return -1;
}
- rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_IN]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_PKTS_IN));
int reply_len;
reply_len = gtphub_handle_echo_req(hub, &p, reply_buf);
@@ -2156,8 +2145,8 @@ int gtphub_handle_buf(struct gtphub *hub,
sgsn_sockaddr_copy(to_addr, from_addr);
*to_ofd = &from_bind->ofd;
- rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
- rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT],
+ rate_ctr_inc(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_PKTS_OUT));
+ rate_ctr_add(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_BYTES_OUT),
reply_len);
LOG(LOGL_DEBUG, "%s Echo response to %s: %d bytes to %s\n",
(side_idx == GTPH_SIDE_GGSN)? "-->" : "<--",
@@ -2236,9 +2225,9 @@ int gtphub_handle_buf(struct gtphub *hub,
return -1;
}
- rate_ctr_add(&from_peer->counters_io->ctr[GTPH_CTR_BYTES_IN],
+ rate_ctr_add(rate_ctr_group_get_ctr(from_peer->counters_io, GTPH_CTR_BYTES_IN),
received);
- rate_ctr_inc(&from_peer->counters_io->ctr[GTPH_CTR_PKTS_IN]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(from_peer->counters_io, GTPH_CTR_PKTS_IN));
LOG(LOGL_DEBUG, "from %s peer: %s\n", gtphub_side_idx_names[side_idx],
gtphub_port_str(from_peer));
@@ -2257,9 +2246,9 @@ int gtphub_handle_buf(struct gtphub *hub,
if (p.tun) {
struct gtphub_tunnel_endpoint *te = &p.tun->endpoint[p.side_idx][p.plane_idx];
- rate_ctr_add(&te->counters_io->ctr[GTPH_CTR_BYTES_IN],
+ rate_ctr_add(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_BYTES_IN),
received);
- rate_ctr_inc(&te->counters_io->ctr[GTPH_CTR_PKTS_IN]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_PKTS_IN));
}
if ((!to_peer) && (side_idx == GTPH_SIDE_SGSN)) {
@@ -2294,7 +2283,7 @@ int gtphub_handle_buf(struct gtphub *hub,
!= 0)
return -1;
}
-
+
/* Either to_peer was resolved from an existing tunnel,
* or a PDP Ctx and thus a tunnel has just been created,
* or the tunnel has been deleted due to this message. */
@@ -2311,19 +2300,19 @@ int gtphub_handle_buf(struct gtphub *hub,
*reply_buf = (uint8_t*)p.data;
if (received) {
- rate_ctr_inc(&to_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
- rate_ctr_add(&to_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT],
+ rate_ctr_inc(rate_ctr_group_get_ctr(to_bind->counters_io, GTPH_CTR_PKTS_OUT));
+ rate_ctr_add(rate_ctr_group_get_ctr(to_bind->counters_io, GTPH_CTR_BYTES_OUT),
received);
- rate_ctr_inc(&to_peer->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
- rate_ctr_add(&to_peer->counters_io->ctr[GTPH_CTR_BYTES_OUT],
+ rate_ctr_inc(rate_ctr_group_get_ctr(to_peer->counters_io, GTPH_CTR_PKTS_OUT));
+ rate_ctr_add(rate_ctr_group_get_ctr(to_peer->counters_io, GTPH_CTR_BYTES_OUT),
received);
}
if (p.tun) {
struct gtphub_tunnel_endpoint *te = &p.tun->endpoint[other_side_idx(p.side_idx)][p.plane_idx];
- rate_ctr_inc(&te->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
- rate_ctr_add(&te->counters_io->ctr[GTPH_CTR_BYTES_OUT],
+ rate_ctr_inc(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_PKTS_OUT));
+ rate_ctr_add(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_BYTES_OUT),
received);
}
@@ -2701,7 +2690,7 @@ static struct gtphub_peer_addr *gtphub_addr_have(struct gtphub *hub,
struct gtphub_peer *peer = gtphub_peer_new(hub, bind);
a = gtphub_peer_add_addr(peer, addr);
-
+
LOG(LOGL_DEBUG, "New peer address: %s %s\n",
bind->label,
gsn_addr_to_str(&a->addr));
diff --git a/src/gtphub/gtphub_ares.c b/src/gtphub/gtphub_ares.c
index 87dc860c4..774563db4 100644
--- a/src/gtphub/gtphub_ares.c
+++ b/src/gtphub/gtphub_ares.c
@@ -28,11 +28,12 @@
#include <string.h>
#include <unistd.h>
-#include <osmocom/sgsn/gtphub.h>
+#include <osmocom/gtphub/gtphub.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/apn.h>
+#include <osmocom/gsm/protocol/gsm_23_003.h>
/* TODO split GRX ares from sgsn into a separate struct and allow use without
* globals. */
@@ -56,8 +57,8 @@ struct ggsn_lookup {
struct gtphub *hub;
char imsi_str[GSM23003_IMSI_MAX_DIGITS+1];
- char apn_ni_str[GSM_APN_LENGTH];
- char apn_oi_str[GSM_APN_LENGTH];
+ char apn_ni_str[APN_MAXLEN+1];
+ char apn_oi_str[APN_MAXLEN+1];
int have_3dig_mnc;
};
diff --git a/src/gtphub/gtphub_main.c b/src/gtphub/gtphub_main.c
index a9a7529cc..9b0532b24 100644
--- a/src/gtphub/gtphub_main.c
+++ b/src/gtphub/gtphub_main.c
@@ -34,6 +34,7 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/msgb.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/telnet_interface.h>
@@ -41,10 +42,10 @@
#include <osmocom/vty/misc.h>
#include <osmocom/sgsn/debug.h>
-#include <osmocom/sgsn/gtphub.h>
+#include <osmocom/gtphub/gtphub.h>
#include <osmocom/sgsn/vty.h>
-#include "../../bscconfig.h"
+#include "../../config.h"
#if BUILD_IU
#include <osmocom/sigtran/osmo_ss7.h>
@@ -353,8 +354,7 @@ int main(int argc, char **argv)
}
/* start telnet after reading config for vty_get_bind_addr() */
- rc = telnet_init_dynif(osmo_gtphub_ctx, 0, vty_get_bind_addr(),
- OSMO_VTY_PORT_GTPHUB);
+ rc = telnet_init_default(osmo_gtphub_ctx, NULL, OSMO_VTY_PORT_GTPHUB);
if (rc < 0)
exit(1);
diff --git a/src/gtphub/gtphub_sock.c b/src/gtphub/gtphub_sock.c
index 183753348..6f299d2d6 100644
--- a/src/gtphub/gtphub_sock.c
+++ b/src/gtphub/gtphub_sock.c
@@ -25,7 +25,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <osmocom/sgsn/gtphub.h>
+#include <errno.h>
+#include <string.h>
+
+#include <osmocom/core/utils.h>
+
+#include <osmocom/gtphub/gtphub.h>
#include <osmocom/sgsn/debug.h>
/* Convenience makro, note: only within this C file. */
diff --git a/src/gtphub/gtphub_vty.c b/src/gtphub/gtphub_vty.c
index abc08fd69..b5f102ae6 100644
--- a/src/gtphub/gtphub_vty.c
+++ b/src/gtphub/gtphub_vty.c
@@ -31,7 +31,7 @@
#include <osmocom/vty/misc.h>
#include <osmocom/sgsn/vty.h>
-#include <osmocom/sgsn/gtphub.h>
+#include <osmocom/gtphub/gtphub.h>
/* TODO split GRX ares from sgsn into a separate struct and allow use without
* globals. */
diff --git a/src/sgsn/Makefile.am b/src/sgsn/Makefile.am
index 873898626..93b9fa058 100644
--- a/src/sgsn/Makefile.am
+++ b/src/sgsn/Makefile.am
@@ -40,12 +40,13 @@ bin_PROGRAMS = \
$(NULL)
osmo_sgsn_SOURCES = \
- gprs_gb.c \
+ apn.c \
+ gprs_bssgp.c \
gprs_gmm_attach.c \
gprs_gmm.c \
gprs_gmm_fsm.c \
gprs_mm_state_gb_fsm.c \
- gprs_sgsn.c \
+ gprs_ns.c \
gprs_sm.c \
gprs_sndcp.c \
gprs_sndcp_comp.c \
@@ -53,11 +54,16 @@ osmo_sgsn_SOURCES = \
gprs_sndcp_pcomp.c \
gprs_sndcp_vty.c \
gprs_sndcp_xid.c \
+ gtp_ggsn.c \
+ gtp_mme.c \
+ sgsn.c \
sgsn_main.c \
sgsn_vty.c \
sgsn_libgtp.c \
gprs_llc.c \
gprs_llc_vty.c \
+ mmctx.c \
+ pdpctx.c \
sgsn_ctrl.c \
sgsn_auth.c \
gprs_subscriber.c \
diff --git a/src/sgsn/apn.c b/src/sgsn/apn.c
new file mode 100644
index 000000000..a89d15866
--- /dev/null
+++ b/src/sgsn/apn.c
@@ -0,0 +1,123 @@
+/* APN contexts */
+
+/* (C) 2009-2015 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by On-Waves
+ * (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string.h>
+#include <talloc.h>
+
+#include <osmocom/sgsn/apn.h>
+#include <osmocom/sgsn/sgsn.h>
+
+static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix)
+{
+ struct apn_ctx *actx;
+
+ actx = talloc_zero(sgsn, struct apn_ctx);
+ if (!actx)
+ return NULL;
+ actx->name = talloc_strdup(actx, ap_name);
+ actx->imsi_prefix = talloc_strdup(actx, imsi_prefix);
+
+ llist_add_tail(&actx->list, &sgsn->apn_list);
+
+ return actx;
+}
+
+void sgsn_apn_ctx_free(struct apn_ctx *actx)
+{
+ llist_del(&actx->list);
+ talloc_free(actx);
+}
+
+struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi)
+{
+ struct apn_ctx *actx;
+ struct apn_ctx *found_actx = NULL;
+ size_t imsi_prio = 0;
+ size_t name_prio = 0;
+ size_t name_req_len = strlen(name);
+
+ llist_for_each_entry(actx, &sgsn->apn_list, list) {
+ size_t name_ref_len, imsi_ref_len;
+ const char *name_ref_start, *name_match_start;
+
+ imsi_ref_len = strlen(actx->imsi_prefix);
+ if (strncmp(actx->imsi_prefix, imsi, imsi_ref_len) != 0)
+ continue;
+
+ if (imsi_ref_len < imsi_prio)
+ continue;
+
+ /* IMSI matches */
+
+ name_ref_start = &actx->name[0];
+ if (name_ref_start[0] == '*') {
+ /* Suffix match */
+ name_ref_start += 1;
+ name_ref_len = strlen(name_ref_start);
+ if (name_ref_len > name_req_len)
+ continue;
+ } else {
+ name_ref_len = strlen(name_ref_start);
+ if (name_ref_len != name_req_len)
+ continue;
+ }
+
+ name_match_start = name + (name_req_len - name_ref_len);
+ if (strcasecmp(name_match_start, name_ref_start) != 0)
+ continue;
+
+ /* IMSI and name match */
+
+ if (imsi_ref_len == imsi_prio && name_ref_len < name_prio)
+ /* Lower priority, skip */
+ continue;
+
+ imsi_prio = imsi_ref_len;
+ name_prio = name_ref_len;
+ found_actx = actx;
+ }
+ return found_actx;
+}
+
+struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix)
+{
+ struct apn_ctx *actx;
+
+ llist_for_each_entry(actx, &sgsn->apn_list, list) {
+ if (strcasecmp(name, actx->name) == 0 &&
+ strcasecmp(imsi_prefix, actx->imsi_prefix) == 0)
+ return actx;
+ }
+ return NULL;
+}
+
+struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix)
+{
+ struct apn_ctx *actx;
+
+ actx = sgsn_apn_ctx_by_name(name, imsi_prefix);
+ if (!actx)
+ actx = sgsn_apn_ctx_alloc(name, imsi_prefix);
+
+ return actx;
+}
diff --git a/src/sgsn/gprs_bssgp.c b/src/sgsn/gprs_bssgp.c
new file mode 100644
index 000000000..5db751cce
--- /dev/null
+++ b/src/sgsn/gprs_bssgp.c
@@ -0,0 +1,95 @@
+/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */
+
+/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by On-Waves
+ * (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <osmocom/core/prim.h>
+#include <osmocom/core/rate_ctr.h>
+
+#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/gprs/gprs_ns2.h>
+
+#include <osmocom/sgsn/gprs_llc.h>
+#include <osmocom/sgsn/gprs_gmm.h>
+#include <osmocom/sgsn/sgsn_rim.h>
+#include <osmocom/sgsn/mmctx.h>
+
+/* call-back function for the BSSGP protocol */
+int sgsn_bssgp_rx_prim(struct osmo_prim_hdr *oph)
+{
+ struct osmo_bssgp_prim *bp;
+ bp = container_of(oph, struct osmo_bssgp_prim, oph);
+
+ switch (oph->sap) {
+ case SAP_BSSGP_LL:
+ switch (oph->primitive) {
+ case PRIM_BSSGP_UL_UD:
+ return gprs_llc_rcvmsg(oph->msg, bp->tp);
+ }
+ break;
+ case SAP_BSSGP_GMM:
+ switch (oph->primitive) {
+ case PRIM_BSSGP_GMM_SUSPEND:
+ return gprs_gmm_rx_suspend(bp->ra_id, bp->tlli);
+ case PRIM_BSSGP_GMM_RESUME:
+ return gprs_gmm_rx_resume(bp->ra_id, bp->tlli,
+ bp->u.resume.suspend_ref);
+ }
+ break;
+ case SAP_BSSGP_NM:
+ break;
+ case SAP_BSSGP_RIM:
+ return sgsn_rim_rx_from_gb(bp, oph->msg);
+ }
+ return 0;
+}
+
+int sgsn_bssgp_page_ps_ra(struct sgsn_mm_ctx *mmctx)
+{
+ struct bssgp_paging_info pinfo;
+ int rc;
+
+ /* FIXME: page whole routing area, not only the last known cell */
+
+ /* initiate PS PAGING procedure */
+ memset(&pinfo, 0, sizeof(pinfo));
+ pinfo.mode = BSSGP_PAGING_PS;
+ pinfo.scope = BSSGP_PAGING_BVCI;
+ pinfo.bvci = mmctx->gb.bvci;
+ pinfo.imsi = mmctx->imsi;
+ pinfo.ptmsi = &mmctx->p_tmsi;
+ pinfo.drx_params = mmctx->drx_parms;
+ pinfo.qos[0] = 0; // FIXME
+ rc = bssgp_tx_paging(mmctx->gb.nsei, 0, &pinfo);
+ rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PAGING_PS));
+
+ return rc;
+}
+
+/* called by the bssgp layer to send NS PDUs */
+int sgsn_bssgp_dispatch_ns_unitdata_req_cb(void *ctx, struct msgb *msg)
+{
+ struct gprs_ns2_inst *nsi = (struct gprs_ns2_inst *) ctx;
+ struct osmo_gprs_ns2_prim nsp = {};
+ nsp.nsei = msgb_nsei(msg);
+ nsp.bvci = msgb_bvci(msg);
+ osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg);
+ return gprs_ns2_recv_prim(nsi, &nsp.oph);
+}
diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c
index 2367338a4..c3f5cd3d2 100644
--- a/src/sgsn/gprs_gmm.c
+++ b/src/sgsn/gprs_gmm.c
@@ -30,7 +30,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
-#include "bscconfig.h"
+#include "config.h"
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
@@ -41,13 +41,14 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/tdef.h>
#include <osmocom/crypt/auth.h>
+#include <osmocom/crypt/utran_cipher.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_llc.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/sgsn/gprs_subscriber.h>
@@ -59,17 +60,17 @@
#include <osmocom/sgsn/signal.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gprs_ranap.h>
+#include <osmocom/sgsn/gprs_sm.h>
+#include <osmocom/sgsn/gtp.h>
+#include <osmocom/sgsn/pdpctx.h>
#include <pdp.h>
#define PTMSI_ALLOC
-extern struct sgsn_instance *sgsn;
-extern void *tall_sgsn_ctx;
-
static const struct tlv_definition gsm48_gmm_att_tlvdef = {
.def = {
- [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_FIXED, 1 },
+ [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_SINGLE_TV, 1 },
[GSM48_IE_GMM_TIMER_READY] = { TLV_TYPE_TV, 1 },
[GSM48_IE_GMM_ALLOC_PTMSI] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_PTMSI_SIG] = { TLV_TYPE_FIXED, 3 },
@@ -78,6 +79,7 @@ static const struct tlv_definition gsm48_gmm_att_tlvdef = {
[GSM48_IE_GMM_AUTH_RES_EXT] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_AUTH_FAIL_PAR] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_IMEISV] = { TLV_TYPE_TLV, 0 },
+ [GSM48_IE_GMM_RX_NPDU_NUM_LIST] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_DRX_PARAM] = { TLV_TYPE_FIXED, 2 },
[GSM48_IE_GMM_MS_NET_CAPA] = { TLV_TYPE_TLV, 0 },
[GSM48_IE_GMM_PDP_CTX_STATUS] = { TLV_TYPE_TLV, 0 },
@@ -131,7 +133,7 @@ int gsm48_gmm_sendmsg(struct msgb *msg, int command,
struct sgsn_mm_ctx *mm, bool encryptable)
{
if (mm) {
- rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_PKTS_SIG_OUT));
#ifdef BUILD_IU
if (mm->ran_type == MM_CTX_T_UTRAN_Iu)
return ranap_iu_tx(msg, GPRS_SAPI_GMM);
@@ -197,10 +199,10 @@ static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
switch(ctx->ran_type) {
case MM_CTX_T_UTRAN_Iu:
- osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
+ osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_DETACH, NULL);
break;
case MM_CTX_T_GERAN_Gb:
- osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
+ osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_GPRS_DETACH, NULL);
break;
}
@@ -215,7 +217,7 @@ static int _tx_status(struct msgb *msg, uint8_t cause,
/* MMCTX might be NULL! */
- DEBUGP(DMM, "<- GPRS MM STATUS (cause: %s)\n",
+ DEBUGP(DMM, "<- GMM STATUS (cause: %s)\n",
get_value_string(gsm48_gmm_cause_names, cause));
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
@@ -241,7 +243,7 @@ static int _tx_detach_req(struct msgb *msg, uint8_t detach_type, uint8_t cause,
/* MMCTX might be NULL! */
- DEBUGP(DMM, "<- GPRS MM DETACH REQ (type: %s, cause: %s)\n",
+ DEBUGP(DMM, "<- GMM DETACH REQ (type: %s, cause: %s)\n",
get_value_string(gprs_det_t_mt_strs, detach_type),
get_value_string(gsm48_gmm_cause_names, cause));
@@ -290,8 +292,8 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
uint8_t *ptsig;
#endif
- LOGMMCTXP(LOGL_INFO, mm, "<- GPRS ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi);
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_ACKED]);
+ LOGMMCTXP(LOGL_INFO, mm, "<- GMM ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_ACKED));
mmctx2msgid(msg, mm);
@@ -354,9 +356,9 @@ static int _tx_gmm_att_rej(struct msgb *msg, uint8_t gmm_cause,
{
struct gsm48_hdr *gh;
- LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS ATTACH REJECT: %s\n",
+ LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM ATTACH REJECT: %s\n",
get_value_string(gsm48_gmm_cause_names, gmm_cause));
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REJECTED]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REJECTED));
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM_GPRS;
@@ -388,8 +390,8 @@ static int _tx_detach_ack(struct msgb *msg, uint8_t force_stby,
/* MMCTX might be NULL! */
- DEBUGP(DMM, "<- GPRS MM DETACH ACC (force-standby: %d)\n", force_stby);
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_ACKED]);
+ DEBUGP(DMM, "<- GMM DETACH ACC (force-standby: %d)\n", force_stby);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_DETACH_ACKED));
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM_GPRS;
@@ -421,7 +423,7 @@ int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ID REQ");
struct gsm48_hdr *gh;
- LOGMMCTXP(LOGL_DEBUG, mm, "<- GPRS IDENTITY REQUEST: mi_type=%s\n",
+ LOGMMCTXP(LOGL_DEBUG, mm, "<- GMM IDENTITY REQUEST: mi_type=%s\n",
gsm48_mi_type_name(id_type));
mmctx2msgid(msg, mm);
@@ -445,6 +447,17 @@ static bool mmctx_is_r99(const struct sgsn_mm_ctx *mm)
return false;
}
+static enum gprs_ciph_algo gprs_ms_net_select_best_gea(uint8_t net_mask, uint8_t ms_mask) {
+ uint8_t common_mask = net_mask & ms_mask;
+ uint8_t r = 0;
+
+ while (common_mask >>= 1) {
+ r++;
+ }
+
+ return r;
+}
+
/* 3GPP TS 24.008 § 9.4.9: Authentication and Ciphering Request */
int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
const struct osmo_auth_vector *vec,
@@ -456,7 +469,7 @@ int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
uint8_t *m_rand, *m_cksn, rbyte;
int rc;
- LOGMMCTXP(LOGL_INFO, mm, "<- GPRS AUTH AND CIPHERING REQ (rand = %s,"
+ LOGMMCTXP(LOGL_INFO, mm, "<- GMM AUTH AND CIPHERING REQ (rand = %s,"
" mmctx_is_r99=%d, vec->auth_types=0x%x",
osmo_hexdump(vec->rand, sizeof(vec->rand)),
mmctx_is_r99(mm), vec->auth_types);
@@ -519,7 +532,7 @@ static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REJ");
struct gsm48_hdr *gh;
- LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS AUTH AND CIPH REJECT\n");
+ LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM AUTH AND CIPH REJECT\n");
mmctx2msgid(msg, mm);
@@ -599,7 +612,7 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
uint8_t res_len;
int rc;
- LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH RESPONSE\n");
+ LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH RESPONSE\n");
if (ctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
LOGMMCTXP(LOGL_NOTICE, ctx,
@@ -650,7 +663,7 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
ctx->sec_ctx = check_auth_resp(ctx, false, &at->vec, res, res_len);
if (!sgsn_mm_ctx_is_authenticated(ctx)) {
rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
- mm_ctx_cleanup_free(ctx, "GPRS AUTH AND CIPH REJECT");
+ mm_ctx_cleanup_free(ctx, "GMM AUTH AND CIPH REJECT");
return rc;
}
@@ -673,7 +686,7 @@ static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx,
const uint8_t *auts;
int rc;
- LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH FAILURE (cause = %s)\n",
+ LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH FAILURE (cause = %s)\n",
get_value_string(gsm48_gmm_cause_names, gmm_cause));
tlv_parse(&tp, &gsm48_gmm_att_tlvdef, gh->data+1, msg->len - 1, 0, 0);
@@ -713,7 +726,7 @@ static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx,
LOGMMCTXP(LOGL_NOTICE, ctx, "Authentication failed\n");
rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
- mm_ctx_cleanup_free(ctx, "GPRS AUTH FAILURE");
+ mm_ctx_cleanup_free(ctx, "GMM AUTH FAILURE");
return rc;
}
@@ -792,7 +805,7 @@ static int gsm48_tx_gmm_service_ack(struct sgsn_mm_ctx *mm)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE ACK");
struct gsm48_hdr *gh;
- LOGMMCTXP(LOGL_INFO, mm, "<- GPRS SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi);
+ LOGMMCTXP(LOGL_INFO, mm, "<- GMM SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi);
mmctx2msgid(msg, mm);
@@ -813,7 +826,7 @@ static int _tx_gmm_service_rej(struct msgb *msg, uint8_t gmm_cause,
{
struct gsm48_hdr *gh;
- LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS SERVICE REJECT: %s\n",
+ LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM SERVICE REJECT: %s\n",
get_value_string(gsm48_gmm_cause_names, gmm_cause));
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
@@ -905,7 +918,13 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
/* The MS is authorized */
#ifdef BUILD_IU
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) {
- rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 0, ctx->iu.new_key);
+ /* Is any encryption above UEA0 enabled? */
+ bool send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0);
+ LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA encryption mask = 0x%x)\n",
+ send_ck ? "sending" : "not sending", sgsn->cfg.uea_encryption_mask);
+ /* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2(). However, this
+ * is not possible in the iu_client API. See OS#5487. */
+ rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck, ctx->iu.new_key);
ctx->iu.new_key = 0;
return rc;
}
@@ -936,7 +955,7 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
#ifdef BUILD_IU
case GSM48_MT_GMM_SERVICE_REQ:
ctx->pending_req = 0;
- osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_ATTACH, NULL);
+ osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_CONN_ESTABLISH, NULL);
rc = gsm48_tx_gmm_service_ack(ctx);
if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING)
@@ -1087,7 +1106,7 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
"p_tmsi_old=0x%08x\n",
ictx->p_tmsi);
- mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use");
+ mm_ctx_cleanup_free(ictx, "GMM IMSI re-use");
}
}
OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);
@@ -1147,6 +1166,21 @@ static void mmctx_handle_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
}
+static uint8_t gprs_ms_net_cap_gea_mask(const uint8_t *ms_net_cap, uint8_t cap_len)
+{
+ uint8_t mask = (1 << GPRS_ALGO_GEA0);
+ mask |= (0x80 & ms_net_cap[0]) ? (1 << GPRS_ALGO_GEA1) : 0;
+
+ if (cap_len < 2)
+ return mask;
+
+ /* extended GEA bits start from 2nd bit of the next byte */
+ mask |= (0x40 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA2) : 0;
+ mask |= (0x20 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA3) : 0;
+ mask |= (0x10 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA4) : 0;
+ return mask;
+}
+
/* 3GPP TS 24.008 § 9.4.1 Attach request */
static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
struct gprs_llc_llme *llme)
@@ -1163,7 +1197,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
int rc;
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST ");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REQUEST]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REQUEST));
/* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either
* with a foreign TLLI (P-TMSI that was allocated to the MS before),
@@ -1290,15 +1324,27 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
ctx->ms_radio_access_capa.len);
ctx->ms_network_capa.len = msnc_len;
memcpy(ctx->ms_network_capa.buf, msnc, msnc_len);
- if (!gprs_ms_net_cap_gea_supported(ctx->ms_network_capa.buf, msnc_len,
- ctx->ciph_algo)) {
+
+ ctx->ue_cipher_mask = gprs_ms_net_cap_gea_mask(ctx->ms_network_capa.buf, msnc_len);
+
+ if (!(ctx->ue_cipher_mask & sgsn->cfg.gea_encryption_mask)) {
reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "
- "%s because MS do not support required %s "
- "encryption\n", mi_log_string,
- get_value_string(gprs_cipher_names,ctx->ciph_algo));
+ "%s because MS do not support required encryption, mask UE:0x%02x NW:0x%02x \n",
+ mi_log_string, ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask);
goto rejected;
}
+
+ /* just assume that everythig is fine if the phone offers a5/4:
+ * it requires a valid umts security context which we can only have after
+ * 1) IDENTITY REQUEST to know what to ask the HLR for
+ * 2) and AUTHENTICATION AND CIPHERING REQUEST
+ * ... but 2) already requires selecting a cipher mode.
+ * So let's just assume we will have the auth data required to make it work.
+ */
+
+ ctx->ciph_algo = gprs_ms_net_select_best_gea(ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask);
+
#ifdef PTMSI_ALLOC
/* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */
ptmsi_update(ctx);
@@ -1330,7 +1376,7 @@ rejected:
get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
rc = gsm48_tx_gmm_att_rej_oldmsg(msg, reject_cause);
if (ctx)
- mm_ctx_cleanup_free(ctx, "GPRS ATTACH REJ");
+ mm_ctx_cleanup_free(ctx, "GMM ATTACH REJ");
else if (llme)
gprs_llgmm_unassign(llme);
@@ -1343,7 +1389,7 @@ static int gsm48_rx_gmm_att_compl(struct sgsn_mm_ctx *mmctx)
{
struct sgsn_signal_data sig_data;
/* only in case SGSN offered new P-TMSI */
- LOGMMCTXP(LOGL_INFO, mmctx, "-> ATTACH COMPLETE\n");
+ LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM ATTACH COMPLETE\n");
#ifdef BUILD_IU
if (mmctx->iu.ue_ctx) {
@@ -1410,7 +1456,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
power_off = gh->data[0] & 0x8;
/* FIXME: In 24.008 there is an optional P-TMSI and P-TMSI signature IE */
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_REQUEST]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_DETACH_REQUEST));
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM DETACH REQUEST TLLI=0x%08x type=%s %s\n",
msgb_tlli(msg), get_value_string(gprs_det_t_mo_strs, detach_type),
power_off ? "Power-off" : "");
@@ -1430,7 +1476,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
memset(&sig_data, 0, sizeof(sig_data));
sig_data.mm = ctx;
osmo_signal_dispatch(SS_SGSN, S_SGSN_DETACH, &sig_data);
- mm_ctx_cleanup_free(ctx, "GPRS DETACH REQUEST");
+ mm_ctx_cleanup_free(ctx, "GMM DETACH REQUEST");
}
return rc;
@@ -1449,8 +1495,8 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
struct osmo_mobile_identity mi;
#endif
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_ACKED]);
- LOGMMCTXP(LOGL_INFO, mm, "<- ROUTING AREA UPDATE ACCEPT\n");
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_ACKED));
+ LOGMMCTXP(LOGL_INFO, mm, "<- GMM ROUTING AREA UPDATE ACCEPT\n");
mmctx2msgid(msg, mm);
@@ -1505,7 +1551,7 @@ int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause)
struct gsm48_hdr *gh;
LOGP(DMM, LOGL_NOTICE, "<- ROUTING AREA UPDATE REJECT\n");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REJECT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REJECT));
gmm_copy_id(msg, old_msg);
@@ -1585,7 +1631,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
/* Update Type 10.5.5.18 */
upd_type = *cur++ & 0x07;
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REQUEST]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REQUEST));
LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM RA UPDATE REQUEST type=\"%s\"\n",
get_value_string(gprs_upd_t_strs, upd_type));
@@ -1713,7 +1759,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
/* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */
msgid2mmctx(mmctx, msg);
/* Bump the statistics of received signalling msgs for this MM context */
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN));
/* Update the MM context with the new RA-ID */
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb && msgb_bcid(msg)) {
@@ -1721,10 +1767,14 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
/* Update the MM context with the new (i.e. foreign) TLLI */
mmctx->gb.tlli = msgb_tlli(msg);
}
+ /* Update the MM context with the new DRX params */
+ if (TLVP_PRESENT(&tp, GSM48_IE_GMM_DRX_PARAM))
+ memcpy(&mmctx->drx_parms, TLVP_VAL(&tp, GSM48_IE_GMM_DRX_PARAM), sizeof(mmctx->drx_parms));
+
/* FIXME: Update the MM context with the MS radio acc capabilities */
/* FIXME: Update the MM context with the MS network capabilities */
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_RA_UPDATE));
#ifdef PTMSI_ALLOC
ptmsi_update(mmctx);
@@ -1770,7 +1820,7 @@ rejected:
get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause);
if (mmctx)
- mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ");
+ mm_ctx_cleanup_free(mmctx, "GMM RA UPDATE REJ");
else if (llme)
gprs_llgmm_unassign(llme);
#ifdef BUILD_IU
@@ -1952,7 +2002,7 @@ static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
- LOGMMCTXP(LOGL_INFO, mmctx, "-> GPRS MM STATUS (cause: %s)\n",
+ LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM STATUS (cause: %s)\n",
get_value_string(gsm48_gmm_cause_names, gh->data[0]));
return 0;
@@ -2071,7 +2121,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
if (!mmctx)
goto null_mmctx;
LOGMMCTXP(LOGL_INFO, mmctx, "-> DETACH ACK\n");
- mm_ctx_cleanup_free(mmctx, "GPRS DETACH ACK");
+ mm_ctx_cleanup_free(mmctx, "GMM DETACH ACK");
rc = 0;
break;
case GSM48_MT_GMM_ATTACH_COMPL:
@@ -2111,9 +2161,9 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
null_mmctx:
LOGGBIUP(llme, msg, LOGL_ERROR,
- "Received GSM 04.08 message type 0x%02x,"
+ "Received GSM 04.08 message type %s,"
" but no MM context available\n",
- gh->msg_type);
+ get_value_string(gprs_msgt_gmm_names, gh->msg_type));
return -EINVAL;
}
@@ -2180,7 +2230,7 @@ static void mmctx_timer_cb(void *_mm)
if (mm->num_T_exp >= 5) {
LOGMMCTXP(LOGL_NOTICE, mm, "T3370 expired >= 5 times\n");
gsm48_tx_gmm_att_rej(mm, GMM_CAUSE_MS_ID_NOT_DERIVED);
- mm_ctx_cleanup_free(mm, "GPRS ATTACH REJECT (T3370)");
+ mm_ctx_cleanup_free(mm, "GMM ATTACH REJECT (T3370)");
break;
}
/* re-tranmit IDENTITY REQUEST and re-start timer */
@@ -2268,3 +2318,51 @@ int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RESUME, NULL);
return 0;
}
+
+/* Has to be called whenever any PDU (signaling, data, ...) has been received */
+void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg)
+{
+ msgid2mmctx(mmctx, msg);
+ if (mmctx->gb.llme)
+ osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL);
+}
+
+/* Main entry point for incoming 04.08 GPRS messages from Gb */
+int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
+ bool drop_cipherable)
+{
+ struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+ uint8_t pdisc = gsm48_hdr_pdisc(gh);
+ struct sgsn_mm_ctx *mmctx;
+ struct gprs_ra_id ra_id;
+ int rc = -EINVAL;
+
+ bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
+ mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
+ if (mmctx) {
+ rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN));
+ mmctx->gb.llme = llme;
+ gprs_gb_recv_pdu(mmctx, msg);
+ }
+
+ /* MMCTX can be NULL */
+
+ switch (pdisc) {
+ case GSM48_PDISC_MM_GPRS:
+ rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable);
+ break;
+ case GSM48_PDISC_SM_GPRS:
+ rc = gsm0408_rcv_gsm(mmctx, msg, llme);
+ break;
+ default:
+ LOGMMCTXP(LOGL_NOTICE, mmctx,
+ "Unknown GSM 04.08 discriminator 0x%02x: %s\n",
+ pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
+ /* FIXME: return status message */
+ break;
+ }
+
+ /* MMCTX can be invalid */
+
+ return rc;
+}
diff --git a/src/sgsn/gprs_gmm_attach.c b/src/sgsn/gprs_gmm_attach.c
index c903a016b..708ea8f23 100644
--- a/src/sgsn/gprs_gmm_attach.c
+++ b/src/sgsn/gprs_gmm_attach.c
@@ -1,10 +1,12 @@
#include <osmocom/core/tdef.h>
+#include <osmocom/crypt/utran_cipher.h>
#include <osmocom/sgsn/gprs_gmm_attach.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_gmm.h>
+#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/sgsn.h>
#define X(s) (1 << (s))
@@ -257,6 +259,7 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_
{
#ifdef BUILD_IU
struct sgsn_mm_ctx *ctx = fi->priv;
+ bool send_ck;
/* TODO: shouldn't this set always? not only when the integrity_active? */
if (ctx->iu.ue_ctx->integrity_active) {
@@ -264,7 +267,14 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_
return;
}
- ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 0, ctx->iu.new_key);
+ /* Is any encryption above UEA0 enabled? */
+ send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0);
+ LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA encryption mask = 0x%x)\n",
+ send_ck ? "sending" : "not sending", sgsn->cfg.uea_encryption_mask);
+
+ /* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2(). However, this
+ * is not possible in the iu_client API. See OS#5487. */
+ ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck, ctx->iu.new_key);
ctx->iu.new_key = 0;
#endif
}
@@ -272,6 +282,13 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_
static void st_iu_security_cmd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch(event) {
+ case E_VLR_ANSWERED:
+ /* We may receive an event due to rx
+ * OSMO_GSUP_MSGT_INSERT_DATA_REQUEST here. Do nothing, update of
+ * subscriber is done by lower layers before event is signalled.
+ * In this state we simply wait for E_IU_SECURITY_CMD_COMPLETE
+ */
+ break;
case E_IU_SECURITY_CMD_COMPLETE:
gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
break;
@@ -308,7 +325,7 @@ static struct osmo_fsm_state gmm_attach_req_fsm_states[] = {
.action = st_auth,
},
[ST_IU_SECURITY_CMD] = {
- .in_event_mask = X(E_IU_SECURITY_CMD_COMPLETE),
+ .in_event_mask = X(E_IU_SECURITY_CMD_COMPLETE) | X(E_VLR_ANSWERED),
.out_state_mask = X(ST_INIT) | X(ST_AUTH) | X(ST_ACCEPT) | X(ST_REJECT),
.name = "IuSecurityCommand",
.onenter = st_iu_security_cmd_on_enter,
diff --git a/src/sgsn/gprs_gmm_fsm.c b/src/sgsn/gprs_gmm_fsm.c
index 886726c68..57e1ec3bb 100644
--- a/src/sgsn/gprs_gmm_fsm.c
+++ b/src/sgsn/gprs_gmm_fsm.c
@@ -1,6 +1,6 @@
/* GMM mobility management states on the network side, 3GPP TS 24.008 § 4.1.3.3 */
/*
- * (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
+ * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
@@ -57,6 +57,10 @@ static void st_gmm_deregistered(struct osmo_fsm_inst *fi, uint32_t event, void *
static void st_gmm_common_proc_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch(event) {
+ case E_GMM_COMMON_PROC_INIT_REQ:
+ /* MS may retransmit GPRS Attach Request if for some reason
+ * CommonProcedure didn't go forward correctly */
+ break;
/* TODO: events not used
case E_GMM_LOWER_LAYER_FAILED:
case E_GMM_COMMON_PROC_FAILED:
@@ -76,6 +80,11 @@ static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, v
case E_GMM_COMMON_PROC_INIT_REQ:
gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
break;
+ case E_GMM_COMMON_PROC_SUCCESS:
+ /* If we were moved from ST_GMM_COMMON_PROC_INIT here by
+ * E_GMM_ATTACH_SUCCESS instead of E_GMM_COMMON_PROC_SUCCESS then we'll receive the latter here:
+ * we should simply ignore it */
+ break;
/* case E_GMM_NET_INIT_DETACH_REQ:
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED_INIT);
break; */
@@ -126,7 +135,8 @@ static struct osmo_fsm_state gmm_fsm_states[] = {
/* X(E_GMM_LOWER_LAYER_FAILED) | */
/* X(E_GMM_COMMON_PROC_FAILED) | */
X(E_GMM_COMMON_PROC_SUCCESS) |
- X(E_GMM_ATTACH_SUCCESS),
+ X(E_GMM_ATTACH_SUCCESS) |
+ X(E_GMM_COMMON_PROC_INIT_REQ),
.out_state_mask =
X(ST_GMM_DEREGISTERED) |
X(ST_GMM_REGISTERED_NORMAL),
@@ -136,6 +146,7 @@ static struct osmo_fsm_state gmm_fsm_states[] = {
[ST_GMM_REGISTERED_NORMAL] = {
.in_event_mask =
X(E_GMM_COMMON_PROC_INIT_REQ) |
+ X(E_GMM_COMMON_PROC_SUCCESS) |
/* X(E_GMM_NET_INIT_DETACH_REQ) | */
/* X(E_GMM_MS_INIT_DETACH_REQ) | */
X(E_GMM_SUSPEND),
@@ -194,9 +205,9 @@ void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *dat
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
default:
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
- osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
+ osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_GPRS_DETACH, NULL);
else if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) {
- osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
+ osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_PS_DETACH, NULL);
mmctx->gb.llme = rat_chg->llme;
}
diff --git a/src/sgsn/gprs_llc.c b/src/sgsn/gprs_llc.c
index e357d16f2..6f563851f 100644
--- a/src/sgsn/gprs_llc.c
+++ b/src/sgsn/gprs_llc.c
@@ -33,7 +33,7 @@
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/sgsn/debug.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/crc24.h>
@@ -42,16 +42,29 @@
#include <osmocom/sgsn/gprs_sndcp_comp.h>
#include <osmocom/sgsn/gprs_sndcp.h>
+#include <osmocom/crypt/kdf.h>
+
const struct value_string gprs_llc_llme_state_names[] = {
{ GPRS_LLMS_UNASSIGNED, "UNASSIGNED" },
{ GPRS_LLMS_ASSIGNED, "ASSIGNED" },
{ 0, NULL }
};
+const struct value_string gprs_llc_lle_state_names[] = {
+ { GPRS_LLES_UNASSIGNED, "TLLI Unassigned" },
+ { GPRS_LLES_ASSIGNED_ADM, "TLLI Assigned" },
+ { GPRS_LLES_LOCAL_EST, "Local Establishment" },
+ { GPRS_LLES_REMOTE_EST, "Remote Establishment" },
+ { GPRS_LLES_ABM, "Asynchronous Balanced Mode" },
+ { GPRS_LLES_LOCAL_REL, "Local Release" },
+ { GPRS_LLES_TIMER_REC, "Timer Recovery" },
+ { 0, NULL }
+};
+
static struct gprs_llc_llme *llme_alloc(uint32_t tlli);
-static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
+static int gprs_llc_tx_xid(const struct gprs_llc_lle *lle, struct msgb *msg,
int command);
-static int gprs_llc_tx_dm(struct gprs_llc_lle *lle);
+static int gprs_llc_tx_dm(const struct gprs_llc_lle *lle);
static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi,
int command, enum gprs_llc_u_cmd u_cmd, int pf_bit);
@@ -210,7 +223,7 @@ static int gprs_llc_process_xid_ind(uint8_t *bytes_request,
int bytes_request_len,
uint8_t *bytes_response,
int bytes_response_maxlen,
- struct gprs_llc_lle *lle)
+ const struct gprs_llc_lle *lle)
{
/* Note: This function computes the response that is sent back to the
* MS when a mobile originated XID is received. The function is
@@ -286,7 +299,7 @@ static int gprs_llc_process_xid_ind(uint8_t *bytes_request,
/* Dispatch XID indications and responses comming from the MS */
static void rx_llc_xid(struct gprs_llc_lle *lle,
- struct gprs_llc_hdr_parsed *gph)
+ const struct gprs_llc_hdr_parsed *gph)
{
uint8_t response[1024];
int response_len;
@@ -588,6 +601,7 @@ static struct gprs_llc_llme *llme_alloc(uint32_t tlli)
static void llme_free(struct gprs_llc_llme *llme)
{
+ gprs_sndcp_sm_deactivate_ind_by_llme(llme);
gprs_sndcp_comp_free(llme->comp.proto);
gprs_sndcp_comp_free(llme->comp.data);
llist_del(&llme->list);
@@ -670,15 +684,15 @@ int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command,
/* Identifiers passed down: (BVCI, NSEI) */
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_PACKETS]);
- rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_BYTES], msg->len);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_PACKETS));
+ rate_ctr_add(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_BYTES), msg->len);
/* Send BSSGP-DL-UNITDATA.req */
return _bssgp_tx_dl_ud(msg, NULL);
}
/* Send XID response to LLE */
-static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
+static int gprs_llc_tx_xid(const struct gprs_llc_lle *lle, struct msgb *msg,
int command)
{
/* copy identifiers from LLE to ensure lower layers can route */
@@ -689,7 +703,7 @@ static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
return gprs_llc_tx_u(msg, lle->sapi, command, GPRS_LLC_U_XID, 1);
}
-static int gprs_llc_tx_dm(struct gprs_llc_lle *lle)
+static int gprs_llc_tx_dm(const struct gprs_llc_lle *lle)
{
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_DM");
@@ -702,7 +716,7 @@ static int gprs_llc_tx_dm(struct gprs_llc_lle *lle)
}
/* encrypt information field + FCS, if needed! */
-static int apply_gea(struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu,
+static int apply_gea(const struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu,
uint32_t oc, uint8_t sapi, uint8_t *fcs, uint8_t *data)
{
uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
@@ -814,8 +828,8 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
}
}
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_PACKETS]);
- rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_BYTES], msg->len);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_PACKETS));
+ rate_ctr_add(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_BYTES), msg->len);
/* Identifiers passed down: (BVCI, NSEI) */
@@ -962,9 +976,9 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
llhp.data);
if (rc < 0)
return rc;
- llhp.fcs = *(llhp.data + llhp.data_len);
- llhp.fcs |= *(llhp.data + llhp.data_len + 1) << 8;
- llhp.fcs |= *(llhp.data + llhp.data_len + 2) << 16;
+ llhp.fcs = *(llhp.data + llhp.data_len);
+ llhp.fcs |= *(llhp.data + llhp.data_len + 1) << 8;
+ llhp.fcs |= *(llhp.data + llhp.data_len + 2) << 16;
} else {
LOGP(DLLC, LOGL_NOTICE, "encrypted frame for LLC that "
"has no KC/Algo! Dropping.\n");
@@ -1000,8 +1014,8 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
msgb_l3trim(msg, llhp.data_len);
}
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_UL_PACKETS]);
- rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_UL_BYTES], msg->len);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_UL_PACKETS));
+ rate_ctr_add(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_UL_BYTES), msg->len);
/* llhp.data is only set when we need to send LL_[UNIT]DATA_IND up */
if (llhp.cmd == GPRS_LLC_UI && llhp.data && llhp.data_len) {
@@ -1016,7 +1030,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
case GPRS_SAPI_SNDCP9:
case GPRS_SAPI_SNDCP11:
/* send LL_DATA_IND/LL_UNITDATA_IND to SNDCP */
- rc = sndcp_llunitdata_ind(msg, lle, llhp.data, llhp.data_len);
+ rc = sndcp_ll_unitdata_ind(msg, lle, llhp.data, llhp.data_len);
break;
case GPRS_SAPI_SMS:
/* FIXME */
@@ -1034,7 +1048,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
}
/* Propagate crypto parameters MM -> LLME */
-void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
+void gprs_llme_copy_key(const struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
{
if (!mm)
return;
@@ -1042,8 +1056,13 @@ void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
llme->algo = mm->ciph_algo;
if (llme->cksn != mm->auth_triplet.key_seq &&
mm->auth_triplet.key_seq != GSM_KEY_SEQ_INVAL) {
- memcpy(llme->kc, mm->auth_triplet.vec.kc,
- gprs_cipher_key_length(mm->ciph_algo));
+
+ /* gea4 needs kc128 */
+ if (mm->ciph_algo == GPRS_ALGO_GEA4)
+ osmo_kdf_kc128(mm->auth_triplet.vec.ck, mm->auth_triplet.vec.ik, llme->kc);
+ else
+ memcpy(llme->kc, mm->auth_triplet.vec.kc, gprs_cipher_key_length(mm->ciph_algo));
+
llme->cksn = mm->auth_triplet.key_seq;
}
} else
diff --git a/src/sgsn/gprs_llc_vty.c b/src/sgsn/gprs_llc_vty.c
index 418be8348..4572f957c 100644
--- a/src/sgsn/gprs_llc_vty.c
+++ b/src/sgsn/gprs_llc_vty.c
@@ -39,22 +39,11 @@
#include <osmocom/vty/vty.h>
#include <osmocom/vty/command.h>
-struct value_string gprs_llc_state_strs[] = {
- { GPRS_LLES_UNASSIGNED, "TLLI Unassigned" },
- { GPRS_LLES_ASSIGNED_ADM, "TLLI Assigned" },
- { GPRS_LLES_LOCAL_EST, "Local Establishment" },
- { GPRS_LLES_REMOTE_EST, "Remote Establishment" },
- { GPRS_LLES_ABM, "Asynchronous Balanced Mode" },
- { GPRS_LLES_LOCAL_REL, "Local Release" },
- { GPRS_LLES_TIMER_REC, "Timer Recovery" },
- { 0, NULL }
-};
-
static void vty_dump_lle(struct vty *vty, struct gprs_llc_lle *lle)
{
struct gprs_llc_params *par = &lle->params;
- vty_out(vty, " SAPI %2u State %s VUsend=%u, VUrecv=%u", lle->sapi,
- get_value_string(gprs_llc_state_strs, lle->state),
+ vty_out(vty, " SAPI %2u State %s VUsend=%u, VUrecv=%u", lle->sapi,
+ get_value_string(gprs_llc_lle_state_names, lle->state),
lle->vu_send, lle->vu_recv);
vty_out(vty, " Vsent=%u Vack=%u Vrecv=%u, RetransCtr=%u%s",
lle->v_sent, lle->v_ack, lle->v_recv,
@@ -79,7 +68,7 @@ static void vty_dump_llme(struct vty *vty, struct gprs_llc_llme *llme)
get_value_string(gprs_cipher_names, llme->algo), llme->iov_ui,
llme->cksn, llme->age_timestamp == GPRS_LLME_RESET_AGE ? 0 :
(int)(now_tp.tv_sec - (time_t)llme->age_timestamp),
- get_value_string(gprs_llc_state_strs, llme->state), VTY_NEWLINE);
+ get_value_string(gprs_llc_llme_state_names, llme->state), VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(valid_sapis); i++) {
struct gprs_llc_lle *lle;
diff --git a/src/sgsn/gprs_mm_state_gb_fsm.c b/src/sgsn/gprs_mm_state_gb_fsm.c
index d3f2ea323..dde7b770a 100644
--- a/src/sgsn/gprs_mm_state_gb_fsm.c
+++ b/src/sgsn/gprs_mm_state_gb_fsm.c
@@ -1,3 +1,25 @@
+/* TS 23.060 § 6.1.1 Mobility Management States (A/Gb mode) */
+/*
+ * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: AGPL-3.0+
+ *
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
#include <osmocom/core/tdef.h>
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
@@ -5,6 +27,7 @@
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
#define X(s) (1 << (s))
@@ -49,7 +72,7 @@ static void st_mm_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data)
case E_MM_READY_TIMER_EXPIRY:
mm_state_gb_fsm_state_chg(fi, ST_MM_STANDBY);
break;
- case E_MM_IMPLICIT_DETACH:
+ case E_MM_GPRS_DETACH:
mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
break;
case E_MM_PDU_RECEPTION:
@@ -68,7 +91,7 @@ static void st_mm_standby(struct osmo_fsm_inst *fi, uint32_t event, void *data)
case E_MM_PDU_RECEPTION:
mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
break;
- case E_MM_IMPLICIT_DETACH:
+ case E_MM_GPRS_DETACH:
mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
break;
}
@@ -83,13 +106,13 @@ static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
.action = st_mm_idle,
},
[ST_MM_READY] = {
- .in_event_mask = X(E_MM_READY_TIMER_EXPIRY) | X(E_MM_RA_UPDATE) | X(E_MM_IMPLICIT_DETACH) | X(E_MM_PDU_RECEPTION),
+ .in_event_mask = X(E_MM_READY_TIMER_EXPIRY) | X(E_MM_RA_UPDATE) | X(E_MM_GPRS_DETACH) | X(E_MM_PDU_RECEPTION),
.out_state_mask = X(ST_MM_IDLE) | X(ST_MM_STANDBY),
.name = "Ready",
.action = st_mm_ready,
},
[ST_MM_STANDBY] = {
- .in_event_mask = X(E_MM_PDU_RECEPTION) | X(E_MM_IMPLICIT_DETACH),
+ .in_event_mask = X(E_MM_PDU_RECEPTION) | X(E_MM_GPRS_DETACH),
.out_state_mask = X(ST_MM_IDLE) | X(ST_MM_READY),
.name = "Standby",
.action = st_mm_standby,
@@ -99,7 +122,7 @@ static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
const struct value_string mm_state_gb_fsm_event_names[] = {
OSMO_VALUE_STRING(E_MM_GPRS_ATTACH),
OSMO_VALUE_STRING(E_MM_PDU_RECEPTION),
- OSMO_VALUE_STRING(E_MM_IMPLICIT_DETACH),
+ OSMO_VALUE_STRING(E_MM_GPRS_DETACH),
OSMO_VALUE_STRING(E_MM_READY_TIMER_EXPIRY),
OSMO_VALUE_STRING(E_MM_RA_UPDATE),
{ 0, NULL }
diff --git a/src/sgsn/gprs_mm_state_iu_fsm.c b/src/sgsn/gprs_mm_state_iu_fsm.c
index e571026c8..c2e9c4498 100644
--- a/src/sgsn/gprs_mm_state_iu_fsm.c
+++ b/src/sgsn/gprs_mm_state_iu_fsm.c
@@ -1,3 +1,25 @@
+/* TS 23.060 § 6.1.2 Mobility Management States (Iu mode) */
+/*
+ * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: AGPL-3.0+
+ *
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
#include <arpa/inet.h>
#include <osmocom/core/tdef.h>
@@ -7,13 +29,15 @@
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_ranap.h>
+#include <osmocom/sgsn/gtp.h>
+#include <osmocom/sgsn/pdpctx.h>
+#include <osmocom/sgsn/mmctx.h>
#define X(s) (1 << (s))
static const struct osmo_tdef_state_timeout mm_state_iu_fsm_timeouts[32] = {
[ST_PMM_DETACHED] = { },
- /* non-spec -T3314 (User inactivity timer) */
- [ST_PMM_CONNECTED] = { .T=-3314 },
+ [ST_PMM_CONNECTED] = { },
[ST_PMM_IDLE] = { },
};
@@ -40,7 +64,7 @@ static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data
case E_PMM_PS_ATTACH:
mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
break;
- case E_PMM_IMPLICIT_DETACH:
+ case E_PMM_PS_DETACH:
break;
}
}
@@ -48,24 +72,16 @@ static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data
static void st_pmm_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct sgsn_mm_ctx *ctx = fi->priv;
- const struct RANAP_Cause user_inactive_cause = {
- .present = RANAP_Cause_PR_radioNetwork,
- .choice.radioNetwork = RANAP_CauseRadioNetwork_user_inactivity,
- };
switch(event) {
case E_PMM_PS_CONN_RELEASE:
sgsn_ranap_iu_free(ctx);
mm_state_iu_fsm_state_chg(fi, ST_PMM_IDLE);
break;
- case E_PMM_IMPLICIT_DETACH:
+ case E_PMM_PS_DETACH:
sgsn_ranap_iu_release_free(ctx, NULL);
mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
break;
- case E_PMM_USER_INACTIVITY:
- sgsn_ranap_iu_release_free(ctx, &user_inactive_cause);
- mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
- break;
case E_PMM_RA_UPDATE:
break;
}
@@ -81,43 +97,37 @@ static void st_pmm_idle_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
static void st_pmm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch(event) {
+ case E_PMM_PS_ATTACH:
case E_PMM_PS_CONN_ESTABLISH:
mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
break;
- case E_PMM_IMPLICIT_DETACH:
+ case E_PMM_PS_DETACH:
mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
break;
}
}
-static int pmm_state_fsm_timer_cb(struct osmo_fsm_inst *fi)
-{
- switch(fi->state) {
- case ST_PMM_CONNECTED:
- /* timer for pmm state. state=CONNECTED: -T3314 (User inactivity timer) */
- osmo_fsm_inst_dispatch(fi, E_PMM_USER_INACTIVITY, NULL);
- break;
- }
-
- return 0;
-}
-
static struct osmo_fsm_state mm_state_iu_fsm_states[] = {
[ST_PMM_DETACHED] = {
- .in_event_mask = X(E_PMM_PS_ATTACH) | X(E_PMM_IMPLICIT_DETACH),
+ .in_event_mask = X(E_PMM_PS_ATTACH) | X(E_PMM_PS_DETACH),
.out_state_mask = X(ST_PMM_CONNECTED),
.name = "Detached",
.action = st_pmm_detached,
},
[ST_PMM_CONNECTED] = {
- .in_event_mask = X(E_PMM_PS_CONN_RELEASE) | X(E_PMM_RA_UPDATE)
- | X(E_PMM_IMPLICIT_DETACH) | X(E_PMM_USER_INACTIVITY),
+ .in_event_mask =
+ X(E_PMM_PS_CONN_RELEASE) |
+ X(E_PMM_RA_UPDATE) |
+ X(E_PMM_PS_DETACH),
.out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_IDLE),
.name = "Connected",
.action = st_pmm_connected,
},
[ST_PMM_IDLE] = {
- .in_event_mask = X(E_PMM_IMPLICIT_DETACH) | X(E_PMM_PS_CONN_ESTABLISH),
+ .in_event_mask =
+ X(E_PMM_PS_DETACH) |
+ X(E_PMM_PS_CONN_ESTABLISH) |
+ X(E_PMM_PS_ATTACH),
.out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_CONNECTED),
.name = "Idle",
.onenter = st_pmm_idle_on_enter,
@@ -129,9 +139,8 @@ const struct value_string mm_state_iu_fsm_event_names[] = {
OSMO_VALUE_STRING(E_PMM_PS_ATTACH),
OSMO_VALUE_STRING(E_PMM_PS_CONN_RELEASE),
OSMO_VALUE_STRING(E_PMM_PS_CONN_ESTABLISH),
- OSMO_VALUE_STRING(E_PMM_IMPLICIT_DETACH),
+ OSMO_VALUE_STRING(E_PMM_PS_DETACH),
OSMO_VALUE_STRING(E_PMM_RA_UPDATE),
- OSMO_VALUE_STRING(E_PMM_USER_INACTIVITY),
{ 0, NULL }
};
@@ -140,7 +149,6 @@ struct osmo_fsm mm_state_iu_fsm = {
.states = mm_state_iu_fsm_states,
.num_states = ARRAY_SIZE(mm_state_iu_fsm_states),
.event_names = mm_state_iu_fsm_event_names,
- .timer_cb = pmm_state_fsm_timer_cb,
.log_subsys = DMM,
};
diff --git a/src/sgsn/gprs_gb.c b/src/sgsn/gprs_ns.c
index cddd1b1e1..eb447facd 100644
--- a/src/sgsn/gprs_gb.c
+++ b/src/sgsn/gprs_ns.c
@@ -29,95 +29,10 @@
#include <osmocom/gprs/gprs_bssgp_bss.h>
#include <osmocom/sgsn/gprs_llc.h>
-#include "bscconfig.h"
+#include "config.h"
-#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
-#include <osmocom/sgsn/gprs_gmm.h>
-#include <osmocom/sgsn/gprs_sm.h>
#include <osmocom/sgsn/debug.h>
-/* Has to be called whenever any PDU (signaling, data, ...) has been received */
-void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg) {
- msgid2mmctx(mmctx, msg);
- if (mmctx->gb.llme)
- osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL);
-}
-
-/* Main entry point for incoming 04.08 GPRS messages from Gb */
-int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
- bool drop_cipherable)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t pdisc = gsm48_hdr_pdisc(gh);
- struct sgsn_mm_ctx *mmctx;
- struct gprs_ra_id ra_id;
- int rc = -EINVAL;
-
- bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
- mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
- if (mmctx) {
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
- mmctx->gb.llme = llme;
- gprs_gb_recv_pdu(mmctx, msg);
- }
-
- /* MMCTX can be NULL */
-
- switch (pdisc) {
- case GSM48_PDISC_MM_GPRS:
- rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable);
- break;
- case GSM48_PDISC_SM_GPRS:
- rc = gsm0408_rcv_gsm(mmctx, msg, llme);
- break;
- default:
- LOGMMCTXP(LOGL_NOTICE, mmctx,
- "Unknown GSM 04.08 discriminator 0x%02x: %s\n",
- pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
- /* FIXME: return status message */
- break;
- }
-
- /* MMCTX can be invalid */
-
- return rc;
-}
-
-
-int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx)
-{
- struct bssgp_paging_info pinfo;
- int rc;
-
- /* FIXME: page whole routing area, not only the last known cell */
-
- /* initiate PS PAGING procedure */
- memset(&pinfo, 0, sizeof(pinfo));
- pinfo.mode = BSSGP_PAGING_PS;
- pinfo.scope = BSSGP_PAGING_BVCI;
- pinfo.bvci = mmctx->gb.bvci;
- pinfo.imsi = mmctx->imsi;
- pinfo.ptmsi = &mmctx->p_tmsi;
- pinfo.drx_params = mmctx->drx_parms;
- pinfo.qos[0] = 0; // FIXME
- rc = bssgp_tx_paging(mmctx->gb.nsei, 0, &pinfo);
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PAGING_PS]);
-
- return rc;
-}
-
-/* called by the bssgp layer to send NS PDUs */
-int gprs_gb_send_cb(void *ctx, struct msgb *msg)
-{
- struct gprs_ns2_inst *nsi = (struct gprs_ns2_inst *) ctx;
- struct osmo_gprs_ns2_prim nsp = {};
- nsp.nsei = msgb_nsei(msg);
- nsp.bvci = msgb_bvci(msg);
- osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg);
- return gprs_ns2_recv_prim(nsi, &nsp.oph);
-}
-
void gprs_ns_prim_status_cb(struct osmo_gprs_ns2_prim *nsp)
{
switch (nsp->u.status.cause) {
diff --git a/src/sgsn/gprs_ranap.c b/src/sgsn/gprs_ranap.c
index 1f8ed97dd..5e0d8edc6 100644
--- a/src/sgsn/gprs_ranap.c
+++ b/src/sgsn/gprs_ranap.c
@@ -21,7 +21,7 @@
*
*/
-#include "bscconfig.h"
+#include "config.h"
#include <gtp.h>
#include <osmocom/core/rate_ctr.h>
@@ -37,6 +37,10 @@
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_gmm_attach.h>
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
+#include <osmocom/sgsn/gtp_ggsn.h>
+#include <osmocom/sgsn/gtp.h>
+#include <osmocom/sgsn/pdpctx.h>
+#include <osmocom/sgsn/mmctx.h>
/* Send RAB activation requests for all PDP contexts */
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx)
@@ -120,7 +124,8 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
mm = sgsn_mm_ctx_by_ue_ctx(ctx);
if (!mm) {
- LOGIUP(ctx, LOGL_NOTICE, "Cannot find mm ctx for IU event %d\n", type);
+ LOGIUP(ctx, LOGL_NOTICE, "Cannot find mm ctx for IU event %s\n",
+ ranap_iu_event_type_str(type));
ranap_iu_free_ue(ctx);
return rc;
}
@@ -133,10 +138,9 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
/* fall thru */
case RANAP_IU_EVENT_LINK_INVALIDATED:
/* Clean up ranap_ue_conn_ctx here */
- LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi);
- if (mm->iu.mm_state_fsm->state == ST_PMM_CONNECTED)
- osmo_fsm_inst_dispatch(mm->iu.mm_state_fsm, E_PMM_PS_CONN_RELEASE, NULL);
- else
+ LOGMMCTXP(LOGL_INFO, mm, "IU release (cause=%s)\n", ranap_iu_event_type_str(type));
+ rc = osmo_fsm_inst_dispatch(mm->iu.mm_state_fsm, E_PMM_PS_CONN_RELEASE, NULL);
+ if (rc < 0)
sgsn_ranap_iu_free(mm);
/* TODO: move this into FSM */
@@ -145,6 +149,11 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
rc = 0;
break;
case RANAP_IU_EVENT_SECURITY_MODE_COMPLETE:
+ /* FIXME: verify that a permitted UEA level was chosen. Compare how osmo-msc does it in
+ * msc_a_ran_dec_from_msc_i(), case RAN_MSG_CIPHER_MODE_COMPLETE.
+ * We should dissolve iu_client.c, it was a design mistake when first implementing Iu support. osmo-msc
+ * has moved away from it a long time ago.
+ */
/* Continue authentication here */
mm->iu.ue_ctx->integrity_active = 1;
ranap_iu_tx_common_id(mm->iu.ue_ctx, mm->imsi);
@@ -232,7 +241,7 @@ int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
mmctx = sgsn_mm_ctx_by_ue_ctx(MSG_IU_UE_CTX(msg));
if (mmctx) {
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN));
if (ra_id)
memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra));
}
diff --git a/src/sgsn/gprs_sm.c b/src/sgsn/gprs_sm.c
index 3bdad3bf6..88d1feb5a 100644
--- a/src/sgsn/gprs_sm.c
+++ b/src/sgsn/gprs_sm.c
@@ -26,7 +26,7 @@
#include <arpa/inet.h>
#include <netdb.h>
-#include "bscconfig.h"
+#include "config.h"
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/tdef.h>
@@ -36,13 +36,15 @@
#include <osmocom/sgsn/gprs_sm.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_utils.h>
+#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gprs_ranap.h>
-
-extern void *tall_sgsn_ctx;
+#include <osmocom/sgsn/gtp.h>
+#include <osmocom/sgsn/pdpctx.h>
+#include <osmocom/sgsn/mmctx.h>
/* 3GPP TS 04.08 sec 6.1.3.4.3(.a) "Abnormal cases" */
#define T339X_MAX_RETRANS 4
@@ -186,7 +188,7 @@ int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp)
uint8_t transaction_id = pdp->ti ^ 0x8; /* flip */
LOGPDPCTXP(LOGL_INFO, pdp, "<- ACTIVATE PDP CONTEXT ACK\n");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_ACCEPT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_ACTIVATE_ACCEPT));
mmctx2msgid(msg, pdp->mm);
@@ -232,7 +234,7 @@ int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
LOGMMCTXP(LOGL_NOTICE, mm, "<- ACTIVATE PDP CONTEXT REJ: %s\n",
get_value_string(gsm48_gsm_cause_names, cause));
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REJECT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_ACTIVATE_REJECT));
mmctx2msgid(msg, mm);
@@ -257,7 +259,7 @@ static int _gsm48_tx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, uint8_t tid,
uint8_t tear_down_ind = (0x9 << 4) | (!!teardown);
LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT REQ\n");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_REQUEST]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_DL_DEACTIVATE_REQUEST));
mmctx2msgid(msg, mm);
@@ -285,7 +287,7 @@ static int _gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mm, uint8_t tid)
uint8_t transaction_id = tid ^ 0x8; /* flip */
LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT ACK\n");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_ACCEPT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_DL_DEACTIVATE_ACCEPT));
mmctx2msgid(msg, mm);
@@ -376,7 +378,7 @@ static void ggsn_lookup_cb(void *arg, int status, int timeouts, struct hostent *
goto reject_due_failure;
}
- ggsn = sgsn_ggsn_ctx_alloc(UINT32_MAX);
+ ggsn = sgsn_ggsn_ctx_alloc(sgsn, UINT32_MAX);
if (!ggsn) {
LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "Failed to create ggsn.\n");
goto reject_due_failure;
@@ -448,7 +450,7 @@ static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *del
DEBUGPC(DMM, "IPv4 ");
if (req_pdpa_len >= 6) {
struct in_addr ia;
- ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2)));
+ ia.s_addr = osmo_load32be(req_pdpa+2);
DEBUGPC(DMM, "%s ", inet_ntop(AF_INET, &ia, buf, sizeof(buf)));
}
break;
@@ -533,7 +535,7 @@ static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *del
/* Only increment counter for a real activation, after we checked
* for re-transmissions */
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PDP_CTX_ACT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PDP_CTX_ACT));
/* Determine GGSN based on APN and subscription options */
ggsn = sgsn_mm_ctx_find_ggsn_ctx(mmctx, &tp, &gsm_cause, apn_str);
@@ -591,7 +593,7 @@ static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,
struct msgb *msg;
int rc;
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REQUEST]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_ACTIVATE_REQUEST));
/*
* This is painful. We might not have a static GGSN
@@ -629,7 +631,7 @@ static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)
LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT REQ (cause: %s)\n",
get_value_string(gsm48_gsm_cause_names, gh->data[0]));
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_REQUEST]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_UL_DEACTIVATE_REQUEST));
pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
if (!pdp) {
@@ -654,7 +656,7 @@ static int gsm48_rx_gsm_deact_pdp_ack(struct sgsn_mm_ctx *mm, struct msgb *msg)
struct sgsn_pdp_ctx *pdp;
LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT ACK\n");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_ACCEPT]);
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_UL_DEACTIVATE_ACCEPT));
pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
if (!pdp) {
diff --git a/src/sgsn/gprs_sndcp.c b/src/sgsn/gprs_sndcp.c
index 6692f1ae5..3eae127fc 100644
--- a/src/sgsn/gprs_sndcp.c
+++ b/src/sgsn/gprs_sndcp.c
@@ -32,7 +32,7 @@
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/sgsn/debug.h>
-#include <osmocom/sgsn/gprs_gb.h>
+#include <osmocom/sgsn/gprs_ns.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_sndcp.h>
@@ -41,6 +41,9 @@
#include <osmocom/sgsn/gprs_sndcp_pcomp.h>
#include <osmocom/sgsn/gprs_sndcp_dcomp.h>
#include <osmocom/sgsn/gprs_sndcp_comp.h>
+#include <osmocom/sgsn/gprs_gmm.h>
+#include <osmocom/sgsn/mmctx.h>
+#include <osmocom/sgsn/gtp.h>
#define DEBUG_IP_PACKETS 0 /* 0=Disabled, 1=Enabled */
@@ -66,7 +69,7 @@ static uint16_t calc_ip_csum(uint8_t *data, int len)
}
/* Calculate TCP/IP checksum */
-static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len)
+static uint16_t calc_tcpip_csum(const void *ctx, const uint8_t *packet, int len)
{
uint8_t *buf;
uint16_t csum;
@@ -84,7 +87,7 @@ static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len)
}
/* Show some ip packet details */
-static void debug_ip_packet(uint8_t *data, int len, int dir, char *info)
+static void debug_ip_packet(const uint8_t *data, int len, int dir, const char *info)
{
uint8_t tcp_flags;
char flags_debugmsg[256];
@@ -173,7 +176,7 @@ struct sndcp_common_hdr {
uint8_t first:1;
uint8_t spare:1;
#elif OSMO_IS_BIG_ENDIAN
-/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
uint8_t spare:1, first:1, type:1, more:1, nsapi:4;
#endif
} __attribute__((packed));
@@ -185,7 +188,7 @@ struct sndcp_comp_hdr {
uint8_t pcomp:4;
uint8_t dcomp:4;
#elif OSMO_IS_BIG_ENDIAN
-/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
uint8_t dcomp:4, pcomp:4;
#endif
} __attribute__((packed));
@@ -198,7 +201,7 @@ struct sndcp_udata_hdr {
/* octet 4 */
uint8_t npdu_low;
#elif OSMO_IS_BIG_ENDIAN
-/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
uint8_t seg_nr:4, npdu_high:4;
uint8_t npdu_low;
#endif
@@ -221,7 +224,8 @@ struct defrag_queue_entry {
LLIST_HEAD(gprs_sndcp_entities);
/* Check if any compression parameters are set in the sgsn configuration */
-static inline int any_pcomp_or_dcomp_active(struct sgsn_instance *sgsn) {
+static inline int any_pcomp_or_dcomp_active(const struct sgsn_instance *sgsn)
+{
if (sgsn->cfg.pcomp_rfc1144.active || sgsn->cfg.pcomp_rfc1144.passive ||
sgsn->cfg.dcomp_v42bis.active || sgsn->cfg.dcomp_v42bis.passive)
return true;
@@ -260,7 +264,7 @@ static int defrag_enqueue(struct gprs_sndcp_entity *sne, uint8_t seg_nr,
}
/* return if we have all segments of this N-PDU */
-static int defrag_have_all_segments(struct gprs_sndcp_entity *sne)
+static int defrag_have_all_segments(const struct gprs_sndcp_entity *sne)
{
uint32_t seg_needed = 0;
unsigned int i;
@@ -275,7 +279,7 @@ static int defrag_have_all_segments(struct gprs_sndcp_entity *sne)
return 0;
}
-static struct defrag_queue_entry *defrag_get_seg(struct gprs_sndcp_entity *sne,
+static struct defrag_queue_entry *defrag_get_seg(const struct gprs_sndcp_entity *sne,
uint32_t seg_nr)
{
struct defrag_queue_entry *dqe;
@@ -289,13 +293,62 @@ static struct defrag_queue_entry *defrag_get_seg(struct gprs_sndcp_entity *sne,
return NULL;
}
+/* Returns talloced buffer containing decompressed data, NULL on error. */
+static uint8_t *decompress_segment(struct gprs_sndcp_entity *sne, void *ctx,
+ const uint8_t *compressed_data, unsigned int compressed_data_len,
+ unsigned int *decompressed_data_len)
+{
+ int rc;
+ uint8_t *expnd = NULL;
+ *decompressed_data_len = 0;
+
+#if DEBUG_IP_PACKETS == 1
+ DEBUGP(DSNDCP, "\n");
+ DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
+ DEBUGP(DSNDCP, "===================================================\n");
+#endif
+
+ expnd = talloc_zero_size(ctx, compressed_data_len * MAX_DATADECOMPR_FAC +
+ MAX_HDRDECOMPR_INCR);
+ memcpy(expnd, compressed_data, compressed_data_len);
+
+ /* Apply data decompression */
+ rc = gprs_sndcp_dcomp_expand(expnd, compressed_data_len, sne->defrag.dcomp,
+ sne->defrag.data);
+ if (rc < 0) {
+ LOGP(DSNDCP, LOGL_ERROR,
+ "Data decompression failed!\n");
+ talloc_free(expnd);
+ return NULL;
+ }
+
+ /* Apply header decompression */
+ rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp, sne->defrag.proto);
+ if (rc < 0) {
+ LOGP(DSNDCP, LOGL_ERROR,
+ "TCP/IP Header decompression failed!\n");
+ talloc_free(expnd);
+ return NULL;
+ }
+
+ *decompressed_data_len = rc;
+
+#if DEBUG_IP_PACKETS == 1
+ debug_ip_packet(expnd, *decompressed_data_len, 1, "defrag_segments()");
+ DEBUGP(DSNDCP, "===================================================\n");
+ DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
+ DEBUGP(DSNDCP, "\n");
+#endif
+ return expnd;
+}
+
/* Perform actual defragmentation and create an output packet */
static int defrag_segments(struct gprs_sndcp_entity *sne)
{
struct msgb *msg;
unsigned int seg_nr;
uint8_t *npdu;
- int npdu_len;
+ unsigned int npdu_len;
int rc;
uint8_t *expnd = NULL;
@@ -336,53 +389,20 @@ static int defrag_segments(struct gprs_sndcp_entity *sne)
* hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */
/* Decompress packet */
-#if DEBUG_IP_PACKETS == 1
- DEBUGP(DSNDCP, " \n");
- DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
- DEBUGP(DSNDCP, "===================================================\n");
-#endif
if (any_pcomp_or_dcomp_active(sgsn)) {
-
- expnd = talloc_zero_size(msg, npdu_len * MAX_DATADECOMPR_FAC +
- MAX_HDRDECOMPR_INCR);
- memcpy(expnd, npdu, npdu_len);
-
- /* Apply data decompression */
- rc = gprs_sndcp_dcomp_expand(expnd, npdu_len, sne->defrag.dcomp,
- sne->defrag.data);
- if (rc < 0) {
- LOGP(DSNDCP, LOGL_ERROR,
- "Data decompression failed!\n");
- talloc_free(expnd);
- return -EIO;
+ expnd = decompress_segment(sne, msg, npdu, npdu_len, &npdu_len);
+ if (!expnd) {
+ rc = -EIO;
+ goto ret_free;
}
-
- /* Apply header decompression */
- rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp,
- sne->defrag.proto);
- if (rc < 0) {
- LOGP(DSNDCP, LOGL_ERROR,
- "TCP/IP Header decompression failed!\n");
- talloc_free(expnd);
- return -EIO;
- }
-
- /* Modify npu length, expnd is handed directly handed
- * over to gsn_rx_sndcp_ud_ind(), see below */
- npdu_len = rc;
- } else
+ } else {
expnd = npdu;
-#if DEBUG_IP_PACKETS == 1
- debug_ip_packet(expnd, npdu_len, 1, "defrag_segments()");
- DEBUGP(DSNDCP, "===================================================\n");
- DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
- DEBUGP(DSNDCP, " \n");
-#endif
+ }
- /* Hand off packet to gtp */
- rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli,
- sne->nsapi, msg, npdu_len, expnd);
+ /* Hand off packet to SGSN (SNDCP SN-UNITDATA.ind), which will forward it to GGSN (GTP): */
+ rc = sndcp_sn_unitdata_ind(sne, msg, npdu_len, expnd);
+ret_free:
/* we must free the memory we allocated above; ownership is not transferred
* downwards in the call above */
msgb_free(msg);
@@ -522,7 +542,7 @@ int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
}
/* Entry point for the SNSM-DEACTIVATE.indication */
-int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
+int sndcp_sm_deactivate_ind(const struct gprs_llc_lle *lle, uint8_t nsapi)
{
struct gprs_sndcp_entity *sne;
@@ -544,6 +564,20 @@ int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
return 0;
}
+/* Clean up all gprs_sndcp_entities related to llme (OS#4824) */
+void gprs_sndcp_sm_deactivate_ind_by_llme(const struct gprs_llc_llme *llme)
+{
+ struct gprs_sndcp_entity *sne, *sne2;
+
+ llist_for_each_entry_safe(sne, sne2, &gprs_sndcp_entities, list) {
+ if (sne->lle->llme == llme) {
+ LOGP(DSNDCP, LOGL_INFO, "SNSM-DEACTIVATE.ind for SNDCP attached to llme=%p\n", llme);
+ /* Free and remove from list */
+ sndcp_sm_deactivate_ind(sne->lle, sne->nsapi);
+ }
+ }
+}
+
/* Fragmenter state */
struct sndcp_frag_state {
uint8_t frag_nr;
@@ -651,7 +685,7 @@ static int sndcp_send_ud_frag(struct sndcp_frag_state *fs,
}
/* Request transmission of a SN-PDU over specified LLC Entity + SAPI */
-int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
+int sndcp_sn_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
void *mmcontext)
{
struct gprs_sndcp_entity *sne;
@@ -709,13 +743,14 @@ int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi
sne = gprs_sndcp_entity_by_lle(lle, nsapi);
if (!sne) {
- LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity\n");
+ LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity (lle=%p, TLLI=%08x, SAPI=%u, NSAPI=%u)\n",
+ lle, lle->llme->tlli, lle->sapi, nsapi);
msgb_free(msg);
return -EIO;
}
/* Check if we need to fragment this N-PDU into multiple SN-PDUs */
- if (msg->len > lle->params.n201_u -
+ if (msg->len > lle->params.n201_u -
(sizeof(*sch) + sizeof(*suh) + sizeof(*scomph))) {
/* initialize the fragmenter state */
fs.msg = msg;
@@ -760,7 +795,7 @@ int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi
}
/* Section 5.1.2.17 LL-UNITDATA.ind */
-int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
+int sndcp_ll_unitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
uint8_t *hdr, uint16_t len)
{
struct gprs_sndcp_entity *sne;
@@ -830,63 +865,40 @@ int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len);
return -EIO;
}
- /* actually send the N-PDU to the SGSN core code, which then
- * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */
+ /* actually send the N-PDU to the SGSN core code (SNDCP SN-UNITDATA.ind) */
/* Decompress packet */
-#if DEBUG_IP_PACKETS == 1
- DEBUGP(DSNDCP, " \n");
- DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
- DEBUGP(DSNDCP, "===================================================\n");
-#endif
if (any_pcomp_or_dcomp_active(sgsn)) {
-
- expnd = talloc_zero_size(msg, npdu_len * MAX_DATADECOMPR_FAC +
- MAX_HDRDECOMPR_INCR);
- memcpy(expnd, npdu, npdu_len);
-
- /* Apply data decompression */
- rc = gprs_sndcp_dcomp_expand(expnd, npdu_len, sne->defrag.dcomp,
- sne->defrag.data);
- if (rc < 0) {
- LOGP(DSNDCP, LOGL_ERROR,
- "Data decompression failed!\n");
- talloc_free(expnd);
- return -EIO;
- }
-
- /* Apply header decompression */
- rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp,
- sne->defrag.proto);
- if (rc < 0) {
- LOGP(DSNDCP, LOGL_ERROR,
- "TCP/IP Header decompression failed!\n");
- talloc_free(expnd);
- return -EIO;
+ expnd = decompress_segment(sne, msg, npdu, npdu_len, (unsigned int *)&npdu_len);
+ if (!expnd) {
+ rc = -EIO;
+ goto ret_free;
}
-
- /* Modify npu length, expnd is handed directly handed
- * over to gsn_rx_sndcp_ud_ind(), see below */
- npdu_len = rc;
- } else
+ } else {
expnd = npdu;
-#if DEBUG_IP_PACKETS == 1
- debug_ip_packet(expnd, npdu_len, 1, "sndcp_llunitdata_ind()");
- DEBUGP(DSNDCP, "===================================================\n");
- DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
- DEBUGP(DSNDCP, " \n");
-#endif
+ }
/* Hand off packet to gtp */
- rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli,
- sne->nsapi, msg, npdu_len, expnd);
+ rc = sndcp_sn_unitdata_ind(sne, msg, npdu_len, expnd);
+ret_free:
if (any_pcomp_or_dcomp_active(sgsn))
talloc_free(expnd);
return rc;
}
+/* 5.1.1.4 SN-UNITDATA.indication
+ * Called by SNDCP when it has received/re-assembled a N-PDU
+ */
+int sndcp_sn_unitdata_ind(struct gprs_sndcp_entity *sne,
+ struct msgb *msg, uint32_t npdu_len, uint8_t *npdu)
+{
+ /* Hand it off N-PDU to the correct GTP tunnel + GGSN: */
+ return sgsn_gtp_data_req(&sne->ra_id, sne->lle->llme->tlli,
+ sne->nsapi, msg, npdu_len, npdu);
+}
+
#if 0
/* Section 5.1.2.1 LL-RESET.ind */
static int sndcp_ll_reset_ind(struct gprs_sndcp_entity *se)
@@ -1042,7 +1054,7 @@ int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi)
/* Handle header compression entites */
static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field,
- struct gprs_llc_lle *lle)
+ const struct gprs_llc_lle *lle)
{
/* Note: This functions also transforms the comp_field into its
* echo form (strips comp values, resets propose bit etc...)
@@ -1092,7 +1104,7 @@ static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field,
/* Hanle data compression entites */
static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field,
- struct gprs_llc_lle *lle)
+ const struct gprs_llc_lle *lle)
{
/* See note in handle_pcomp_entities() */
@@ -1134,7 +1146,7 @@ static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field,
* (See also: TS 144 065, Section 6.8 XID parameter negotiation) */
int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication,
struct gprs_llc_xid_field *xid_field_response,
- struct gprs_llc_lle *lle)
+ const struct gprs_llc_lle *lle)
{
/* Note: This function computes the SNDCP-XID response that is sent
* back to the ms when a ms originated XID is received. The
diff --git a/src/sgsn/gprs_subscriber.c b/src/sgsn/gprs_subscriber.c
index 943fbc3dc..a52abe8f1 100644
--- a/src/sgsn/gprs_subscriber.c
+++ b/src/sgsn/gprs_subscriber.c
@@ -30,7 +30,7 @@
#include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/sgsn/sgsn.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_utils.h>
@@ -48,8 +48,6 @@
(gsup)->imsi, \
## args)
-extern void *tall_sgsn_ctx;
-
LLIST_HEAD(_gprs_subscribers);
struct llist_head * const gprs_subscribers = &_gprs_subscribers;
@@ -378,7 +376,8 @@ static void gprs_subscr_gsup_insert_data(struct gprs_subscr *subscr,
}
OSMO_ASSERT(pdp_data != NULL);
- pdp_data->pdp_type = pdp_info->pdp_type;
+ pdp_data->pdp_type_org = pdp_info->pdp_type_org;
+ pdp_data->pdp_type_nr = pdp_info->pdp_type_nr;
osmo_apn_to_str(pdp_data->apn_str,
pdp_info->apn_enc, pdp_info->apn_enc_len);
diff --git a/src/sgsn/gtp_ggsn.c b/src/sgsn/gtp_ggsn.c
new file mode 100644
index 000000000..14cdfea00
--- /dev/null
+++ b/src/sgsn/gtp_ggsn.c
@@ -0,0 +1,178 @@
+/* GGSN context (peer) */
+
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/stats.h>
+
+#include <osmocom/sgsn/gtp_ggsn.h>
+#include <osmocom/sgsn/gtp.h>
+#include <osmocom/sgsn/sgsn.h>
+#include <osmocom/sgsn/debug.h>
+#include <osmocom/sgsn/gprs_gmm_fsm.h>
+#include <osmocom/sgsn/gprs_sm.h>
+#include <osmocom/sgsn/pdpctx.h>
+
+void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc)
+{
+ bool pending = osmo_timer_pending(&ggc->echo_timer);
+
+ /* Only enable if allowed by policy and at least 1 pdp ctx exists against ggsn */
+ if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval) {
+ if (!pending)
+ osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
+ } else {
+ if (pending)
+ osmo_timer_del(&ggc->echo_timer);
+ }
+}
+
+/* GGSN contexts */
+static void echo_timer_cb(void *data)
+{
+ struct sgsn_ggsn_ctx *ggc = (struct sgsn_ggsn_ctx *) data;
+ sgsn_ggsn_echo_req(ggc);
+ osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
+}
+
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(struct sgsn_instance *sgsn, uint32_t id)
+{
+ struct sgsn_ggsn_ctx *ggc;
+
+ ggc = talloc_zero(sgsn, struct sgsn_ggsn_ctx);
+ if (!ggc)
+ return NULL;
+
+ ggc->id = id;
+ ggc->gtp_version = 1;
+ ggc->remote_restart_ctr = -1;
+ /* if we are called from config file parse, this gsn doesn't exist yet */
+ ggc->gsn = sgsn->gsn;
+ INIT_LLIST_HEAD(&ggc->pdp_list);
+ osmo_timer_setup(&ggc->echo_timer, echo_timer_cb, ggc);
+ llist_add(&ggc->list, &sgsn->ggsn_list);
+
+ return ggc;
+}
+
+void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc)
+{
+ OSMO_ASSERT(llist_empty(&ggc->pdp_list));
+ llist_del(&ggc->list);
+ talloc_free(ggc);
+}
+
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(struct sgsn_instance *sgsn, uint32_t id)
+{
+ struct sgsn_ggsn_ctx *ggc;
+
+ llist_for_each_entry(ggc, &sgsn->ggsn_list, list) {
+ if (id == ggc->id)
+ return ggc;
+ }
+ return NULL;
+}
+
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct sgsn_instance *sgsn, struct in_addr *addr)
+{
+ struct sgsn_ggsn_ctx *ggc;
+
+ llist_for_each_entry(ggc, &sgsn->ggsn_list, list) {
+ if (!memcmp(addr, &ggc->remote_addr, sizeof(*addr)))
+ return ggc;
+ }
+ return NULL;
+}
+
+
+struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(struct sgsn_instance *sgsn, uint32_t id)
+{
+ struct sgsn_ggsn_ctx *ggc;
+
+ ggc = sgsn_ggsn_ctx_by_id(sgsn, id);
+ if (!ggc)
+ ggc = sgsn_ggsn_ctx_alloc(sgsn, id);
+ return ggc;
+}
+
+void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx)
+{
+ /* the MM context can be deleted while the GGSN is not reachable or
+ * if has been crashed. */
+ if (pctx->mm && pctx->mm->gmm_fsm->state == ST_GMM_REGISTERED_NORMAL) {
+ gsm48_tx_gsm_deact_pdp_req(pctx, GSM_CAUSE_NET_FAIL, true);
+ sgsn_ggsn_ctx_remove_pdp(pctx->ggsn, pctx);
+ } else {
+ /* FIXME: GPRS paging in case MS is SUSPENDED */
+ LOGPDPCTXP(LOGL_NOTICE, pctx, "Hard-dropping PDP ctx due to GGSN "
+ "recovery\n");
+ /* FIXME: how to tell this to libgtp? */
+ sgsn_pdp_ctx_free(pctx);
+ }
+}
+
+/* High-level function to be called in case a GGSN has disappeared or
+ * otherwise lost state (recovery procedure). It will detach all related pdp ctx
+ * from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can
+ * be kept alive to allow handling later message which contained the Recovery IE. */
+int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except)
+{
+ int num = 0;
+
+ struct sgsn_pdp_ctx *pdp, *pdp2;
+ llist_for_each_entry_safe(pdp, pdp2, &ggsn->pdp_list, ggsn_list) {
+ if (pdp == except)
+ continue;
+ sgsn_ggsn_ctx_drop_pdp(pdp);
+ num++;
+ }
+
+ return num;
+}
+
+int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn)
+{
+ return sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, NULL);
+}
+
+void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
+{
+ llist_add(&pdp->ggsn_list, &ggc->pdp_list);
+ sgsn_ggsn_ctx_check_echo_timer(ggc);
+}
+
+void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
+{
+ llist_del(&pdp->ggsn_list);
+ sgsn_ggsn_ctx_check_echo_timer(ggc);
+ if (pdp->destroy_ggsn)
+ sgsn_ggsn_ctx_free(pdp->ggsn);
+ pdp->ggsn = NULL;
+ /* Drop references to libgtp since the conn is down */
+ if (pdp->lib)
+ pdp_freepdp(pdp->lib);
+ pdp->lib = NULL;
+}
diff --git a/src/sgsn/gtp_mme.c b/src/sgsn/gtp_mme.c
new file mode 100644
index 000000000..3d7ec76b6
--- /dev/null
+++ b/src/sgsn/gtp_mme.c
@@ -0,0 +1,143 @@
+/* TS 29.060 § 7.5.14 RAN Information Management Messages */
+/*
+ * (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: AGPL-3.0+
+ *
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <talloc.h>
+
+#include <osmocom/sgsn/gtp_mme.h>
+#include <osmocom/sgsn/sgsn.h>
+
+static bool _eutran_tai_equal(const struct osmo_eutran_tai *t1, const struct osmo_eutran_tai *t2)
+{
+ return t1->mcc == t2->mcc &&
+ t1->mnc == t2->mnc &&
+ t1->mnc_3_digits == t2->mnc_3_digits &&
+ t1->tac == t2->tac;
+}
+
+struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name)
+{
+ struct sgsn_mme_ctx *mme;
+ mme = talloc_zero(sgsn, struct sgsn_mme_ctx);
+ if (!mme)
+ return NULL;
+
+ /* if we are called from config file parse, this gsn doesn't exist yet */
+ mme->sgsn = sgsn;
+
+ mme->name = talloc_strdup(mme, name);
+
+ INIT_LLIST_HEAD(&mme->routes);
+ llist_add_tail(&mme->list, &sgsn->mme_list);
+
+ return mme;
+}
+
+void sgsn_mme_ctx_free(struct sgsn_mme_ctx *mme)
+{
+ struct mme_rim_route *rt, *rt2;
+ llist_del(&mme->list);
+
+ llist_for_each_entry_safe(rt, rt2, &mme->routes, list) {
+ llist_del(&rt->list);
+ talloc_free(rt);
+ }
+
+ talloc_free(mme);
+}
+
+struct sgsn_mme_ctx *sgsn_mme_ctx_find_alloc(struct sgsn_instance *sgsn, const char *name)
+{
+ struct sgsn_mme_ctx *mme;
+
+ mme = sgsn_mme_ctx_by_name(sgsn, name);
+ if (!mme)
+ mme = sgsn_mme_ctx_alloc(sgsn, name);
+ return mme;
+}
+
+void sgsn_mme_ctx_route_add(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai)
+{
+ struct mme_rim_route *rt = talloc_zero(mme, struct mme_rim_route);
+ rt->tai = *tai;
+ llist_add_tail(&rt->list, &mme->routes);
+}
+
+void sgsn_mme_ctx_route_del(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai)
+{
+ struct mme_rim_route *rt;
+
+ llist_for_each_entry(rt, &mme->routes, list) {
+ if (_eutran_tai_equal(tai, &rt->tai)) {
+ llist_del(&rt->list);
+ talloc_free(rt);
+ return;
+ }
+ }
+}
+
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_name(const struct sgsn_instance *sgsn, const char *name)
+{
+ struct sgsn_mme_ctx *mme;
+
+ llist_for_each_entry(mme, &sgsn->mme_list, list) {
+ if (!strcmp(name, mme->name))
+ return mme;
+ }
+ return NULL;
+}
+
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_addr(const struct sgsn_instance *sgsn, const struct in_addr *addr)
+{
+ struct sgsn_mme_ctx *mme;
+
+ llist_for_each_entry(mme, &sgsn->mme_list, list) {
+ if (!memcmp(addr, &mme->remote_addr, sizeof(*addr)))
+ return mme;
+ }
+ return NULL;
+}
+
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_route(const struct sgsn_instance *sgsn, const struct osmo_eutran_tai *tai)
+{
+ struct sgsn_mme_ctx *mme;
+ llist_for_each_entry(mme, &sgsn->mme_list, list) {
+ struct mme_rim_route *rt;
+ llist_for_each_entry(rt, &mme->routes, list) {
+ if (_eutran_tai_equal(tai, &rt->tai)) {
+ return mme;
+ }
+ }
+ }
+ return NULL;
+}
+
+struct sgsn_mme_ctx *sgsn_mme_ctx_by_default_route(const struct sgsn_instance *sgsn)
+{
+ struct sgsn_mme_ctx *mme;
+
+ llist_for_each_entry(mme, &sgsn->mme_list, list) {
+ if (mme->default_route)
+ return mme;
+ }
+ return NULL;
+}
diff --git a/src/sgsn/gprs_sgsn.c b/src/sgsn/mmctx.c
index d4bc554cd..0e9309284 100644
--- a/src/sgsn/gprs_sgsn.c
+++ b/src/sgsn/mmctx.c
@@ -1,4 +1,4 @@
-/* GPRS SGSN functionality */
+/* Mobility Management context */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
@@ -27,6 +27,8 @@
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/backtrace.h>
+#include <osmocom/ctrl/control_if.h>
+#include <osmocom/ctrl/ports.h>
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
@@ -36,7 +38,7 @@
#include <osmocom/sgsn/gprs_subscriber.h>
#include <osmocom/sgsn/debug.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_sm.h>
@@ -47,22 +49,16 @@
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gprs_llc.h>
+#include <osmocom/sgsn/gprs_sndcp.h>
+#include <osmocom/sgsn/gtp_ggsn.h>
+#include <osmocom/sgsn/gtp.h>
+#include <osmocom/sgsn/pdpctx.h>
#include <pdp.h>
#include <time.h>
-#include "../../bscconfig.h"
-
-#define GPRS_LLME_CHECK_TICK 30
-
-extern struct sgsn_instance *sgsn;
-extern void *tall_sgsn_ctx;
-
-LLIST_HEAD(sgsn_mm_ctxts);
-LLIST_HEAD(sgsn_ggsn_ctxts);
-LLIST_HEAD(sgsn_apn_ctxts);
-LLIST_HEAD(sgsn_pdp_ctxts);
+#include "../../config.h"
const struct value_string sgsn_ran_type_names[] = {
{ MM_CTX_T_GERAN_Gb, "GPRS/EDGE via Gb" },
@@ -95,66 +91,12 @@ static const struct rate_ctr_group_desc mmctx_ctrg_desc = {
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
};
-static const struct rate_ctr_desc pdpctx_ctr_description[] = {
- { "udata:packets:in", "User Data Messages ( In)" },
- { "udata:packets:out", "User Data Messages (Out)" },
- { "udata:bytes:in", "User Data Bytes ( In)" },
- { "udata:bytes:out", "User Data Bytes (Out)" },
-};
-
-static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
- .group_name_prefix = "sgsn:pdpctx",
- .group_description = "SGSN PDP Context Statistics",
- .num_ctr = ARRAY_SIZE(pdpctx_ctr_description),
- .ctr_desc = pdpctx_ctr_description,
- .class_id = OSMO_STATS_CLASS_SUBSCRIBER,
-};
-
-static const struct rate_ctr_desc sgsn_ctr_description[] = {
- { "llc:dl_bytes", "Count sent LLC bytes before giving it to the bssgp layer" },
- { "llc:ul_bytes", "Count successful received LLC bytes (encrypt & fcs correct)" },
- { "llc:dl_packets", "Count successful sent LLC packets before giving it to the bssgp layer" },
- { "llc:ul_packets", "Count successful received LLC packets (encrypt & fcs correct)" },
- { "gprs:attach_requested", "Received attach requests" },
- { "gprs:attach_accepted", "Sent attach accepts" },
- { "gprs:attach_rejected", "Sent attach rejects" },
- { "gprs:detach_requested", "Received detach requests" },
- { "gprs:detach_acked", "Sent detach acks" },
- { "gprs:routing_area_requested", "Received routing area requests" },
- { "gprs:routing_area_requested", "Sent routing area acks" },
- { "gprs:routing_area_requested", "Sent routing area rejects" },
- { "pdp:activate_requested", "Received activate requests" },
- { "pdp:activate_rejected", "Sent activate rejects" },
- { "pdp:activate_accepted", "Sent activate accepts" },
- { "pdp:request_activated", "unused" },
- { "pdp:request_activate_rejected", "unused" },
- { "pdp:modify_requested", "unused" },
- { "pdp:modify_accepted", "unused" },
- { "pdp:dl_deactivate_requested", "Sent deactivate requests" },
- { "pdp:dl_deactivate_accepted", "Sent deactivate accepted" },
- { "pdp:ul_deactivate_requested", "Received deactivate requests" },
- { "pdp:ul_deactivate_accepted", "Received deactivate accepts" },
-};
-
-static const struct rate_ctr_group_desc sgsn_ctrg_desc = {
- "sgsn",
- "SGSN Overall Statistics",
- OSMO_STATS_CLASS_GLOBAL,
- ARRAY_SIZE(sgsn_ctr_description),
- sgsn_ctr_description,
-};
-
-void sgsn_rate_ctr_init() {
- sgsn->rate_ctrs = rate_ctr_group_alloc(tall_sgsn_ctx, &sgsn_ctrg_desc, 0);
- OSMO_ASSERT(sgsn->rate_ctrs);
-}
-
/* look-up an SGSN MM context based on Iu UE context (struct ue_conn_ctx)*/
struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx)
{
struct sgsn_mm_ctx *ctx;
- llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
+ llist_for_each_entry(ctx, &sgsn->mm_list, list) {
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu
&& uectx == ctx->iu.ue_ctx)
return ctx;
@@ -169,7 +111,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
{
struct sgsn_mm_ctx *ctx;
- llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
+ llist_for_each_entry(ctx, &sgsn->mm_list, list) {
if ((tlli == ctx->gb.tlli || tlli == ctx->gb.tlli_new) &&
gprs_ra_id_equals(raid, &ctx->ra))
return ctx;
@@ -193,7 +135,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
if (tlli_type != TLLI_FOREIGN && tlli_type != TLLI_LOCAL)
return NULL;
- llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
+ llist_for_each_entry(ctx, &sgsn->mm_list, list) {
if ((gprs_tmsi2tlli(ctx->p_tmsi, tlli_type) == tlli ||
gprs_tmsi2tlli(ctx->p_tmsi_old, tlli_type) == tlli) &&
gprs_ra_id_equals(raid, &ctx->ra))
@@ -207,7 +149,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t p_tmsi)
{
struct sgsn_mm_ctx *ctx;
- llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
+ llist_for_each_entry(ctx, &sgsn->mm_list, list) {
if (p_tmsi == ctx->p_tmsi ||
(ctx->p_tmsi_old && ctx->p_tmsi_old == p_tmsi))
return ctx;
@@ -219,7 +161,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi)
{
struct sgsn_mm_ctx *ctx;
- llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
+ llist_for_each_entry(ctx, &sgsn->mm_list, list) {
if (!strcmp(imsi, ctx->imsi))
return ctx;
}
@@ -261,7 +203,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t rate_ctr_id)
INIT_LLIST_HEAD(&ctx->pdp_list);
- llist_add(&ctx->list, &sgsn_mm_ctxts);
+ llist_add(&ctx->list, &sgsn->mm_list);
return ctx;
@@ -293,11 +235,8 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
memcpy(&ctx->ra, raid, sizeof(ctx->ra));
ctx->ran_type = MM_CTX_T_GERAN_Gb;
ctx->gb.tlli = tlli;
- ctx->ciph_algo = sgsn->cfg.cipher;
osmo_fsm_inst_update_id_f(ctx->gb.mm_state_fsm, "%" PRIu32, tlli);
- LOGMMCTXP(LOGL_DEBUG, ctx, "Allocated with %s cipher.\n",
- get_value_string(gprs_cipher_names, ctx->ciph_algo));
return ctx;
}
@@ -435,288 +374,6 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
return NULL;
}
-/* you don't want to use this directly, call sgsn_create_pdp_ctx() */
-struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
- struct sgsn_ggsn_ctx *ggsn,
- uint8_t nsapi)
-{
- struct sgsn_pdp_ctx *pdp;
-
- pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi);
- if (pdp)
- return NULL;
-
- pdp = talloc_zero(tall_sgsn_ctx, struct sgsn_pdp_ctx);
- if (!pdp)
- return NULL;
-
- pdp->mm = mm;
- pdp->ggsn = ggsn;
- pdp->nsapi = nsapi;
- pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi);
- if (!pdp->ctrg) {
- LOGPDPCTXP(LOGL_ERROR, pdp, "Error allocation counter group\n");
- talloc_free(pdp);
- return NULL;
- }
- llist_add(&pdp->list, &mm->pdp_list);
- sgsn_ggsn_ctx_add_pdp(pdp->ggsn, pdp);
- llist_add(&pdp->g_list, &sgsn_pdp_ctxts);
-
- return pdp;
-}
-
-/*
- * This function will not trigger any GSM DEACT PDP ACK messages, so you
- * probably want to call sgsn_delete_pdp_ctx() instead if the connection
- * isn't detached already.
- */
-void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp)
-{
- struct sgsn_signal_data sig_data;
-
- OSMO_ASSERT(pdp->mm != NULL);
-
- /* There might still be pending callbacks in libgtp. So the parts of
- * this object relevant to GTP need to remain intact in this case. */
-
- LOGPDPCTXP(LOGL_INFO, pdp, "Forcing release of PDP context\n");
-
- if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {
- /* Force the deactivation of the SNDCP layer */
- if (pdp->mm->gb.llme)
- sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi);
- }
-
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.pdp = pdp;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_TERMINATE, &sig_data);
-
- /* Detach from MM context */
- pdp_ctx_detach_mm_ctx(pdp);
- if (pdp->ggsn)
- sgsn_delete_pdp_ctx(pdp);
-}
-
-/*
- * Don't call this function directly unless you know what you are doing.
- * In normal conditions use sgsn_delete_pdp_ctx and in unspecified or
- * implementation dependent abnormal ones sgsn_pdp_ctx_terminate.
- */
-void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
-{
- struct sgsn_signal_data sig_data;
-
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.pdp = pdp;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data);
-
- if (osmo_timer_pending(&pdp->timer)) {
- LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T);
- osmo_timer_del(&pdp->timer);
- }
-
- rate_ctr_group_free(pdp->ctrg);
- if (pdp->mm)
- llist_del(&pdp->list);
- if (pdp->ggsn)
- sgsn_ggsn_ctx_remove_pdp(pdp->ggsn, pdp);
- llist_del(&pdp->g_list);
-
- /* _if_ we still have a library handle, at least set it to NULL
- * to avoid any dereferences of the now-deleted PDP context from
- * sgsn_libgtp:cb_data_ind() */
- if (pdp->lib) {
- struct pdp_t *lib = pdp->lib;
- LOGPDPCTXP(LOGL_NOTICE, pdp, "freeing PDP context that still "
- "has a libgtp handle attached to it, this shouldn't "
- "happen!\n");
- osmo_generate_backtrace();
- lib->priv = NULL;
- }
-
- talloc_free(pdp);
-}
-
-void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc)
-{
- bool pending = osmo_timer_pending(&ggc->echo_timer);
-
- /* Only enable if allowed by policy and at least 1 pdp ctx exists against ggsn */
- if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval) {
- if (!pending)
- osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
- } else {
- if (pending)
- osmo_timer_del(&ggc->echo_timer);
- }
-}
-
-/* GGSN contexts */
-static void echo_timer_cb(void *data)
-{
- struct sgsn_ggsn_ctx *ggc = (struct sgsn_ggsn_ctx *) data;
- sgsn_ggsn_echo_req(ggc);
- osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
-}
-
-struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id)
-{
- struct sgsn_ggsn_ctx *ggc;
-
- ggc = talloc_zero(tall_sgsn_ctx, struct sgsn_ggsn_ctx);
- if (!ggc)
- return NULL;
-
- ggc->id = id;
- ggc->gtp_version = 1;
- ggc->remote_restart_ctr = -1;
- /* if we are called from config file parse, this gsn doesn't exist yet */
- ggc->gsn = sgsn->gsn;
- INIT_LLIST_HEAD(&ggc->pdp_list);
- osmo_timer_setup(&ggc->echo_timer, echo_timer_cb, ggc);
- llist_add(&ggc->list, &sgsn_ggsn_ctxts);
-
- return ggc;
-}
-
-void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc)
-{
- OSMO_ASSERT(llist_empty(&ggc->pdp_list));
- llist_del(&ggc->list);
- talloc_free(ggc);
-}
-
-struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id)
-{
- struct sgsn_ggsn_ctx *ggc;
-
- llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
- if (id == ggc->id)
- return ggc;
- }
- return NULL;
-}
-
-struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr)
-{
- struct sgsn_ggsn_ctx *ggc;
-
- llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
- if (!memcmp(addr, &ggc->remote_addr, sizeof(*addr)))
- return ggc;
- }
- return NULL;
-}
-
-
-struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id)
-{
- struct sgsn_ggsn_ctx *ggc;
-
- ggc = sgsn_ggsn_ctx_by_id(id);
- if (!ggc)
- ggc = sgsn_ggsn_ctx_alloc(id);
- return ggc;
-}
-
-/* APN contexts */
-
-static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix)
-{
- struct apn_ctx *actx;
-
- actx = talloc_zero(tall_sgsn_ctx, struct apn_ctx);
- if (!actx)
- return NULL;
- actx->name = talloc_strdup(actx, ap_name);
- actx->imsi_prefix = talloc_strdup(actx, imsi_prefix);
-
- llist_add_tail(&actx->list, &sgsn_apn_ctxts);
-
- return actx;
-}
-
-void sgsn_apn_ctx_free(struct apn_ctx *actx)
-{
- llist_del(&actx->list);
- talloc_free(actx);
-}
-
-struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi)
-{
- struct apn_ctx *actx;
- struct apn_ctx *found_actx = NULL;
- size_t imsi_prio = 0;
- size_t name_prio = 0;
- size_t name_req_len = strlen(name);
-
- llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
- size_t name_ref_len, imsi_ref_len;
- const char *name_ref_start, *name_match_start;
-
- imsi_ref_len = strlen(actx->imsi_prefix);
- if (strncmp(actx->imsi_prefix, imsi, imsi_ref_len) != 0)
- continue;
-
- if (imsi_ref_len < imsi_prio)
- continue;
-
- /* IMSI matches */
-
- name_ref_start = &actx->name[0];
- if (name_ref_start[0] == '*') {
- /* Suffix match */
- name_ref_start += 1;
- name_ref_len = strlen(name_ref_start);
- if (name_ref_len > name_req_len)
- continue;
- } else {
- name_ref_len = strlen(name_ref_start);
- if (name_ref_len != name_req_len)
- continue;
- }
-
- name_match_start = name + (name_req_len - name_ref_len);
- if (strcasecmp(name_match_start, name_ref_start) != 0)
- continue;
-
- /* IMSI and name match */
-
- if (imsi_ref_len == imsi_prio && name_ref_len < name_prio)
- /* Lower priority, skip */
- continue;
-
- imsi_prio = imsi_ref_len;
- name_prio = name_ref_len;
- found_actx = actx;
- }
- return found_actx;
-}
-
-struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix)
-{
- struct apn_ctx *actx;
-
- llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
- if (strcasecmp(name, actx->name) == 0 &&
- strcasecmp(imsi_prefix, actx->imsi_prefix) == 0)
- return actx;
- }
- return NULL;
-}
-
-struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix)
-{
- struct apn_ctx *actx;
-
- actx = sgsn_apn_ctx_by_name(name, imsi_prefix);
- if (!actx)
- actx = sgsn_apn_ctx_alloc(name, imsi_prefix);
-
- return actx;
-}
-
uint32_t sgsn_alloc_ptmsi(void)
{
struct sgsn_mm_ctx *mm;
@@ -752,7 +409,7 @@ restart:
goto restart;
}
- llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
+ llist_for_each_entry(mm, &sgsn->mm_list, list) {
if (mm->p_tmsi == ptmsi) {
if (!max_retries--)
goto failed;
@@ -767,64 +424,6 @@ failed:
return GSM_RESERVED_TMSI;
}
-void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx)
-{
- /* the MM context can be deleted while the GGSN is not reachable or
- * if has been crashed. */
- if (pctx->mm && pctx->mm->gmm_fsm->state == ST_GMM_REGISTERED_NORMAL) {
- gsm48_tx_gsm_deact_pdp_req(pctx, GSM_CAUSE_NET_FAIL, true);
- sgsn_ggsn_ctx_remove_pdp(pctx->ggsn, pctx);
- } else {
- /* FIXME: GPRS paging in case MS is SUSPENDED */
- LOGPDPCTXP(LOGL_NOTICE, pctx, "Hard-dropping PDP ctx due to GGSN "
- "recovery\n");
- /* FIXME: how to tell this to libgtp? */
- sgsn_pdp_ctx_free(pctx);
- }
-}
-
-/* High-level function to be called in case a GGSN has disappeared or
- * otherwise lost state (recovery procedure). It will detach all related pdp ctx
- * from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can
- * be kept alive to allow handling later message which contained the Recovery IE. */
-int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except)
-{
- int num = 0;
-
- struct sgsn_pdp_ctx *pdp, *pdp2;
- llist_for_each_entry_safe(pdp, pdp2, &ggsn->pdp_list, ggsn_list) {
- if (pdp == except)
- continue;
- sgsn_ggsn_ctx_drop_pdp(pdp);
- num++;
- }
-
- return num;
-}
-
-int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn)
-{
- return sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, NULL);
-}
-
-void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
-{
- llist_add(&pdp->ggsn_list, &ggc->pdp_list);
- sgsn_ggsn_ctx_check_echo_timer(ggc);
-}
-void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
-{
- llist_del(&pdp->ggsn_list);
- sgsn_ggsn_ctx_check_echo_timer(ggc);
- if (pdp->destroy_ggsn)
- sgsn_ggsn_ctx_free(pdp->ggsn);
- pdp->ggsn = NULL;
- /* Drop references to libgtp since the conn is down */
- if (pdp->lib)
- pdp_freepdp(pdp->lib);
- pdp->lib = NULL;
-}
-
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
{
OSMO_ASSERT(mmctx != NULL);
@@ -899,7 +498,7 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
insert_extra(tp, mmctx->subscr->sgsn_data, pdp);
continue;
}
- if (!llist_empty(&sgsn_apn_ctxts)) {
+ if (!llist_empty(&sgsn->apn_list)) {
apn_ctx = sgsn_apn_ctx_match(req_apn_str, mmctx->imsi);
/* Not configured */
if (apn_ctx == NULL)
@@ -952,13 +551,13 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
if (apn_ctx != NULL) {
ggsn = apn_ctx->ggsn;
- } else if (llist_empty(&sgsn_apn_ctxts)) {
+ } else if (llist_empty(&sgsn->apn_list)) {
/* No configuration -> use GGSN 0 */
- ggsn = sgsn_ggsn_ctx_by_id(0);
+ ggsn = sgsn_ggsn_ctx_by_id(sgsn, 0);
} else if (allow_any_apn &&
(selected_apn_str == NULL || strlen(selected_apn_str) == 0)) {
/* No APN given and no default configuration -> Use GGSN 0 */
- ggsn = sgsn_ggsn_ctx_by_id(0);
+ ggsn = sgsn_ggsn_ctx_by_id(sgsn, 0);
} else {
/* No matching configuration found */
LOGMMCTXP(LOGL_NOTICE, mmctx,
@@ -983,70 +582,3 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
return ggsn;
}
-
-static void sgsn_llme_cleanup_free(struct gprs_llc_llme *llme)
-{
- struct sgsn_mm_ctx *mmctx = NULL;
-
- llist_for_each_entry(mmctx, &sgsn_mm_ctxts, list) {
- if (llme == mmctx->gb.llme) {
- gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE);
- return;
- }
- }
-
- /* No MM context found */
- LOGP(DGPRS, LOGL_INFO, "Deleting orphaned LLME, TLLI 0x%08x\n",
- llme->tlli);
- gprs_llgmm_unassign(llme);
-}
-
-static void sgsn_llme_check_cb(void *data_)
-{
- struct gprs_llc_llme *llme, *llme_tmp;
- struct timespec now_tp;
- time_t now, age;
- time_t max_age = gprs_max_time_to_idle();
-
- int rc;
-
- rc = osmo_clock_gettime(CLOCK_MONOTONIC, &now_tp);
- OSMO_ASSERT(rc >= 0);
- now = now_tp.tv_sec;
-
- LOGP(DGPRS, LOGL_DEBUG,
- "Checking for inactive LLMEs, time = %u\n", (unsigned)now);
-
- llist_for_each_entry_safe(llme, llme_tmp, &gprs_llc_llmes, list) {
- if (llme->age_timestamp == GPRS_LLME_RESET_AGE)
- llme->age_timestamp = now;
-
- age = now - llme->age_timestamp;
-
- if (age > max_age || age < 0) {
- LOGP(DGPRS, LOGL_INFO,
- "Inactivity timeout for TLLI 0x%08x, age %d\n",
- llme->tlli, (int)age);
- sgsn_llme_cleanup_free(llme);
- }
- }
-
- osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
-}
-
-struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx)
-{
- struct sgsn_instance *inst;
- inst = talloc_zero(talloc_ctx, struct sgsn_instance);
- inst->cfg.gtp_statedir = talloc_strdup(inst, "./");
- inst->cfg.auth_policy = SGSN_AUTH_POLICY_CLOSED;
- inst->cfg.require_authentication = true; /* only applies if auth_policy is REMOTE */
- inst->cfg.gsup_server_port = OSMO_GSUP_PORT;
- return inst;
-}
-
-void sgsn_inst_init(struct sgsn_instance *sgsn)
-{
- osmo_timer_setup(&sgsn->llme_timer, sgsn_llme_check_cb, NULL);
- osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
-}
diff --git a/src/sgsn/pdpctx.c b/src/sgsn/pdpctx.c
new file mode 100644
index 000000000..e77942040
--- /dev/null
+++ b/src/sgsn/pdpctx.c
@@ -0,0 +1,158 @@
+/* PDP context functionality */
+
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/stats.h>
+
+#include <osmocom/sgsn/pdpctx.h>
+#include <osmocom/sgsn/mmctx.h>
+#include <osmocom/sgsn/sgsn.h>
+#include <osmocom/sgsn/debug.h>
+#include <osmocom/sgsn/signal.h>
+#include <osmocom/sgsn/gtp_ggsn.h>
+#include <osmocom/sgsn/gprs_llc_xid.h>
+#include <osmocom/sgsn/gprs_sndcp.h>
+#include <osmocom/sgsn/gprs_llc.h>
+#include <osmocom/sgsn/gprs_sm.h>
+#include <osmocom/sgsn/gtp.h>
+
+static const struct rate_ctr_desc pdpctx_ctr_description[] = {
+ { "udata:packets:in", "User Data Messages ( In)" },
+ { "udata:packets:out", "User Data Messages (Out)" },
+ { "udata:bytes:in", "User Data Bytes ( In)" },
+ { "udata:bytes:out", "User Data Bytes (Out)" },
+};
+
+static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
+ .group_name_prefix = "sgsn:pdpctx",
+ .group_description = "SGSN PDP Context Statistics",
+ .num_ctr = ARRAY_SIZE(pdpctx_ctr_description),
+ .ctr_desc = pdpctx_ctr_description,
+ .class_id = OSMO_STATS_CLASS_SUBSCRIBER,
+};
+
+/* you don't want to use this directly, call sgsn_create_pdp_ctx() */
+struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
+ struct sgsn_ggsn_ctx *ggsn,
+ uint8_t nsapi)
+{
+ struct sgsn_pdp_ctx *pdp;
+
+ pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi);
+ if (pdp)
+ return NULL;
+
+ pdp = talloc_zero(sgsn, struct sgsn_pdp_ctx);
+ if (!pdp)
+ return NULL;
+
+ pdp->mm = mm;
+ pdp->ggsn = ggsn;
+ pdp->nsapi = nsapi;
+ pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi);
+ if (!pdp->ctrg) {
+ LOGPDPCTXP(LOGL_ERROR, pdp, "Error allocation counter group\n");
+ talloc_free(pdp);
+ return NULL;
+ }
+ llist_add(&pdp->list, &mm->pdp_list);
+ sgsn_ggsn_ctx_add_pdp(pdp->ggsn, pdp);
+ llist_add(&pdp->g_list, &sgsn->pdp_list);
+
+ return pdp;
+}
+
+/*
+ * This function will not trigger any GSM DEACT PDP ACK messages, so you
+ * probably want to call sgsn_delete_pdp_ctx() instead if the connection
+ * isn't detached already.
+ */
+void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp)
+{
+ struct sgsn_signal_data sig_data;
+
+ OSMO_ASSERT(pdp->mm != NULL);
+
+ /* There might still be pending callbacks in libgtp. So the parts of
+ * this object relevant to GTP need to remain intact in this case. */
+
+ LOGPDPCTXP(LOGL_INFO, pdp, "Forcing release of PDP context\n");
+
+ if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {
+ /* Force the deactivation of the SNDCP layer */
+ if (pdp->mm->gb.llme)
+ sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi);
+ }
+
+ memset(&sig_data, 0, sizeof(sig_data));
+ sig_data.pdp = pdp;
+ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_TERMINATE, &sig_data);
+
+ /* Detach from MM context */
+ pdp_ctx_detach_mm_ctx(pdp);
+ if (pdp->ggsn)
+ sgsn_delete_pdp_ctx(pdp);
+}
+
+/*
+ * Don't call this function directly unless you know what you are doing.
+ * In normal conditions use sgsn_delete_pdp_ctx and in unspecified or
+ * implementation dependent abnormal ones sgsn_pdp_ctx_terminate.
+ */
+void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
+{
+ struct sgsn_signal_data sig_data;
+
+ memset(&sig_data, 0, sizeof(sig_data));
+ sig_data.pdp = pdp;
+ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data);
+
+ if (osmo_timer_pending(&pdp->timer)) {
+ LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T);
+ osmo_timer_del(&pdp->timer);
+ }
+
+ rate_ctr_group_free(pdp->ctrg);
+ if (pdp->mm)
+ llist_del(&pdp->list);
+ if (pdp->ggsn)
+ sgsn_ggsn_ctx_remove_pdp(pdp->ggsn, pdp);
+ llist_del(&pdp->g_list);
+
+ /* _if_ we still have a library handle, at least set it to NULL
+ * to avoid any dereferences of the now-deleted PDP context from
+ * sgsn_libgtp:cb_data_ind() */
+ if (pdp->lib) {
+ struct pdp_t *lib = pdp->lib;
+ LOGPDPCTXP(LOGL_NOTICE, pdp, "freeing PDP context that still "
+ "has a libgtp handle attached to it, this shouldn't "
+ "happen!\n");
+ osmo_generate_backtrace();
+ lib->priv = NULL;
+ }
+
+ talloc_free(pdp);
+}
diff --git a/src/sgsn/sgsn.c b/src/sgsn/sgsn.c
new file mode 100644
index 000000000..6619bf263
--- /dev/null
+++ b/src/sgsn/sgsn.c
@@ -0,0 +1,215 @@
+/* SGSN instance */
+
+/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/stats.h>
+#include <osmocom/core/backtrace.h>
+#include <osmocom/ctrl/control_if.h>
+#include <osmocom/ctrl/ports.h>
+#include <osmocom/gprs/gprs_ns2.h>
+#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
+#include <osmocom/gsm/apn.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/gsup.h>
+
+#include <osmocom/sgsn/gprs_subscriber.h>
+#include <osmocom/sgsn/debug.h>
+#include <osmocom/sgsn/sgsn.h>
+#include <osmocom/sgsn/gprs_gmm.h>
+#include <osmocom/sgsn/gprs_sm.h>
+#include <osmocom/sgsn/gprs_utils.h>
+#include <osmocom/sgsn/signal.h>
+#include <osmocom/sgsn/gprs_gmm_attach.h>
+#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
+#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
+#include <osmocom/sgsn/gprs_gmm_fsm.h>
+#include <osmocom/sgsn/gprs_llc.h>
+#include <osmocom/sgsn/gprs_sndcp.h>
+#include <osmocom/sgsn/gtp_ggsn.h>
+#include <osmocom/sgsn/gtp.h>
+#include <osmocom/sgsn/pdpctx.h>
+
+#include <pdp.h>
+
+#include <time.h>
+
+#define GPRS_LLME_CHECK_TICK 30
+
+extern struct osmo_tdef sgsn_T_defs[];
+
+static const struct rate_ctr_desc sgsn_ctr_description[] = {
+ { "llc:dl_bytes", "Count sent LLC bytes before giving it to the bssgp layer" },
+ { "llc:ul_bytes", "Count successful received LLC bytes (encrypt & fcs correct)" },
+ { "llc:dl_packets", "Count successful sent LLC packets before giving it to the bssgp layer" },
+ { "llc:ul_packets", "Count successful received LLC packets (encrypt & fcs correct)" },
+ { "gprs:attach_requested", "Received attach requests" },
+ { "gprs:attach_accepted", "Sent attach accepts" },
+ { "gprs:attach_rejected", "Sent attach rejects" },
+ { "gprs:detach_requested", "Received detach requests" },
+ { "gprs:detach_acked", "Sent detach acks" },
+ { "gprs:routing_area_requested", "Received routing area requests" },
+ { "gprs:routing_area_requested", "Sent routing area acks" },
+ { "gprs:routing_area_requested", "Sent routing area rejects" },
+ { "pdp:activate_requested", "Received activate requests" },
+ { "pdp:activate_rejected", "Sent activate rejects" },
+ { "pdp:activate_accepted", "Sent activate accepts" },
+ { "pdp:request_activated", "unused" },
+ { "pdp:request_activate_rejected", "unused" },
+ { "pdp:modify_requested", "unused" },
+ { "pdp:modify_accepted", "unused" },
+ { "pdp:dl_deactivate_requested", "Sent deactivate requests" },
+ { "pdp:dl_deactivate_accepted", "Sent deactivate accepted" },
+ { "pdp:ul_deactivate_requested", "Received deactivate requests" },
+ { "pdp:ul_deactivate_accepted", "Received deactivate accepts" },
+};
+
+static const struct rate_ctr_group_desc sgsn_ctrg_desc = {
+ "sgsn",
+ "SGSN Overall Statistics",
+ OSMO_STATS_CLASS_GLOBAL,
+ ARRAY_SIZE(sgsn_ctr_description),
+ sgsn_ctr_description,
+};
+
+static void sgsn_llme_cleanup_free(struct gprs_llc_llme *llme)
+{
+ struct sgsn_mm_ctx *mmctx = NULL;
+
+ llist_for_each_entry(mmctx, &sgsn->mm_list, list) {
+ if (llme == mmctx->gb.llme) {
+ gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE);
+ return;
+ }
+ }
+
+ /* No MM context found */
+ LOGP(DGPRS, LOGL_INFO, "Deleting orphaned LLME, TLLI 0x%08x\n",
+ llme->tlli);
+ gprs_llgmm_unassign(llme);
+}
+
+static void sgsn_llme_check_cb(void *data_)
+{
+ struct gprs_llc_llme *llme, *llme_tmp;
+ struct timespec now_tp;
+ time_t now, age;
+ time_t max_age = gprs_max_time_to_idle();
+
+ int rc;
+
+ rc = osmo_clock_gettime(CLOCK_MONOTONIC, &now_tp);
+ OSMO_ASSERT(rc >= 0);
+ now = now_tp.tv_sec;
+
+ LOGP(DGPRS, LOGL_DEBUG,
+ "Checking for inactive LLMEs, time = %u\n", (unsigned)now);
+
+ llist_for_each_entry_safe(llme, llme_tmp, &gprs_llc_llmes, list) {
+ if (llme->age_timestamp == GPRS_LLME_RESET_AGE)
+ llme->age_timestamp = now;
+
+ age = now - llme->age_timestamp;
+
+ if (age > max_age || age < 0) {
+ LOGP(DGPRS, LOGL_INFO,
+ "Inactivity timeout for TLLI 0x%08x, age %d\n",
+ llme->tlli, (int)age);
+ sgsn_llme_cleanup_free(llme);
+ }
+ }
+
+ osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
+}
+
+static int sgsn_instance_talloc_destructor(struct sgsn_instance *sgi)
+{
+ sgsn_cdr_release(sgi);
+ osmo_timer_del(&sgi->llme_timer);
+ rate_ctr_group_free(sgi->rate_ctrs);
+ return 0;
+}
+
+struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx)
+{
+ struct sgsn_instance *inst;
+ inst = talloc_zero(talloc_ctx, struct sgsn_instance);
+
+ talloc_set_destructor(inst, sgsn_instance_talloc_destructor);
+
+ inst->cfg.gtp_statedir = talloc_strdup(inst, "./");
+ inst->cfg.auth_policy = SGSN_AUTH_POLICY_CLOSED;
+ inst->cfg.require_authentication = true; /* only applies if auth_policy is REMOTE */
+ inst->cfg.gsup_server_port = OSMO_GSUP_PORT;
+
+ inst->cfg.T_defs = sgsn_T_defs;
+ osmo_tdefs_reset(inst->cfg.T_defs);
+ inst->cfg.T_defs_gtp = gtp_T_defs;
+ osmo_tdefs_reset(inst->cfg.T_defs_gtp);
+
+ inst->rate_ctrs = rate_ctr_group_alloc(inst, &sgsn_ctrg_desc, 0);
+ OSMO_ASSERT(inst->rate_ctrs);
+
+ INIT_LLIST_HEAD(&inst->apn_list);
+ INIT_LLIST_HEAD(&inst->ggsn_list);
+ INIT_LLIST_HEAD(&inst->mme_list);
+ INIT_LLIST_HEAD(&inst->mm_list);
+ INIT_LLIST_HEAD(&inst->pdp_list);
+
+ osmo_timer_setup(&inst->llme_timer, sgsn_llme_check_cb, NULL);
+ osmo_timer_schedule(&inst->llme_timer, GPRS_LLME_CHECK_TICK, 0);
+ /* These are mostly setting up stuff not related to VTY cfg, so they can be set up here: */
+ sgsn_auth_init(inst);
+ sgsn_cdr_init(inst);
+ return inst;
+}
+
+/* To be called after VTY config parsing: */
+int sgsn_inst_init(struct sgsn_instance *sgsn)
+{
+ int rc;
+
+ /* start control interface after reading config for
+ * ctrl_vty_get_bind_addr() */
+ sgsn->ctrlh = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_SGSN, NULL);
+ if (!sgsn->ctrlh) {
+ LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n");
+ return -EIO;
+ }
+
+ rc = sgsn_ctrl_cmds_install();
+ if (rc != 0) {
+ LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n");
+ return -EFAULT;
+ }
+
+ rc = gprs_subscr_init(sgsn);
+ if (rc < 0) {
+ LOGP(DGPRS, LOGL_FATAL, "Cannot set up SGSN\n");
+ return rc;
+ }
+ return 0;
+}
diff --git a/src/sgsn/sgsn_auth.c b/src/sgsn/sgsn_auth.c
index b8d803590..cbff6f8ba 100644
--- a/src/sgsn/sgsn_auth.c
+++ b/src/sgsn/sgsn_auth.c
@@ -22,7 +22,7 @@
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/core/utils.h>
#include <osmocom/sgsn/sgsn.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_subscriber.h>
#include <osmocom/sgsn/debug.h>
diff --git a/src/sgsn/sgsn_cdr.c b/src/sgsn/sgsn_cdr.c
index a50b4dfdd..1536c135a 100644
--- a/src/sgsn/sgsn_cdr.c
+++ b/src/sgsn/sgsn_cdr.c
@@ -27,6 +27,9 @@
#include <osmocom/gsm/apn.h>
#include <osmocom/sgsn/vty.h>
+#include <osmocom/sgsn/gtp_ggsn.h>
+#include <osmocom/sgsn/pdpctx.h>
+#include <osmocom/sgsn/mmctx.h>
#include <gtp.h>
#include <pdp.h>
@@ -38,10 +41,6 @@
#include <stdio.h>
#include <inttypes.h>
-/* TODO...avoid going through a global */
-extern struct sgsn_instance *sgsn;
-extern struct ctrl_handle *g_ctrlh;
-
/**
* The CDR module will generate an entry like:
*
@@ -64,7 +63,7 @@ extern struct ctrl_handle *g_ctrlh;
static void send_cdr_trap(char *value)
{
- if (ctrl_cmd_send_trap(g_ctrlh, "cdr-v1", value) < 0)
+ if (ctrl_cmd_send_trap(sgsn->ctrlh, "cdr-v1", value) < 0)
LOGP(DGPRS, LOGL_ERROR, "Failed to create and send TRAP cdr-v1\n");
}
@@ -299,3 +298,8 @@ int sgsn_cdr_init(struct sgsn_instance *sgsn)
return 0;
}
+
+void sgsn_cdr_release(struct sgsn_instance *sgsn)
+{
+ osmo_signal_unregister_handler(SS_SGSN, handle_sgsn_sig, sgsn);
+}
diff --git a/src/sgsn/sgsn_ctrl.c b/src/sgsn/sgsn_ctrl.c
index ad91d25a5..069304abd 100644
--- a/src/sgsn/sgsn_ctrl.c
+++ b/src/sgsn/sgsn_ctrl.c
@@ -21,20 +21,19 @@
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/control_cmd.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
+#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/debug.h>
#include <pdp.h>
-extern vector ctrl_node_vec;
-
static int get_subscriber_list(struct ctrl_cmd *cmd, void *d)
{
struct sgsn_mm_ctx *mm;
cmd->reply = talloc_strdup(cmd, "");
- llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
+ llist_for_each_entry(mm, &sgsn->mm_list, list) {
char *addr = NULL;
struct sgsn_pdp_ctx *pdp;
@@ -43,7 +42,7 @@ static int get_subscriber_list(struct ctrl_cmd *cmd, void *d)
llist_for_each_entry(pdp, &mm->pdp_list, list)
addr = gprs_pdpaddr2str(pdp->lib->eua.v,
- pdp->lib->eua.l);
+ pdp->lib->eua.l, false);
cmd->reply = talloc_asprintf_append(
cmd->reply,
diff --git a/src/sgsn/sgsn_libgtp.c b/src/sgsn/sgsn_libgtp.c
index 367570d3e..9edd0c60e 100644
--- a/src/sgsn/sgsn_libgtp.c
+++ b/src/sgsn/sgsn_libgtp.c
@@ -34,7 +34,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
-#include "bscconfig.h"
+#include "config.h"
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
@@ -45,9 +45,9 @@
#include <osmocom/sgsn/signal.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
-#include <osmocom/sgsn/gprs_gb.h>
+#include <osmocom/sgsn/gprs_ns.h>
#include <osmocom/sgsn/gprs_llc.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_sm.h>
#include <osmocom/sgsn/gprs_subscriber.h>
@@ -55,6 +55,11 @@
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
+#include <osmocom/sgsn/gtp_ggsn.h>
+#include <osmocom/sgsn/gtp_mme.h>
+#include <osmocom/sgsn/sgsn_rim.h>
+#include <osmocom/sgsn/gprs_bssgp.h>
+#include <osmocom/sgsn/pdpctx.h>
#include <gtp.h>
#include <pdp.h>
@@ -226,18 +231,11 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
qos = TLVP_VAL(tp, OSMO_IE_GSM_REQ_QOS);
}
- if (qos_len <= 3) {
- pdp->qos_req.l = qos_len + 1;
- if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
- pdp->qos_req.l = sizeof(pdp->qos_req.v);
- pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */
- memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1);
- } else {
- pdp->qos_req.l = qos_len;
- if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
- pdp->qos_req.l = sizeof(pdp->qos_req.v);
- memcpy(pdp->qos_req.v, qos, pdp->qos_req.l);
- }
+ pdp->qos_req.l = qos_len + 1;
+ if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
+ pdp->qos_req.l = sizeof(pdp->qos_req.v);
+ pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */
+ memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1);
/* charging characteristics if present */
if (TLVP_LEN(tp, OSMO_IE_GSM_CHARG_CHAR) >= sizeof(pdp->cch_pdp))
@@ -419,7 +417,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
}
/* Check for cause value if it was really successful */
- if (cause != GTPCAUSE_ACC_REQ) {
+ if (!gtp_cause_successful(cause)) {
reject_cause = cause_map(gtp2sm_cause_map, cause,
GSM_CAUSE_ACT_REJ_GGSN);
goto reject;
@@ -479,6 +477,70 @@ void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc)
gtp_echo_req(ggc->gsn, ggc->gtp_version, ggc, &ggc->remote_addr);
}
+int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu)
+{
+ char ri_src_str[64], ri_dest_str[64];
+ int ri_len;
+ struct msgb *msg;
+ struct bssgp_normal_hdr *bgph;
+ int rc;
+ uint8_t ri_buf[64];
+ uint8_t *ri_ptr = &ri_buf[0];
+ struct sockaddr_in sk_in = {
+ .sin_family = AF_INET,
+ .sin_port = htons(GTP1C_PORT),
+ .sin_addr = mme->remote_addr,
+ };
+
+ msg = bssgp_encode_rim_pdu(pdu);
+ if (!msg) {
+ LOGMME(mme, DRIM, LOGL_ERROR, "Tx GTP RAN Information Relay: failed to encode pdu\n");
+ return -EINVAL;
+ }
+ bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
+ DEBUGP(DLBSSGP, "Tx GTP RAN Information Relay: RIM-PDU:%s, src=%s, dest=%s\n",
+ bssgp_pdu_str(bgph->pdu_type),
+ bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &pdu->routing_info_src),
+ bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &pdu->routing_info_dest));
+
+ if ((ri_len = bssgp_create_rim_ri(ri_ptr, &pdu->routing_info_dest)) < 0) {
+ ri_ptr = NULL;
+ ri_len = 0;
+ }
+
+ rc = gtp_ran_info_relay_req(mme->sgsn->gsn, &sk_in, msgb_data(msg), msgb_length(msg),
+ ri_ptr, ri_len, pdu->routing_info_dest.discr);
+ msgb_free(msg);
+ return rc;
+}
+
+/* Confirmation of a PDP Context Update */
+static int update_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
+{
+ struct sgsn_pdp_ctx *pctx = cbp;
+ int rc;
+
+ LOGPDPCTXP(LOGL_INFO, pctx, "Received Update PDP CTX CONF, cause=%d(%s)\n",
+ cause, get_value_string(gtp_cause_strs, cause));
+
+ /* 3GPP TS 29.060 "7.3.4":
+ * "If the SGSN receives an Update PDP Context Response with a Cause
+ * value other than "Request accepted", it shall abort the update of the
+ * PDP context.""
+ * "If the SGSN receives an Update PDP Context Response with
+ * a Cause value "Non-existent", it shall delete the PDP Context."
+ */
+ if (cause != GTPCAUSE_NON_EXIST)
+ return 0; /* Nothing to do */
+
+ LOGPDPCTXP(LOGL_INFO, pctx, "PDP CTX we tried to update doesn't exist in "
+ "the GGSN anymore, deleting it locally.\n");
+
+ rc = gtp_freepdp(pctx->ggsn->gsn, pctx->lib);
+ /* related mmctx is torn down in cb_delete_context called by gtp_freepdp() */
+ return rc;
+}
+
/* Confirmation of a PDP Context Delete */
static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
{
@@ -534,12 +596,12 @@ static int echo_conf(void *cbp, bool timeout)
}
/* Any message received by GGSN contains a recovery IE */
-static int cb_recovery2(struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery)
+static int cb_recovery3(struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery)
{
struct sgsn_ggsn_ctx *ggsn;
struct sgsn_pdp_ctx *pctx = NULL;
- ggsn = sgsn_ggsn_ctx_by_addr(&peer->sin_addr);
+ ggsn = sgsn_ggsn_ctx_by_addr(sgsn, &peer->sin_addr);
if (!ggsn) {
LOGP(DGPRS, LOGL_NOTICE, "Received Recovery IE for unknown GGSN\n");
return -EINVAL;
@@ -577,6 +639,8 @@ static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
return echo_conf(cbp, cause == EOF);
case GTP_CREATE_PDP_REQ:
return create_pdp_conf(pdp, cbp, cause);
+ case GTP_UPDATE_PDP_REQ:
+ return update_pdp_conf(pdp, cbp, cause);
case GTP_DELETE_PDP_REQ:
return delete_pdp_conf(pdp, cbp, cause);
default:
@@ -619,6 +683,74 @@ static int cb_extheader_ind(struct sockaddr_in *peer)
return 0;
}
+static int cb_gtp_ran_info_relay_ind(struct sockaddr_in *peer, union gtpie_member **ie)
+{
+ char addrbuf[INET_ADDRSTRLEN];
+ struct sgsn_mme_ctx *mme = sgsn_mme_ctx_by_addr(sgsn, &peer->sin_addr);
+ if (!mme) {
+ LOGP(DGTP, LOGL_NOTICE, "Rx GTP RAN Information Relay from unknown MME %s\n",
+ inet_ntop(AF_INET, &peer->sin_addr, addrbuf, sizeof(addrbuf)));
+ return -ECONNREFUSED;
+ }
+
+ LOGMME(mme, DGTP, LOGL_INFO, "Rx GTP RAN Information Relay\n");
+
+ int rc;
+ unsigned int len = 0;
+ struct msgb *msg = bssgp_msgb_alloc();
+
+ uint8_t rim_ra_encoded[256];
+ unsigned int rim_ra_encoded_len = 0;
+ struct bssgp_rim_routing_info rim_ra;
+
+ unsigned int rim_ra_discr_encoded_len = 0;
+ uint8_t rim_ra_discr;
+
+ /* Read RIM Routing Address Discriminator (optional) */
+ rc = gtpie_gettlv(ie, GTPIE_RIM_RA_DISCR, 0, &rim_ra_discr_encoded_len, &rim_ra_discr,
+ sizeof(rim_ra_discr));
+ if (rc || rim_ra_discr_encoded_len <= 0) {
+ LOGMME(mme, DGTP, LOGL_NOTICE, "Rx GTP RAN Information Relay: No RIM Routing Address Discriminator IE found!\n");
+
+ /* It is not an error when the RIM ROUTING ADDRESS DISCRIMINATOR IE is missing. The RIM ROUTING ADDRESS
+ * DISCRIMINATOR IE is an optional IE. When it is missing, the RIM Routing Address shall be processed
+ * as an RNC address ("0001") See also: 3GPP TS 29.060 */
+ rim_ra_discr = BSSGP_RIM_ROUTING_INFO_UTRAN;
+ }
+
+ /* Read RIM Routing Address (optional) */
+ rc = gtpie_gettlv(ie, GTPIE_RIM_ROUT_ADDR, 0, &rim_ra_encoded_len, rim_ra_encoded, sizeof(rim_ra_encoded));
+ if (rc || rim_ra_encoded_len <= 0) {
+ LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: No RIM Routing Address IE found!\n");
+
+ /* TODO: The (usually included) RIM ROUTING ADDRESS field is an optional field. However, we cannot
+ * proceed without a destination address. A possible way to fix this would be a default route that
+ * can be configured via the VTY. */
+ goto ret_error;
+ } else {
+ rc = bssgp_parse_rim_ra(&rim_ra, rim_ra_encoded, rim_ra_encoded_len, rim_ra_discr);
+ if (rc < 0) {
+ LOGMME(mme, DGTP, LOGL_ERROR,
+ "Rx GTP RAN Information Relay: Failed parsing RIM Routing Address/RIM Routing Address Discriminator IE!\n");
+ goto ret_error;
+ }
+ }
+
+ if (gtpie_gettlv(ie, GTPIE_RAN_T_CONTAIN, 0, &len, msgb_data(msg), 4096) || len <= 0) {
+ LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: No Transparent Container IE found!\n");
+ goto ret_error;
+ }
+ msgb_put(msg, len);
+ msgb_bssgph(msg) = msg->data;
+ msgb_nsei(msg) = 0;
+
+ return sgsn_rim_rx_from_gtp(msg, &rim_ra);
+
+ret_error:
+ msgb_free(msg);
+ return -EINVAL;
+}
+
/* Called whenever we receive a DATA packet */
static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
{
@@ -671,15 +803,24 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
msgb_free(msg);
return -1;
case ST_GMM_REGISTERED_NORMAL:
- OSMO_ASSERT(mm->gb.mm_state_fsm->state != ST_MM_IDLE);
- if (mm->gb.mm_state_fsm->state == ST_MM_STANDBY) {
+ switch (mm->gb.mm_state_fsm->state) {
+ case ST_MM_IDLE:
+ LOGP(DGPRS, LOGL_ERROR, "Dropping DL packet for MS in MM state %s\n",
+ osmo_fsm_inst_state_name(mm->gb.mm_state_fsm));
+ msgb_free(msg);
+ return -1;
+ case ST_MM_READY:
+ /* Go ahead */
+ break;
+ case ST_MM_STANDBY:
LOGMMCTXP(LOGL_INFO, mm, "Paging MS in GMM state %s, MM state %s\n",
osmo_fsm_inst_state_name(mm->gmm_fsm),
osmo_fsm_inst_state_name(mm->gb.mm_state_fsm));
- gprs_gb_page_ps_ra(mm);
- }
+ sgsn_bssgp_page_ps_ra(mm);
- /* FIXME: queue the packet we received from GTP */
+ /* FIXME: queue the packet we received from GTP */
+ break;
+ }
break;
default:
LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state "
@@ -688,20 +829,20 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
return -1;
}
- rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_OUT]);
- rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_OUT], len);
- rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_UDATA_OUT]);
- rate_ctr_add(&mm->ctrg->ctr[GMM_CTR_BYTES_UDATA_OUT], len);
+ rate_ctr_inc(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_PKTS_UDATA_OUT));
+ rate_ctr_add(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_BYTES_UDATA_OUT), len);
+ rate_ctr_inc(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_PKTS_UDATA_OUT));
+ rate_ctr_add(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_BYTES_UDATA_OUT), len);
/* It is easier to have a global count */
pdp->cdr_bytes_out += len;
- return sndcp_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi],
+ return sndcp_sn_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi],
pdp->nsapi, mm);
}
/* Called by SNDCP when it has received/re-assembled a N-PDU */
-int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
+int sgsn_gtp_data_req(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
struct msgb *msg, uint32_t npdu_len, uint8_t *npdu)
{
struct sgsn_mm_ctx *mmctx;
@@ -726,10 +867,10 @@ int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
return -EIO;
}
- rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_IN]);
- rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_IN], npdu_len);
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_UDATA_IN]);
- rate_ctr_add(&mmctx->ctrg->ctr[GMM_CTR_BYTES_UDATA_IN], npdu_len);
+ rate_ctr_inc(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_PKTS_UDATA_IN));
+ rate_ctr_add(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_BYTES_UDATA_IN), npdu_len);
+ rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_UDATA_IN));
+ rate_ctr_add(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_BYTES_UDATA_IN), npdu_len);
/* It is easier to have a global count */
pdp->cdr_bytes_in += npdu_len;
@@ -804,10 +945,11 @@ int sgsn_gtp_init(struct sgsn_instance *sgi)
/* Register callbackcs with libgtp */
gtp_set_cb_delete_context(gsn, cb_delete_context);
gtp_set_cb_conf(gsn, cb_conf);
- gtp_set_cb_recovery2(gsn, cb_recovery2);
+ gtp_set_cb_recovery3(gsn, cb_recovery3);
gtp_set_cb_data_ind(gsn, cb_data_ind);
gtp_set_cb_unsup_ind(gsn, cb_unsup_ind);
gtp_set_cb_extheader_ind(gsn, cb_extheader_ind);
+ gtp_set_cb_ran_info_relay_ind(gsn, cb_gtp_ran_info_relay_ind);
return 0;
}
diff --git a/src/sgsn/sgsn_main.c b/src/sgsn/sgsn_main.c
index 2cabbf3cf..d6afdef52 100644
--- a/src/sgsn/sgsn_main.c
+++ b/src/sgsn/sgsn_main.c
@@ -59,17 +59,18 @@
#include <osmocom/sgsn/vty.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_llc.h>
+#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_ranap.h>
-#include <osmocom/sgsn/gprs_gb.h>
-
-#include <osmocom/ctrl/control_if.h>
-#include <osmocom/ctrl/ports.h>
+#include <osmocom/sgsn/gprs_ns.h>
+#include <osmocom/sgsn/gprs_bssgp.h>
+#include <osmocom/sgsn/gprs_subscriber.h>
+#include <osmocom/sgsn/gtp.h>
#include <gtp.h>
#include <osmocom/sgsn/sgsn_rim.h>
-#include "../../bscconfig.h"
+#include "../../config.h"
#if BUILD_IU
#include <osmocom/sigtran/osmo_ss7.h>
@@ -81,7 +82,6 @@
#include <getopt.h>
void *tall_sgsn_ctx;
-struct ctrl_handle *g_ctrlh;
struct gprs_ns2_inst *sgsn_nsi;
static int daemonize = 0;
@@ -97,34 +97,11 @@ const char *openbsc_copyright =
struct sgsn_instance *sgsn;
-/* call-back function for the BSSGP protocol */
+/* call-back function for the BSSGP protocol.
+ * Must be left here so that we can add a new one in tests/sgsn_test */
int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
- struct osmo_bssgp_prim *bp;
- bp = container_of(oph, struct osmo_bssgp_prim, oph);
-
- switch (oph->sap) {
- case SAP_BSSGP_LL:
- switch (oph->primitive) {
- case PRIM_BSSGP_UL_UD:
- return gprs_llc_rcvmsg(oph->msg, bp->tp);
- }
- break;
- case SAP_BSSGP_GMM:
- switch (oph->primitive) {
- case PRIM_BSSGP_GMM_SUSPEND:
- return gprs_gmm_rx_suspend(bp->ra_id, bp->tlli);
- case PRIM_BSSGP_GMM_RESUME:
- return gprs_gmm_rx_resume(bp->ra_id, bp->tlli,
- bp->u.resume.suspend_ref);
- }
- break;
- case SAP_BSSGP_NM:
- break;
- case SAP_BSSGP_RIM:
- return sgsn_rim_rx(bp, oph->msg);
- }
- return 0;
+ return sgsn_bssgp_rx_prim(oph);
}
static void signal_handler(int signum)
@@ -162,15 +139,36 @@ static void signal_handler(int signum)
}
}
+static int sgsn_vty_go_parent(struct vty *vty)
+{
+ switch (vty->node) {
+ case SGSN_NODE:
+ vty->node = CONFIG_NODE;
+ break;
+ case MME_NODE:
+ vty->node = SGSN_NODE;
+ vty->index = NULL;
+ break;
+ default:
+#if BUILD_IU
+ osmo_ss7_vty_go_parent(vty);
+#else
+ vty->node = CONFIG_NODE;
+ vty->index = NULL;
+#endif
+ break;
+ }
+
+ return vty->node;
+}
+
/* NSI that BSSGP uses when transmitting on NS */
extern struct gprs_ns_inst *bssgp_nsi;
static struct vty_app_info vty_info = {
.name = "OsmoSGSN",
.version = PACKAGE_VERSION,
-#if BUILD_IU
- .go_parent_cb = osmo_ss7_vty_go_parent,
-#endif
+ .go_parent_cb = sgsn_vty_go_parent,
};
static void print_help(void)
@@ -310,11 +308,6 @@ static struct log_info_cat gprs_categories[] = {
.description = "GPRS Packet Service",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
- [DNS] = {
- .name = "DNS",
- .description = "GPRS Network Service (NS)",
- .enabled = 1, .loglevel = LOGL_NOTICE,
- },
[DLLC] = {
.name = "DLLC",
.description = "GPRS Logical Link Control Protocol (LLC)",
@@ -410,6 +403,7 @@ int main(int argc, char **argv)
rate_ctr_init(tall_sgsn_ctx);
logging_vty_add_deprecated_subsys(tall_sgsn_ctx, "bssgp");
+ logging_vty_add_deprecated_subsys(tall_sgsn_ctx, "ns");
sgsn_nsi = gprs_ns2_instantiate(tall_sgsn_ctx, &gprs_ns_prim_cb, NULL);
if (!sgsn_nsi) {
@@ -417,19 +411,12 @@ int main(int argc, char **argv)
exit(1);
}
sgsn->cfg.nsi = sgsn_nsi;
- bssgp_set_bssgp_callback(gprs_gb_send_cb, sgsn_nsi);
-
- gprs_llc_init("/usr/local/lib/osmocom/crypt/");
- sgsn_rate_ctr_init();
- sgsn_inst_init(sgsn);
-
+ bssgp_set_bssgp_callback(sgsn_bssgp_dispatch_ns_unitdata_req_cb, sgsn_nsi);
gprs_ns2_vty_init(sgsn_nsi);
bssgp_vty_init();
gprs_llc_vty_init();
gprs_sndcp_vty_init();
- sgsn_auth_init(sgsn);
- sgsn_cdr_init(sgsn);
handle_options(argc, argv);
@@ -455,25 +442,11 @@ int main(int argc, char **argv)
}
/* start telnet after reading config for vty_get_bind_addr() */
- rc = telnet_init_dynif(tall_sgsn_ctx, NULL,
- vty_get_bind_addr(), OSMO_VTY_PORT_SGSN);
+ rc = telnet_init_default(tall_sgsn_ctx, NULL, OSMO_VTY_PORT_SGSN);
if (rc < 0)
exit(1);
- /* start control interface after reading config for
- * ctrl_vty_get_bind_addr() */
- g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(),
- OSMO_CTRL_PORT_SGSN, NULL);
- if (!g_ctrlh) {
- LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n");
- exit(1);
- }
-
- if (sgsn_ctrl_cmds_install() != 0) {
- LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n");
- exit(1);
- }
-
+ gprs_llc_init(sgsn->cfg.crypt_cipher_plugin_path);
rc = sgsn_gtp_init(sgsn);
if (rc) {
@@ -482,9 +455,9 @@ int main(int argc, char **argv)
} else
LOGP(DGPRS, LOGL_NOTICE, "libGTP v%s initialized\n", gtp_version());
- rc = gprs_subscr_init(sgsn);
+ rc = sgsn_inst_init(sgsn);
if (rc < 0) {
- LOGP(DGPRS, LOGL_FATAL, "Cannot set up subscriber management\n");
+ LOGP(DGPRS, LOGL_FATAL, "Cannot set up SGSN\n");
exit(2);
}
diff --git a/src/sgsn/sgsn_rim.c b/src/sgsn/sgsn_rim.c
index 71e6d9883..40e1f9033 100644
--- a/src/sgsn/sgsn_rim.c
+++ b/src/sgsn/sgsn_rim.c
@@ -11,57 +11,117 @@
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_bssgp_rim.h>
#include <osmocom/sgsn/sgsn_rim.h>
+#include <osmocom/sgsn/gtp_mme.h>
+#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/debug.h>
+#include <osmocom/sgsn/sgsn.h>
-/* Find an NSEI for the destination cell, this function works only for GERAN! */
-static int find_dest_nsei_geran(struct bssgp_rim_routing_info *dest_rim_ri, uint16_t nsei)
+static int sgsn_bssgp_fwd_rim_to_geran(const struct bssgp_ran_information_pdu *pdu)
{
struct bssgp_bvc_ctx *bvc_ctx;
+ OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_GERAN);
- OSMO_ASSERT(dest_rim_ri->discr == BSSGP_RIM_ROUTING_INFO_GERAN);
+ /* Resolve RIM ROUTING ADDRESS to a BVC context */
+ bvc_ctx = btsctx_by_raid_cid(&pdu->routing_info_dest.geran.raid, pdu->routing_info_dest.geran.cid);
+ if (!bvc_ctx) {
+ LOGP(DRIM, LOGL_ERROR, "Unable to find NSEI for destination cell %s\n",
+ bssgp_rim_ri_name(&pdu->routing_info_dest));
+ return -EINVAL;
+ }
- bvc_ctx = btsctx_by_raid_cid(&dest_rim_ri->geran.raid, dest_rim_ri->geran.cid);
+ /* Forward PDU to the NSEI of the resolved BVC context */
+ return bssgp_tx_rim(pdu, bvc_ctx->nsei);
+}
+
+static int sgsn_bssgp_fwd_rim_to_geran_encoded(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address)
+{
+ struct bssgp_bvc_ctx *bvc_ctx;
+ OSMO_ASSERT(rim_routing_address->discr == BSSGP_RIM_ROUTING_INFO_GERAN);
+
+ /* Resolve RIM ROUTING ADDRESS to a BVC context */
+ bvc_ctx = btsctx_by_raid_cid(&rim_routing_address->geran.raid, rim_routing_address->geran.cid);
if (!bvc_ctx) {
- LOGP(DRIM, LOGL_ERROR, "BSSGP RIM (NSEI=%u) cannot find NSEI for destination cell\n", nsei);
+ LOGP(DRIM, LOGL_ERROR, "Unable to find NSEI for destination cell %s\n",
+ bssgp_rim_ri_name(rim_routing_address));
return -EINVAL;
}
- return bvc_ctx->nsei;
+ /* Forward PDU to the NSEI of the resolved BVC context */
+ return bssgp_tx_rim_encoded(msg, bvc_ctx->nsei);
}
-int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg)
+static int sgsn_bssgp_fwd_rim_to_eutran(const struct bssgp_ran_information_pdu *pdu)
+{
+ struct sgsn_mme_ctx *mme;
+ OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_EUTRAN);
+
+ mme = sgsn_mme_ctx_by_route(sgsn, &pdu->routing_info_dest.eutran.tai);
+ if (!mme) { /* See if we have a default route configured */
+ mme = sgsn_mme_ctx_by_default_route(sgsn);
+ if (!mme) {
+ LOGP(DRIM, LOGL_ERROR, "Unable to find MME for destination cell %s\n",
+ bssgp_rim_ri_name(&pdu->routing_info_dest));
+ return -EINVAL;
+ }
+ }
+
+ return sgsn_mme_ran_info_req(mme, pdu);
+}
+
+/* Receive a RIM PDU from BSSGP (GERAN) */
+int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg)
{
- struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;
- int d_nsei;
uint16_t nsei = msgb_nsei(msg);
+ struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;
- /* At the moment we only support GERAN, so we block all other network
- * types here. */
- if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
+ if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
LOGP(DRIM, LOGL_ERROR,
- "BSSGP RIM (NSEI=%u) only GERAN supported, destination cell is not a GERAN cell -- rejected.\n",
- nsei);
- /* At the moment we can only handle GERAN addresses, any other
- * type of address will be consideres as an invalid address.
- * see also: 3GPP TS 48.018, section 8c.3.1.3 */
- return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
+ "Rx BSSGP RIM (NSEI=%u): Expected src %s, got %s\n", nsei,
+ bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN),
+ bssgp_rim_routing_info_discr_str(pdu->routing_info_src.discr));
+ goto err;
}
- if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
+
+ switch (pdu->routing_info_dest.discr) {
+ case BSSGP_RIM_ROUTING_INFO_GERAN:
+ return sgsn_bssgp_fwd_rim_to_geran(pdu);
+ case BSSGP_RIM_ROUTING_INFO_EUTRAN:
+ return sgsn_bssgp_fwd_rim_to_eutran(pdu);
+ default:
+ /* At the moment we can only handle GERAN/EUTRAN addresses, any
+ * other type of address will be considered as an invalid
+ * address. see also: 3GPP TS 48.018, section 8c.3.1.3
+ */
LOGP(DRIM, LOGL_ERROR,
- "BSSGP RIM (NSEI=%u) only GERAN supported, source cell is not a GERAN cell -- rejected.\n", nsei);
- /* See comment above */
- return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
+ "Rx BSSGP RIM (NSEI=%u): Unsupported dst %s\n", nsei,
+ bssgp_rim_routing_info_discr_str(pdu->routing_info_dest.discr));
}
- d_nsei = find_dest_nsei_geran(&pdu->routing_info_dest, nsei);
- if (d_nsei < 0) {
- LOGP(DRIM, LOGL_NOTICE, "BSSGP RIM (NSEI=%u) Cell %s unknown to this sgsn\n",
- nsei, bssgp_rim_ri_name(&pdu->routing_info_dest));
- /* In case of an invalid destination address we respond with
- * a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */
- return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
+ LOGP(DRIM, LOGL_INFO, "Rx BSSGP RIM (NSEI=%u): for dest cell %s\n", nsei,
+ bssgp_rim_ri_name(&pdu->routing_info_dest));
+
+err:
+ /* In case of an invalid destination address we respond with
+ * a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */
+ bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
+ return -1;
+}
+
+/* Receive a RIM PDU from GTPv1C (EUTRAN) */
+int sgsn_rim_rx_from_gtp(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address)
+{
+ /* TODO: In this code path, we currently only support RIM message forwarding to GERAN (BSSGP). However, it
+ * technically also be possible to route a message back to GTP (BSSGP_RIM_ROUTING_INFO_EUTRAN) or to
+ * IuPS (BSSGP_RIM_ROUTING_INFO_UTRAN) */
+ if (rim_routing_address->discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
+ LOGP(DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected dst %s, got %s\n",
+ bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN),
+ bssgp_rim_routing_info_discr_str(rim_routing_address->discr));
+ return -EINVAL;
}
- /* Forward PDU as it is to the correct interface */
- return bssgp_tx_rim(pdu, (uint16_t) d_nsei);
+ LOGP(DRIM, LOGL_INFO, "Rx GTP RAN Information Relay for dest cell %s\n",
+ bssgp_rim_ri_name(rim_routing_address));
+
+ return sgsn_bssgp_fwd_rim_to_geran_encoded(msg, rim_routing_address);
}
diff --git a/src/sgsn/sgsn_vty.c b/src/sgsn/sgsn_vty.c
index d7584bcb4..29f9cd604 100644
--- a/src/sgsn/sgsn_vty.c
+++ b/src/sgsn/sgsn_vty.c
@@ -35,9 +35,14 @@
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/gprs/gprs_ns2.h>
+#include <osmocom/sgsn/gprs_ns.h>
#include <osmocom/sgsn/gprs_gmm.h>
-#include <osmocom/sgsn/gprs_sgsn.h>
+#include <osmocom/sgsn/gprs_bssgp.h>
+#include <osmocom/sgsn/mmctx.h>
+#include <osmocom/sgsn/gtp_ggsn.h>
+#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/sgsn/vty.h>
+#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/vty/tdef_vty.h>
@@ -45,6 +50,7 @@
#include <osmocom/vty/vty.h>
#include <osmocom/vty/misc.h>
#include <osmocom/crypt/gprs_cipher.h>
+#include <osmocom/crypt/utran_cipher.h>
#include <osmocom/abis/ipa.h>
#include <osmocom/gprs/gprs_bssgp.h>
@@ -52,14 +58,12 @@
#include <pdp.h>
#include <gtp.h>
-#include "../../bscconfig.h"
+#include "../../config.h"
#ifdef BUILD_IU
#include <osmocom/ranap/iu_client.h>
#endif
-extern void *tall_sgsn_ctx;
-
static struct sgsn_config *g_cfg = NULL;
const struct value_string sgsn_auth_pol_strs[] = {
@@ -94,7 +98,7 @@ const struct value_string sgsn_auth_pol_strs[] = {
#define NONSPEC_X1001_SECS 5 /* wait for a RANAP Release Complete */
-static struct osmo_tdef sgsn_T_defs[] = {
+struct osmo_tdef sgsn_T_defs[] = {
{ .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" },
{ .T=3313, .default_val=GSM0408_T3313_SECS, .desc="Waiting for paging response timer (s)" },
{ .T=3314, .default_val=GSM0408_T3314_SECS, .desc="READY timer. Force to STANDBY on expiry timer (s)" },
@@ -110,7 +114,6 @@ static struct osmo_tdef sgsn_T_defs[] = {
/* non spec timers */
{ .T=-1001, .default_val=NONSPEC_X1001_SECS, .desc="RANAP Release timeout. Wait for RANAP Release Complete."
"On expiry release Iu connection (s)" },
- { .T=-3314, .default_val=GSM0408_T3314_SECS, .desc="Iu User inactivity timer. On expiry release Iu connection (s)" },
{}
};
@@ -134,7 +137,27 @@ DEFUN(cfg_sgsn_timer, cfg_sgsn_timer_cmd,
return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs, argv);
}
-char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
+DEFUN(show_timer_gtp, show_timer_gtp_cmd,
+ "show timer gtp " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
+ SHOW_STR "Show timers\n" "GTP (libgtp) timers\n"
+ OSMO_TDEF_VTY_DOC_T)
+{
+ const char *T_arg = argc > 0 ? argv[0] : NULL;
+ return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs_gtp, T_arg, NULL);
+}
+
+DEFUN(cfg_sgsn_timer_gtp, cfg_sgsn_timer_gtp_cmd,
+ "timer gtp " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
+ "Configure or show timers\n" "GTP (libgtp) timers\n"
+ OSMO_TDEF_VTY_DOC_SET)
+{
+ /* If any arguments are missing, redirect to 'show' */
+ if (argc < 2)
+ return show_timer(self, vty, argc, argv);
+ return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs_gtp, argv);
+}
+
+char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6)
{
static char str[INET6_ADDRSTRLEN + 10];
@@ -147,15 +170,28 @@ char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
case PDP_TYPE_N_IETF_IPv4:
if (len < 2 + 4)
break;
- strcpy(str, "IPv4 ");
+ osmo_strlcpy(str, "IPv4 ", sizeof(str));
inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
return str;
case PDP_TYPE_N_IETF_IPv6:
if (len < 2 + 8)
break;
- strcpy(str, "IPv6 ");
+ osmo_strlcpy(str, "IPv6 ", sizeof(str));
inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
return str;
+ case PDP_TYPE_N_IETF_IPv4v6:
+ if (len < 2 + 20)
+ break;
+ if (return_ipv6) {
+ /* The IPv6 token, (rightmost four fields) is a duplicate of
+ * the site prefix + subnetID (leftmost fields) in pdpa here */
+ osmo_strlcpy(str, "IPv6 ", sizeof(str));
+ inet_ntop(AF_INET6, pdpa+6, str+5, sizeof(str)-5);
+ return str;
+ }
+ osmo_strlcpy(str, "IPv4 ", sizeof(str));
+ inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
+ return str;
default:
break;
}
@@ -177,12 +213,36 @@ static struct cmd_node sgsn_node = {
1,
};
+static struct cmd_node mme_node = {
+ MME_NODE,
+ "%s(config-sgsn-mme)# ",
+ 1,
+};
+
+static void config_write_mme(struct vty *vty, const struct sgsn_mme_ctx *mme, const char *prefix)
+{
+ struct mme_rim_route *rt;
+
+ vty_out(vty, "%smme %s%s", prefix, mme->name, VTY_NEWLINE);
+
+ vty_out(vty, "%s gtp remote-ip %s%s", prefix, inet_ntoa(mme->remote_addr), VTY_NEWLINE);
+ if (mme->default_route)
+ vty_out(vty, "%s gtp ran-info-relay default%s", prefix, VTY_NEWLINE);
+ llist_for_each_entry(rt, &mme->routes, list) {
+ vty_out(vty, "%s gtp ran-info-relay %s %s %u%s", prefix,
+ osmo_mcc_name(rt->tai.mcc), osmo_mnc_name(rt->tai.mnc, rt->tai.mnc_3_digits),
+ rt->tai.tac, VTY_NEWLINE);
+ }
+}
+
static int config_write_sgsn(struct vty *vty)
{
struct sgsn_ggsn_ctx *gctx;
struct imsi_acl_entry *acl;
struct apn_ctx *actx;
struct ares_addr_node *server;
+ struct sgsn_mme_ctx *mme;
+ int i;
vty_out(vty, "sgsn%s", VTY_NEWLINE);
@@ -191,7 +251,7 @@ static int config_write_sgsn(struct vty *vty)
vty_out(vty, " gtp local-ip %s%s",
inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
- llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
+ llist_for_each_entry(gctx, &sgsn->ggsn_list, list) {
if (gctx->id == UINT32_MAX)
continue;
@@ -213,10 +273,26 @@ static int config_write_sgsn(struct vty *vty)
for (server = sgsn->ares_servers; server; server = server->next)
vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
- if (g_cfg->cipher != GPRS_ALGO_GEA0)
- vty_out(vty, " encryption %s%s",
- get_value_string(gprs_cipher_names, g_cfg->cipher),
- VTY_NEWLINE);
+ if (g_cfg->gea_encryption_mask != 0) {
+ vty_out(vty, " encryption gea");
+
+ for (i = 0; i < _GPRS_ALGO_NUM; i++)
+ if (g_cfg->gea_encryption_mask >> i & 1)
+ vty_out(vty, " %u", i);
+
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+ if (g_cfg->uea_encryption_mask != 0) {
+ vty_out(vty, " encryption uea");
+
+ for (i = 0; i < _OSMO_UTRAN_UEA_NUM; i++)
+ if (g_cfg->uea_encryption_mask >> i & 1)
+ vty_out(vty, " %u", i);
+
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+ if (g_cfg->crypt_cipher_plugin_path)
+ vty_out(vty, " encryption cipher-plugin-path %s%s", g_cfg->crypt_cipher_plugin_path, VTY_NEWLINE);
if (g_cfg->sgsn_ipa_name)
vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);
if (g_cfg->gsup_server_addr.sin_addr.s_addr)
@@ -245,9 +321,9 @@ static int config_write_sgsn(struct vty *vty)
llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
- if (llist_empty(&sgsn_apn_ctxts))
+ if (llist_empty(&sgsn->apn_list))
vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
- llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
+ llist_for_each_entry(actx, &sgsn->apn_list, list) {
if (strlen(actx->imsi_prefix) > 0)
vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
actx->name, actx->imsi_prefix, actx->ggsn->id,
@@ -268,6 +344,7 @@ static int config_write_sgsn(struct vty *vty)
vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer ");
+ osmo_tdef_vty_write(vty, g_cfg->T_defs_gtp, " timer gtp ");
if (g_cfg->pcomp_rfc1144.active) {
vty_out(vty, " compression rfc1144 active slots %d%s",
@@ -297,6 +374,10 @@ static int config_write_sgsn(struct vty *vty)
} else
vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
+ llist_for_each_entry(mme, &sgsn->mme_list, list) {
+ config_write_mme(vty, mme, " ");
+ }
+
#ifdef BUILD_IU
vty_out(vty, " cs7-instance-iu %u%s", g_cfg->iu.cs7_instance,
VTY_NEWLINE);
@@ -351,7 +432,7 @@ DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
"IPv4 Address\n")
{
uint32_t id = atoi(argv[0]);
- struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
+ struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
inet_aton(argv[1], &ggc->remote_addr);
@@ -376,7 +457,7 @@ DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
"Version 0\n" "Version 1\n")
{
uint32_t id = atoi(argv[0]);
- struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
+ struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
if (atoi(argv[1]))
ggc->gtp_version = 1;
@@ -394,7 +475,7 @@ DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
"Interval between echo requests in seconds.\n")
{
uint32_t id = atoi(argv[0]);
- struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
+ struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
ggc->echo_interval = atoi(argv[1]);
@@ -413,7 +494,7 @@ 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")
{
uint32_t id = atoi(argv[0]);
- struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
+ struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
ggc->echo_interval = 0;
sgsn_ggsn_ctx_check_echo_timer(ggc);
@@ -454,7 +535,7 @@ static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
struct apn_ctx *actx;
struct sgsn_ggsn_ctx *ggsn;
- ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
+ ggsn = sgsn_ggsn_ctx_by_id(sgsn, ggsn_id);
if (ggsn == NULL) {
vty_out(vty, "%% a GGSN with id %d has not been defined%s",
ggsn_id, VTY_NEWLINE);
@@ -518,8 +599,13 @@ static void vty_dump_pdp(struct vty *vty, const char *pfx,
osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
VTY_NEWLINE);
vty_out(vty, "%s PDP Address: %s%s", pfx,
- gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
+ gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, false),
VTY_NEWLINE);
+ if (pdp->lib->eua.v[1] == PDP_TYPE_N_IETF_IPv4v6) {
+ vty_out(vty, "%s PDP Address: %s%s", pfx,
+ gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, true),
+ VTY_NEWLINE);
+ }
vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
@@ -627,7 +713,7 @@ DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
- vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
+ vty_dump_mmctx(vty, "", mm, (argc > 1) ? 1 : 0);
return CMD_SUCCESS;
}
@@ -636,9 +722,8 @@ DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
{
struct sgsn_mm_ctx *mm;
-
- llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
- vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
+ llist_for_each_entry(mm, &sgsn->mm_list, list)
+ vty_dump_mmctx(vty, "", mm, (argc > 0) ? 1 : 0);
return CMD_SUCCESS;
}
@@ -649,7 +734,7 @@ DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
{
struct sgsn_pdp_ctx *pdp;
- llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
+ llist_for_each_entry(pdp, &sgsn->pdp_list, g_list)
vty_dump_pdp(vty, "", pdp);
return CMD_SUCCESS;
@@ -695,15 +780,19 @@ DEFUN(imsi_acl, cfg_imsi_acl_cmd,
return CMD_SUCCESS;
}
-DEFUN(cfg_encrypt, cfg_encrypt_cmd,
+DEFUN_DEPRECATED(cfg_encrypt, cfg_encrypt_cmd,
"encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
"Set encryption algorithm for SGSN\n"
"Use GEA0 (no encryption)\n"
"Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
{
enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
+
+ if (strcmp(argv[0], "gea") == 0)
+ return CMD_SUCCESS;
+
if (c != GPRS_ALGO_GEA0) {
- if (!gprs_cipher_supported(c)) {
+ if (gprs_cipher_supported(c) <= 0) {
vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
@@ -715,11 +804,73 @@ DEFUN(cfg_encrypt, cfg_encrypt_cmd,
}
}
- g_cfg->cipher = c;
+ g_cfg->gea_encryption_mask |= (1 << c);
return CMD_SUCCESS;
}
+#define ENCRYPTION_STR "Set encryption algorithms for SGSN\n"
+
+DEFUN(cfg_encrypt2, cfg_encrypt2_cmd,
+ "encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>]",
+ ENCRYPTION_STR
+ "GPRS Encryption Algorithm\n"
+ "GEAn Algorithm Number\n"
+ "GEAn Algorithm Number\n"
+ "GEAn Algorithm Number\n"
+ "GEAn Algorithm Number\n"
+ "GEAn Algorithm Number\n")
+{
+ int i = 0;
+
+ g_cfg->gea_encryption_mask = 0;
+ for (i = 0; i < argc; i++)
+ g_cfg->gea_encryption_mask |= (1 << atoi(argv[i]));
+
+ for (i = 0; i < _GPRS_ALGO_NUM; i++) {
+ if (g_cfg->gea_encryption_mask >> i & 1) {
+
+ if (i == GPRS_ALGO_GEA0)
+ continue;
+
+ if (gprs_cipher_supported(i) <= 0) {
+ vty_out(vty, "%% cipher %d is unsupported in current version%s", i, VTY_NEWLINE);
+ return CMD_ERR_INCOMPLETE;
+ }
+
+ if (!g_cfg->require_authentication) {
+ vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
+ argv[i], VTY_NEWLINE);
+ return CMD_ERR_INCOMPLETE;
+ }
+
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_encrypt_cipher_plugin_path, cfg_encrypt_cipher_plugin_path_cmd,
+ "encryption cipher-plugin-path PATH",
+ ENCRYPTION_STR
+ "Path to gprs encryption cipher plugin directory\n"
+ "Plugin path\n")
+{
+ osmo_talloc_replace_string(sgsn, &sgsn->cfg.crypt_cipher_plugin_path, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_encrypt_cipher_plugin_path, cfg_no_encrypt_cipher_plugin_path_cmd,
+ "no encryption cipher-plugin-path PATH",
+ NO_STR ENCRYPTION_STR
+ "Path to gprs encryption cipher plugin directory\n"
+ "Plugin path\n")
+{
+ TALLOC_FREE(sgsn->cfg.crypt_cipher_plugin_path);
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_authentication, cfg_authentication_cmd,
"authentication (optional|required)",
"Whether to enforce MS authentication in GERAN (only with auth-policy remote)\n"
@@ -741,6 +892,23 @@ DEFUN(cfg_authentication, cfg_authentication_cmd,
return CMD_SUCCESS;
}
+DEFUN(cfg_encryption_uea, cfg_encryption_uea_cmd,
+ "encryption uea <0-2> [<0-2>] [<0-2>]",
+ ENCRYPTION_STR
+ "UTRAN (3G) encryption algorithms to allow: 0 = UEA0 (no encryption), 1 = UEA1, 2 = UEA2.\n"
+ "UEAn Algorithm Number\n"
+ "UEAn Algorithm Number\n"
+ "UEAn Algorithm Number\n")
+{
+ unsigned int i;
+
+ g_cfg->uea_encryption_mask = 0;
+ for (i = 0; i < argc; i++)
+ g_cfg->uea_encryption_mask |= (1 << atoi(argv[i]));
+
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
"auth-policy (accept-all|closed|acl-only|remote)",
"Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
@@ -822,8 +990,17 @@ static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int
}
llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
- vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'",
- pdp->context_id, pdp->pdp_type, pdp->apn_str);
+ char ip_str[INET6_ADDRSTRLEN] = { 0 };
+
+ vty_out(vty, " PDP info: Id: %d, Addr(Org: 0x%02x Type: 0x%02x",
+ pdp->context_id, pdp->pdp_type_org, pdp->pdp_type_nr);
+
+ if (pdp->pdp_address[0].u.sa.sa_family != AF_UNSPEC)
+ vty_out(vty, " Addr[0]: %s", osmo_sockaddr_ntop(&pdp->pdp_address[0].u.sa, ip_str));
+ if (pdp->pdp_address[0].u.sa.sa_family != AF_UNSPEC)
+ vty_out(vty, " Addr[1]: %s", osmo_sockaddr_ntop(&pdp->pdp_address[1].u.sa, ip_str));
+
+ vty_out(vty, ") APN: '%s'", pdp->apn_str);
if (pdp->qos_subscribed_len)
vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len));
@@ -870,7 +1047,7 @@ DEFUN_HIDDEN(reset_sgsn_state,
struct gprs_subscr *subscr, *tmp_subscr;
struct sgsn_mm_ctx *mm, *tmp_mm;
- llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
+ llist_for_each_entry_safe(mm, tmp_mm, &sgsn->mm_list, list)
{
gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
}
@@ -1134,6 +1311,25 @@ DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
return CMD_SUCCESS;
}
+DEFUN(page_subscr, page_subscr_info_cmd,
+ "page imsi IMSI",
+ "Send a PS paging request to subscriber\n"
+ "Use the IMSI to select the subscriber\n"
+ "The IMSI\n")
+{
+ const char *imsi = argv[0];
+ struct sgsn_mm_ctx *mm;
+
+ mm = sgsn_mm_ctx_by_imsi(imsi);
+ if (!mm) {
+ vty_out(vty, "No MM context for IMSI %s%s", imsi, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ sgsn_bssgp_page_ps_ra(mm);
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_gsup_ipa_name,
cfg_gsup_ipa_name_cmd,
"gsup ipa-name NAME",
@@ -1424,13 +1620,165 @@ DEFUN(cfg_sgsn_cs7_instance_iu,
}
#endif
+DEFUN(cfg_sgsn_mme, cfg_sgsn_mme_cmd,
+ "mme NAME",
+ "Configure an MME peer\n"
+ "Name identifying the MME peer\n")
+{
+ struct sgsn_mme_ctx *mme;
+
+ mme = sgsn_mme_ctx_find_alloc(sgsn, argv[0]);
+ if (!mme)
+ return CMD_WARNING;
+
+ vty->node = MME_NODE;
+ vty->index = mme;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_sgsn_no_mme, cfg_sgsn_no_mme_cmd,
+ "no mme NAME",
+ NO_STR "Delete an MME peer configuration\n"
+ "Name identifying the MME peer\n")
+{
+ struct sgsn_mme_ctx *mme;
+
+ mme = sgsn_mme_ctx_by_name(sgsn, argv[0]);
+ if (!mme) {
+ vty_out(vty, "%% MME %s doesn't exist.%s",
+ argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ sgsn_mme_ctx_free(mme);
+
+ return CMD_SUCCESS;
+}
+
+#define GTP_STR "Configure GTP connection\n"
+
+DEFUN(cfg_mme_remote_ip, cfg_mme_remote_ip_cmd,
+ "gtp remote-ip A.B.C.D",
+ GTP_STR "Set Remote GTP IP address\n" IP_STR)
+{
+ struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
+
+ inet_aton(argv[0], &mme->remote_addr);
+
+ return CMD_SUCCESS;
+}
+
+#define RAN_INFO_STR "Configure RAN Information Relay routing\n"
+#define TAI_DOC "MCC\n" "MNC\n" "TAC\n"
+
+DEFUN(cfg_mme_ran_info_relay_tai, cfg_mme_ran_info_relay_tai_cmd,
+ "gtp ran-info-relay <0-999> <0-999> <0-65535>",
+ GTP_STR RAN_INFO_STR TAI_DOC)
+{
+ struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
+ struct sgsn_mme_ctx *mme_tmp;
+ struct osmo_eutran_tai tai;
+
+ const char *mcc = argv[0];
+ const char *mnc = argv[1];
+ const char *tac = argv[2];
+
+ if (osmo_mcc_from_str(mcc, &tai.mcc)) {
+ vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
+ vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ tai.tac = atoi(tac);
+
+ if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
+ if (mme_tmp != mme) {
+ vty_out(vty, "%% Another MME %s already contains this route%s",
+ mme_tmp->name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ /* else: NO-OP, return */
+ return CMD_SUCCESS;
+ }
+
+ sgsn_mme_ctx_route_add(mme, &tai);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mme_no_ran_info_relay_tai, cfg_mme_no_ran_info_relay_tai_cmd,
+ "no gtp ran-info-relay <0-999> <0-999> <0-65535>",
+ NO_STR GTP_STR RAN_INFO_STR TAI_DOC)
+{
+ struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
+ struct sgsn_mme_ctx *mme_tmp;
+ struct osmo_eutran_tai tai;
+
+ const char *mcc = argv[0];
+ const char *mnc = argv[1];
+ const char *tac = argv[2];
+
+ if (osmo_mcc_from_str(mcc, &tai.mcc)) {
+ vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
+ vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ tai.tac = atoi(tac);
+
+ if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
+ if (mme_tmp != mme) {
+ vty_out(vty, "%% Another MME %s contains this route%s",
+ mme_tmp->name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ sgsn_mme_ctx_route_del(mme, &tai);
+ return CMD_SUCCESS;
+ } else {
+ vty_out(vty, "%% This route doesn't exist in current MME %s%s",
+ mme->name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+}
+
+DEFUN(cfg_mme_ran_info_relay_default, cfg_mme_ran_info_relay_default_cmd,
+ "gtp ran-info-relay default",
+ GTP_STR RAN_INFO_STR "Set as default route")
+{
+ struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
+ struct sgsn_mme_ctx *default_mme;
+
+ if (mme->default_route)
+ return CMD_SUCCESS; /* NO-OP */
+
+ if ((default_mme = sgsn_mme_ctx_by_default_route(sgsn))) {
+ vty_out(vty, "%% Another MME %s is already set as default route, "
+ "remove it before setting it here.%s",
+ default_mme->name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ mme->default_route = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mme_no_ran_info_relay_default, cfg_mme_no_ran_info_relay_default_cmd,
+ "no gtp ran-info-relay default",
+ NO_STR GTP_STR RAN_INFO_STR "Set as default route")
+{
+ struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
+ mme->default_route = false;
+ return CMD_SUCCESS;
+}
+
int sgsn_vty_init(struct sgsn_config *cfg)
{
g_cfg = cfg;
- g_cfg->T_defs = sgsn_T_defs;
- osmo_tdefs_reset(g_cfg->T_defs);
-
install_element_ve(&show_sgsn_cmd);
//install_element_ve(&show_mmctx_tlli_cmd);
install_element_ve(&show_mmctx_imsi_cmd);
@@ -1438,6 +1786,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element_ve(&show_pdpctx_all_cmd);
install_element_ve(&show_subscr_cache_cmd);
install_element_ve(&show_timer_cmd);
+ install_element_ve(&show_timer_gtp_cmd);
install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
install_element(ENABLE_NODE, &update_subscr_create_cmd);
@@ -1445,6 +1794,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
+ install_element(ENABLE_NODE, &page_subscr_info_cmd);
install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
install_element(CONFIG_NODE, &cfg_sgsn_cmd);
@@ -1459,7 +1809,14 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
install_element(SGSN_NODE, &cfg_auth_policy_cmd);
install_element(SGSN_NODE, &cfg_authentication_cmd);
+
+ /* order matters here: ensure we attempt to parse our new command first! */
+ install_element(SGSN_NODE, &cfg_encrypt2_cmd);
install_element(SGSN_NODE, &cfg_encrypt_cmd);
+ install_element(SGSN_NODE, &cfg_encryption_uea_cmd);
+ install_element(SGSN_NODE, &cfg_encrypt_cipher_plugin_path_cmd);
+ install_element(SGSN_NODE, &cfg_no_encrypt_cipher_plugin_path_cmd);
+
install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
@@ -1479,6 +1836,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
install_element(SGSN_NODE, &cfg_sgsn_timer_cmd);
+ install_element(SGSN_NODE, &cfg_sgsn_timer_gtp_cmd);
install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
@@ -1487,6 +1845,15 @@ int sgsn_vty_init(struct sgsn_config *cfg)
install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
+ install_element(SGSN_NODE, &cfg_sgsn_mme_cmd);
+ install_element(SGSN_NODE, &cfg_sgsn_no_mme_cmd);
+ install_node(&mme_node, NULL);
+ install_element(MME_NODE, &cfg_mme_remote_ip_cmd);
+ install_element(MME_NODE, &cfg_mme_ran_info_relay_default_cmd);
+ install_element(MME_NODE, &cfg_mme_no_ran_info_relay_default_cmd);
+ install_element(MME_NODE, &cfg_mme_ran_info_relay_tai_cmd);
+ install_element(MME_NODE, &cfg_mme_no_ran_info_relay_tai_cmd);
+
#ifdef BUILD_IU
install_element(SGSN_NODE, &cfg_sgsn_cs7_instance_iu_cmd);
ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
@@ -1501,6 +1868,9 @@ int sgsn_parse_config(const char *config_file)
/* make sure sgsn_vty_init() was called before this */
OSMO_ASSERT(g_cfg);
+ g_cfg->gea_encryption_mask = 0x1; /* support GEA0 by default unless specific encryption config exists */
+ g_cfg->uea_encryption_mask = (1 << OSMO_UTRAN_UEA0); /* support UEA0 by default unless specific encryption config exists */
+
rc = vty_read_config_file(config_file, NULL);
if (rc < 0) {
fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
diff --git a/src/sgsn/v42bis.c b/src/sgsn/v42bis.c
index 0759cdf1c..ddca5f8c9 100644
--- a/src/sgsn/v42bis.c
+++ b/src/sgsn/v42bis.c
@@ -17,10 +17,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index cb6d343b5..2c07ac96e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -42,38 +42,38 @@ DISTCLEANFILES = \
$(NULL)
if ENABLE_EXT_TESTS
-python-tests: $(BUILT_SOURCES)
+python-tests:
$(MAKE) vty-test
$(MAKE) ctrl-python-test
else
-python-tests: $(BUILT_SOURCES)
+python-tests:
echo "Not running python-based tests (determined at configure-time)"
endif
-vty-python-test: $(BUILT_SOURCES)
+vty-python-test: $(top_builddir)/src/sgsn/osmo-sgsn
osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
$(srcdir)/vty_test_runner.py -w $(abs_top_builddir) -v
- rm -f $(top_builddir)/sms.db $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count
+ rm -f $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count
# To update the VTY script from current application behavior,
# pass -u to vty_script_runner.py by doing:
# make vty-transcript-test U=-u
-vty-transcript-test:
+vty-transcript-test: $(top_builddir)/src/sgsn/osmo-sgsn
osmo_verify_transcript_vty.py -v \
-n OsmoSGSN -p 4245 \
-r "$(top_builddir)/src/sgsn/osmo-sgsn -c $(top_srcdir)/doc/examples/osmo-sgsn/osmo-sgsn.cfg" \
$(U) $${T:-$(srcdir)/osmo-sgsn*.vty}
- rm -f $(builddir)/sms.db $(builddir)/gsn_restart
+ rm -f $(builddir)/gsn_restart
# don't run multiple tests concurrently so that the ports don't conflict
vty-test:
$(MAKE) vty-python-test
$(MAKE) vty-transcript-test
-ctrl-python-test: $(BUILT_SOURCES)
+ctrl-python-test: $(top_builddir)/src/sgsn/osmo-sgsn
$(srcdir)/ctrl_test_runner.py -w $(abs_top_builddir) -v
- rm -f $(top_builddir)/sms.db $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count
+ rm -f $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count
check-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
diff --git a/tests/gprs/Makefile.am b/tests/gprs/Makefile.am
index 902313f2a..ddfd2aec0 100644
--- a/tests/gprs/Makefile.am
+++ b/tests/gprs/Makefile.am
@@ -1,9 +1,10 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS)
+AM_LDFLAGS = -no-install
EXTRA_DIST = gprs_test.ok
-noinst_PROGRAMS = gprs_test
+check_PROGRAMS = gprs_test
gprs_test_SOURCES = gprs_test.c $(top_srcdir)/src/gprs/gprs_utils.c
diff --git a/tests/gprs/gprs_test.c b/tests/gprs/gprs_test.c
index 99e3ea519..f239b7032 100644
--- a/tests/gprs/gprs_test.c
+++ b/tests/gprs/gprs_test.c
@@ -24,7 +24,7 @@ static int nu_is_retransmission(uint16_t nu, uint16_t vur)
return ret;
}
-static void test_8_4_2()
+static void test_8_4_2(void)
{
printf("Testing gprs_llc_is_retransmit.\n");
@@ -48,6 +48,22 @@ static void test_8_4_2()
ASSERT_FALSE(nu_is_retransmission(479, 511)); // wrapped
}
+/* GSM 04.08, 10.5.7.3 GPRS Timer */
+static int gprs_tmr_to_secs(uint8_t tmr)
+{
+ switch (tmr & GPRS_TMR_UNIT_MASK) {
+ case GPRS_TMR_2SECONDS:
+ return 2 * (tmr & GPRS_TMR_FACT_MASK);
+ default:
+ case GPRS_TMR_MINUTE:
+ return 60 * (tmr & GPRS_TMR_FACT_MASK);
+ case GPRS_TMR_6MINUTE:
+ return 360 * (tmr & GPRS_TMR_FACT_MASK);
+ case GPRS_TMR_DEACTIVATED:
+ return -1;
+ }
+}
+
static void test_gprs_timer_enc_dec(void)
{
int i, u, secs, tmr;
diff --git a/tests/gtphub/Makefile.am b/tests/gtphub/Makefile.am
index fea01e0d1..22b2a522c 100644
--- a/tests/gtphub/Makefile.am
+++ b/tests/gtphub/Makefile.am
@@ -12,11 +12,13 @@ AM_CFLAGS = \
$(LIBGTP_CFLAGS) \
$(NULL)
+AM_LDFLAGS = -no-install
+
EXTRA_DIST = \
gtphub_test.ok \
$(NULL)
-noinst_PROGRAMS = \
+check_PROGRAMS = \
gtphub_test \
$(NULL)
@@ -28,6 +30,7 @@ gtphub_test_LDFLAGS = \
-Wl,--wrap=gtphub_resolve_ggsn_addr \
-Wl,--wrap=gtphub_ares_init \
-Wl,--wrap=gtphub_write \
+ $(AM_LDFLAGS) \
$(NULL)
gtphub_test_LDADD = \
diff --git a/tests/gtphub/gtphub_test.c b/tests/gtphub/gtphub_test.c
index dab39775b..5fa730a05 100644
--- a/tests/gtphub/gtphub_test.c
+++ b/tests/gtphub/gtphub_test.c
@@ -27,10 +27,11 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/application.h>
+#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/sgsn/debug.h>
-#include <osmocom/sgsn/gtphub.h>
+#include <osmocom/gtphub/gtphub.h>
#include <gtp.h>
#include <gtpie.h>
@@ -376,7 +377,7 @@ static void test_expiry(void)
}
char resolve_ggsn_got_imsi[GSM23003_IMSI_MAX_DIGITS+1];
-char resolve_ggsn_got_ni[GSM_APN_LENGTH];
+char resolve_ggsn_got_ni[APN_MAXLEN+1];
struct sgsn_sockaddr resolved_ggsn_addr;
static int resolve_to_ggsn(const char *addr, uint16_t port)
@@ -577,7 +578,7 @@ time_t now;
static struct gtphub _hub;
static struct gtphub *hub = &_hub;
-static int setup_test_hub()
+static int setup_test_hub(void)
{
/* Not really needed, but to make 100% sure... */
ZERO_STRUCT(hub);
@@ -613,7 +614,7 @@ static int setup_test_hub()
return 1;
}
-static int clear_test_hub()
+static int clear_test_hub(void)
{
/* expire all */
gtphub_gc(hub, now + (60 * GTPH_EXPIRE_SLOWLY_MINUTES) + 1);
@@ -817,7 +818,7 @@ static void test_echo(void)
"87" /* 135: Quality of Service (QoS) Profile */ \
"0004" /* length */ \
"00" /* priority */ \
- "0b921f" /* QoS profile data */
+ "0b921f" /* QoS profile data */
#define MSG_PDP_CTX_RSP(len, tei_h, seq, restart, tei_u, tei_c, gsn_c, gsn_u) \
"32" \
@@ -898,7 +899,7 @@ static int msg_from_ggsn(int plane_idx,
return 1;
}
-static int create_pdp_ctx()
+static int create_pdp_ctx(void)
{
const char *gtp_req_from_sgsn =
MSG_PDP_CTX_REQ("0068",
diff --git a/tests/osmo-sgsn_test-nodes.vty b/tests/osmo-sgsn_test-nodes.vty
index 109e2ece2..32ff8e71d 100644
--- a/tests/osmo-sgsn_test-nodes.vty
+++ b/tests/osmo-sgsn_test-nodes.vty
@@ -13,7 +13,6 @@ T3386 = 8 s Wait for MODIFY PDP CTX ACK timer (s) (default: 8 s)
T3395 = 8 s Wait for DEACT PDP CTX ACK timer (s) (default: 8 s)
T3397 = 8 s Wait for DEACT AA PDP CTX ACK timer (s) (default: 8 s)
X1001 = 5 s RANAP Release timeout. Wait for RANAP Release Complete.On expiry release Iu connection (s) (default: 5 s)
-X3314 = 44 s Iu User inactivity timer. On expiry release Iu connection (s) (default: 44 s)
OsmoSGSN# configure terminal
OsmoSGSN(config)# list
...
@@ -36,7 +35,10 @@ OsmoSGSN(config-sgsn)# list
imsi-acl (add|del) IMSI
auth-policy (accept-all|closed|acl-only|remote)
authentication (optional|required)
- encryption (GEA0|GEA1|GEA2|GEA3|GEA4)
+ encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>]
+ encryption uea <0-2> [<0-2>] [<0-2>]
+ encryption cipher-plugin-path PATH
+ no encryption cipher-plugin-path PATH
gsup ipa-name NAME
gsup remote-ip A.B.C.D
gsup remote-port <0-65535>
@@ -55,6 +57,7 @@ OsmoSGSN(config-sgsn)# list
ggsn dynamic
grx-dns-add A.B.C.D
timer [TNNNN] [(<0-2147483647>|default)]
+ timer gtp [TNNNN] [(<0-2147483647>|default)]
no compression rfc1144
compression rfc1144 active slots <1-256>
compression rfc1144 passive
@@ -62,3 +65,69 @@ OsmoSGSN(config-sgsn)# list
compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>
compression v42bis passive
...
+
+OsmoSGSN(config-sgsn)# mme test0
+OsmoSGSN(config-sgsn-mme)# gtp remote-ip 1.2.3.4
+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay 907 10 567
+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay 202 12 51
+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay 907 10 567
+OsmoSGSN(config-sgsn-mme)# exit
+OsmoSGSN(config-sgsn)# mme test1
+OsmoSGSN(config-sgsn-mme)# gtp remote-ip 5.6.7.8
+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay default
+OsmoSGSN(config-sgsn-mme)# exit
+OsmoSGSN(config-sgsn)# show running-config
+...
+sgsn
+...
+ mme test0
+ gtp remote-ip 1.2.3.4
+ gtp ran-info-relay 907 10 567
+ gtp ran-info-relay 202 12 51
+ mme test1
+ gtp remote-ip 5.6.7.8
+ gtp ran-info-relay default
+...
+OsmoSGSN(config-sgsn)# mme test0
+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay default
+% Another MME test1 is already set as default route, remove it before setting it here.
+OsmoSGSN(config-sgsn-mme)# exit
+OsmoSGSN(config-sgsn)# mme test1
+OsmoSGSN(config-sgsn-mme)# no gtp ran-info-relay default
+OsmoSGSN(config-sgsn-mme)# exit
+OsmoSGSN(config-sgsn)# mme test0
+OsmoSGSN(config-sgsn-mme)# gtp ran-info-relay default
+OsmoSGSN(config-sgsn-mme)# exit
+OsmoSGSN(config-sgsn)# show running-config
+...
+sgsn
+...
+ mme test0
+ gtp remote-ip 1.2.3.4
+ gtp ran-info-relay default
+ gtp ran-info-relay 907 10 567
+ gtp ran-info-relay 202 12 51
+ mme test1
+ gtp remote-ip 5.6.7.8
+...
+OsmoSGSN(config-sgsn)# no mme test0
+OsmoSGSN(config-sgsn)# show running-config
+...
+sgsn
+...
+ no compression v42bis
+ mme test1
+ gtp remote-ip 5.6.7.8
+...
+OsmoSGSN(config-sgsn)# no mme test1
+OsmoSGSN(config-sgsn)# encryption gea 0 3
+OsmoSGSN(config-sgsn)# encryption uea 1 2
+OsmoSGSN(config-sgsn)# encryption cipher-plugin-path /foo/bar
+OsmoSGSN(config-sgsn)# show running-config
+...
+sgsn
+...
+ encryption gea 0 3
+ encryption uea 1 2
+ encryption cipher-plugin-path /foo/bar
+...
diff --git a/tests/sgsn/Makefile.am b/tests/sgsn/Makefile.am
index b72c44634..c6c1f4a68 100644
--- a/tests/sgsn/Makefile.am
+++ b/tests/sgsn/Makefile.am
@@ -7,6 +7,7 @@ AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOCTRL_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOGSUPCLIENT_CFLAGS) \
@@ -21,16 +22,23 @@ AM_CFLAGS += \
$(NULL)
endif
+AM_LDFLAGS = -no-install
+
EXTRA_DIST = \
sgsn_test.ok \
$(NULL)
-noinst_PROGRAMS = \
+check_PROGRAMS = \
sgsn_test \
$(NULL)
+noinst_HEADERS = \
+ gprs_gb_parse.h \
+ $(NULL)
+
sgsn_test_SOURCES = \
sgsn_test.c \
+ gprs_gb_parse.c \
$(NULL)
sgsn_test_LDFLAGS = \
@@ -39,17 +47,26 @@ sgsn_test_LDFLAGS = \
-Wl,--wrap=gprs_subscr_request_update_location \
-Wl,--wrap=gprs_subscr_request_auth_info \
-Wl,--wrap=osmo_gsup_client_send \
+ $(AM_LDFLAGS) \
$(NULL)
sgsn_test_LDADD = \
+ $(top_builddir)/src/sgsn/apn.o \
+ $(top_builddir)/src/sgsn/gprs_bssgp.o \
$(top_builddir)/src/sgsn/gprs_llc.o \
- $(top_builddir)/src/sgsn/gprs_gb.o \
+ $(top_builddir)/src/sgsn/gprs_ns.o \
$(top_builddir)/src/sgsn/gprs_sndcp.o \
$(top_builddir)/src/sgsn/gprs_gmm_attach.o \
$(top_builddir)/src/sgsn/gprs_gmm.o \
$(top_builddir)/src/sgsn/gprs_gmm_fsm.o \
$(top_builddir)/src/sgsn/gprs_mm_state_gb_fsm.o \
- $(top_builddir)/src/sgsn/gprs_sgsn.o \
+ $(top_builddir)/src/sgsn/gtp_ggsn.o \
+ $(top_builddir)/src/sgsn/gtp_mme.o \
+ $(top_builddir)/src/sgsn/mmctx.o \
+ $(top_builddir)/src/sgsn/pdpctx.o \
+ $(top_builddir)/src/sgsn/sgsn.o \
+ $(top_builddir)/src/sgsn/sgsn_cdr.o \
+ $(top_builddir)/src/sgsn/sgsn_ctrl.o \
$(top_builddir)/src/sgsn/sgsn_vty.o \
$(top_builddir)/src/sgsn/sgsn_libgtp.o \
$(top_builddir)/src/sgsn/sgsn_auth.o \
@@ -62,13 +79,14 @@ sgsn_test_LDADD = \
$(top_builddir)/src/sgsn/gprs_sndcp_pcomp.o \
$(top_builddir)/src/sgsn/v42bis.o \
$(top_builddir)/src/sgsn/gprs_sndcp_dcomp.o \
+ $(top_builddir)/src/sgsn/sgsn_rim.o \
$(top_builddir)/src/gprs/gprs_utils.o \
$(top_builddir)/src/gprs/gprs_llc_parse.o \
- $(top_builddir)/src/gprs/gprs_gb_parse.o \
$(top_builddir)/src/gprs/crc24.o \
$(top_builddir)/src/gprs/sgsn_ares.o \
$(LIBOSMOABIS_LIBS) \
$(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOCTRL_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOGB_LIBS) \
$(LIBOSMOGSUPCLIENT_LIBS) \
diff --git a/src/gprs/gprs_gb_parse.c b/tests/sgsn/gprs_gb_parse.c
index e6a82acb2..670839f73 100644
--- a/src/gprs/gprs_gb_parse.c
+++ b/tests/sgsn/gprs_gb_parse.c
@@ -18,10 +18,12 @@
*
*/
+#include <arpa/inet.h>
+
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
-#include <osmocom/sgsn/gprs_gb_parse.h>
+#include "gprs_gb_parse.h"
#include <osmocom/sgsn/gprs_utils.h>
diff --git a/include/osmocom/sgsn/gprs_gb_parse.h b/tests/sgsn/gprs_gb_parse.h
index 58de17f81..58de17f81 100644
--- a/include/osmocom/sgsn/gprs_gb_parse.h
+++ b/tests/sgsn/gprs_gb_parse.h
diff --git a/tests/sgsn/sgsn_test.c b/tests/sgsn/sgsn_test.c
index 057462062..a149b8e2c 100644
--- a/tests/sgsn/sgsn_test.c
+++ b/tests/sgsn/sgsn_test.c
@@ -19,43 +19,38 @@
*
*/
+#include <osmocom/core/application.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/rate_ctr.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/apn.h>
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/gsup.h>
+#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/vty/vty.h>
+
+#include <osmocom/gsupclient/gsup_client.h>
+
#include <osmocom/sgsn/gprs_llc.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/gprs_subscriber.h>
-#include <osmocom/gsm/gsup.h>
-#include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/sgsn/gprs_utils.h>
-#include <osmocom/sgsn/gprs_gb_parse.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
-
-#include <osmocom/gprs/gprs_bssgp.h>
-
-#include <osmocom/gsm/gsm_utils.h>
-
-#include <osmocom/core/application.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/rate_ctr.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/vty/vty.h>
+#include <osmocom/sgsn/gtp_ggsn.h>
#include <stdio.h>
+#include "gprs_gb_parse.h"
+
void *tall_sgsn_ctx;
-static struct sgsn_instance sgsn_inst = {
- .config_file = "osmo_sgsn.cfg",
- .cfg = {
- .gtp_statedir = "./",
- .auth_policy = SGSN_AUTH_POLICY_CLOSED,
- },
-};
-struct sgsn_instance *sgsn = &sgsn_inst;
+struct sgsn_instance *sgsn;
unsigned sgsn_tx_counter = 0;
struct msgb *last_msg = NULL;
struct gprs_gb_parse_context last_dl_parse_ctx;
-static void reset_last_msg()
+static void reset_last_msg(void)
{
if (last_msg)
msgb_free(last_msg);
@@ -64,9 +59,10 @@ static void reset_last_msg()
memset(&last_dl_parse_ctx, 0, sizeof(last_dl_parse_ctx));
}
-static void cleanup_test()
+static void cleanup_test(void)
{
reset_last_msg();
+ TALLOC_FREE(sgsn);
}
static uint32_t get_new_ptmsi(const struct gprs_gb_parse_context *parse_ctx)
@@ -281,7 +277,7 @@ static void show_subscrs(FILE *out)
}
}
-static void assert_no_subscrs()
+static void assert_no_subscrs(void)
{
show_subscrs(stdout);
fflush(stdout);
@@ -383,6 +379,7 @@ static void test_auth_triplets(void)
uint32_t local_tlli = 0xffeeddcc;
printf("Testing authentication triplet handling\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* Check for emptiness */
OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL);
@@ -571,6 +568,7 @@ static void test_subscriber_gsup(void)
printf("Testing subscriber GSUP handling\n");
update_subscriber_data_cb = my_dummy_sgsn_update_subscriber_data;
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* Check for emptiness */
OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL);
@@ -747,6 +745,7 @@ static void test_gmm_detach(void)
uint32_t local_tlli;
printf("Testing GMM detach\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* DTAP - Detach Request (MO) */
/* normal detach, power_off = 0 */
@@ -788,6 +787,7 @@ static void test_gmm_detach_power_off(void)
uint32_t local_tlli;
printf("Testing GMM detach (power off)\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* DTAP - Detach Request (MO) */
/* normal detach, power_off = 1 */
@@ -828,6 +828,7 @@ static void test_gmm_detach_no_mmctx(void)
uint32_t local_tlli;
printf("Testing GMM detach (no MMCTX)\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* DTAP - Detach Request (MO) */
/* normal detach, power_off = 0 */
@@ -864,6 +865,7 @@ static void test_gmm_detach_accept_unexpected(void)
uint32_t local_tlli;
printf("Testing GMM detach accept (unexpected)\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* DTAP - Detach Accept (MT) */
/* normal detach */
@@ -900,6 +902,7 @@ static void test_gmm_status_no_mmctx(void)
uint32_t local_tlli;
printf("Testing GMM Status (no MMCTX)\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* DTAP - GMM Status, protocol error */
static const unsigned char gmm_status[] = {
@@ -1194,6 +1197,7 @@ static void test_gmm_reject(void)
};
printf("Testing GMM reject\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* reset the PRNG used by sgsn_alloc_ptmsi */
srand(1);
@@ -1240,6 +1244,9 @@ static void test_gmm_cancel(void)
uint32_t foreign_tlli;
uint32_t local_tlli = 0;
struct gprs_llc_lle *lle;
+
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
+ sgsn->cfg.gea_encryption_mask = 0x1;
const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy;
/* DTAP - Attach Request */
@@ -1270,8 +1277,7 @@ static void test_gmm_cancel(void)
};
printf("Testing cancellation\n");
-
- sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_OPEN;
+ sgsn->cfg.auth_policy = SGSN_AUTH_POLICY_OPEN;
foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN);
@@ -1343,6 +1349,7 @@ static void test_apn_matching(void)
struct apn_ctx *actx, *actxs[9];
printf("Testing APN matching\n");
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
actxs[0] = sgsn_apn_ctx_find_alloc("*.test", "");
actxs[1] = sgsn_apn_ctx_find_alloc("*.def.test", "");
@@ -1432,9 +1439,6 @@ static void test_apn_matching(void)
cleanup_test();
}
-struct sgsn_subscriber_pdp_data* sgsn_subscriber_pdp_data_alloc(
- struct sgsn_subscriber_data *sdata);
-
static void test_ggsn_selection(void)
{
struct apn_ctx *actxs[4];
@@ -1453,6 +1457,7 @@ static void test_ggsn_selection(void)
printf("Testing GGSN selection\n");
osmo_gsup_client_send_cb = my_gsup_client_send_dummy;
+ sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
/* Check for emptiness */
OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL);
@@ -1471,9 +1476,9 @@ static void test_ggsn_selection(void)
/* TODO: Add PDP info entries to s1 */
- ggcs[0] = sgsn_ggsn_ctx_find_alloc(0);
- ggcs[1] = sgsn_ggsn_ctx_find_alloc(1);
- ggcs[2] = sgsn_ggsn_ctx_find_alloc(2);
+ ggcs[0] = sgsn_ggsn_ctx_find_alloc(sgsn, 0);
+ ggcs[1] = sgsn_ggsn_ctx_find_alloc(sgsn, 1);
+ ggcs[2] = sgsn_ggsn_ctx_find_alloc(sgsn, 2);
actxs[0] = sgsn_apn_ctx_find_alloc("test.apn", "123456");
actxs[0]->ggsn = ggcs[0];
@@ -1484,13 +1489,14 @@ static void test_ggsn_selection(void)
pdp_data = sgsn_subscriber_pdp_data_alloc(s1->sgsn_data);
pdp_data->context_id = 1;
- pdp_data->pdp_type = 0x0121;
+ pdp_data->pdp_type_org = PDP_TYPE_ORG_IETF;
+ pdp_data->pdp_type_nr = PDP_TYPE_N_IETF_IPv4;
osmo_strlcpy(pdp_data->apn_str, "*", sizeof(pdp_data->apn_str));
/* Resolve GGSNs */
tp.lv[GSM48_IE_GSM_APN].len =
- gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Test.Apn");
+ osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Test.Apn");
ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str);
OSMO_ASSERT(ggc != NULL);
@@ -1498,7 +1504,7 @@ static void test_ggsn_selection(void)
OSMO_ASSERT(strcmp(apn_str, "Test.Apn") == 0);
tp.lv[GSM48_IE_GSM_APN].len =
- gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Other.Apn");
+ osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Other.Apn");
ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str);
OSMO_ASSERT(ggc != NULL);
@@ -1524,7 +1530,7 @@ static void test_ggsn_selection(void)
tp.lv[GSM48_IE_GSM_APN].val = apn_enc;
tp.lv[GSM48_IE_GSM_APN].len =
- gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Foo.Bar");
+ osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Foo.Bar");
ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str);
OSMO_ASSERT(ggc == NULL);
@@ -1541,7 +1547,7 @@ static void test_ggsn_selection(void)
osmo_strlcpy(pdp_data->apn_str, "Test.Apn", sizeof(pdp_data->apn_str));
tp.lv[GSM48_IE_GSM_APN].len =
- gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Test.Apn");
+ osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Test.Apn");
ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str);
OSMO_ASSERT(ggc != NULL);
@@ -1549,7 +1555,7 @@ static void test_ggsn_selection(void)
OSMO_ASSERT(strcmp(apn_str, "Test.Apn") == 0);
tp.lv[GSM48_IE_GSM_APN].len =
- gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Other.Apn");
+ osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Other.Apn");
ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str);
OSMO_ASSERT(ggc == NULL);
@@ -1620,11 +1626,6 @@ static struct log_info_cat gprs_categories[] = {
.description = "GPRS Packet Service",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
- [DNS] = {
- .name = "DNS",
- .description = "GPRS Network Service (NS)",
- .enabled = 1, .loglevel = LOGL_INFO,
- },
[DLLC] = {
.name = "DLLC",
.description = "GPRS Logical Link Control Protocol (LLC)",
@@ -1656,11 +1657,7 @@ int main(int argc, char **argv)
tall_sgsn_ctx = talloc_named_const(osmo_sgsn_ctx, 0, "sgsn");
msgb_ctx = msgb_talloc_ctx_init(osmo_sgsn_ctx, 0);
- sgsn_rate_ctr_init();
- sgsn_auth_init(sgsn);
- gprs_subscr_init(sgsn);
vty_init(&vty_info);
- sgsn_vty_init(&sgsn->cfg);
test_llme();
test_subscriber();
@@ -1680,7 +1677,7 @@ int main(int argc, char **argv)
talloc_report_full(osmo_sgsn_ctx, stderr);
OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
- OSMO_ASSERT(talloc_total_blocks(tall_sgsn_ctx) == 2);
+ OSMO_ASSERT(talloc_total_blocks(tall_sgsn_ctx) == 1);
return 0;
}
diff --git a/tests/slhc/Makefile.am b/tests/slhc/Makefile.am
index b6738c25d..33cb7faac 100644
--- a/tests/slhc/Makefile.am
+++ b/tests/slhc/Makefile.am
@@ -1,9 +1,10 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS)
+AM_LDFLAGS = -no-install
EXTRA_DIST = slhc_test.ok
-noinst_PROGRAMS = slhc_test
+check_PROGRAMS = slhc_test
slhc_test_SOURCES = slhc_test.c
diff --git a/tests/sndcp_xid/Makefile.am b/tests/sndcp_xid/Makefile.am
index 24626b32e..c4702b893 100644
--- a/tests/sndcp_xid/Makefile.am
+++ b/tests/sndcp_xid/Makefile.am
@@ -1,9 +1,10 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS)
+AM_LDFLAGS = -no-install
EXTRA_DIST = sndcp_xid_test.ok
-noinst_PROGRAMS = sndcp_xid_test
+check_PROGRAMS = sndcp_xid_test
sndcp_xid_test_SOURCES = sndcp_xid_test.c
diff --git a/tests/v42bis/Makefile.am b/tests/v42bis/Makefile.am
index 744239279..0e544a684 100644
--- a/tests/v42bis/Makefile.am
+++ b/tests/v42bis/Makefile.am
@@ -1,9 +1,10 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS)
+AM_LDFLAGS = -no-install
EXTRA_DIST = v42bis_test.ok
-noinst_PROGRAMS = v42bis_test
+check_PROGRAMS = v42bis_test
v42bis_test_SOURCES = v42bis_test.c
diff --git a/tests/xid/Makefile.am b/tests/xid/Makefile.am
index 6f058f5a6..d3a260bca 100644
--- a/tests/xid/Makefile.am
+++ b/tests/xid/Makefile.am
@@ -11,11 +11,13 @@ AM_CFLAGS = \
$(LIBCARES_CFLAGS) \
$(NULL)
+AM_LDFLAGS = -no-install
+
EXTRA_DIST = \
xid_test.ok \
$(NULL)
-noinst_PROGRAMS = \
+check_PROGRAMS = \
xid_test \
$(NULL)