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-RELEASE3
-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/changelog180
-rw-r--r--debian/compat2
-rw-r--r--debian/control24
-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.adoc1
-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.am12
-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/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_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/mmctx.h (renamed from include/osmocom/sgsn/gprs_sgsn.h)254
-rw-r--r--include/osmocom/sgsn/pdpctx.h94
-rw-r--r--include/osmocom/sgsn/sgsn.h56
-rw-r--r--include/osmocom/sgsn/sgsn_rim.h2
-rw-r--r--include/osmocom/sgsn/v42bis.h4
-rw-r--r--include/osmocom/sgsn/v42bis_private.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.c14
-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.am9
-rw-r--r--src/sgsn/apn.c123
-rw-r--r--src/sgsn/gprs_bssgp.c95
-rw-r--r--src/sgsn/gprs_gmm.c80
-rw-r--r--src/sgsn/gprs_gmm_attach.c12
-rw-r--r--src/sgsn/gprs_gmm_fsm.c8
-rw-r--r--src/sgsn/gprs_llc.c38
-rw-r--r--src/sgsn/gprs_llc_vty.c17
-rw-r--r--src/sgsn/gprs_mm_state_gb_fsm.c3
-rw-r--r--src/sgsn/gprs_mm_state_iu_fsm.c5
-rw-r--r--src/sgsn/gprs_ns.c (renamed from src/sgsn/gprs_gb.c)87
-rw-r--r--src/sgsn/gprs_ranap.c11
-rw-r--r--src/sgsn/gprs_sm.c12
-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.c6
-rw-r--r--src/sgsn/mmctx.c (renamed from src/sgsn/gprs_sgsn.c)507
-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.c105
-rw-r--r--src/sgsn/sgsn_main.c72
-rw-r--r--src/sgsn/sgsn_rim.c60
-rw-r--r--src/sgsn/sgsn_vty.c174
-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.vty15
-rw-r--r--tests/sgsn/Makefile.am24
-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.c89
-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
101 files changed, 2289 insertions, 1558 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 44ee42144..df983c1c4 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -1,3 +1,2 @@
#component what description / commit summary line
-libosmogb > 1.5.1 bssgp_encode_rim_pdu symbol was not exported previously
-libgtp > 1.7.1 use gtp_ran_info_relay_req(), gtp_set_cb_ran_info_relay_ind()
+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 c29bacb50..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.5.0)
-PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
-PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
-PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0)
-PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.5.0)
-PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0)
-PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
-PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.3.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.4.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.7.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.7.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 f661fa0c8..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.7.0
-BuildRequires: pkgconfig(libosmo-gsup-client) >= 1.3.0
-BuildRequires: pkgconfig(libosmo-netif) >= 1.1.0
-BuildRequires: pkgconfig(libosmoabis) >= 1.1.0
-BuildRequires: pkgconfig(libosmocore) >= 1.5.0
-BuildRequires: pkgconfig(libosmoctrl) >= 1.5.0
-BuildRequires: pkgconfig(libosmogb) >= 1.5.0
-BuildRequires: pkgconfig(libosmogsm) >= 1.5.0
-BuildRequires: pkgconfig(libosmovty) >= 1.5.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.7.0
-BuildRequires: pkgconfig(libosmo-sigtran) >= 1.4.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 2edc6e66f..cb629fbdc 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,183 @@
+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 ]
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 bc9c8abc7..aa594553b 100644
--- a/debian/control
+++ b/debian/control
@@ -2,7 +2,7 @@ Source: osmo-sgsn
Section: net
Priority: extra
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
-Build-Depends: debhelper (>=9),
+Build-Depends: debhelper (>= 10),
dh-autoreconf,
autotools-dev,
autoconf,
@@ -11,19 +11,19 @@ Build-Depends: debhelper (>=9),
pkg-config,
libtalloc-dev,
libc-ares-dev,
- libgtp-dev (>= 1.7.0),
- libosmocore-dev (>= 1.5.0),
- libosmo-abis-dev (>= 1.1.0),
- libosmo-netif-dev (>= 1.1.0),
- libosmo-gsup-client-dev (>= 1.3.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.7.0),
- libosmo-sigtran-dev (>= 1.4.0),
- libosmo-sccp-dev (>= 1.4.0),
- osmo-gsm-manuals-dev (>= 1.1.0)
+ 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 d51dd77f7..d6ddcd34a 100644
--- a/doc/manuals/chapters/configuration.adoc
+++ b/doc/manuals/chapters/configuration.adoc
@@ -422,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/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 289f502e8..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,8 +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/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_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/gprs_sgsn.h b/include/osmocom/sgsn/mmctx.h
index c176494b1..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 {
@@ -295,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);
@@ -360,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 5b29873b6..6e93178af 100644
--- a/include/osmocom/sgsn/sgsn.h
+++ b/include/osmocom/sgsn/sgsn.h
@@ -8,13 +8,13 @@
#include <osmocom/gprs/gprs_ns2.h>
#include <osmocom/gprs/gprs_bssgp.h>
-#include <osmocom/sgsn/gprs_sgsn.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>
@@ -25,6 +25,8 @@
struct hostent;
+#define SGSN_ERROR_CAUSE_NONE (-1)
+
enum sgsn_auth_policy {
SGSN_AUTH_POLICY_OPEN,
SGSN_AUTH_POLICY_CLOSED,
@@ -75,8 +77,10 @@ struct sgsn_config {
/* misc */
struct gprs_ns2_inst *nsi;
+ char *crypt_cipher_plugin_path;
enum sgsn_auth_policy auth_policy;
- uint8_t cipher_support_mask;
+ uint8_t gea_encryption_mask;
+ uint8_t uea_encryption_mask;
struct llist_head imsi_acl;
struct sockaddr_in gsup_server_addr;
@@ -92,6 +96,7 @@ struct sgsn_config {
/* Timer defintions */
struct osmo_tdef *T_defs;
+ struct osmo_tdef *T_defs_gtp;
int dynamic_lookup;
@@ -149,10 +154,22 @@ struct sgsn_instance {
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 */
@@ -161,40 +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);
-int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu);
-
-/* 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 aa5a72664..fc87b468e 100644
--- a/include/osmocom/sgsn/sgsn_rim.h
+++ b/include/osmocom/sgsn/sgsn_rim.h
@@ -3,4 +3,4 @@
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 bssgp_ran_information_pdu *pdu, struct sgsn_mme_ctx *mme);
+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/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 09d01fcc2..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>
@@ -475,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)
@@ -971,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);
@@ -995,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];
@@ -1104,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);
@@ -2283,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. */
@@ -2690,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 9e4a34264..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,12 +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 1f68558ef..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 },
@@ -916,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;
}
@@ -1319,11 +1327,11 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
ctx->ue_cipher_mask = gprs_ms_net_cap_gea_mask(ctx->ms_network_capa.buf, msnc_len);
- if (!(ctx->ue_cipher_mask & sgsn->cfg.cipher_support_mask)) {
+ 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 encryption, mask UE:0x%02x NW:0x%02x \n",
- mi_log_string, ctx->ue_cipher_mask, sgsn->cfg.cipher_support_mask);
+ mi_log_string, ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask);
goto rejected;
}
@@ -1335,7 +1343,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
* 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.cipher_support_mask);
+ 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 */
@@ -1759,6 +1767,10 @@ 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 */
@@ -2306,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 629cc53fe..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
}
diff --git a/src/sgsn/gprs_gmm_fsm.c b/src/sgsn/gprs_gmm_fsm.c
index 78946b5b1..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+
@@ -80,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; */
@@ -141,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),
diff --git a/src/sgsn/gprs_llc.c b/src/sgsn/gprs_llc.c
index eea1cecfa..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>
@@ -50,10 +50,21 @@ const struct value_string gprs_llc_llme_state_names[] = {
{ 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);
@@ -212,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
@@ -288,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;
@@ -590,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);
@@ -680,7 +692,7 @@ int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command,
}
/* 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 */
@@ -691,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");
@@ -704,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];
@@ -964,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");
@@ -1018,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 */
@@ -1036,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;
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 6e812d31d..dde7b770a 100644
--- a/src/sgsn/gprs_mm_state_gb_fsm.c
+++ b/src/sgsn/gprs_mm_state_gb_fsm.c
@@ -1,6 +1,6 @@
/* TS 23.060 § 6.1.1 Mobility Management States (A/Gb mode) */
/*
- * (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+
@@ -27,6 +27,7 @@
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
+#include <osmocom/sgsn/mmctx.h>
#define X(s) (1 << (s))
diff --git a/src/sgsn/gprs_mm_state_iu_fsm.c b/src/sgsn/gprs_mm_state_iu_fsm.c
index b1604f83b..c2e9c4498 100644
--- a/src/sgsn/gprs_mm_state_iu_fsm.c
+++ b/src/sgsn/gprs_mm_state_iu_fsm.c
@@ -1,6 +1,6 @@
/* TS 23.060 § 6.1.2 Mobility Management States (Iu mode) */
/*
- * (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+
@@ -29,6 +29,9 @@
#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))
diff --git a/src/sgsn/gprs_gb.c b/src/sgsn/gprs_ns.c
index 96157a01e..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(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;
-}
-
-
-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(rate_ctr_group_get_ctr(mmctx->ctrg, 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 ead20f776..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)
@@ -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);
diff --git a/src/sgsn/gprs_sm.c b/src/sgsn/gprs_sm.c
index 6c09c4f97..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
@@ -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;
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
index 4fe804d94..3d7ec76b6 100644
--- a/src/sgsn/gtp_mme.c
+++ b/src/sgsn/gtp_mme.c
@@ -1,6 +1,6 @@
/* TS 29.060 § 7.5.14 RAN Information Management Messages */
/*
- * (C) 2021 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
+ * (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
@@ -26,8 +26,6 @@
#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/sgsn/sgsn.h>
-extern void *tall_sgsn_ctx;
-
static bool _eutran_tai_equal(const struct osmo_eutran_tai *t1, const struct osmo_eutran_tai *t2)
{
return t1->mcc == t2->mcc &&
@@ -39,7 +37,7 @@ static bool _eutran_tai_equal(const struct osmo_eutran_tai *t1, const struct osm
struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name)
{
struct sgsn_mme_ctx *mme;
- mme = talloc_zero(tall_sgsn_ctx, struct sgsn_mme_ctx);
+ mme = talloc_zero(sgsn, struct sgsn_mme_ctx);
if (!mme)
return NULL;
diff --git a/src/sgsn/gprs_sgsn.c b/src/sgsn/mmctx.c
index 304ecc516..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;
@@ -432,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;
@@ -749,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;
@@ -764,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);
@@ -896,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)
@@ -949,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,
@@ -980,72 +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;
-
- INIT_LLIST_HEAD(&inst->mme_list);
- 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 1ac3b44cd..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,8 +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>
@@ -228,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))
@@ -421,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;
@@ -600,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;
@@ -699,9 +695,46 @@ static int cb_gtp_ran_info_relay_ind(struct sockaddr_in *peer, union gtpie_membe
LOGMME(mme, DGTP, LOGL_INFO, "Rx GTP RAN Information Relay\n");
+ int rc;
unsigned int len = 0;
- struct msgb *msg = msgb_alloc(4096, "gtpcv1_ran_info");
- struct bssgp_ran_information_pdu pdu;
+ 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");
@@ -710,13 +743,8 @@ static int cb_gtp_ran_info_relay_ind(struct sockaddr_in *peer, union gtpie_membe
msgb_put(msg, len);
msgb_bssgph(msg) = msg->data;
msgb_nsei(msg) = 0;
- if (bssgp_parse_rim_pdu(&pdu, msg) < 0) {
- LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: Failed parsing Transparent Container IE!\n");
- goto ret_error;
- }
- msgb_free(msg);
- return sgsn_rim_rx_from_gtp(&pdu, mme);
+ return sgsn_rim_rx_from_gtp(msg, &rim_ra);
ret_error:
msgb_free(msg);
@@ -775,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 "
@@ -800,12 +837,12 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int 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;
@@ -908,7 +945,7 @@ 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);
diff --git a/src/sgsn/sgsn_main.c b/src/sgsn/sgsn_main.c
index af9757a89..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_from_gb(bp, oph->msg);
- }
- return 0;
+ return sgsn_bssgp_rx_prim(oph);
}
static void signal_handler(int signum)
@@ -434,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);
@@ -472,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) {
@@ -499,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 f28ba60bf..40e1f9033 100644
--- a/src/sgsn/sgsn_rim.c
+++ b/src/sgsn/sgsn_rim.c
@@ -12,6 +12,7 @@
#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>
@@ -20,6 +21,7 @@ static int sgsn_bssgp_fwd_rim_to_geran(const struct bssgp_ran_information_pdu *p
struct bssgp_bvc_ctx *bvc_ctx;
OSMO_ASSERT(pdu->routing_info_dest.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",
@@ -27,10 +29,27 @@ static int sgsn_bssgp_fwd_rim_to_geran(const struct bssgp_ran_information_pdu *p
return -EINVAL;
}
- /* Forward PDU as it is to the correct interface */
+ /* 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, "Unable to find NSEI for destination cell %s\n",
+ bssgp_rim_ri_name(rim_routing_address));
+ return -EINVAL;
+ }
+
+ /* Forward PDU to the NSEI of the resolved BVC context */
+ return bssgp_tx_rim_encoded(msg, bvc_ctx->nsei);
+}
+
static int sgsn_bssgp_fwd_rim_to_eutran(const struct bssgp_ran_information_pdu *pdu)
{
struct sgsn_mme_ctx *mme;
@@ -88,36 +107,21 @@ err:
return -1;
}
-/* Receive a RIM PDU from GTPvC1 (EUTRAN) */
-int sgsn_rim_rx_from_gtp(struct bssgp_ran_information_pdu *pdu, struct sgsn_mme_ctx *mme)
+/* Receive a RIM PDU from GTPv1C (EUTRAN) */
+int sgsn_rim_rx_from_gtp(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address)
{
- struct sgsn_mme_ctx *mme_tmp;
- if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_EUTRAN) {
- LOGMME(mme, DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected src %s, got %s\n",
- bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_EUTRAN),
- bssgp_rim_routing_info_discr_str(pdu->routing_info_src.discr));
- return -EINVAL;
- }
-
- if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
- LOGMME(mme, 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(pdu->routing_info_dest.discr));
- return -EINVAL;
- }
-
- mme_tmp = sgsn_mme_ctx_by_route(sgsn, &pdu->routing_info_src.eutran.tai);
- if (!mme_tmp)/* See if we have a default route configured */
- mme_tmp = sgsn_mme_ctx_by_default_route(sgsn);
- if (mme != mme_tmp) {
- LOGP(DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: "
- "Source MME doesn't have RIM routing configured for TAI: %s\n",
- bssgp_rim_ri_name(&pdu->routing_info_src));
+ /* 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;
}
- LOGMME(mme, DRIM, LOGL_INFO, "Rx GTP RAN Information Relay for dest cell %s\n",
- bssgp_rim_ri_name(&pdu->routing_info_dest));
+ 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(pdu);
+ 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 e0e26775e..29f9cd604 100644
--- a/src/sgsn/sgsn_vty.c
+++ b/src/sgsn/sgsn_vty.c
@@ -35,11 +35,14 @@
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/gprs/gprs_ns2.h>
-#include <osmocom/sgsn/gprs_gb.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>
@@ -47,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>
@@ -54,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[] = {
@@ -96,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)" },
@@ -135,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];
@@ -148,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;
}
@@ -216,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;
@@ -238,15 +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_support_mask != 0) {
+ if (g_cfg->gea_encryption_mask != 0) {
vty_out(vty, " encryption gea");
for (i = 0; i < _GPRS_ALGO_NUM; i++)
- if (g_cfg->cipher_support_mask >> i & 1)
+ 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)
@@ -275,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,
@@ -298,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",
@@ -385,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);
@@ -410,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;
@@ -428,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]);
@@ -447,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);
@@ -488,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);
@@ -552,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",
@@ -670,7 +722,7 @@ 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)
+ llist_for_each_entry(mm, &sgsn->mm_list, list)
vty_dump_mmctx(vty, "", mm, (argc > 0) ? 1 : 0);
return CMD_SUCCESS;
@@ -682,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;
@@ -752,14 +804,16 @@ DEFUN_DEPRECATED(cfg_encrypt, cfg_encrypt_cmd,
}
}
- g_cfg->cipher_support_mask |= (1 << 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>]",
- "Set encryption algorithms for SGSN\n"
+ ENCRYPTION_STR
"GPRS Encryption Algorithm\n"
"GEAn Algorithm Number\n"
"GEAn Algorithm Number\n"
@@ -769,12 +823,12 @@ DEFUN(cfg_encrypt2, cfg_encrypt2_cmd,
{
int i = 0;
- g_cfg->cipher_support_mask = 0;
+ g_cfg->gea_encryption_mask = 0;
for (i = 0; i < argc; i++)
- g_cfg->cipher_support_mask |= (1 << atoi(argv[i]));
+ g_cfg->gea_encryption_mask |= (1 << atoi(argv[i]));
for (i = 0; i < _GPRS_ALGO_NUM; i++) {
- if (g_cfg->cipher_support_mask >> i & 1) {
+ if (g_cfg->gea_encryption_mask >> i & 1) {
if (i == GPRS_ALGO_GEA0)
continue;
@@ -796,6 +850,27 @@ DEFUN(cfg_encrypt2, cfg_encrypt2_cmd,
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"
@@ -817,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"
@@ -898,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));
@@ -946,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);
}
@@ -1225,7 +1326,7 @@ DEFUN(page_subscr, page_subscr_info_cmd,
return CMD_WARNING;
}
- gprs_gb_page_ps_ra(mm);
+ sgsn_bssgp_page_ps_ra(mm);
return CMD_SUCCESS;
}
@@ -1678,9 +1779,6 @@ 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);
@@ -1688,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);
@@ -1714,6 +1813,9 @@ int sgsn_vty_init(struct sgsn_config *cfg)
/* 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);
@@ -1734,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);
@@ -1765,7 +1868,8 @@ int sgsn_parse_config(const char *config_file)
/* make sure sgsn_vty_init() was called before this */
OSMO_ASSERT(g_cfg);
- g_cfg->cipher_support_mask = 0x1; /* support GEA0 by default unless specific encryption config exists */
+ 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) {
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 f2ed2dce7..32ff8e71d 100644
--- a/tests/osmo-sgsn_test-nodes.vty
+++ b/tests/osmo-sgsn_test-nodes.vty
@@ -36,6 +36,9 @@ OsmoSGSN(config-sgsn)# list
auth-policy (accept-all|closed|acl-only|remote)
authentication (optional|required)
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>
@@ -54,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
@@ -116,3 +120,14 @@ sgsn
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 bdf941dad..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,18 +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 \
@@ -66,11 +82,11 @@ sgsn_test_LDADD = \
$(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 562ae845d..a149b8e2c 100644
--- a/tests/sgsn/sgsn_test.c
+++ b/tests/sgsn/sgsn_test.c
@@ -19,44 +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,
- .cipher_support_mask = 0x1,
- },
-};
-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);
@@ -65,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)
@@ -282,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);
@@ -384,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);
@@ -572,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);
@@ -748,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 */
@@ -789,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 */
@@ -829,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 */
@@ -865,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 */
@@ -901,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[] = {
@@ -1195,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);
@@ -1241,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 */
@@ -1271,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);
@@ -1344,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", "");
@@ -1433,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];
@@ -1454,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);
@@ -1472,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];
@@ -1485,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);
@@ -1499,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);
@@ -1525,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);
@@ -1542,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);
@@ -1550,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);
@@ -1652,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();
@@ -1676,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)