Compare commits
138 Commits
Author | SHA1 | Date |
---|---|---|
Oliver Smith | b3ce06058c | |
Oliver Smith | 0a6fe9727f | |
Oliver Smith | 7ba62d3061 | |
Vadim Yanitskiy | 62b28ffe1b | |
Vadim Yanitskiy | cdf716cf9a | |
Oliver Smith | a9c39c04de | |
Vadim Yanitskiy | 282de031f1 | |
Vadim Yanitskiy | c3156193da | |
Alexander Couzens | cd3a8cfad6 | |
Alexander Couzens | e51b3be379 | |
Alexander Couzens | b34e0a5720 | |
Oliver Smith | 05363e0a32 | |
Max | a07e6d9c58 | |
Harald Welte | 1ede89a35a | |
Harald Welte | 647304fbe5 | |
Harald Welte | 370d6e8b59 | |
Pau Espin | dc4c294f94 | |
Vadim Yanitskiy | f2545b1b8f | |
Andreas Eversberg | 1f1d90f175 | |
Oliver Smith | 2a89bbf66f | |
Daniel Willmann | 676777c5f9 | |
Daniel Willmann | ff9c46cc61 | |
Daniel Willmann | 75a0aa78a3 | |
Daniel Willmann | 20aef4de28 | |
Philipp Maier | e746b0bef6 | |
Pau Espin | 57567968ea | |
Philipp Maier | 7e4dbb4b34 | |
Philipp Maier | 7840375d51 | |
Philipp Maier | 429d332ece | |
Philipp Maier | f24970a7ca | |
Pau Espin | 2365fec0fb | |
Pau Espin | 5df65b6c30 | |
Pau Espin | 5f1020b963 | |
Oliver Smith | eda1b83f75 | |
Vadim Yanitskiy | b83aabaa95 | |
Pau Espin | 1bebd08a4b | |
Oliver Smith | a86056fdf3 | |
Vadim Yanitskiy | 99ec755643 | |
Pau Espin | d5dca3a67f | |
Vadim Yanitskiy | 3c26a1dc3c | |
arehbein | 642019f288 | |
Oliver Smith | f8a5066ad0 | |
Pau Espin | 8c42673eba | |
Pau Espin | 07feb06d54 | |
Pau Espin | 86b630cfe1 | |
Pau Espin | 93bc518b53 | |
Pau Espin | 58101ea587 | |
Pau Espin | 6aad14c3fa | |
Pau Espin | f44dfa8a0e | |
Pau Espin | e931b39b3c | |
Pau Espin | fd9e82da31 | |
Pau Espin | f2307c483f | |
Pau Espin | 15a52d92c4 | |
Pau Espin | 05190c36bb | |
Pau Espin | 3d3c8c55f0 | |
Pau Espin | 164a1eeb8a | |
Pau Espin | 69569879ae | |
Pau Espin | fd4d435442 | |
Pau Espin | 8ec269a0e0 | |
Pau Espin | 4bd6f663a7 | |
Pau Espin | 52c9b8e593 | |
Pau Espin | 51028e2c16 | |
Pau Espin | e69f460ae7 | |
Pau Espin | 0e707fc83a | |
Pau Espin | ffd6e37eb5 | |
Pau Espin | 44bde6b85a | |
Pau Espin | e659f75cf1 | |
Pau Espin | 67e71eac1c | |
Pau Espin | c1cf4af11b | |
Pau Espin | f37aedbf76 | |
Pau Espin | 920c6c8c81 | |
Pau Espin | df203361e8 | |
Pau Espin | b61ab9b9ac | |
Pau Espin | 5f4736aa85 | |
Pau Espin | fc1a5538d0 | |
Pau Espin | eb967fccb2 | |
Pau Espin | 13c00008b4 | |
Pau Espin | e5614e434f | |
Pau Espin | b0b582bff8 | |
Pau Espin | bc46812bd7 | |
Pau Espin | 4398ac073b | |
Pau Espin | 05d5f28e93 | |
Pau Espin | 7a74ae492e | |
Pau Espin | 749ca7c850 | |
Max | e7ccfdb4aa | |
Oliver Smith | e39ff86dd9 | |
Pau Espin | 57b63875c7 | |
Oliver Smith | 55e3dc8ec8 | |
Oliver Smith | acd967a177 | |
Pau Espin | 8501126031 | |
Max | b43496a60d | |
Max | caff83e702 | |
Max | 61f2186592 | |
Max | 559636a4a2 | |
Vadim Yanitskiy | 13ccbc1e61 | |
Vadim Yanitskiy | d32852664d | |
Max | 77cdc424cb | |
Vadim Yanitskiy | fb6cf3221e | |
Vadim Yanitskiy | c63a8381e5 | |
Pau Espin | 328ed94040 | |
Harald Welte | c230f0c283 | |
Harald Welte | e2b9b7ee57 | |
Vadim Yanitskiy | 199f295d36 | |
Neels Hofmeyr | 3c7656a481 | |
Neels Hofmeyr | 340a7e9339 | |
Pau Espin | 938ebfb129 | |
Pau Espin | d06c717e30 | |
Oliver Smith | 57425a3805 | |
Oliver Smith | f76428500a | |
Pau Espin | 0f9966e307 | |
Vadim Yanitskiy | 245ac9501b | |
Oliver Smith | 2d0e22960c | |
Keith Whyte | 6cee1a1ded | |
Oliver Smith | c0e146467a | |
Oliver Smith | ab39b622cc | |
Oliver Smith | 3aba7ad2ae | |
Vadim Yanitskiy | e9336a72a0 | |
Eric Wild | 2f898265d0 | |
Pau Espin | a33f00637e | |
Keith Whyte | c12c1a6b0c | |
Pau Espin | e5c8998f9c | |
Pau Espin | 8969db7a49 | |
Pau Espin | 0b0b59a8ff | |
Pau Espin | 888052e71c | |
Pau Espin | 913dbcd552 | |
Pau Espin | 922684f318 | |
Pau Espin | 3caa7f6d97 | |
Pau Espin | 223754fde5 | |
Pau Espin | f025e582bb | |
Pau Espin | e8cd6856a5 | |
Pau Espin | c67c90b47e | |
Pau Espin | c26072a77f | |
Pau Espin | ce0a0e9beb | |
Pau Espin | c8ace5a03c | |
Pau Espin | 183e6c3367 | |
Vadim Yanitskiy | 8de4be261d | |
Daniel Willmann | 6fd19da165 | |
Harald Welte | adcf97d095 |
|
@ -0,0 +1 @@
|
|||
open_collective: osmocom
|
|
@ -6,8 +6,8 @@ debian/*.log
|
|||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
bscconfig.h
|
||||
bscconfig.h.in
|
||||
config.h
|
||||
config.h.in
|
||||
*.*~
|
||||
*.sw?
|
||||
.libs
|
||||
|
|
|
@ -19,7 +19,7 @@ SUBDIRS = \
|
|||
BUILT_SOURCES = $(top_srcdir)/.version
|
||||
EXTRA_DIST = \
|
||||
.version \
|
||||
contrib/osmo-sgsn.spec.in \
|
||||
README.md \
|
||||
debian \
|
||||
git-version-gen \
|
||||
osmoappdesc.py \
|
||||
|
|
17
README
17
README
|
@ -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
|
|
@ -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.
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
#component what description / commit summary line
|
||||
libosmocore > 1.9.0 gsup.h: Using new fields in struct osmo_gsup_pdp_info (ABI break)
|
48
configure.ac
48
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
|
||||
|
@ -274,5 +255,4 @@ AC_OUTPUT(
|
|||
doc/manuals/Makefile
|
||||
contrib/Makefile
|
||||
contrib/systemd/Makefile
|
||||
contrib/osmo-sgsn.spec
|
||||
Makefile)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,118 +0,0 @@
|
|||
#
|
||||
# spec file for package osmo-sgsn
|
||||
#
|
||||
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
|
||||
#
|
||||
# All modifications and additions to the file contributed by third parties
|
||||
# remain the property of their copyright owners, unless otherwise agreed
|
||||
# upon. The license for this file, and modifications and additions to the
|
||||
# file, is the same license as for the pristine package itself (unless the
|
||||
# license for the pristine package is not an Open Source License, in which
|
||||
# case the license is the MIT License). An "Open Source License" is a
|
||||
# license that conforms to the Open Source Definition (Version 1.9)
|
||||
# published by the Open Source Initiative.
|
||||
|
||||
## Disable LTO for now since it breaks compilation of the tests
|
||||
## https://osmocom.org/issues/4116
|
||||
%define _lto_cflags %{nil}
|
||||
|
||||
%define with_iu 1
|
||||
Name: osmo-sgsn
|
||||
Version: @VERSION@
|
||||
Release: 0
|
||||
Summary: Osmocom's SGSN for 2G and 3G packet-switched mobile networks
|
||||
License: AGPL-3.0-or-later AND GPL-2.0-or-later
|
||||
Group: Productivity/Telephony/Servers
|
||||
URL: https://osmocom.org/projects/osmosgsn
|
||||
Source: %{name}-%{version}.tar.xz
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: automake
|
||||
BuildRequires: libtool
|
||||
BuildRequires: pkgconfig
|
||||
%if 0%{?suse_version}
|
||||
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
|
||||
%{?systemd_requires}
|
||||
%if %{with_iu}
|
||||
BuildRequires: pkgconfig(libasn1c)
|
||||
BuildRequires: pkgconfig(libosmo-ranap) >= 0.7.0
|
||||
BuildRequires: pkgconfig(libosmo-sigtran) >= 1.4.0
|
||||
%endif
|
||||
|
||||
%description
|
||||
OsmoSGSN is Osmocom's Serving GPRS Support Node for 2G and 3G
|
||||
packet-switched mobile networks.
|
||||
|
||||
%package -n osmo-gtphub
|
||||
Summary: Osmocom GTP Hub: Proxy for GTP traffic between multiple SGSNs and GGSNs
|
||||
Group: Productivity/Telephony/Servers
|
||||
|
||||
%description -n osmo-gtphub
|
||||
Osmocom GTP Hub: Proxy for GTP traffic between multiple SGSNs and GGSNs.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
echo "%{version}" >.tarball-version
|
||||
autoreconf -fi
|
||||
%configure \
|
||||
%if %{with_iu}
|
||||
--enable-iu \
|
||||
%endif
|
||||
--docdir=%{_docdir}/%{name} \
|
||||
--with-systemdsystemunitdir=%{_unitdir}
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
%make_install
|
||||
|
||||
%if 0%{?suse_version}
|
||||
%preun %service_del_preun %{name}.service
|
||||
%postun %service_del_postun %{name}.service
|
||||
%pre %service_add_pre %{name}.service
|
||||
%post %service_add_post %{name}.service
|
||||
%preun -n osmo-gtphub %service_del_preun osmo-gtphub.service
|
||||
%postun -n osmo-gtphub %service_del_postun osmo-gtphub.service
|
||||
%pre -n osmo-gtphub %service_add_pre osmo-gtphub.service
|
||||
%post -n osmo-gtphub %service_add_post osmo-gtphub.service
|
||||
%endif
|
||||
|
||||
%check
|
||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
|
||||
|
||||
%files
|
||||
%doc AUTHORS README
|
||||
%dir %{_docdir}/%{name}/examples
|
||||
%dir %{_docdir}/%{name}/examples/osmo-sgsn
|
||||
%exclude %{_docdir}/%{name}/examples/osmo-gtphub
|
||||
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg
|
||||
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn.cfg
|
||||
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg
|
||||
%{_bindir}/osmo-sgsn
|
||||
%dir %{_sysconfdir}/osmocom
|
||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-sgsn.cfg
|
||||
%{_unitdir}/%{name}.service
|
||||
|
||||
%files -n osmo-gtphub
|
||||
%dir %{_docdir}/%{name}/examples
|
||||
%dir %{_docdir}/%{name}/examples/osmo-gtphub
|
||||
%{_docdir}/%{name}/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
|
||||
%{_docdir}/%{name}/examples/osmo-gtphub/osmo-gtphub.cfg
|
||||
%{_bindir}/osmo-gtphub
|
||||
%dir %{_sysconfdir}/osmocom
|
||||
%config(noreplace) %{_sysconfdir}/osmocom/osmo-gtphub.cfg
|
||||
%{_unitdir}/osmo-gtphub.service
|
||||
|
||||
%changelog
|
|
@ -1,9 +1,15 @@
|
|||
[Unit]
|
||||
Description=Osmocom GTP Hub
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=osmocom
|
||||
Group=osmocom
|
||||
ExecStart=/usr/bin/osmo-gtphub -c /etc/osmocom/osmo-gtphub.cfg
|
||||
StateDirectory=osmocom
|
||||
WorkingDirectory=%S/osmocom
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
RestartPreventExitStatus=1
|
||||
|
|
|
@ -3,10 +3,16 @@ 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
|
||||
User=osmocom
|
||||
Group=osmocom
|
||||
ExecStart=/usr/bin/osmo-sgsn -c /etc/osmocom/osmo-sgsn.cfg
|
||||
RestartSec=2
|
||||
|
||||
|
|
|
@ -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 ]
|
||||
|
|
|
@ -1 +1 @@
|
|||
9
|
||||
10
|
||||
|
|
|
@ -2,9 +2,8 @@ Source: osmo-sgsn
|
|||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||
Build-Depends: debhelper (>=9),
|
||||
Build-Depends: debhelper (>= 10),
|
||||
dh-autoreconf,
|
||||
dh-systemd (>= 1.5),
|
||||
autotools-dev,
|
||||
autoconf,
|
||||
automake,
|
||||
|
@ -12,19 +11,19 @@ Build-Depends: debhelper (>=9),
|
|||
pkg-config,
|
||||
libtalloc-dev,
|
||||
libc-ares-dev,
|
||||
libgtp-dev (>= 1.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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
#!/bin/sh -e
|
||||
case "$1" in
|
||||
configure)
|
||||
# Create the osmocom group and user (if it doesn't exist yet)
|
||||
if ! getent group osmocom >/dev/null; then
|
||||
groupadd --system osmocom
|
||||
fi
|
||||
if ! getent passwd osmocom >/dev/null; then
|
||||
useradd \
|
||||
--system \
|
||||
--gid osmocom \
|
||||
--home-dir /var/lib/osmocom \
|
||||
--shell /sbin/nologin \
|
||||
--comment "Open Source Mobile Communications" \
|
||||
osmocom
|
||||
fi
|
||||
|
||||
# Fix permissions of previous (root-owned) install (OS#4107)
|
||||
if dpkg --compare-versions "$2" le "1.12.0"; then
|
||||
if [ -e /etc/osmocom/osmo-sgsn.cfg ]; then
|
||||
chown -v osmocom:osmocom /etc/osmocom/osmo-sgsn.cfg
|
||||
chmod -v 0660 /etc/osmocom/osmo-sgsn.cfg
|
||||
fi
|
||||
|
||||
if [ -d /etc/osmocom ]; then
|
||||
chown -v root:osmocom /etc/osmocom
|
||||
chmod -v 2775 /etc/osmocom
|
||||
fi
|
||||
|
||||
mkdir -p /var/lib/osmocom
|
||||
chown -R -v osmocom:osmocom /var/lib/osmocom
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb(1) will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
#DEBHELPER#
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
!
|
||||
|
|
|
@ -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
|
||||
!
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -11,7 +11,8 @@ explicit configuration of each PCU connecting to the SGSN. The
|
|||
administrator only has to ensure that the NS and BSSGP layer identities
|
||||
(NSEI, NSVCI, BVCI) are unique for each PCU connecting to the SGSN.
|
||||
|
||||
=== Configuring the Gp interface
|
||||
[[gp-if-ggsn]]
|
||||
=== Configuring the Gp interface (towards GGSN)
|
||||
|
||||
The Gp interface is the GTP-C and GTP-U based interface between the SGSN
|
||||
and the GGSNs. It is implemented via UDP on well-known source and
|
||||
|
@ -67,6 +68,58 @@ OsmoSGSN(config-sgsn)# grx-dns-add 1.2.3.4 <3>
|
|||
<2> Enable the dynamic GGSN resolving mode
|
||||
<3> Specify the IP address of a DNS server for APN resolution
|
||||
|
||||
[[gp-if-mme]]
|
||||
=== Configuring the Gp interface (towards MME)
|
||||
|
||||
The Gp interface also contains the GTP-C v1 based interface between the SGSN
|
||||
and the MMEs. This interface between SGSN and MMEs is used to transfer _RAN
|
||||
Information Relay_ GTP-C messages between them, which are used as containers to
|
||||
allow PCUs under the SGSN and eNodeBs under MMEs to exchange cell information
|
||||
(RIM).
|
||||
|
||||
In the SGSN, this interface re-uses the same socket local configuration as per
|
||||
the GGSN connections (see _gtp local-ip_ VTY command in <<gp-if-ggsn>>).
|
||||
|
||||
Similarly as with GGSNs, (again see <<gp-if-ggsn>>), selection of destination
|
||||
peers for the _RAN Information Relay_ message can be configured statically or
|
||||
dynamically over GRX.
|
||||
|
||||
|
||||
==== Static MME/TAI configuration
|
||||
|
||||
In this mode, there is a static list of MMEs and TAIs configured in
|
||||
OsmoSGSN via the VTY / config file. One MME in the list can be configured as the
|
||||
_default route_, where all unspecified TAIs are routed too.
|
||||
|
||||
This is a non-standard method outside of the 3GPP specifications for the
|
||||
SGSN, and is typically only used in private/small GPRS networks without
|
||||
any access to a GRX.
|
||||
|
||||
.Example: Static MME/TAI configuration (single catch-all GGSN)
|
||||
----
|
||||
sgsn
|
||||
...
|
||||
gtp local-ip 192.168.0.10 <1>
|
||||
mme test-mme0 <2>
|
||||
gtp remote-ip 192.168.0.20 <3>
|
||||
gtp ran-info-relay 262 42 3 <4>
|
||||
gtp ran-info-relay 262 42 4
|
||||
mme test-mme1 <5>
|
||||
gtp remote-ip 192.168.0.30
|
||||
gtp ran-info-relay default <6>
|
||||
----
|
||||
<1> Configure the local IP address at the SGSN used for Gp/GTP
|
||||
<2> Configure an MME named "test-mme0"
|
||||
<3> Specify the remote IP address of the MME (for MME "test-mme0")
|
||||
<4> Route specified TAIs towards this MME
|
||||
<5> Configure an MME named "test-mme1"
|
||||
<6> Route all TAIs with an unspecified MME towards MM "test-mme1"
|
||||
|
||||
==== Dynamic MME/TAI configuration
|
||||
|
||||
Dynamic MME/TAI peer look up over GRX is not yet supported by OsmoSGSN.
|
||||
|
||||
|
||||
[[auth-pol]]
|
||||
=== Authorization Policy
|
||||
|
||||
|
@ -345,16 +398,16 @@ Encryption can be enabled if the auth-policy is set to remote and the
|
|||
HLR subscriber entries contain the keys of the SIM card. See
|
||||
<<sgsn-ex-gsup>> on how to connect to an external HLR.
|
||||
|
||||
.Example: Turn on encryption (GEA3)
|
||||
.Example: Turn on encryption (GEA3 and GEA4)
|
||||
----
|
||||
sgsn
|
||||
encryption GEA3
|
||||
encryption gea 3 4
|
||||
----
|
||||
|
||||
.Example: Turn off encryption (GEA0)
|
||||
----
|
||||
sgsn
|
||||
encryption GEA0
|
||||
encryption gea 0
|
||||
----
|
||||
|
||||
=== Configure SCCP/M3UA to accept _IuPS_ links
|
||||
|
@ -369,6 +422,7 @@ cs7 instance 0
|
|||
point-code 0.23.4
|
||||
asp asp-clnt-OsmoSGSN 2905 0 m3ua
|
||||
remote-ip 127.0.0.1
|
||||
role asp
|
||||
sctp-role client
|
||||
as as-clnt-OsmoSGSN m3ua
|
||||
asp asp-clnt-OsmoSGSN
|
||||
|
|
|
@ -15,6 +15,14 @@
|
|||
Conversion to asciidoc, removal of sysmoBTS specific parts.
|
||||
</revremark>
|
||||
</revision>
|
||||
<revision>
|
||||
<revnumber>3</revnumber>
|
||||
<date>April 2024</date>
|
||||
<authorinitials>AC</authorinitials>
|
||||
<revremark>
|
||||
Replace NS chapter with new NS2 chapter to match the code.
|
||||
</revremark>
|
||||
</revision>
|
||||
</revhistory>
|
||||
|
||||
<authorgroup>
|
||||
|
@ -29,10 +37,21 @@
|
|||
<jobtitle>Managing Director</jobtitle>
|
||||
</affiliation>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Alexander</firstname>
|
||||
<surname>Couzens</surname>
|
||||
<email>acouzens@sysmocom.de</email>
|
||||
<authorinitials>AC</authorinitials>
|
||||
<affiliation>
|
||||
<shortaffil>sysmocom</shortaffil>
|
||||
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
|
||||
<jobtitle>Developer</jobtitle>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<copyright>
|
||||
<year>2013-2016</year>
|
||||
<year>2013-2024</year>
|
||||
<holder>sysmocom - s.f.m.c. GmbH</holder>
|
||||
</copyright>
|
||||
|
||||
|
@ -47,8 +66,8 @@
|
|||
</para>
|
||||
<para>
|
||||
The Asciidoc source code of this manual can be found at
|
||||
<ulink url="http://git.osmocom.org/osmo-gsm-manuals/">
|
||||
http://git.osmocom.org/osmo-gsm-manuals/
|
||||
<ulink url="https://git.osmocom.org/osmo-gsm-manuals/">
|
||||
https://git.osmocom.org/osmo-gsm-manuals/
|
||||
</ulink>
|
||||
</para>
|
||||
</legalnotice>
|
||||
|
|
|
@ -21,7 +21,7 @@ include::{srcdir}/chapters/configuration.adoc[]
|
|||
|
||||
include::./common/chapters/cs7-config.adoc[]
|
||||
|
||||
include::./common/chapters/gb.adoc[]
|
||||
include::./common/chapters/gb-ns2.adoc[]
|
||||
|
||||
include::./common/chapters/control_if.adoc[]
|
||||
|
||||
|
|
|
@ -1,71 +1,17 @@
|
|||
#!/bin/sh -e
|
||||
#!/bin/sh -x
|
||||
|
||||
require_osmo_interact_vty() {
|
||||
if command -v osmo_interact_vty.py >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
echo "ERROR: osmo_interact_vty.py not found. Are osmo-python-tests in PATH?"
|
||||
if [ -z "$DOCKER_PLAYGROUND" ]; then
|
||||
echo "You need to set DOCKER_PLAYGROUND"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
# $1: "update_vty_reference" or "update_counters"
|
||||
# $2: output file
|
||||
# $3: port
|
||||
# $4-$n: command
|
||||
interact_vty() {
|
||||
action="$1"
|
||||
output="$2"
|
||||
port="$3"
|
||||
log="/tmp/$4.log"
|
||||
shift 3
|
||||
SCRIPT=$(realpath "$0")
|
||||
MANUAL_DIR=$(dirname "$SCRIPT")
|
||||
|
||||
echo "Starting in background: $@"
|
||||
"$@" > "$log" 2>&1 &
|
||||
pid="$!"
|
||||
COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
|
||||
|
||||
sleep 0.5
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
echo "ERROR: start failed!"
|
||||
cat "$log"
|
||||
exit 1
|
||||
fi
|
||||
cd "$DOCKER_PLAYGROUND/scripts" || exit 1
|
||||
|
||||
case "$action" in
|
||||
"update_vty_reference")
|
||||
echo "Updating VTY reference: $output"
|
||||
osmo_interact_vty.py -X -p "$port" -H 127.0.0.1 -O "$output"
|
||||
;;
|
||||
"update_counters")
|
||||
echo "Updating asciidoc counters: $output"
|
||||
osmo_interact_vty.py -c "enable;show asciidoc counters" -p "$port" -H 127.0.0.1 -O "$output"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: invalid argument: $action"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
kill "$pid"
|
||||
echo "Done (killed $1)"
|
||||
echo
|
||||
}
|
||||
|
||||
DIR="$(cd "$(dirname "$0")"; pwd)"
|
||||
cd "$DIR"
|
||||
|
||||
require_osmo_interact_vty
|
||||
|
||||
interact_vty \
|
||||
"update_vty_reference" \
|
||||
"vty/sgsn_vty_reference.xml" \
|
||||
4245 \
|
||||
osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
|
||||
|
||||
interact_vty \
|
||||
"update_counters" \
|
||||
"chapters/counters_generated.adoc" \
|
||||
4245 \
|
||||
osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
|
||||
|
||||
|
||||
echo "Done with all"
|
||||
OSMO_BSC_BRANCH=$COMMIT ./regen_doc.sh osmo-sgsn 4245 \
|
||||
"$MANUAL_DIR/chapters/counters_generated.adoc" \
|
||||
"$MANUAL_DIR/vty/sgsn_vty_reference.xml"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
SUBDIRS = \
|
||||
gtphub \
|
||||
sgsn \
|
||||
$(NULL)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
noinst_HEADERS = \
|
||||
gtphub.h \
|
||||
$(NULL)
|
|
@ -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;
|
|
@ -1,18 +1,19 @@
|
|||
noinst_HEADERS = \
|
||||
apn.h \
|
||||
auth.h \
|
||||
common.h \
|
||||
crc24.h \
|
||||
debug.h \
|
||||
gprs_gb.h \
|
||||
gprs_gb_parse.h \
|
||||
gprs_bssgp.h \
|
||||
gprs_gmm.h \
|
||||
gprs_gmm_fsm.h \
|
||||
gprs_gmm_attach.h \
|
||||
gprs_mm_state_gb_fsm.h \
|
||||
gprs_mm_state_iu_fsm.h \
|
||||
gprs_ns.h \
|
||||
gprs_llc.h \
|
||||
gprs_llc_xid.h \
|
||||
gprs_ranap.h \
|
||||
gprs_sgsn.h \
|
||||
gprs_sm.h \
|
||||
gprs_sndcp_comp.h \
|
||||
gprs_sndcp_dcomp.h \
|
||||
|
@ -21,7 +22,11 @@ noinst_HEADERS = \
|
|||
gprs_sndcp_xid.h \
|
||||
gprs_subscriber.h \
|
||||
gprs_utils.h \
|
||||
gtphub.h \
|
||||
gtp.h \
|
||||
gtp_ggsn.h \
|
||||
gtp_mme.h \
|
||||
mmctx.h \
|
||||
pdpctx.h \
|
||||
sgsn.h \
|
||||
sgsn_rim.h \
|
||||
signal.h \
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
|
@ -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
|
||||
|
|
|
@ -13,7 +13,6 @@ enum {
|
|||
DMEAS,
|
||||
DREF,
|
||||
DGPRS,
|
||||
DNS,
|
||||
DLLC,
|
||||
DSNDCP,
|
||||
DSLHC,
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
|
@ -1,11 +1,15 @@
|
|||
#ifndef _GPRS_GMM_H
|
||||
#define _GPRS_GMM_H
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/gsm/gsm48.h>
|
||||
#include <osmocom/crypt/auth.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,
|
||||
uint8_t key_seq, bool force_standby);
|
||||
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
struct sgsn_mm_ctx;
|
||||
|
||||
|
||||
/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
|
||||
/* TS 23.060 § 6.1.1 Mobility Management States (A/Gb mode) */
|
||||
enum mm_state_gb_fsm_states {
|
||||
ST_MM_IDLE,
|
||||
ST_MM_READY,
|
||||
|
@ -14,9 +14,8 @@ enum mm_state_gb_fsm_states {
|
|||
|
||||
enum mm_state_gb_fsm_events {
|
||||
E_MM_GPRS_ATTACH,
|
||||
/* E_GPRS_DETACH, TODO: not used */
|
||||
E_MM_GPRS_DETACH, /* MS becomes detached: due to Detach Req, RAU reject, implicit detach, etc. */
|
||||
E_MM_PDU_RECEPTION,
|
||||
E_MM_IMPLICIT_DETACH, /* = E_MM_CANCEL_LOCATION */
|
||||
E_MM_READY_TIMER_EXPIRY,
|
||||
/* E_FORCE_TO_STANDBY, TODO: not used */
|
||||
/* E_ABNSORMAL_RLC_CONDITION, TODO: not used */
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
struct sgsn_mm_ctx;
|
||||
|
||||
|
||||
/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
|
||||
/* TS 23.060 § 6.1.2 Mobility Management States (Iu mode) */
|
||||
enum mm_state_iu_fsm_states {
|
||||
ST_PMM_DETACHED,
|
||||
ST_PMM_CONNECTED,
|
||||
|
@ -14,12 +13,10 @@ enum mm_state_iu_fsm_states {
|
|||
|
||||
enum mm_state_iu_fsm_events {
|
||||
E_PMM_PS_ATTACH,
|
||||
/* E_PS_DETACH, TODO: not used */
|
||||
E_PMM_PS_DETACH, /* UE becomes detached: due to Detach Req, RAU reject, implicit detach, etc. */
|
||||
E_PMM_PS_CONN_RELEASE,
|
||||
E_PMM_PS_CONN_ESTABLISH,
|
||||
E_PMM_IMPLICIT_DETACH, /* = E_PS_ATTACH_REJECT, E_RAU_REJECT */
|
||||
E_PMM_RA_UPDATE, /* = Serving RNC relocation */
|
||||
E_PMM_USER_INACTIVITY, /* when the inactivity timer runs out */
|
||||
};
|
||||
|
||||
extern struct osmo_fsm mm_state_iu_fsm;
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
|
@ -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)
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/gprs/protocol/gsm_24_301.h>
|
||||
|
||||
struct gsn_t;
|
||||
|
||||
struct mme_rim_route {
|
||||
struct llist_head list; /* item in struct sgsn_mme_ctx */
|
||||
struct osmo_eutran_tai tai;
|
||||
};
|
||||
|
||||
struct sgsn_mme_ctx {
|
||||
struct llist_head list; /* item in sgsn_mme_ctxts */
|
||||
struct llist_head routes; /* list of struct mme_rim_route */
|
||||
struct sgsn_instance *sgsn; /* backpointer */
|
||||
char *name;
|
||||
struct in_addr remote_addr;
|
||||
|
||||
/* is it the default route for outgoing message? are all incoming messages accepted? */
|
||||
bool default_route;
|
||||
};
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name);
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_find_alloc(struct sgsn_instance *sgsn, const char *name);
|
||||
void sgsn_mme_ctx_free(struct sgsn_mme_ctx *mme);
|
||||
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_name(const struct sgsn_instance *sgsn, const char *name);
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_addr(const struct sgsn_instance *sgsn, const struct in_addr *addr);
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_route(const struct sgsn_instance *sgsn, const struct osmo_eutran_tai *tai);
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_default_route(const struct sgsn_instance *sgsn);
|
||||
|
||||
void sgsn_mme_ctx_route_add(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);
|
||||
void sgsn_mme_ctx_route_del(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai);
|
||||
|
||||
#define LOGMME(mme, cat, level, fmt, args...) { \
|
||||
char _buf[INET_ADDRSTRLEN]; \
|
||||
LOGP(cat, level, "MME(%s:%s): " fmt, (mme)->name, inet_ntop(AF_INET, &(mme)->remote_addr, _buf, sizeof(_buf)), ## args); \
|
||||
} while (0)
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef _GPRS_SGSN_H
|
||||
#define _GPRS_SGSN_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
|
@ -14,12 +13,17 @@
|
|||
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
||||
#include <osmocom/crypt/auth.h>
|
||||
|
||||
#include <osmocom/sgsn/apn.h>
|
||||
#include <osmocom/sgsn/auth.h>
|
||||
#include <osmocom/sgsn/gprs_subscriber.h>
|
||||
|
||||
#define GSM_EXTENSION_LENGTH 15
|
||||
#define GSM_APN_LENGTH 102
|
||||
|
||||
struct gprs_llc_lle;
|
||||
struct ctrl_handle;
|
||||
struct gprs_subscr;
|
||||
struct sgsn_ggsn_ctx;
|
||||
struct sgsn_pdp_ctx;
|
||||
|
||||
enum gsm48_gsm_cause;
|
||||
|
||||
|
@ -37,13 +41,6 @@ enum gprs_mm_ctr {
|
|||
GMM_CTR_RA_UPDATE,
|
||||
};
|
||||
|
||||
enum gprs_pdp_ctx {
|
||||
PDP_CTR_PKTS_UDATA_IN,
|
||||
PDP_CTR_PKTS_UDATA_OUT,
|
||||
PDP_CTR_BYTES_UDATA_IN,
|
||||
PDP_CTR_BYTES_UDATA_OUT,
|
||||
};
|
||||
|
||||
enum gprs_t3350_mode {
|
||||
GMM_T3350_MODE_NONE,
|
||||
GMM_T3350_MODE_ATT,
|
||||
|
@ -51,17 +48,6 @@ enum gprs_t3350_mode {
|
|||
GMM_T3350_MODE_PTMSI_REALL,
|
||||
};
|
||||
|
||||
/* Authorization/ACL handling */
|
||||
enum sgsn_auth_state {
|
||||
SGSN_AUTH_UNKNOWN,
|
||||
SGSN_AUTH_AUTHENTICATE,
|
||||
SGSN_AUTH_UMTS_RESYNC,
|
||||
SGSN_AUTH_ACCEPTED,
|
||||
SGSN_AUTH_REJECTED
|
||||
};
|
||||
|
||||
#define MS_RADIO_ACCESS_CAPA
|
||||
|
||||
enum sgsn_ggsn_lookup_state {
|
||||
SGSN_GGSN_2DIGIT,
|
||||
SGSN_GGSN_3DIGIT,
|
||||
|
@ -104,13 +90,6 @@ struct service_info {
|
|||
|
||||
struct ranap_ue_conn_ctx;
|
||||
|
||||
struct gsm_auth_tuple {
|
||||
int use_count;
|
||||
int key_seq;
|
||||
struct osmo_auth_vector vec;
|
||||
};
|
||||
#define GSM_KEY_SEQ_INVAL 7 /* GSM 04.08 - 10.5.1.2 */
|
||||
|
||||
/* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */
|
||||
/* Extended by 3GPP TS 23.060, Table 6: SGSN MM and PDP Contexts */
|
||||
struct sgsn_mm_ctx {
|
||||
|
@ -175,6 +154,7 @@ struct sgsn_mm_ctx {
|
|||
/* Iu: CK, IK, KSI */
|
||||
/* CKSN */
|
||||
enum gprs_ciph_algo ciph_algo;
|
||||
uint8_t ue_cipher_mask;
|
||||
/* Auth & Ciphering Request reference from 3GPP TS 24.008 § 10.5.5.19: */
|
||||
uint8_t ac_ref_nr_used;
|
||||
|
||||
|
@ -294,64 +274,6 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
|
|||
enum gsm48_gsm_cause *gsm_cause,
|
||||
char *apn_str);
|
||||
|
||||
enum pdp_ctx_state {
|
||||
PDP_STATE_NONE,
|
||||
PDP_STATE_CR_REQ,
|
||||
PDP_STATE_CR_CONF,
|
||||
|
||||
/* 04.08 / Figure 6.2 / 6.1.2.2 */
|
||||
PDP_STATE_INACT_PEND,
|
||||
PDP_STATE_INACTIVE = PDP_STATE_NONE,
|
||||
};
|
||||
|
||||
enum pdp_type {
|
||||
PDP_TYPE_NONE,
|
||||
PDP_TYPE_ETSI_PPP,
|
||||
PDP_TYPE_IANA_IPv4,
|
||||
PDP_TYPE_IANA_IPv6,
|
||||
};
|
||||
|
||||
struct sgsn_pdp_ctx {
|
||||
struct llist_head list; /* list_head for mmctx->pdp_list */
|
||||
struct llist_head g_list; /* list_head for global list */
|
||||
struct sgsn_mm_ctx *mm; /* back pointer to MM CTX */
|
||||
int destroy_ggsn; /* destroy it on destruction */
|
||||
struct sgsn_ggsn_ctx *ggsn; /* which GGSN serves this PDP */
|
||||
struct llist_head ggsn_list; /* list_head for ggsn->pdp_list */
|
||||
struct rate_ctr_group *ctrg;
|
||||
|
||||
//unsigned int id;
|
||||
struct pdp_t *lib; /* pointer to libgtp PDP ctx */
|
||||
enum pdp_ctx_state state;
|
||||
enum pdp_type type;
|
||||
uint32_t address;
|
||||
char *apn_subscribed;
|
||||
//char *apn_used;
|
||||
uint16_t nsapi; /* SNDCP */
|
||||
uint16_t sapi; /* LLC */
|
||||
uint8_t ti; /* transaction identifier */
|
||||
int vplmn_allowed;
|
||||
uint32_t qos_profile_subscr;
|
||||
//uint32_t qos_profile_req;
|
||||
//uint32_t qos_profile_neg;
|
||||
uint8_t radio_prio;
|
||||
//uint32_t charging_id;
|
||||
|
||||
struct osmo_timer_list timer;
|
||||
unsigned int T; /* Txxxx number */
|
||||
unsigned int num_T_exp; /* number of consecutive T expirations */
|
||||
|
||||
struct osmo_timer_list cdr_timer; /* CDR record wird timer */
|
||||
struct timespec cdr_start; /* The start of the CDR */
|
||||
uint64_t cdr_bytes_in;
|
||||
uint64_t cdr_bytes_out;
|
||||
uint32_t cdr_charging_id;
|
||||
};
|
||||
|
||||
#define LOGPDPCTXP(level, pdp, fmt, args...) \
|
||||
LOGP(DGPRS, level, "PDP(%s/%u) " \
|
||||
fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args)
|
||||
|
||||
/* look up PDP context by MM context and NSAPI */
|
||||
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
|
||||
uint8_t nsapi);
|
||||
|
@ -359,168 +281,7 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
|
|||
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
|
||||
uint8_t tid);
|
||||
|
||||
struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
|
||||
struct sgsn_ggsn_ctx *ggsn,
|
||||
uint8_t nsapi);
|
||||
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp);
|
||||
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp);
|
||||
|
||||
|
||||
struct sgsn_ggsn_ctx {
|
||||
struct llist_head list;
|
||||
uint32_t id;
|
||||
unsigned int gtp_version;
|
||||
struct in_addr remote_addr;
|
||||
int remote_restart_ctr;
|
||||
struct gsn_t *gsn;
|
||||
struct llist_head pdp_list; /* list of associated pdp ctx (struct sgsn_pdp_ctx*) */
|
||||
struct osmo_timer_list echo_timer;
|
||||
unsigned int echo_interval;
|
||||
};
|
||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id);
|
||||
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
|
||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id);
|
||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr);
|
||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id);
|
||||
void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx);
|
||||
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except);
|
||||
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn);
|
||||
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
|
||||
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp);
|
||||
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc);
|
||||
|
||||
#define LOGGGSN(ggc, level, fmt, args...) { \
|
||||
char _buf[INET_ADDRSTRLEN]; \
|
||||
LOGP(DGTP, level, "GGSN(%" PRIu32 ":%s): " fmt, (ggc)->id, inet_ntop(AF_INET, &(ggc)->remote_addr, _buf, sizeof(_buf)), ## args); \
|
||||
} while (0)
|
||||
|
||||
struct apn_ctx {
|
||||
struct llist_head list;
|
||||
struct sgsn_ggsn_ctx *ggsn;
|
||||
char *name;
|
||||
char *imsi_prefix;
|
||||
char *description;
|
||||
};
|
||||
|
||||
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix);
|
||||
void sgsn_apn_ctx_free(struct apn_ctx *actx);
|
||||
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix);
|
||||
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix);
|
||||
|
||||
extern struct llist_head sgsn_mm_ctxts;
|
||||
extern struct llist_head sgsn_ggsn_ctxts;
|
||||
extern struct llist_head sgsn_apn_ctxts;
|
||||
extern struct llist_head sgsn_pdp_ctxts;
|
||||
|
||||
uint32_t sgsn_alloc_ptmsi(void);
|
||||
struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx);
|
||||
void sgsn_inst_init(struct sgsn_instance *sgsn);
|
||||
|
||||
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len);
|
||||
|
||||
/*
|
||||
* ctrl interface related work
|
||||
*/
|
||||
int sgsn_ctrl_cmds_install(void);
|
||||
|
||||
/*
|
||||
* Authorization/ACL handling
|
||||
*/
|
||||
struct imsi_acl_entry {
|
||||
struct llist_head list;
|
||||
char imsi[OSMO_IMSI_BUF_SIZE];
|
||||
};
|
||||
|
||||
/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */
|
||||
/* see GSM 09.02, B.1, gprsSubscriptionData */
|
||||
struct sgsn_subscriber_pdp_data {
|
||||
struct llist_head list;
|
||||
|
||||
unsigned int context_id;
|
||||
uint16_t pdp_type;
|
||||
char apn_str[GSM_APN_LENGTH];
|
||||
uint8_t qos_subscribed[20];
|
||||
size_t qos_subscribed_len;
|
||||
uint8_t pdp_charg[2];
|
||||
bool has_pdp_charg;
|
||||
};
|
||||
|
||||
struct sgsn_subscriber_data {
|
||||
struct sgsn_mm_ctx *mm;
|
||||
struct gsm_auth_tuple auth_triplets[5];
|
||||
int auth_triplets_updated;
|
||||
struct llist_head pdp_list;
|
||||
int error_cause;
|
||||
|
||||
uint8_t msisdn[9];
|
||||
size_t msisdn_len;
|
||||
|
||||
uint8_t hlr[9];
|
||||
size_t hlr_len;
|
||||
|
||||
uint8_t pdp_charg[2];
|
||||
bool has_pdp_charg;
|
||||
};
|
||||
|
||||
#define SGSN_ERROR_CAUSE_NONE (-1)
|
||||
|
||||
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
|
||||
LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \
|
||||
(subscr) ? (subscr)->imsi : "---", \
|
||||
## args)
|
||||
|
||||
struct sgsn_config;
|
||||
struct sgsn_instance;
|
||||
extern const struct value_string *sgsn_auth_state_names;
|
||||
|
||||
void sgsn_auth_init(struct sgsn_instance *sgsn);
|
||||
struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, const struct sgsn_config *cfg);
|
||||
int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg);
|
||||
int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg);
|
||||
/* Request authorization */
|
||||
int sgsn_auth_request(struct sgsn_mm_ctx *mm);
|
||||
enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm);
|
||||
void sgsn_auth_update(struct sgsn_mm_ctx *mm);
|
||||
struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx,
|
||||
unsigned key_seq);
|
||||
|
||||
/*
|
||||
* GPRS subscriber data
|
||||
*/
|
||||
#define GPRS_SUBSCRIBER_FIRST_CONTACT 0x00000001
|
||||
#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING (1 << 16)
|
||||
#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING (1 << 17)
|
||||
#define GPRS_SUBSCRIBER_CANCELLED (1 << 18)
|
||||
#define GPRS_SUBSCRIBER_ENABLE_PURGE (1 << 19)
|
||||
|
||||
#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \
|
||||
GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \
|
||||
GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING \
|
||||
)
|
||||
|
||||
int gprs_subscr_init(struct sgsn_instance *sgi);
|
||||
int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx);
|
||||
int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx,
|
||||
const uint8_t *auts,
|
||||
const uint8_t *auts_rand);
|
||||
int gprs_subscr_auth_sync(struct gprs_subscr *subscr,
|
||||
const uint8_t *auts, const uint8_t *auts_rand);
|
||||
void gprs_subscr_cleanup(struct gprs_subscr *subscr);
|
||||
struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi);
|
||||
struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx( struct sgsn_mm_ctx *mmctx);
|
||||
struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi);
|
||||
void gprs_subscr_cancel(struct gprs_subscr *subscr);
|
||||
void gprs_subscr_update(struct gprs_subscr *subscr);
|
||||
void gprs_subscr_update_auth_info(struct gprs_subscr *subscr);
|
||||
int gprs_subscr_rx_gsup_message(struct msgb *msg);
|
||||
|
||||
/* Called on subscriber data updates */
|
||||
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx);
|
||||
|
||||
int gprs_sndcp_vty_init(void);
|
||||
struct sgsn_instance;
|
||||
int sgsn_gtp_init(struct sgsn_instance *sgi);
|
||||
|
||||
void sgsn_rate_ctr_init();
|
||||
|
||||
#endif /* _GPRS_SGSN_H */
|
|
@ -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);
|
||||
|
|
@ -6,12 +6,15 @@
|
|||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/crypt/gprs_cipher.h>
|
||||
#include <osmocom/gprs/gprs_ns2.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
|
||||
#include <osmocom/sgsn/auth.h>
|
||||
#include <osmocom/sgsn/gtp_mme.h>
|
||||
#include <osmocom/gsm/oap_client.h>
|
||||
#include <osmocom/gsupclient/gsup_client.h>
|
||||
#include <osmocom/sgsn/common.h>
|
||||
|
||||
#include "../../bscconfig.h"
|
||||
#include "../../config.h"
|
||||
|
||||
#if BUILD_IU
|
||||
#include <osmocom/ranap/iu_client.h>
|
||||
|
@ -22,6 +25,8 @@
|
|||
|
||||
struct hostent;
|
||||
|
||||
#define SGSN_ERROR_CAUSE_NONE (-1)
|
||||
|
||||
enum sgsn_auth_policy {
|
||||
SGSN_AUTH_POLICY_OPEN,
|
||||
SGSN_AUTH_POLICY_CLOSED,
|
||||
|
@ -72,8 +77,10 @@ struct sgsn_config {
|
|||
/* misc */
|
||||
struct gprs_ns2_inst *nsi;
|
||||
|
||||
char *crypt_cipher_plugin_path;
|
||||
enum sgsn_auth_policy auth_policy;
|
||||
enum gprs_ciph_algo cipher;
|
||||
uint8_t gea_encryption_mask;
|
||||
uint8_t uea_encryption_mask;
|
||||
struct llist_head imsi_acl;
|
||||
|
||||
struct sockaddr_in gsup_server_addr;
|
||||
|
@ -89,6 +96,7 @@ struct sgsn_config {
|
|||
|
||||
/* Timer defintions */
|
||||
struct osmo_tdef *T_defs;
|
||||
struct osmo_tdef *T_defs_gtp;
|
||||
|
||||
int dynamic_lookup;
|
||||
|
||||
|
@ -145,9 +153,23 @@ struct sgsn_instance {
|
|||
struct ares_addr_node *ares_servers;
|
||||
|
||||
struct rate_ctr_group *rate_ctrs;
|
||||
|
||||
struct llist_head apn_list; /* list of struct sgsn_apn_ctx */
|
||||
struct llist_head ggsn_list; /* list of struct sgsn_ggsn_ctx */
|
||||
struct llist_head mme_list; /* list of struct sgsn_mme_ctx */
|
||||
struct llist_head mm_list; /* list of struct sgsn_mm_ctx */
|
||||
struct llist_head pdp_list; /* list of struct sgsn_pdp_ctx */
|
||||
|
||||
struct ctrl_handle *ctrlh;
|
||||
};
|
||||
|
||||
extern struct sgsn_instance *sgsn;
|
||||
extern void *tall_sgsn_ctx;
|
||||
|
||||
/*
|
||||
* ctrl interface related work (sgsn_ctrl.c)
|
||||
*/
|
||||
int sgsn_ctrl_cmds_install(void);
|
||||
|
||||
/* sgsn_vty.c */
|
||||
|
||||
|
@ -156,39 +178,13 @@ int sgsn_parse_config(const char *config_file);
|
|||
char *sgsn_gtp_ntoa(struct ul16_t *ul);
|
||||
|
||||
/* sgsn.c */
|
||||
|
||||
/* Main input function for Gb proxy */
|
||||
int sgsn_rcvmsg(struct msgb *msg, struct gprs_ns2_vc *nsvc, uint16_t ns_bvci);
|
||||
|
||||
/* sgsn_libgtp.c */
|
||||
struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
|
||||
struct sgsn_mm_ctx *mmctx,
|
||||
uint16_t nsapi,
|
||||
struct tlv_parsed *tp);
|
||||
int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx);
|
||||
void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen);
|
||||
void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc);
|
||||
int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx);
|
||||
|
||||
/* gprs_sndcp.c */
|
||||
|
||||
/* Entry point for the SNSM-ACTIVATE.indication */
|
||||
int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
|
||||
/* Entry point for the SNSM-DEACTIVATE.indication */
|
||||
int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi);
|
||||
/* Called by SNDCP when it has received/re-assembled a N-PDU */
|
||||
int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
|
||||
struct msgb *msg, uint32_t npdu_len, uint8_t *npdu);
|
||||
int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi,
|
||||
void *mmcontext);
|
||||
int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
|
||||
uint8_t *hdr, uint16_t len);
|
||||
|
||||
|
||||
struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx);
|
||||
int sgsn_inst_init(struct sgsn_instance *sgsn);
|
||||
/*
|
||||
* CDR related functionality
|
||||
*/
|
||||
int sgsn_cdr_init(struct sgsn_instance *sgsn);
|
||||
void sgsn_cdr_release(struct sgsn_instance *sgsn);
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg);
|
||||
struct sgsn_mme_ctx;
|
||||
|
||||
int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg);
|
||||
int sgsn_rim_rx_from_gtp(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <osmocom/vty/command.h>
|
||||
|
||||
enum bsc_vty_node {
|
||||
GBPROXY_NODE = _LAST_OSMOVTY_NODE + 1,
|
||||
SGSN_NODE,
|
||||
SGSN_NODE = _LAST_OSMOVTY_NODE + 1,
|
||||
GTPHUB_NODE,
|
||||
MME_NODE,
|
||||
};
|
||||
|
|
|
@ -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
|
|
@ -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 \
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
|
||||
#include <netdb.h>
|
||||
|
||||
extern void *tall_sgsn_ctx;
|
||||
|
||||
struct cares_event_fd {
|
||||
struct llist_head head;
|
||||
struct osmo_fd fd;
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <gtp.h>
|
||||
#include <gtpie.h>
|
||||
|
||||
#include <osmocom/sgsn/gtphub.h>
|
||||
#include <osmocom/gtphub/gtphub.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/gprs_utils.h>
|
||||
|
||||
|
@ -59,15 +59,6 @@ void *osmo_gtphub_ctx;
|
|||
/* TODO move this to osmocom/core/select.h ? */
|
||||
typedef int (*osmo_fd_cb_t)(struct osmo_fd *fd, unsigned int what);
|
||||
|
||||
/* TODO move this to osmocom/core/linuxlist.h ? */
|
||||
#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next)
|
||||
#define llist_first(head, type, entry) \
|
||||
llist_entry(__llist_first(head), type, entry)
|
||||
|
||||
#define __llist_last(head) (((head)->next == (head)) ? NULL : (head)->prev)
|
||||
#define llist_last(head, type, entry) \
|
||||
llist_entry(__llist_last(head), type, entry)
|
||||
|
||||
/* TODO move GTP header stuff to openggsn/gtp/ ? See gtp_decaps*() */
|
||||
|
||||
enum gtp_rc {
|
||||
|
@ -484,7 +475,7 @@ static int get_ie_imsi_str(union gtpie_member *ie[], int i,
|
|||
* present but cannot be decoded. */
|
||||
static int get_ie_apn_str(union gtpie_member *ie[], const char **apn_str)
|
||||
{
|
||||
static char apn_buf[GSM_APN_LENGTH];
|
||||
static char apn_buf[APN_MAXLEN+1];
|
||||
unsigned int len;
|
||||
if (gtpie_gettlv(ie, GTPIE_APN, 0,
|
||||
&len, apn_buf, sizeof(apn_buf)) != 0)
|
||||
|
@ -613,7 +604,7 @@ void expiry_add(struct expiry *exq, struct expiring_item *item, time_t now)
|
|||
|
||||
OSMO_ASSERT(llist_empty(&exq->items)
|
||||
|| (item->expiry
|
||||
>= llist_last(&exq->items, struct expiring_item, entry)->expiry));
|
||||
>= llist_last_entry(&exq->items, struct expiring_item, entry)->expiry));
|
||||
|
||||
/* Add/move to the tail to always sort by expiry, ascending. */
|
||||
llist_del(&item->entry);
|
||||
|
@ -980,7 +971,7 @@ static inline void set_tei(struct gtp_packet_desc *p, uint32_t tei)
|
|||
|
||||
static void gtphub_mapping_del_cb(struct expiring_item *expi);
|
||||
|
||||
static struct nr_mapping *gtphub_mapping_new()
|
||||
static struct nr_mapping *gtphub_mapping_new(void)
|
||||
{
|
||||
struct nr_mapping *nrm;
|
||||
nrm = talloc_zero(osmo_gtphub_ctx, struct nr_mapping);
|
||||
|
@ -1004,7 +995,7 @@ static const char *gtphub_tunnel_side_str(struct gtphub_tunnel *tun,
|
|||
char *pos = buf;
|
||||
int left = sizeof(buf);
|
||||
int l;
|
||||
|
||||
|
||||
struct gtphub_tunnel_endpoint *c, *u;
|
||||
c = &tun->endpoint[side_idx][GTPH_PLANE_CTRL];
|
||||
u = &tun->endpoint[side_idx][GTPH_PLANE_USER];
|
||||
|
@ -1113,7 +1104,7 @@ static void gtphub_tunnel_del_cb(struct expiring_item *expi)
|
|||
/* rate counter index for hubs: [7; 10] */
|
||||
#define CTR_IDX_HUB(s, p) CTR_IDX(s, p, 3, 2)
|
||||
|
||||
static struct gtphub_tunnel *gtphub_tunnel_new()
|
||||
static struct gtphub_tunnel *gtphub_tunnel_new(void)
|
||||
{
|
||||
struct gtphub_tunnel *tun;
|
||||
tun = talloc_zero(osmo_gtphub_ctx, struct gtphub_tunnel);
|
||||
|
@ -1142,9 +1133,7 @@ static const char *gtphub_peer_strb(struct gtphub_peer *peer, char *buf,
|
|||
if (llist_empty(&peer->addresses))
|
||||
return "(addressless)";
|
||||
|
||||
struct gtphub_peer_addr *a = llist_first(&peer->addresses,
|
||||
struct gtphub_peer_addr,
|
||||
entry);
|
||||
struct gtphub_peer_addr *a = llist_first_entry_or_null(&peer->addresses, struct gtphub_peer_addr, entry);
|
||||
return gsn_addr_to_strb(&a->addr, buf, buflen);
|
||||
}
|
||||
|
||||
|
@ -2125,7 +2114,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||
struct gtphub_bind *from_bind = &hub->to_gsns[side_idx][plane_idx];
|
||||
struct gtphub_bind *to_bind = &hub->to_gsns[other_side_idx(side_idx)][plane_idx];
|
||||
|
||||
rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_IN],
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_BYTES_IN),
|
||||
received);
|
||||
|
||||
struct gtp_packet_desc p;
|
||||
|
@ -2147,7 +2136,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||
return -1;
|
||||
}
|
||||
|
||||
rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_IN]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_PKTS_IN));
|
||||
|
||||
int reply_len;
|
||||
reply_len = gtphub_handle_echo_req(hub, &p, reply_buf);
|
||||
|
@ -2156,8 +2145,8 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||
sgsn_sockaddr_copy(to_addr, from_addr);
|
||||
*to_ofd = &from_bind->ofd;
|
||||
|
||||
rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
|
||||
rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT],
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_PKTS_OUT));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(from_bind->counters_io, GTPH_CTR_BYTES_OUT),
|
||||
reply_len);
|
||||
LOG(LOGL_DEBUG, "%s Echo response to %s: %d bytes to %s\n",
|
||||
(side_idx == GTPH_SIDE_GGSN)? "-->" : "<--",
|
||||
|
@ -2236,9 +2225,9 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||
return -1;
|
||||
}
|
||||
|
||||
rate_ctr_add(&from_peer->counters_io->ctr[GTPH_CTR_BYTES_IN],
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(from_peer->counters_io, GTPH_CTR_BYTES_IN),
|
||||
received);
|
||||
rate_ctr_inc(&from_peer->counters_io->ctr[GTPH_CTR_PKTS_IN]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(from_peer->counters_io, GTPH_CTR_PKTS_IN));
|
||||
|
||||
LOG(LOGL_DEBUG, "from %s peer: %s\n", gtphub_side_idx_names[side_idx],
|
||||
gtphub_port_str(from_peer));
|
||||
|
@ -2257,9 +2246,9 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||
|
||||
if (p.tun) {
|
||||
struct gtphub_tunnel_endpoint *te = &p.tun->endpoint[p.side_idx][p.plane_idx];
|
||||
rate_ctr_add(&te->counters_io->ctr[GTPH_CTR_BYTES_IN],
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_BYTES_IN),
|
||||
received);
|
||||
rate_ctr_inc(&te->counters_io->ctr[GTPH_CTR_PKTS_IN]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_PKTS_IN));
|
||||
}
|
||||
|
||||
if ((!to_peer) && (side_idx == GTPH_SIDE_SGSN)) {
|
||||
|
@ -2294,7 +2283,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||
!= 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Either to_peer was resolved from an existing tunnel,
|
||||
* or a PDP Ctx and thus a tunnel has just been created,
|
||||
* or the tunnel has been deleted due to this message. */
|
||||
|
@ -2311,19 +2300,19 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||
*reply_buf = (uint8_t*)p.data;
|
||||
|
||||
if (received) {
|
||||
rate_ctr_inc(&to_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
|
||||
rate_ctr_add(&to_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT],
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(to_bind->counters_io, GTPH_CTR_PKTS_OUT));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(to_bind->counters_io, GTPH_CTR_BYTES_OUT),
|
||||
received);
|
||||
|
||||
rate_ctr_inc(&to_peer->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
|
||||
rate_ctr_add(&to_peer->counters_io->ctr[GTPH_CTR_BYTES_OUT],
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(to_peer->counters_io, GTPH_CTR_PKTS_OUT));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(to_peer->counters_io, GTPH_CTR_BYTES_OUT),
|
||||
received);
|
||||
}
|
||||
|
||||
if (p.tun) {
|
||||
struct gtphub_tunnel_endpoint *te = &p.tun->endpoint[other_side_idx(p.side_idx)][p.plane_idx];
|
||||
rate_ctr_inc(&te->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
|
||||
rate_ctr_add(&te->counters_io->ctr[GTPH_CTR_BYTES_OUT],
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_PKTS_OUT));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(te->counters_io, GTPH_CTR_BYTES_OUT),
|
||||
received);
|
||||
}
|
||||
|
||||
|
@ -2701,7 +2690,7 @@ static struct gtphub_peer_addr *gtphub_addr_have(struct gtphub *hub,
|
|||
struct gtphub_peer *peer = gtphub_peer_new(hub, bind);
|
||||
|
||||
a = gtphub_peer_add_addr(peer, addr);
|
||||
|
||||
|
||||
LOG(LOGL_DEBUG, "New peer address: %s %s\n",
|
||||
bind->label,
|
||||
gsn_addr_to_str(&a->addr));
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -40,12 +40,13 @@ bin_PROGRAMS = \
|
|||
$(NULL)
|
||||
|
||||
osmo_sgsn_SOURCES = \
|
||||
gprs_gb.c \
|
||||
apn.c \
|
||||
gprs_bssgp.c \
|
||||
gprs_gmm_attach.c \
|
||||
gprs_gmm.c \
|
||||
gprs_gmm_fsm.c \
|
||||
gprs_mm_state_gb_fsm.c \
|
||||
gprs_sgsn.c \
|
||||
gprs_ns.c \
|
||||
gprs_sm.c \
|
||||
gprs_sndcp.c \
|
||||
gprs_sndcp_comp.c \
|
||||
|
@ -53,11 +54,16 @@ osmo_sgsn_SOURCES = \
|
|||
gprs_sndcp_pcomp.c \
|
||||
gprs_sndcp_vty.c \
|
||||
gprs_sndcp_xid.c \
|
||||
gtp_ggsn.c \
|
||||
gtp_mme.c \
|
||||
sgsn.c \
|
||||
sgsn_main.c \
|
||||
sgsn_vty.c \
|
||||
sgsn_libgtp.c \
|
||||
gprs_llc.c \
|
||||
gprs_llc_vty.c \
|
||||
mmctx.c \
|
||||
pdpctx.c \
|
||||
sgsn_ctrl.c \
|
||||
sgsn_auth.c \
|
||||
gprs_subscriber.c \
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 },
|
||||
|
@ -109,9 +111,14 @@ static void mmctx_timer_start(struct sgsn_mm_ctx *mm, unsigned int T)
|
|||
|
||||
static void mmctx_timer_stop(struct sgsn_mm_ctx *mm, unsigned int T)
|
||||
{
|
||||
if (mm->T != T)
|
||||
if (!osmo_timer_pending(&mm->timer)) {
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "Stopping *inactive* MM timer %u\n", T);
|
||||
return;
|
||||
}
|
||||
if (mm->T != T) {
|
||||
LOGMMCTXP(LOGL_ERROR, mm, "Stopping MM timer %u but "
|
||||
"%u is running\n", T, mm->T);
|
||||
}
|
||||
osmo_timer_del(&mm->timer);
|
||||
}
|
||||
|
||||
|
@ -131,7 +138,7 @@ int gsm48_gmm_sendmsg(struct msgb *msg, int command,
|
|||
struct sgsn_mm_ctx *mm, bool encryptable)
|
||||
{
|
||||
if (mm) {
|
||||
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_PKTS_SIG_OUT));
|
||||
#ifdef BUILD_IU
|
||||
if (mm->ran_type == MM_CTX_T_UTRAN_Iu)
|
||||
return ranap_iu_tx(msg, GPRS_SAPI_GMM);
|
||||
|
@ -197,10 +204,10 @@ static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
|
|||
|
||||
switch(ctx->ran_type) {
|
||||
case MM_CTX_T_UTRAN_Iu:
|
||||
osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
|
||||
osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_DETACH, NULL);
|
||||
break;
|
||||
case MM_CTX_T_GERAN_Gb:
|
||||
osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
|
||||
osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_GPRS_DETACH, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -215,7 +222,7 @@ static int _tx_status(struct msgb *msg, uint8_t cause,
|
|||
|
||||
/* MMCTX might be NULL! */
|
||||
|
||||
DEBUGP(DMM, "<- GPRS MM STATUS (cause: %s)\n",
|
||||
DEBUGP(DMM, "<- GMM STATUS (cause: %s)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, cause));
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
|
||||
|
@ -241,7 +248,7 @@ static int _tx_detach_req(struct msgb *msg, uint8_t detach_type, uint8_t cause,
|
|||
|
||||
/* MMCTX might be NULL! */
|
||||
|
||||
DEBUGP(DMM, "<- GPRS MM DETACH REQ (type: %s, cause: %s)\n",
|
||||
DEBUGP(DMM, "<- GMM DETACH REQ (type: %s, cause: %s)\n",
|
||||
get_value_string(gprs_det_t_mt_strs, detach_type),
|
||||
get_value_string(gsm48_gmm_cause_names, cause));
|
||||
|
||||
|
@ -290,8 +297,8 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
|
|||
uint8_t *ptsig;
|
||||
#endif
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- GPRS ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi);
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_ACKED]);
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- GMM ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_ACKED));
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
|
@ -354,9 +361,9 @@ static int _tx_gmm_att_rej(struct msgb *msg, uint8_t gmm_cause,
|
|||
{
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS ATTACH REJECT: %s\n",
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM ATTACH REJECT: %s\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gmm_cause));
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REJECTED]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REJECTED));
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
|
||||
gh->proto_discr = GSM48_PDISC_MM_GPRS;
|
||||
|
@ -388,8 +395,8 @@ static int _tx_detach_ack(struct msgb *msg, uint8_t force_stby,
|
|||
|
||||
/* MMCTX might be NULL! */
|
||||
|
||||
DEBUGP(DMM, "<- GPRS MM DETACH ACC (force-standby: %d)\n", force_stby);
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_ACKED]);
|
||||
DEBUGP(DMM, "<- GMM DETACH ACC (force-standby: %d)\n", force_stby);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_DETACH_ACKED));
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
|
||||
gh->proto_discr = GSM48_PDISC_MM_GPRS;
|
||||
|
@ -421,7 +428,7 @@ int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type)
|
|||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ID REQ");
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
LOGMMCTXP(LOGL_DEBUG, mm, "<- GPRS IDENTITY REQUEST: mi_type=%s\n",
|
||||
LOGMMCTXP(LOGL_DEBUG, mm, "<- GMM IDENTITY REQUEST: mi_type=%s\n",
|
||||
gsm48_mi_type_name(id_type));
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
@ -445,6 +452,17 @@ static bool mmctx_is_r99(const struct sgsn_mm_ctx *mm)
|
|||
return false;
|
||||
}
|
||||
|
||||
static enum gprs_ciph_algo gprs_ms_net_select_best_gea(uint8_t net_mask, uint8_t ms_mask) {
|
||||
uint8_t common_mask = net_mask & ms_mask;
|
||||
uint8_t r = 0;
|
||||
|
||||
while (common_mask >>= 1) {
|
||||
r++;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 § 9.4.9: Authentication and Ciphering Request */
|
||||
int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
|
||||
const struct osmo_auth_vector *vec,
|
||||
|
@ -456,7 +474,7 @@ int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
|
|||
uint8_t *m_rand, *m_cksn, rbyte;
|
||||
int rc;
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- GPRS AUTH AND CIPHERING REQ (rand = %s,"
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- GMM AUTH AND CIPHERING REQ (rand = %s,"
|
||||
" mmctx_is_r99=%d, vec->auth_types=0x%x",
|
||||
osmo_hexdump(vec->rand, sizeof(vec->rand)),
|
||||
mmctx_is_r99(mm), vec->auth_types);
|
||||
|
@ -519,7 +537,7 @@ static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm)
|
|||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REJ");
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS AUTH AND CIPH REJECT\n");
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM AUTH AND CIPH REJECT\n");
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
|
@ -599,7 +617,7 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
|
|||
uint8_t res_len;
|
||||
int rc;
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH RESPONSE\n");
|
||||
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH RESPONSE\n");
|
||||
|
||||
if (ctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
|
||||
LOGMMCTXP(LOGL_NOTICE, ctx,
|
||||
|
@ -650,7 +668,7 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
|
|||
ctx->sec_ctx = check_auth_resp(ctx, false, &at->vec, res, res_len);
|
||||
if (!sgsn_mm_ctx_is_authenticated(ctx)) {
|
||||
rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
|
||||
mm_ctx_cleanup_free(ctx, "GPRS AUTH AND CIPH REJECT");
|
||||
mm_ctx_cleanup_free(ctx, "GMM AUTH AND CIPH REJECT");
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -673,7 +691,7 @@ static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx,
|
|||
const uint8_t *auts;
|
||||
int rc;
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH FAILURE (cause = %s)\n",
|
||||
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH FAILURE (cause = %s)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gmm_cause));
|
||||
|
||||
tlv_parse(&tp, &gsm48_gmm_att_tlvdef, gh->data+1, msg->len - 1, 0, 0);
|
||||
|
@ -713,7 +731,7 @@ static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx,
|
|||
|
||||
LOGMMCTXP(LOGL_NOTICE, ctx, "Authentication failed\n");
|
||||
rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
|
||||
mm_ctx_cleanup_free(ctx, "GPRS AUTH FAILURE");
|
||||
mm_ctx_cleanup_free(ctx, "GMM AUTH FAILURE");
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -792,7 +810,7 @@ static int gsm48_tx_gmm_service_ack(struct sgsn_mm_ctx *mm)
|
|||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE ACK");
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- GPRS SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi);
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- GMM SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi);
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
|
@ -813,7 +831,7 @@ static int _tx_gmm_service_rej(struct msgb *msg, uint8_t gmm_cause,
|
|||
{
|
||||
struct gsm48_hdr *gh;
|
||||
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS SERVICE REJECT: %s\n",
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "<- GMM SERVICE REJECT: %s\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gmm_cause));
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
|
||||
|
@ -905,7 +923,13 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
|
|||
/* The MS is authorized */
|
||||
#ifdef BUILD_IU
|
||||
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) {
|
||||
rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 0, ctx->iu.new_key);
|
||||
/* Is any encryption above UEA0 enabled? */
|
||||
bool send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0);
|
||||
LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA encryption mask = 0x%x)\n",
|
||||
send_ck ? "sending" : "not sending", sgsn->cfg.uea_encryption_mask);
|
||||
/* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2(). However, this
|
||||
* is not possible in the iu_client API. See OS#5487. */
|
||||
rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck, ctx->iu.new_key);
|
||||
ctx->iu.new_key = 0;
|
||||
return rc;
|
||||
}
|
||||
|
@ -936,7 +960,7 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
|
|||
#ifdef BUILD_IU
|
||||
case GSM48_MT_GMM_SERVICE_REQ:
|
||||
ctx->pending_req = 0;
|
||||
osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_ATTACH, NULL);
|
||||
osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_CONN_ESTABLISH, NULL);
|
||||
rc = gsm48_tx_gmm_service_ack(ctx);
|
||||
|
||||
if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING)
|
||||
|
@ -1087,7 +1111,7 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
|||
"p_tmsi_old=0x%08x\n",
|
||||
ictx->p_tmsi);
|
||||
|
||||
mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use");
|
||||
mm_ctx_cleanup_free(ictx, "GMM IMSI re-use");
|
||||
}
|
||||
}
|
||||
OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);
|
||||
|
@ -1147,6 +1171,21 @@ static void mmctx_handle_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||
|
||||
}
|
||||
|
||||
static uint8_t gprs_ms_net_cap_gea_mask(const uint8_t *ms_net_cap, uint8_t cap_len)
|
||||
{
|
||||
uint8_t mask = (1 << GPRS_ALGO_GEA0);
|
||||
mask |= (0x80 & ms_net_cap[0]) ? (1 << GPRS_ALGO_GEA1) : 0;
|
||||
|
||||
if (cap_len < 2)
|
||||
return mask;
|
||||
|
||||
/* extended GEA bits start from 2nd bit of the next byte */
|
||||
mask |= (0x40 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA2) : 0;
|
||||
mask |= (0x20 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA3) : 0;
|
||||
mask |= (0x10 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA4) : 0;
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 § 9.4.1 Attach request */
|
||||
static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
||||
struct gprs_llc_llme *llme)
|
||||
|
@ -1163,7 +1202,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
|||
int rc;
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST ");
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REQUEST]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REQUEST));
|
||||
|
||||
/* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either
|
||||
* with a foreign TLLI (P-TMSI that was allocated to the MS before),
|
||||
|
@ -1290,15 +1329,27 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
|||
ctx->ms_radio_access_capa.len);
|
||||
ctx->ms_network_capa.len = msnc_len;
|
||||
memcpy(ctx->ms_network_capa.buf, msnc, msnc_len);
|
||||
if (!gprs_ms_net_cap_gea_supported(ctx->ms_network_capa.buf, msnc_len,
|
||||
ctx->ciph_algo)) {
|
||||
|
||||
ctx->ue_cipher_mask = gprs_ms_net_cap_gea_mask(ctx->ms_network_capa.buf, msnc_len);
|
||||
|
||||
if (!(ctx->ue_cipher_mask & sgsn->cfg.gea_encryption_mask)) {
|
||||
reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
|
||||
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "
|
||||
"%s because MS do not support required %s "
|
||||
"encryption\n", mi_log_string,
|
||||
get_value_string(gprs_cipher_names,ctx->ciph_algo));
|
||||
"%s because MS do not support required encryption, mask UE:0x%02x NW:0x%02x \n",
|
||||
mi_log_string, ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask);
|
||||
goto rejected;
|
||||
}
|
||||
|
||||
/* just assume that everythig is fine if the phone offers a5/4:
|
||||
* it requires a valid umts security context which we can only have after
|
||||
* 1) IDENTITY REQUEST to know what to ask the HLR for
|
||||
* 2) and AUTHENTICATION AND CIPHERING REQUEST
|
||||
* ... but 2) already requires selecting a cipher mode.
|
||||
* So let's just assume we will have the auth data required to make it work.
|
||||
*/
|
||||
|
||||
ctx->ciph_algo = gprs_ms_net_select_best_gea(ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask);
|
||||
|
||||
#ifdef PTMSI_ALLOC
|
||||
/* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */
|
||||
ptmsi_update(ctx);
|
||||
|
@ -1330,7 +1381,7 @@ rejected:
|
|||
get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
|
||||
rc = gsm48_tx_gmm_att_rej_oldmsg(msg, reject_cause);
|
||||
if (ctx)
|
||||
mm_ctx_cleanup_free(ctx, "GPRS ATTACH REJ");
|
||||
mm_ctx_cleanup_free(ctx, "GMM ATTACH REJ");
|
||||
else if (llme)
|
||||
gprs_llgmm_unassign(llme);
|
||||
|
||||
|
@ -1343,13 +1394,13 @@ static int gsm48_rx_gmm_att_compl(struct sgsn_mm_ctx *mmctx)
|
|||
{
|
||||
struct sgsn_signal_data sig_data;
|
||||
/* only in case SGSN offered new P-TMSI */
|
||||
LOGMMCTXP(LOGL_INFO, mmctx, "-> ATTACH COMPLETE\n");
|
||||
LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM ATTACH COMPLETE\n");
|
||||
|
||||
#ifdef BUILD_IU
|
||||
#ifdef BUILD_IU
|
||||
if (mmctx->iu.ue_ctx) {
|
||||
ranap_iu_tx_release(mmctx->iu.ue_ctx, NULL);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mmctx_timer_stop(mmctx, 3350);
|
||||
mmctx->t3350_mode = GMM_T3350_MODE_NONE;
|
||||
|
@ -1410,7 +1461,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
|||
power_off = gh->data[0] & 0x8;
|
||||
|
||||
/* FIXME: In 24.008 there is an optional P-TMSI and P-TMSI signature IE */
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_REQUEST]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_DETACH_REQUEST));
|
||||
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM DETACH REQUEST TLLI=0x%08x type=%s %s\n",
|
||||
msgb_tlli(msg), get_value_string(gprs_det_t_mo_strs, detach_type),
|
||||
power_off ? "Power-off" : "");
|
||||
|
@ -1430,7 +1481,7 @@ static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
|||
memset(&sig_data, 0, sizeof(sig_data));
|
||||
sig_data.mm = ctx;
|
||||
osmo_signal_dispatch(SS_SGSN, S_SGSN_DETACH, &sig_data);
|
||||
mm_ctx_cleanup_free(ctx, "GPRS DETACH REQUEST");
|
||||
mm_ctx_cleanup_free(ctx, "GMM DETACH REQUEST");
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -1449,8 +1500,8 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
|
|||
struct osmo_mobile_identity mi;
|
||||
#endif
|
||||
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_ACKED]);
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- ROUTING AREA UPDATE ACCEPT\n");
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_ACKED));
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- GMM ROUTING AREA UPDATE ACCEPT\n");
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
|
@ -1505,7 +1556,7 @@ int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause)
|
|||
struct gsm48_hdr *gh;
|
||||
|
||||
LOGP(DMM, LOGL_NOTICE, "<- ROUTING AREA UPDATE REJECT\n");
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REJECT]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REJECT));
|
||||
|
||||
gmm_copy_id(msg, old_msg);
|
||||
|
||||
|
@ -1585,7 +1636,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||
/* Update Type 10.5.5.18 */
|
||||
upd_type = *cur++ & 0x07;
|
||||
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REQUEST]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REQUEST));
|
||||
LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM RA UPDATE REQUEST type=\"%s\"\n",
|
||||
get_value_string(gprs_upd_t_strs, upd_type));
|
||||
|
||||
|
@ -1713,7 +1764,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||
/* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */
|
||||
msgid2mmctx(mmctx, msg);
|
||||
/* Bump the statistics of received signalling msgs for this MM context */
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN));
|
||||
|
||||
/* Update the MM context with the new RA-ID */
|
||||
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb && msgb_bcid(msg)) {
|
||||
|
@ -1721,10 +1772,14 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||
/* Update the MM context with the new (i.e. foreign) TLLI */
|
||||
mmctx->gb.tlli = msgb_tlli(msg);
|
||||
}
|
||||
/* Update the MM context with the new DRX params */
|
||||
if (TLVP_PRESENT(&tp, GSM48_IE_GMM_DRX_PARAM))
|
||||
memcpy(&mmctx->drx_parms, TLVP_VAL(&tp, GSM48_IE_GMM_DRX_PARAM), sizeof(mmctx->drx_parms));
|
||||
|
||||
/* FIXME: Update the MM context with the MS radio acc capabilities */
|
||||
/* FIXME: Update the MM context with the MS network capabilities */
|
||||
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_RA_UPDATE));
|
||||
|
||||
#ifdef PTMSI_ALLOC
|
||||
ptmsi_update(mmctx);
|
||||
|
@ -1770,7 +1825,7 @@ rejected:
|
|||
get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
|
||||
rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause);
|
||||
if (mmctx)
|
||||
mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ");
|
||||
mm_ctx_cleanup_free(mmctx, "GMM RA UPDATE REJ");
|
||||
else if (llme)
|
||||
gprs_llgmm_unassign(llme);
|
||||
#ifdef BUILD_IU
|
||||
|
@ -1952,7 +2007,7 @@ static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
|
|||
{
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mmctx, "-> GPRS MM STATUS (cause: %s)\n",
|
||||
LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM STATUS (cause: %s)\n",
|
||||
get_value_string(gsm48_gmm_cause_names, gh->data[0]));
|
||||
|
||||
return 0;
|
||||
|
@ -2071,7 +2126,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||
if (!mmctx)
|
||||
goto null_mmctx;
|
||||
LOGMMCTXP(LOGL_INFO, mmctx, "-> DETACH ACK\n");
|
||||
mm_ctx_cleanup_free(mmctx, "GPRS DETACH ACK");
|
||||
mm_ctx_cleanup_free(mmctx, "GMM DETACH ACK");
|
||||
rc = 0;
|
||||
break;
|
||||
case GSM48_MT_GMM_ATTACH_COMPL:
|
||||
|
@ -2111,9 +2166,9 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||
|
||||
null_mmctx:
|
||||
LOGGBIUP(llme, msg, LOGL_ERROR,
|
||||
"Received GSM 04.08 message type 0x%02x,"
|
||||
"Received GSM 04.08 message type %s,"
|
||||
" but no MM context available\n",
|
||||
gh->msg_type);
|
||||
get_value_string(gprs_msgt_gmm_names, gh->msg_type));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2180,7 +2235,7 @@ static void mmctx_timer_cb(void *_mm)
|
|||
if (mm->num_T_exp >= 5) {
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "T3370 expired >= 5 times\n");
|
||||
gsm48_tx_gmm_att_rej(mm, GMM_CAUSE_MS_ID_NOT_DERIVED);
|
||||
mm_ctx_cleanup_free(mm, "GPRS ATTACH REJECT (T3370)");
|
||||
mm_ctx_cleanup_free(mm, "GMM ATTACH REJECT (T3370)");
|
||||
break;
|
||||
}
|
||||
/* re-tranmit IDENTITY REQUEST and re-start timer */
|
||||
|
@ -2268,3 +2323,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;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#include <osmocom/core/tdef.h>
|
||||
#include <osmocom/crypt/utran_cipher.h>
|
||||
|
||||
#include <osmocom/sgsn/gprs_gmm_attach.h>
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/mmctx.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
|
@ -257,6 +259,7 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_
|
|||
{
|
||||
#ifdef BUILD_IU
|
||||
struct sgsn_mm_ctx *ctx = fi->priv;
|
||||
bool send_ck;
|
||||
|
||||
/* TODO: shouldn't this set always? not only when the integrity_active? */
|
||||
if (ctx->iu.ue_ctx->integrity_active) {
|
||||
|
@ -264,7 +267,14 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_
|
|||
return;
|
||||
}
|
||||
|
||||
ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 0, ctx->iu.new_key);
|
||||
/* Is any encryption above UEA0 enabled? */
|
||||
send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0);
|
||||
LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA encryption mask = 0x%x)\n",
|
||||
send_ck ? "sending" : "not sending", sgsn->cfg.uea_encryption_mask);
|
||||
|
||||
/* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2(). However, this
|
||||
* is not possible in the iu_client API. See OS#5487. */
|
||||
ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck, ctx->iu.new_key);
|
||||
ctx->iu.new_key = 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -272,6 +282,13 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_
|
|||
static void st_iu_security_cmd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
case E_VLR_ANSWERED:
|
||||
/* We may receive an event due to rx
|
||||
* OSMO_GSUP_MSGT_INSERT_DATA_REQUEST here. Do nothing, update of
|
||||
* subscriber is done by lower layers before event is signalled.
|
||||
* In this state we simply wait for E_IU_SECURITY_CMD_COMPLETE
|
||||
*/
|
||||
break;
|
||||
case E_IU_SECURITY_CMD_COMPLETE:
|
||||
gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
|
||||
break;
|
||||
|
@ -308,7 +325,7 @@ static struct osmo_fsm_state gmm_attach_req_fsm_states[] = {
|
|||
.action = st_auth,
|
||||
},
|
||||
[ST_IU_SECURITY_CMD] = {
|
||||
.in_event_mask = X(E_IU_SECURITY_CMD_COMPLETE),
|
||||
.in_event_mask = X(E_IU_SECURITY_CMD_COMPLETE) | X(E_VLR_ANSWERED),
|
||||
.out_state_mask = X(ST_INIT) | X(ST_AUTH) | X(ST_ACCEPT) | X(ST_REJECT),
|
||||
.name = "IuSecurityCommand",
|
||||
.onenter = st_iu_security_cmd_on_enter,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* GMM mobility management states on the network side, 3GPP TS 24.008 § 4.1.3.3 */
|
||||
/*
|
||||
* (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||
* (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
|
@ -57,6 +57,10 @@ static void st_gmm_deregistered(struct osmo_fsm_inst *fi, uint32_t event, void *
|
|||
static void st_gmm_common_proc_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
case E_GMM_COMMON_PROC_INIT_REQ:
|
||||
/* MS may retransmit GPRS Attach Request if for some reason
|
||||
* CommonProcedure didn't go forward correctly */
|
||||
break;
|
||||
/* TODO: events not used
|
||||
case E_GMM_LOWER_LAYER_FAILED:
|
||||
case E_GMM_COMMON_PROC_FAILED:
|
||||
|
@ -76,6 +80,11 @@ static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, v
|
|||
case E_GMM_COMMON_PROC_INIT_REQ:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
|
||||
break;
|
||||
case E_GMM_COMMON_PROC_SUCCESS:
|
||||
/* If we were moved from ST_GMM_COMMON_PROC_INIT here by
|
||||
* E_GMM_ATTACH_SUCCESS instead of E_GMM_COMMON_PROC_SUCCESS then we'll receive the latter here:
|
||||
* we should simply ignore it */
|
||||
break;
|
||||
/* case E_GMM_NET_INIT_DETACH_REQ:
|
||||
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED_INIT);
|
||||
break; */
|
||||
|
@ -126,7 +135,8 @@ static struct osmo_fsm_state gmm_fsm_states[] = {
|
|||
/* X(E_GMM_LOWER_LAYER_FAILED) | */
|
||||
/* X(E_GMM_COMMON_PROC_FAILED) | */
|
||||
X(E_GMM_COMMON_PROC_SUCCESS) |
|
||||
X(E_GMM_ATTACH_SUCCESS),
|
||||
X(E_GMM_ATTACH_SUCCESS) |
|
||||
X(E_GMM_COMMON_PROC_INIT_REQ),
|
||||
.out_state_mask =
|
||||
X(ST_GMM_DEREGISTERED) |
|
||||
X(ST_GMM_REGISTERED_NORMAL),
|
||||
|
@ -136,6 +146,7 @@ static struct osmo_fsm_state gmm_fsm_states[] = {
|
|||
[ST_GMM_REGISTERED_NORMAL] = {
|
||||
.in_event_mask =
|
||||
X(E_GMM_COMMON_PROC_INIT_REQ) |
|
||||
X(E_GMM_COMMON_PROC_SUCCESS) |
|
||||
/* X(E_GMM_NET_INIT_DETACH_REQ) | */
|
||||
/* X(E_GMM_MS_INIT_DETACH_REQ) | */
|
||||
X(E_GMM_SUSPEND),
|
||||
|
@ -194,9 +205,9 @@ void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *dat
|
|||
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
|
||||
default:
|
||||
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
|
||||
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
|
||||
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_GPRS_DETACH, NULL);
|
||||
else if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) {
|
||||
osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
|
||||
osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_PS_DETACH, NULL);
|
||||
mmctx->gb.llme = rat_chg->llme;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include <osmocom/gsm/gsm_utils.h>
|
||||
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
#include <osmocom/sgsn/mmctx.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
#include <osmocom/sgsn/crc24.h>
|
||||
|
@ -42,16 +42,29 @@
|
|||
#include <osmocom/sgsn/gprs_sndcp_comp.h>
|
||||
#include <osmocom/sgsn/gprs_sndcp.h>
|
||||
|
||||
#include <osmocom/crypt/kdf.h>
|
||||
|
||||
const struct value_string gprs_llc_llme_state_names[] = {
|
||||
{ GPRS_LLMS_UNASSIGNED, "UNASSIGNED" },
|
||||
{ GPRS_LLMS_ASSIGNED, "ASSIGNED" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const struct value_string gprs_llc_lle_state_names[] = {
|
||||
{ GPRS_LLES_UNASSIGNED, "TLLI Unassigned" },
|
||||
{ GPRS_LLES_ASSIGNED_ADM, "TLLI Assigned" },
|
||||
{ GPRS_LLES_LOCAL_EST, "Local Establishment" },
|
||||
{ GPRS_LLES_REMOTE_EST, "Remote Establishment" },
|
||||
{ GPRS_LLES_ABM, "Asynchronous Balanced Mode" },
|
||||
{ GPRS_LLES_LOCAL_REL, "Local Release" },
|
||||
{ GPRS_LLES_TIMER_REC, "Timer Recovery" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static struct gprs_llc_llme *llme_alloc(uint32_t tlli);
|
||||
static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
|
||||
static int gprs_llc_tx_xid(const struct gprs_llc_lle *lle, struct msgb *msg,
|
||||
int command);
|
||||
static int gprs_llc_tx_dm(struct gprs_llc_lle *lle);
|
||||
static int gprs_llc_tx_dm(const struct gprs_llc_lle *lle);
|
||||
static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi,
|
||||
int command, enum gprs_llc_u_cmd u_cmd, int pf_bit);
|
||||
|
||||
|
@ -210,7 +223,7 @@ static int gprs_llc_process_xid_ind(uint8_t *bytes_request,
|
|||
int bytes_request_len,
|
||||
uint8_t *bytes_response,
|
||||
int bytes_response_maxlen,
|
||||
struct gprs_llc_lle *lle)
|
||||
const struct gprs_llc_lle *lle)
|
||||
{
|
||||
/* Note: This function computes the response that is sent back to the
|
||||
* MS when a mobile originated XID is received. The function is
|
||||
|
@ -286,7 +299,7 @@ static int gprs_llc_process_xid_ind(uint8_t *bytes_request,
|
|||
|
||||
/* Dispatch XID indications and responses comming from the MS */
|
||||
static void rx_llc_xid(struct gprs_llc_lle *lle,
|
||||
struct gprs_llc_hdr_parsed *gph)
|
||||
const struct gprs_llc_hdr_parsed *gph)
|
||||
{
|
||||
uint8_t response[1024];
|
||||
int response_len;
|
||||
|
@ -588,6 +601,7 @@ static struct gprs_llc_llme *llme_alloc(uint32_t tlli)
|
|||
|
||||
static void llme_free(struct gprs_llc_llme *llme)
|
||||
{
|
||||
gprs_sndcp_sm_deactivate_ind_by_llme(llme);
|
||||
gprs_sndcp_comp_free(llme->comp.proto);
|
||||
gprs_sndcp_comp_free(llme->comp.data);
|
||||
llist_del(&llme->list);
|
||||
|
@ -670,15 +684,15 @@ int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command,
|
|||
|
||||
/* Identifiers passed down: (BVCI, NSEI) */
|
||||
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_PACKETS]);
|
||||
rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_BYTES], msg->len);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_PACKETS));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_BYTES), msg->len);
|
||||
|
||||
/* Send BSSGP-DL-UNITDATA.req */
|
||||
return _bssgp_tx_dl_ud(msg, NULL);
|
||||
}
|
||||
|
||||
/* Send XID response to LLE */
|
||||
static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
|
||||
static int gprs_llc_tx_xid(const struct gprs_llc_lle *lle, struct msgb *msg,
|
||||
int command)
|
||||
{
|
||||
/* copy identifiers from LLE to ensure lower layers can route */
|
||||
|
@ -689,7 +703,7 @@ static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
|
|||
return gprs_llc_tx_u(msg, lle->sapi, command, GPRS_LLC_U_XID, 1);
|
||||
}
|
||||
|
||||
static int gprs_llc_tx_dm(struct gprs_llc_lle *lle)
|
||||
static int gprs_llc_tx_dm(const struct gprs_llc_lle *lle)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_DM");
|
||||
|
||||
|
@ -702,7 +716,7 @@ static int gprs_llc_tx_dm(struct gprs_llc_lle *lle)
|
|||
}
|
||||
|
||||
/* encrypt information field + FCS, if needed! */
|
||||
static int apply_gea(struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu,
|
||||
static int apply_gea(const struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu,
|
||||
uint32_t oc, uint8_t sapi, uint8_t *fcs, uint8_t *data)
|
||||
{
|
||||
uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
|
||||
|
@ -814,8 +828,8 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
|
|||
}
|
||||
}
|
||||
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_PACKETS]);
|
||||
rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_BYTES], msg->len);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_PACKETS));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_DL_BYTES), msg->len);
|
||||
|
||||
/* Identifiers passed down: (BVCI, NSEI) */
|
||||
|
||||
|
@ -962,9 +976,9 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
|
|||
llhp.data);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
llhp.fcs = *(llhp.data + llhp.data_len);
|
||||
llhp.fcs |= *(llhp.data + llhp.data_len + 1) << 8;
|
||||
llhp.fcs |= *(llhp.data + llhp.data_len + 2) << 16;
|
||||
llhp.fcs = *(llhp.data + llhp.data_len);
|
||||
llhp.fcs |= *(llhp.data + llhp.data_len + 1) << 8;
|
||||
llhp.fcs |= *(llhp.data + llhp.data_len + 2) << 16;
|
||||
} else {
|
||||
LOGP(DLLC, LOGL_NOTICE, "encrypted frame for LLC that "
|
||||
"has no KC/Algo! Dropping.\n");
|
||||
|
@ -1000,8 +1014,8 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
|
|||
msgb_l3trim(msg, llhp.data_len);
|
||||
}
|
||||
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_UL_PACKETS]);
|
||||
rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_UL_BYTES], msg->len);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_UL_PACKETS));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_LLC_UL_BYTES), msg->len);
|
||||
|
||||
/* llhp.data is only set when we need to send LL_[UNIT]DATA_IND up */
|
||||
if (llhp.cmd == GPRS_LLC_UI && llhp.data && llhp.data_len) {
|
||||
|
@ -1016,7 +1030,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
|
|||
case GPRS_SAPI_SNDCP9:
|
||||
case GPRS_SAPI_SNDCP11:
|
||||
/* send LL_DATA_IND/LL_UNITDATA_IND to SNDCP */
|
||||
rc = sndcp_llunitdata_ind(msg, lle, llhp.data, llhp.data_len);
|
||||
rc = sndcp_ll_unitdata_ind(msg, lle, llhp.data, llhp.data_len);
|
||||
break;
|
||||
case GPRS_SAPI_SMS:
|
||||
/* FIXME */
|
||||
|
@ -1034,7 +1048,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
|
|||
}
|
||||
|
||||
/* Propagate crypto parameters MM -> LLME */
|
||||
void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
|
||||
void gprs_llme_copy_key(const struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
|
||||
{
|
||||
if (!mm)
|
||||
return;
|
||||
|
@ -1042,8 +1056,13 @@ void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
|
|||
llme->algo = mm->ciph_algo;
|
||||
if (llme->cksn != mm->auth_triplet.key_seq &&
|
||||
mm->auth_triplet.key_seq != GSM_KEY_SEQ_INVAL) {
|
||||
memcpy(llme->kc, mm->auth_triplet.vec.kc,
|
||||
gprs_cipher_key_length(mm->ciph_algo));
|
||||
|
||||
/* gea4 needs kc128 */
|
||||
if (mm->ciph_algo == GPRS_ALGO_GEA4)
|
||||
osmo_kdf_kc128(mm->auth_triplet.vec.ck, mm->auth_triplet.vec.ik, llme->kc);
|
||||
else
|
||||
memcpy(llme->kc, mm->auth_triplet.vec.kc, gprs_cipher_key_length(mm->ciph_algo));
|
||||
|
||||
llme->cksn = mm->auth_triplet.key_seq;
|
||||
}
|
||||
} else
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
/* TS 23.060 § 6.1.1 Mobility Management States (A/Gb mode) */
|
||||
/*
|
||||
* (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
*
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <osmocom/core/tdef.h>
|
||||
|
||||
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
|
||||
|
@ -5,6 +27,7 @@
|
|||
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/mmctx.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
|
||||
|
@ -49,7 +72,7 @@ static void st_mm_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
|||
case E_MM_READY_TIMER_EXPIRY:
|
||||
mm_state_gb_fsm_state_chg(fi, ST_MM_STANDBY);
|
||||
break;
|
||||
case E_MM_IMPLICIT_DETACH:
|
||||
case E_MM_GPRS_DETACH:
|
||||
mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
|
||||
break;
|
||||
case E_MM_PDU_RECEPTION:
|
||||
|
@ -68,7 +91,7 @@ static void st_mm_standby(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
|||
case E_MM_PDU_RECEPTION:
|
||||
mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
|
||||
break;
|
||||
case E_MM_IMPLICIT_DETACH:
|
||||
case E_MM_GPRS_DETACH:
|
||||
mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
|
||||
break;
|
||||
}
|
||||
|
@ -83,13 +106,13 @@ static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
|
|||
.action = st_mm_idle,
|
||||
},
|
||||
[ST_MM_READY] = {
|
||||
.in_event_mask = X(E_MM_READY_TIMER_EXPIRY) | X(E_MM_RA_UPDATE) | X(E_MM_IMPLICIT_DETACH) | X(E_MM_PDU_RECEPTION),
|
||||
.in_event_mask = X(E_MM_READY_TIMER_EXPIRY) | X(E_MM_RA_UPDATE) | X(E_MM_GPRS_DETACH) | X(E_MM_PDU_RECEPTION),
|
||||
.out_state_mask = X(ST_MM_IDLE) | X(ST_MM_STANDBY),
|
||||
.name = "Ready",
|
||||
.action = st_mm_ready,
|
||||
},
|
||||
[ST_MM_STANDBY] = {
|
||||
.in_event_mask = X(E_MM_PDU_RECEPTION) | X(E_MM_IMPLICIT_DETACH),
|
||||
.in_event_mask = X(E_MM_PDU_RECEPTION) | X(E_MM_GPRS_DETACH),
|
||||
.out_state_mask = X(ST_MM_IDLE) | X(ST_MM_READY),
|
||||
.name = "Standby",
|
||||
.action = st_mm_standby,
|
||||
|
@ -99,7 +122,7 @@ static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
|
|||
const struct value_string mm_state_gb_fsm_event_names[] = {
|
||||
OSMO_VALUE_STRING(E_MM_GPRS_ATTACH),
|
||||
OSMO_VALUE_STRING(E_MM_PDU_RECEPTION),
|
||||
OSMO_VALUE_STRING(E_MM_IMPLICIT_DETACH),
|
||||
OSMO_VALUE_STRING(E_MM_GPRS_DETACH),
|
||||
OSMO_VALUE_STRING(E_MM_READY_TIMER_EXPIRY),
|
||||
OSMO_VALUE_STRING(E_MM_RA_UPDATE),
|
||||
{ 0, NULL }
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
/* TS 23.060 § 6.1.2 Mobility Management States (Iu mode) */
|
||||
/*
|
||||
* (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
*
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <osmocom/core/tdef.h>
|
||||
|
@ -7,13 +29,15 @@
|
|||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_ranap.h>
|
||||
#include <osmocom/sgsn/gtp.h>
|
||||
#include <osmocom/sgsn/pdpctx.h>
|
||||
#include <osmocom/sgsn/mmctx.h>
|
||||
|
||||
#define X(s) (1 << (s))
|
||||
|
||||
static const struct osmo_tdef_state_timeout mm_state_iu_fsm_timeouts[32] = {
|
||||
[ST_PMM_DETACHED] = { },
|
||||
/* non-spec -T3314 (User inactivity timer) */
|
||||
[ST_PMM_CONNECTED] = { .T=-3314 },
|
||||
[ST_PMM_CONNECTED] = { },
|
||||
[ST_PMM_IDLE] = { },
|
||||
};
|
||||
|
||||
|
@ -40,7 +64,7 @@ static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data
|
|||
case E_PMM_PS_ATTACH:
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
|
||||
break;
|
||||
case E_PMM_IMPLICIT_DETACH:
|
||||
case E_PMM_PS_DETACH:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -48,24 +72,16 @@ static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data
|
|||
static void st_pmm_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct sgsn_mm_ctx *ctx = fi->priv;
|
||||
const struct RANAP_Cause user_inactive_cause = {
|
||||
.present = RANAP_Cause_PR_radioNetwork,
|
||||
.choice.radioNetwork = RANAP_CauseRadioNetwork_user_inactivity,
|
||||
};
|
||||
|
||||
switch(event) {
|
||||
case E_PMM_PS_CONN_RELEASE:
|
||||
sgsn_ranap_iu_free(ctx);
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_IDLE);
|
||||
break;
|
||||
case E_PMM_IMPLICIT_DETACH:
|
||||
case E_PMM_PS_DETACH:
|
||||
sgsn_ranap_iu_release_free(ctx, NULL);
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
|
||||
break;
|
||||
case E_PMM_USER_INACTIVITY:
|
||||
sgsn_ranap_iu_release_free(ctx, &user_inactive_cause);
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
|
||||
break;
|
||||
case E_PMM_RA_UPDATE:
|
||||
break;
|
||||
}
|
||||
|
@ -81,43 +97,37 @@ static void st_pmm_idle_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
|||
static void st_pmm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch(event) {
|
||||
case E_PMM_PS_ATTACH:
|
||||
case E_PMM_PS_CONN_ESTABLISH:
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
|
||||
break;
|
||||
case E_PMM_IMPLICIT_DETACH:
|
||||
case E_PMM_PS_DETACH:
|
||||
mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int pmm_state_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
switch(fi->state) {
|
||||
case ST_PMM_CONNECTED:
|
||||
/* timer for pmm state. state=CONNECTED: -T3314 (User inactivity timer) */
|
||||
osmo_fsm_inst_dispatch(fi, E_PMM_USER_INACTIVITY, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct osmo_fsm_state mm_state_iu_fsm_states[] = {
|
||||
[ST_PMM_DETACHED] = {
|
||||
.in_event_mask = X(E_PMM_PS_ATTACH) | X(E_PMM_IMPLICIT_DETACH),
|
||||
.in_event_mask = X(E_PMM_PS_ATTACH) | X(E_PMM_PS_DETACH),
|
||||
.out_state_mask = X(ST_PMM_CONNECTED),
|
||||
.name = "Detached",
|
||||
.action = st_pmm_detached,
|
||||
},
|
||||
[ST_PMM_CONNECTED] = {
|
||||
.in_event_mask = X(E_PMM_PS_CONN_RELEASE) | X(E_PMM_RA_UPDATE)
|
||||
| X(E_PMM_IMPLICIT_DETACH) | X(E_PMM_USER_INACTIVITY),
|
||||
.in_event_mask =
|
||||
X(E_PMM_PS_CONN_RELEASE) |
|
||||
X(E_PMM_RA_UPDATE) |
|
||||
X(E_PMM_PS_DETACH),
|
||||
.out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_IDLE),
|
||||
.name = "Connected",
|
||||
.action = st_pmm_connected,
|
||||
},
|
||||
[ST_PMM_IDLE] = {
|
||||
.in_event_mask = X(E_PMM_IMPLICIT_DETACH) | X(E_PMM_PS_CONN_ESTABLISH),
|
||||
.in_event_mask =
|
||||
X(E_PMM_PS_DETACH) |
|
||||
X(E_PMM_PS_CONN_ESTABLISH) |
|
||||
X(E_PMM_PS_ATTACH),
|
||||
.out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_CONNECTED),
|
||||
.name = "Idle",
|
||||
.onenter = st_pmm_idle_on_enter,
|
||||
|
@ -129,9 +139,8 @@ const struct value_string mm_state_iu_fsm_event_names[] = {
|
|||
OSMO_VALUE_STRING(E_PMM_PS_ATTACH),
|
||||
OSMO_VALUE_STRING(E_PMM_PS_CONN_RELEASE),
|
||||
OSMO_VALUE_STRING(E_PMM_PS_CONN_ESTABLISH),
|
||||
OSMO_VALUE_STRING(E_PMM_IMPLICIT_DETACH),
|
||||
OSMO_VALUE_STRING(E_PMM_PS_DETACH),
|
||||
OSMO_VALUE_STRING(E_PMM_RA_UPDATE),
|
||||
OSMO_VALUE_STRING(E_PMM_USER_INACTIVITY),
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
@ -140,7 +149,6 @@ struct osmo_fsm mm_state_iu_fsm = {
|
|||
.states = mm_state_iu_fsm_states,
|
||||
.num_states = ARRAY_SIZE(mm_state_iu_fsm_states),
|
||||
.event_names = mm_state_iu_fsm_event_names,
|
||||
.timer_cb = pmm_state_fsm_timer_cb,
|
||||
.log_subsys = DMM,
|
||||
};
|
||||
|
||||
|
|
|
@ -29,95 +29,10 @@
|
|||
#include <osmocom/gprs/gprs_bssgp_bss.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
|
||||
#include "bscconfig.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_sm.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
|
||||
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
|
||||
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg) {
|
||||
msgid2mmctx(mmctx, msg);
|
||||
if (mmctx->gb.llme)
|
||||
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL);
|
||||
}
|
||||
|
||||
/* Main entry point for incoming 04.08 GPRS messages from Gb */
|
||||
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
|
||||
bool drop_cipherable)
|
||||
{
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||
uint8_t pdisc = gsm48_hdr_pdisc(gh);
|
||||
struct sgsn_mm_ctx *mmctx;
|
||||
struct gprs_ra_id ra_id;
|
||||
int rc = -EINVAL;
|
||||
|
||||
bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
|
||||
mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
|
||||
if (mmctx) {
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
||||
mmctx->gb.llme = llme;
|
||||
gprs_gb_recv_pdu(mmctx, msg);
|
||||
}
|
||||
|
||||
/* MMCTX can be NULL */
|
||||
|
||||
switch (pdisc) {
|
||||
case GSM48_PDISC_MM_GPRS:
|
||||
rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable);
|
||||
break;
|
||||
case GSM48_PDISC_SM_GPRS:
|
||||
rc = gsm0408_rcv_gsm(mmctx, msg, llme);
|
||||
break;
|
||||
default:
|
||||
LOGMMCTXP(LOGL_NOTICE, mmctx,
|
||||
"Unknown GSM 04.08 discriminator 0x%02x: %s\n",
|
||||
pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
|
||||
/* FIXME: return status message */
|
||||
break;
|
||||
}
|
||||
|
||||
/* MMCTX can be invalid */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx)
|
||||
{
|
||||
struct bssgp_paging_info pinfo;
|
||||
int rc;
|
||||
|
||||
/* FIXME: page whole routing area, not only the last known cell */
|
||||
|
||||
/* initiate PS PAGING procedure */
|
||||
memset(&pinfo, 0, sizeof(pinfo));
|
||||
pinfo.mode = BSSGP_PAGING_PS;
|
||||
pinfo.scope = BSSGP_PAGING_BVCI;
|
||||
pinfo.bvci = mmctx->gb.bvci;
|
||||
pinfo.imsi = mmctx->imsi;
|
||||
pinfo.ptmsi = &mmctx->p_tmsi;
|
||||
pinfo.drx_params = mmctx->drx_parms;
|
||||
pinfo.qos[0] = 0; // FIXME
|
||||
rc = bssgp_tx_paging(mmctx->gb.nsei, 0, &pinfo);
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PAGING_PS]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* called by the bssgp layer to send NS PDUs */
|
||||
int gprs_gb_send_cb(void *ctx, struct msgb *msg)
|
||||
{
|
||||
struct gprs_ns2_inst *nsi = (struct gprs_ns2_inst *) ctx;
|
||||
struct osmo_gprs_ns2_prim nsp = {};
|
||||
nsp.nsei = msgb_nsei(msg);
|
||||
nsp.bvci = msgb_bvci(msg);
|
||||
osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg);
|
||||
return gprs_ns2_recv_prim(nsi, &nsp.oph);
|
||||
}
|
||||
|
||||
void gprs_ns_prim_status_cb(struct osmo_gprs_ns2_prim *nsp)
|
||||
{
|
||||
switch (nsp->u.status.cause) {
|
|
@ -21,7 +21,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "bscconfig.h"
|
||||
#include "config.h"
|
||||
#include <gtp.h>
|
||||
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
|
@ -37,6 +37,10 @@
|
|||
#include <osmocom/sgsn/gprs_ranap.h>
|
||||
#include <osmocom/sgsn/gprs_gmm_attach.h>
|
||||
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
|
||||
#include <osmocom/sgsn/gtp_ggsn.h>
|
||||
#include <osmocom/sgsn/gtp.h>
|
||||
#include <osmocom/sgsn/pdpctx.h>
|
||||
#include <osmocom/sgsn/mmctx.h>
|
||||
|
||||
/* Send RAB activation requests for all PDP contexts */
|
||||
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx)
|
||||
|
@ -120,7 +124,8 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
|
|||
|
||||
mm = sgsn_mm_ctx_by_ue_ctx(ctx);
|
||||
if (!mm) {
|
||||
LOGIUP(ctx, LOGL_NOTICE, "Cannot find mm ctx for IU event %d\n", type);
|
||||
LOGIUP(ctx, LOGL_NOTICE, "Cannot find mm ctx for IU event %s\n",
|
||||
ranap_iu_event_type_str(type));
|
||||
ranap_iu_free_ue(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
@ -133,10 +138,9 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
|
|||
/* fall thru */
|
||||
case RANAP_IU_EVENT_LINK_INVALIDATED:
|
||||
/* Clean up ranap_ue_conn_ctx here */
|
||||
LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi);
|
||||
if (mm->iu.mm_state_fsm->state == ST_PMM_CONNECTED)
|
||||
osmo_fsm_inst_dispatch(mm->iu.mm_state_fsm, E_PMM_PS_CONN_RELEASE, NULL);
|
||||
else
|
||||
LOGMMCTXP(LOGL_INFO, mm, "IU release (cause=%s)\n", ranap_iu_event_type_str(type));
|
||||
rc = osmo_fsm_inst_dispatch(mm->iu.mm_state_fsm, E_PMM_PS_CONN_RELEASE, NULL);
|
||||
if (rc < 0)
|
||||
sgsn_ranap_iu_free(mm);
|
||||
|
||||
/* TODO: move this into FSM */
|
||||
|
@ -145,6 +149,11 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
|
|||
rc = 0;
|
||||
break;
|
||||
case RANAP_IU_EVENT_SECURITY_MODE_COMPLETE:
|
||||
/* FIXME: verify that a permitted UEA level was chosen. Compare how osmo-msc does it in
|
||||
* msc_a_ran_dec_from_msc_i(), case RAN_MSG_CIPHER_MODE_COMPLETE.
|
||||
* We should dissolve iu_client.c, it was a design mistake when first implementing Iu support. osmo-msc
|
||||
* has moved away from it a long time ago.
|
||||
*/
|
||||
/* Continue authentication here */
|
||||
mm->iu.ue_ctx->integrity_active = 1;
|
||||
ranap_iu_tx_common_id(mm->iu.ue_ctx, mm->imsi);
|
||||
|
@ -232,7 +241,7 @@ int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
|
|||
|
||||
mmctx = sgsn_mm_ctx_by_ue_ctx(MSG_IU_UE_CTX(msg));
|
||||
if (mmctx) {
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN));
|
||||
if (ra_id)
|
||||
memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra));
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "bscconfig.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
|
@ -36,13 +36,15 @@
|
|||
#include <osmocom/sgsn/gprs_sm.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_utils.h>
|
||||
#include <osmocom/sgsn/gtp_ggsn.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
#include <osmocom/sgsn/gprs_sndcp.h>
|
||||
#include <osmocom/sgsn/gprs_ranap.h>
|
||||
|
||||
extern void *tall_sgsn_ctx;
|
||||
#include <osmocom/sgsn/gtp.h>
|
||||
#include <osmocom/sgsn/pdpctx.h>
|
||||
#include <osmocom/sgsn/mmctx.h>
|
||||
|
||||
/* 3GPP TS 04.08 sec 6.1.3.4.3(.a) "Abnormal cases" */
|
||||
#define T339X_MAX_RETRANS 4
|
||||
|
@ -186,7 +188,7 @@ int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp)
|
|||
uint8_t transaction_id = pdp->ti ^ 0x8; /* flip */
|
||||
|
||||
LOGPDPCTXP(LOGL_INFO, pdp, "<- ACTIVATE PDP CONTEXT ACK\n");
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_ACCEPT]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_ACTIVATE_ACCEPT));
|
||||
|
||||
mmctx2msgid(msg, pdp->mm);
|
||||
|
||||
|
@ -232,7 +234,7 @@ int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
|
|||
|
||||
LOGMMCTXP(LOGL_NOTICE, mm, "<- ACTIVATE PDP CONTEXT REJ: %s\n",
|
||||
get_value_string(gsm48_gsm_cause_names, cause));
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REJECT]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_ACTIVATE_REJECT));
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
|
@ -257,7 +259,7 @@ static int _gsm48_tx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, uint8_t tid,
|
|||
uint8_t tear_down_ind = (0x9 << 4) | (!!teardown);
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT REQ\n");
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_REQUEST]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_DL_DEACTIVATE_REQUEST));
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
|
@ -285,7 +287,7 @@ static int _gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mm, uint8_t tid)
|
|||
uint8_t transaction_id = tid ^ 0x8; /* flip */
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT ACK\n");
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_ACCEPT]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_DL_DEACTIVATE_ACCEPT));
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
|
@ -376,7 +378,7 @@ static void ggsn_lookup_cb(void *arg, int status, int timeouts, struct hostent *
|
|||
goto reject_due_failure;
|
||||
}
|
||||
|
||||
ggsn = sgsn_ggsn_ctx_alloc(UINT32_MAX);
|
||||
ggsn = sgsn_ggsn_ctx_alloc(sgsn, UINT32_MAX);
|
||||
if (!ggsn) {
|
||||
LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "Failed to create ggsn.\n");
|
||||
goto reject_due_failure;
|
||||
|
@ -448,7 +450,7 @@ static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *del
|
|||
DEBUGPC(DMM, "IPv4 ");
|
||||
if (req_pdpa_len >= 6) {
|
||||
struct in_addr ia;
|
||||
ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2)));
|
||||
ia.s_addr = osmo_load32be(req_pdpa+2);
|
||||
DEBUGPC(DMM, "%s ", inet_ntop(AF_INET, &ia, buf, sizeof(buf)));
|
||||
}
|
||||
break;
|
||||
|
@ -533,7 +535,7 @@ static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *del
|
|||
|
||||
/* Only increment counter for a real activation, after we checked
|
||||
* for re-transmissions */
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PDP_CTX_ACT]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PDP_CTX_ACT));
|
||||
|
||||
/* Determine GGSN based on APN and subscription options */
|
||||
ggsn = sgsn_mm_ctx_find_ggsn_ctx(mmctx, &tp, &gsm_cause, apn_str);
|
||||
|
@ -591,7 +593,7 @@ static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,
|
|||
struct msgb *msg;
|
||||
int rc;
|
||||
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REQUEST]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_ACTIVATE_REQUEST));
|
||||
|
||||
/*
|
||||
* This is painful. We might not have a static GGSN
|
||||
|
@ -629,7 +631,7 @@ static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)
|
|||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT REQ (cause: %s)\n",
|
||||
get_value_string(gsm48_gsm_cause_names, gh->data[0]));
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_REQUEST]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_UL_DEACTIVATE_REQUEST));
|
||||
|
||||
pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
|
||||
if (!pdp) {
|
||||
|
@ -654,7 +656,7 @@ static int gsm48_rx_gsm_deact_pdp_ack(struct sgsn_mm_ctx *mm, struct msgb *msg)
|
|||
struct sgsn_pdp_ctx *pdp;
|
||||
|
||||
LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT ACK\n");
|
||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_ACCEPT]);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_PDP_UL_DEACTIVATE_ACCEPT));
|
||||
|
||||
pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
|
||||
if (!pdp) {
|
||||
|
|
|
@ -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;
|
||||
expnd = decompress_segment(sne, msg, npdu, npdu_len, (unsigned int *)&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, "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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/* TS 29.060 § 7.5.14 RAN Information Management Messages */
|
||||
/*
|
||||
* (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0+
|
||||
*
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <talloc.h>
|
||||
|
||||
#include <osmocom/sgsn/gtp_mme.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
|
||||
static bool _eutran_tai_equal(const struct osmo_eutran_tai *t1, const struct osmo_eutran_tai *t2)
|
||||
{
|
||||
return t1->mcc == t2->mcc &&
|
||||
t1->mnc == t2->mnc &&
|
||||
t1->mnc_3_digits == t2->mnc_3_digits &&
|
||||
t1->tac == t2->tac;
|
||||
}
|
||||
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name)
|
||||
{
|
||||
struct sgsn_mme_ctx *mme;
|
||||
mme = talloc_zero(sgsn, struct sgsn_mme_ctx);
|
||||
if (!mme)
|
||||
return NULL;
|
||||
|
||||
/* if we are called from config file parse, this gsn doesn't exist yet */
|
||||
mme->sgsn = sgsn;
|
||||
|
||||
mme->name = talloc_strdup(mme, name);
|
||||
|
||||
INIT_LLIST_HEAD(&mme->routes);
|
||||
llist_add_tail(&mme->list, &sgsn->mme_list);
|
||||
|
||||
return mme;
|
||||
}
|
||||
|
||||
void sgsn_mme_ctx_free(struct sgsn_mme_ctx *mme)
|
||||
{
|
||||
struct mme_rim_route *rt, *rt2;
|
||||
llist_del(&mme->list);
|
||||
|
||||
llist_for_each_entry_safe(rt, rt2, &mme->routes, list) {
|
||||
llist_del(&rt->list);
|
||||
talloc_free(rt);
|
||||
}
|
||||
|
||||
talloc_free(mme);
|
||||
}
|
||||
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_find_alloc(struct sgsn_instance *sgsn, const char *name)
|
||||
{
|
||||
struct sgsn_mme_ctx *mme;
|
||||
|
||||
mme = sgsn_mme_ctx_by_name(sgsn, name);
|
||||
if (!mme)
|
||||
mme = sgsn_mme_ctx_alloc(sgsn, name);
|
||||
return mme;
|
||||
}
|
||||
|
||||
void sgsn_mme_ctx_route_add(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai)
|
||||
{
|
||||
struct mme_rim_route *rt = talloc_zero(mme, struct mme_rim_route);
|
||||
rt->tai = *tai;
|
||||
llist_add_tail(&rt->list, &mme->routes);
|
||||
}
|
||||
|
||||
void sgsn_mme_ctx_route_del(struct sgsn_mme_ctx *mme, const struct osmo_eutran_tai *tai)
|
||||
{
|
||||
struct mme_rim_route *rt;
|
||||
|
||||
llist_for_each_entry(rt, &mme->routes, list) {
|
||||
if (_eutran_tai_equal(tai, &rt->tai)) {
|
||||
llist_del(&rt->list);
|
||||
talloc_free(rt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_name(const struct sgsn_instance *sgsn, const char *name)
|
||||
{
|
||||
struct sgsn_mme_ctx *mme;
|
||||
|
||||
llist_for_each_entry(mme, &sgsn->mme_list, list) {
|
||||
if (!strcmp(name, mme->name))
|
||||
return mme;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_addr(const struct sgsn_instance *sgsn, const struct in_addr *addr)
|
||||
{
|
||||
struct sgsn_mme_ctx *mme;
|
||||
|
||||
llist_for_each_entry(mme, &sgsn->mme_list, list) {
|
||||
if (!memcmp(addr, &mme->remote_addr, sizeof(*addr)))
|
||||
return mme;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_route(const struct sgsn_instance *sgsn, const struct osmo_eutran_tai *tai)
|
||||
{
|
||||
struct sgsn_mme_ctx *mme;
|
||||
llist_for_each_entry(mme, &sgsn->mme_list, list) {
|
||||
struct mme_rim_route *rt;
|
||||
llist_for_each_entry(rt, &mme->routes, list) {
|
||||
if (_eutran_tai_equal(tai, &rt->tai)) {
|
||||
return mme;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sgsn_mme_ctx *sgsn_mme_ctx_by_default_route(const struct sgsn_instance *sgsn)
|
||||
{
|
||||
struct sgsn_mme_ctx *mme;
|
||||
|
||||
llist_for_each_entry(mme, &sgsn->mme_list, list) {
|
||||
if (mme->default_route)
|
||||
return mme;
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/* GPRS SGSN functionality */
|
||||
/* Mobility Management context */
|
||||
|
||||
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
|
@ -27,6 +27,8 @@
|
|||
#include <osmocom/core/rate_ctr.h>
|
||||
#include <osmocom/core/stats.h>
|
||||
#include <osmocom/core/backtrace.h>
|
||||
#include <osmocom/ctrl/control_if.h>
|
||||
#include <osmocom/ctrl/ports.h>
|
||||
#include <osmocom/gprs/gprs_ns2.h>
|
||||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
|
@ -36,7 +38,7 @@
|
|||
|
||||
#include <osmocom/sgsn/gprs_subscriber.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
#include <osmocom/sgsn/mmctx.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_sm.h>
|
||||
|
@ -47,22 +49,16 @@
|
|||
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
|
||||
#include <osmocom/sgsn/gprs_gmm_fsm.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
#include <osmocom/sgsn/gprs_sndcp.h>
|
||||
#include <osmocom/sgsn/gtp_ggsn.h>
|
||||
#include <osmocom/sgsn/gtp.h>
|
||||
#include <osmocom/sgsn/pdpctx.h>
|
||||
|
||||
#include <pdp.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "../../bscconfig.h"
|
||||
|
||||
#define GPRS_LLME_CHECK_TICK 30
|
||||
|
||||
extern struct sgsn_instance *sgsn;
|
||||
extern void *tall_sgsn_ctx;
|
||||
|
||||
LLIST_HEAD(sgsn_mm_ctxts);
|
||||
LLIST_HEAD(sgsn_ggsn_ctxts);
|
||||
LLIST_HEAD(sgsn_apn_ctxts);
|
||||
LLIST_HEAD(sgsn_pdp_ctxts);
|
||||
#include "../../config.h"
|
||||
|
||||
const struct value_string sgsn_ran_type_names[] = {
|
||||
{ MM_CTX_T_GERAN_Gb, "GPRS/EDGE via Gb" },
|
||||
|
@ -95,66 +91,12 @@ static const struct rate_ctr_group_desc mmctx_ctrg_desc = {
|
|||
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
|
||||
};
|
||||
|
||||
static const struct rate_ctr_desc pdpctx_ctr_description[] = {
|
||||
{ "udata:packets:in", "User Data Messages ( In)" },
|
||||
{ "udata:packets:out", "User Data Messages (Out)" },
|
||||
{ "udata:bytes:in", "User Data Bytes ( In)" },
|
||||
{ "udata:bytes:out", "User Data Bytes (Out)" },
|
||||
};
|
||||
|
||||
static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
|
||||
.group_name_prefix = "sgsn:pdpctx",
|
||||
.group_description = "SGSN PDP Context Statistics",
|
||||
.num_ctr = ARRAY_SIZE(pdpctx_ctr_description),
|
||||
.ctr_desc = pdpctx_ctr_description,
|
||||
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
|
||||
};
|
||||
|
||||
static const struct rate_ctr_desc sgsn_ctr_description[] = {
|
||||
{ "llc:dl_bytes", "Count sent LLC bytes before giving it to the bssgp layer" },
|
||||
{ "llc:ul_bytes", "Count successful received LLC bytes (encrypt & fcs correct)" },
|
||||
{ "llc:dl_packets", "Count successful sent LLC packets before giving it to the bssgp layer" },
|
||||
{ "llc:ul_packets", "Count successful received LLC packets (encrypt & fcs correct)" },
|
||||
{ "gprs:attach_requested", "Received attach requests" },
|
||||
{ "gprs:attach_accepted", "Sent attach accepts" },
|
||||
{ "gprs:attach_rejected", "Sent attach rejects" },
|
||||
{ "gprs:detach_requested", "Received detach requests" },
|
||||
{ "gprs:detach_acked", "Sent detach acks" },
|
||||
{ "gprs:routing_area_requested", "Received routing area requests" },
|
||||
{ "gprs:routing_area_requested", "Sent routing area acks" },
|
||||
{ "gprs:routing_area_requested", "Sent routing area rejects" },
|
||||
{ "pdp:activate_requested", "Received activate requests" },
|
||||
{ "pdp:activate_rejected", "Sent activate rejects" },
|
||||
{ "pdp:activate_accepted", "Sent activate accepts" },
|
||||
{ "pdp:request_activated", "unused" },
|
||||
{ "pdp:request_activate_rejected", "unused" },
|
||||
{ "pdp:modify_requested", "unused" },
|
||||
{ "pdp:modify_accepted", "unused" },
|
||||
{ "pdp:dl_deactivate_requested", "Sent deactivate requests" },
|
||||
{ "pdp:dl_deactivate_accepted", "Sent deactivate accepted" },
|
||||
{ "pdp:ul_deactivate_requested", "Received deactivate requests" },
|
||||
{ "pdp:ul_deactivate_accepted", "Received deactivate accepts" },
|
||||
};
|
||||
|
||||
static const struct rate_ctr_group_desc sgsn_ctrg_desc = {
|
||||
"sgsn",
|
||||
"SGSN Overall Statistics",
|
||||
OSMO_STATS_CLASS_GLOBAL,
|
||||
ARRAY_SIZE(sgsn_ctr_description),
|
||||
sgsn_ctr_description,
|
||||
};
|
||||
|
||||
void sgsn_rate_ctr_init() {
|
||||
sgsn->rate_ctrs = rate_ctr_group_alloc(tall_sgsn_ctx, &sgsn_ctrg_desc, 0);
|
||||
OSMO_ASSERT(sgsn->rate_ctrs);
|
||||
}
|
||||
|
||||
/* look-up an SGSN MM context based on Iu UE context (struct ue_conn_ctx)*/
|
||||
struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx)
|
||||
{
|
||||
struct sgsn_mm_ctx *ctx;
|
||||
|
||||
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
|
||||
llist_for_each_entry(ctx, &sgsn->mm_list, list) {
|
||||
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu
|
||||
&& uectx == ctx->iu.ue_ctx)
|
||||
return ctx;
|
||||
|
@ -169,7 +111,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
|
|||
{
|
||||
struct sgsn_mm_ctx *ctx;
|
||||
|
||||
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
|
||||
llist_for_each_entry(ctx, &sgsn->mm_list, list) {
|
||||
if ((tlli == ctx->gb.tlli || tlli == ctx->gb.tlli_new) &&
|
||||
gprs_ra_id_equals(raid, &ctx->ra))
|
||||
return ctx;
|
||||
|
@ -193,7 +135,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
|
|||
if (tlli_type != TLLI_FOREIGN && tlli_type != TLLI_LOCAL)
|
||||
return NULL;
|
||||
|
||||
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
|
||||
llist_for_each_entry(ctx, &sgsn->mm_list, list) {
|
||||
if ((gprs_tmsi2tlli(ctx->p_tmsi, tlli_type) == tlli ||
|
||||
gprs_tmsi2tlli(ctx->p_tmsi_old, tlli_type) == tlli) &&
|
||||
gprs_ra_id_equals(raid, &ctx->ra))
|
||||
|
@ -207,7 +149,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t p_tmsi)
|
|||
{
|
||||
struct sgsn_mm_ctx *ctx;
|
||||
|
||||
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
|
||||
llist_for_each_entry(ctx, &sgsn->mm_list, list) {
|
||||
if (p_tmsi == ctx->p_tmsi ||
|
||||
(ctx->p_tmsi_old && ctx->p_tmsi_old == p_tmsi))
|
||||
return ctx;
|
||||
|
@ -219,7 +161,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi)
|
|||
{
|
||||
struct sgsn_mm_ctx *ctx;
|
||||
|
||||
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
|
||||
llist_for_each_entry(ctx, &sgsn->mm_list, list) {
|
||||
if (!strcmp(imsi, ctx->imsi))
|
||||
return ctx;
|
||||
}
|
||||
|
@ -261,7 +203,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t rate_ctr_id)
|
|||
|
||||
INIT_LLIST_HEAD(&ctx->pdp_list);
|
||||
|
||||
llist_add(&ctx->list, &sgsn_mm_ctxts);
|
||||
llist_add(&ctx->list, &sgsn->mm_list);
|
||||
|
||||
return ctx;
|
||||
|
||||
|
@ -293,11 +235,8 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
|
|||
memcpy(&ctx->ra, raid, sizeof(ctx->ra));
|
||||
ctx->ran_type = MM_CTX_T_GERAN_Gb;
|
||||
ctx->gb.tlli = tlli;
|
||||
ctx->ciph_algo = sgsn->cfg.cipher;
|
||||
osmo_fsm_inst_update_id_f(ctx->gb.mm_state_fsm, "%" PRIu32, tlli);
|
||||
|
||||
LOGMMCTXP(LOGL_DEBUG, ctx, "Allocated with %s cipher.\n",
|
||||
get_value_string(gprs_cipher_names, ctx->ciph_algo));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
@ -435,288 +374,6 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* you don't want to use this directly, call sgsn_create_pdp_ctx() */
|
||||
struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
|
||||
struct sgsn_ggsn_ctx *ggsn,
|
||||
uint8_t nsapi)
|
||||
{
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
|
||||
pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi);
|
||||
if (pdp)
|
||||
return NULL;
|
||||
|
||||
pdp = talloc_zero(tall_sgsn_ctx, struct sgsn_pdp_ctx);
|
||||
if (!pdp)
|
||||
return NULL;
|
||||
|
||||
pdp->mm = mm;
|
||||
pdp->ggsn = ggsn;
|
||||
pdp->nsapi = nsapi;
|
||||
pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi);
|
||||
if (!pdp->ctrg) {
|
||||
LOGPDPCTXP(LOGL_ERROR, pdp, "Error allocation counter group\n");
|
||||
talloc_free(pdp);
|
||||
return NULL;
|
||||
}
|
||||
llist_add(&pdp->list, &mm->pdp_list);
|
||||
sgsn_ggsn_ctx_add_pdp(pdp->ggsn, pdp);
|
||||
llist_add(&pdp->g_list, &sgsn_pdp_ctxts);
|
||||
|
||||
return pdp;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will not trigger any GSM DEACT PDP ACK messages, so you
|
||||
* probably want to call sgsn_delete_pdp_ctx() instead if the connection
|
||||
* isn't detached already.
|
||||
*/
|
||||
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
struct sgsn_signal_data sig_data;
|
||||
|
||||
OSMO_ASSERT(pdp->mm != NULL);
|
||||
|
||||
/* There might still be pending callbacks in libgtp. So the parts of
|
||||
* this object relevant to GTP need to remain intact in this case. */
|
||||
|
||||
LOGPDPCTXP(LOGL_INFO, pdp, "Forcing release of PDP context\n");
|
||||
|
||||
if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||
/* Force the deactivation of the SNDCP layer */
|
||||
if (pdp->mm->gb.llme)
|
||||
sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi);
|
||||
}
|
||||
|
||||
memset(&sig_data, 0, sizeof(sig_data));
|
||||
sig_data.pdp = pdp;
|
||||
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_TERMINATE, &sig_data);
|
||||
|
||||
/* Detach from MM context */
|
||||
pdp_ctx_detach_mm_ctx(pdp);
|
||||
if (pdp->ggsn)
|
||||
sgsn_delete_pdp_ctx(pdp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't call this function directly unless you know what you are doing.
|
||||
* In normal conditions use sgsn_delete_pdp_ctx and in unspecified or
|
||||
* implementation dependent abnormal ones sgsn_pdp_ctx_terminate.
|
||||
*/
|
||||
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
struct sgsn_signal_data sig_data;
|
||||
|
||||
memset(&sig_data, 0, sizeof(sig_data));
|
||||
sig_data.pdp = pdp;
|
||||
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data);
|
||||
|
||||
if (osmo_timer_pending(&pdp->timer)) {
|
||||
LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T);
|
||||
osmo_timer_del(&pdp->timer);
|
||||
}
|
||||
|
||||
rate_ctr_group_free(pdp->ctrg);
|
||||
if (pdp->mm)
|
||||
llist_del(&pdp->list);
|
||||
if (pdp->ggsn)
|
||||
sgsn_ggsn_ctx_remove_pdp(pdp->ggsn, pdp);
|
||||
llist_del(&pdp->g_list);
|
||||
|
||||
/* _if_ we still have a library handle, at least set it to NULL
|
||||
* to avoid any dereferences of the now-deleted PDP context from
|
||||
* sgsn_libgtp:cb_data_ind() */
|
||||
if (pdp->lib) {
|
||||
struct pdp_t *lib = pdp->lib;
|
||||
LOGPDPCTXP(LOGL_NOTICE, pdp, "freeing PDP context that still "
|
||||
"has a libgtp handle attached to it, this shouldn't "
|
||||
"happen!\n");
|
||||
osmo_generate_backtrace();
|
||||
lib->priv = NULL;
|
||||
}
|
||||
|
||||
talloc_free(pdp);
|
||||
}
|
||||
|
||||
void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc)
|
||||
{
|
||||
bool pending = osmo_timer_pending(&ggc->echo_timer);
|
||||
|
||||
/* Only enable if allowed by policy and at least 1 pdp ctx exists against ggsn */
|
||||
if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval) {
|
||||
if (!pending)
|
||||
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
|
||||
} else {
|
||||
if (pending)
|
||||
osmo_timer_del(&ggc->echo_timer);
|
||||
}
|
||||
}
|
||||
|
||||
/* GGSN contexts */
|
||||
static void echo_timer_cb(void *data)
|
||||
{
|
||||
struct sgsn_ggsn_ctx *ggc = (struct sgsn_ggsn_ctx *) data;
|
||||
sgsn_ggsn_echo_req(ggc);
|
||||
osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0);
|
||||
}
|
||||
|
||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id)
|
||||
{
|
||||
struct sgsn_ggsn_ctx *ggc;
|
||||
|
||||
ggc = talloc_zero(tall_sgsn_ctx, struct sgsn_ggsn_ctx);
|
||||
if (!ggc)
|
||||
return NULL;
|
||||
|
||||
ggc->id = id;
|
||||
ggc->gtp_version = 1;
|
||||
ggc->remote_restart_ctr = -1;
|
||||
/* if we are called from config file parse, this gsn doesn't exist yet */
|
||||
ggc->gsn = sgsn->gsn;
|
||||
INIT_LLIST_HEAD(&ggc->pdp_list);
|
||||
osmo_timer_setup(&ggc->echo_timer, echo_timer_cb, ggc);
|
||||
llist_add(&ggc->list, &sgsn_ggsn_ctxts);
|
||||
|
||||
return ggc;
|
||||
}
|
||||
|
||||
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc)
|
||||
{
|
||||
OSMO_ASSERT(llist_empty(&ggc->pdp_list));
|
||||
llist_del(&ggc->list);
|
||||
talloc_free(ggc);
|
||||
}
|
||||
|
||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id)
|
||||
{
|
||||
struct sgsn_ggsn_ctx *ggc;
|
||||
|
||||
llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
|
||||
if (id == ggc->id)
|
||||
return ggc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr)
|
||||
{
|
||||
struct sgsn_ggsn_ctx *ggc;
|
||||
|
||||
llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
|
||||
if (!memcmp(addr, &ggc->remote_addr, sizeof(*addr)))
|
||||
return ggc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id)
|
||||
{
|
||||
struct sgsn_ggsn_ctx *ggc;
|
||||
|
||||
ggc = sgsn_ggsn_ctx_by_id(id);
|
||||
if (!ggc)
|
||||
ggc = sgsn_ggsn_ctx_alloc(id);
|
||||
return ggc;
|
||||
}
|
||||
|
||||
/* APN contexts */
|
||||
|
||||
static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix)
|
||||
{
|
||||
struct apn_ctx *actx;
|
||||
|
||||
actx = talloc_zero(tall_sgsn_ctx, struct apn_ctx);
|
||||
if (!actx)
|
||||
return NULL;
|
||||
actx->name = talloc_strdup(actx, ap_name);
|
||||
actx->imsi_prefix = talloc_strdup(actx, imsi_prefix);
|
||||
|
||||
llist_add_tail(&actx->list, &sgsn_apn_ctxts);
|
||||
|
||||
return actx;
|
||||
}
|
||||
|
||||
void sgsn_apn_ctx_free(struct apn_ctx *actx)
|
||||
{
|
||||
llist_del(&actx->list);
|
||||
talloc_free(actx);
|
||||
}
|
||||
|
||||
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi)
|
||||
{
|
||||
struct apn_ctx *actx;
|
||||
struct apn_ctx *found_actx = NULL;
|
||||
size_t imsi_prio = 0;
|
||||
size_t name_prio = 0;
|
||||
size_t name_req_len = strlen(name);
|
||||
|
||||
llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
|
||||
size_t name_ref_len, imsi_ref_len;
|
||||
const char *name_ref_start, *name_match_start;
|
||||
|
||||
imsi_ref_len = strlen(actx->imsi_prefix);
|
||||
if (strncmp(actx->imsi_prefix, imsi, imsi_ref_len) != 0)
|
||||
continue;
|
||||
|
||||
if (imsi_ref_len < imsi_prio)
|
||||
continue;
|
||||
|
||||
/* IMSI matches */
|
||||
|
||||
name_ref_start = &actx->name[0];
|
||||
if (name_ref_start[0] == '*') {
|
||||
/* Suffix match */
|
||||
name_ref_start += 1;
|
||||
name_ref_len = strlen(name_ref_start);
|
||||
if (name_ref_len > name_req_len)
|
||||
continue;
|
||||
} else {
|
||||
name_ref_len = strlen(name_ref_start);
|
||||
if (name_ref_len != name_req_len)
|
||||
continue;
|
||||
}
|
||||
|
||||
name_match_start = name + (name_req_len - name_ref_len);
|
||||
if (strcasecmp(name_match_start, name_ref_start) != 0)
|
||||
continue;
|
||||
|
||||
/* IMSI and name match */
|
||||
|
||||
if (imsi_ref_len == imsi_prio && name_ref_len < name_prio)
|
||||
/* Lower priority, skip */
|
||||
continue;
|
||||
|
||||
imsi_prio = imsi_ref_len;
|
||||
name_prio = name_ref_len;
|
||||
found_actx = actx;
|
||||
}
|
||||
return found_actx;
|
||||
}
|
||||
|
||||
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix)
|
||||
{
|
||||
struct apn_ctx *actx;
|
||||
|
||||
llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
|
||||
if (strcasecmp(name, actx->name) == 0 &&
|
||||
strcasecmp(imsi_prefix, actx->imsi_prefix) == 0)
|
||||
return actx;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix)
|
||||
{
|
||||
struct apn_ctx *actx;
|
||||
|
||||
actx = sgsn_apn_ctx_by_name(name, imsi_prefix);
|
||||
if (!actx)
|
||||
actx = sgsn_apn_ctx_alloc(name, imsi_prefix);
|
||||
|
||||
return actx;
|
||||
}
|
||||
|
||||
uint32_t sgsn_alloc_ptmsi(void)
|
||||
{
|
||||
struct sgsn_mm_ctx *mm;
|
||||
|
@ -752,7 +409,7 @@ restart:
|
|||
goto restart;
|
||||
}
|
||||
|
||||
llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
|
||||
llist_for_each_entry(mm, &sgsn->mm_list, list) {
|
||||
if (mm->p_tmsi == ptmsi) {
|
||||
if (!max_retries--)
|
||||
goto failed;
|
||||
|
@ -767,64 +424,6 @@ failed:
|
|||
return GSM_RESERVED_TMSI;
|
||||
}
|
||||
|
||||
void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx)
|
||||
{
|
||||
/* the MM context can be deleted while the GGSN is not reachable or
|
||||
* if has been crashed. */
|
||||
if (pctx->mm && pctx->mm->gmm_fsm->state == ST_GMM_REGISTERED_NORMAL) {
|
||||
gsm48_tx_gsm_deact_pdp_req(pctx, GSM_CAUSE_NET_FAIL, true);
|
||||
sgsn_ggsn_ctx_remove_pdp(pctx->ggsn, pctx);
|
||||
} else {
|
||||
/* FIXME: GPRS paging in case MS is SUSPENDED */
|
||||
LOGPDPCTXP(LOGL_NOTICE, pctx, "Hard-dropping PDP ctx due to GGSN "
|
||||
"recovery\n");
|
||||
/* FIXME: how to tell this to libgtp? */
|
||||
sgsn_pdp_ctx_free(pctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* High-level function to be called in case a GGSN has disappeared or
|
||||
* otherwise lost state (recovery procedure). It will detach all related pdp ctx
|
||||
* from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can
|
||||
* be kept alive to allow handling later message which contained the Recovery IE. */
|
||||
int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
struct sgsn_pdp_ctx *pdp, *pdp2;
|
||||
llist_for_each_entry_safe(pdp, pdp2, &ggsn->pdp_list, ggsn_list) {
|
||||
if (pdp == except)
|
||||
continue;
|
||||
sgsn_ggsn_ctx_drop_pdp(pdp);
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn)
|
||||
{
|
||||
return sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, NULL);
|
||||
}
|
||||
|
||||
void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
llist_add(&pdp->ggsn_list, &ggc->pdp_list);
|
||||
sgsn_ggsn_ctx_check_echo_timer(ggc);
|
||||
}
|
||||
void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
llist_del(&pdp->ggsn_list);
|
||||
sgsn_ggsn_ctx_check_echo_timer(ggc);
|
||||
if (pdp->destroy_ggsn)
|
||||
sgsn_ggsn_ctx_free(pdp->ggsn);
|
||||
pdp->ggsn = NULL;
|
||||
/* Drop references to libgtp since the conn is down */
|
||||
if (pdp->lib)
|
||||
pdp_freepdp(pdp->lib);
|
||||
pdp->lib = NULL;
|
||||
}
|
||||
|
||||
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
|
||||
{
|
||||
OSMO_ASSERT(mmctx != NULL);
|
||||
|
@ -899,7 +498,7 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
|
|||
insert_extra(tp, mmctx->subscr->sgsn_data, pdp);
|
||||
continue;
|
||||
}
|
||||
if (!llist_empty(&sgsn_apn_ctxts)) {
|
||||
if (!llist_empty(&sgsn->apn_list)) {
|
||||
apn_ctx = sgsn_apn_ctx_match(req_apn_str, mmctx->imsi);
|
||||
/* Not configured */
|
||||
if (apn_ctx == NULL)
|
||||
|
@ -952,13 +551,13 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
|
|||
|
||||
if (apn_ctx != NULL) {
|
||||
ggsn = apn_ctx->ggsn;
|
||||
} else if (llist_empty(&sgsn_apn_ctxts)) {
|
||||
} else if (llist_empty(&sgsn->apn_list)) {
|
||||
/* No configuration -> use GGSN 0 */
|
||||
ggsn = sgsn_ggsn_ctx_by_id(0);
|
||||
ggsn = sgsn_ggsn_ctx_by_id(sgsn, 0);
|
||||
} else if (allow_any_apn &&
|
||||
(selected_apn_str == NULL || strlen(selected_apn_str) == 0)) {
|
||||
/* No APN given and no default configuration -> Use GGSN 0 */
|
||||
ggsn = sgsn_ggsn_ctx_by_id(0);
|
||||
ggsn = sgsn_ggsn_ctx_by_id(sgsn, 0);
|
||||
} else {
|
||||
/* No matching configuration found */
|
||||
LOGMMCTXP(LOGL_NOTICE, mmctx,
|
||||
|
@ -983,70 +582,3 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
|
|||
|
||||
return ggsn;
|
||||
}
|
||||
|
||||
static void sgsn_llme_cleanup_free(struct gprs_llc_llme *llme)
|
||||
{
|
||||
struct sgsn_mm_ctx *mmctx = NULL;
|
||||
|
||||
llist_for_each_entry(mmctx, &sgsn_mm_ctxts, list) {
|
||||
if (llme == mmctx->gb.llme) {
|
||||
gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* No MM context found */
|
||||
LOGP(DGPRS, LOGL_INFO, "Deleting orphaned LLME, TLLI 0x%08x\n",
|
||||
llme->tlli);
|
||||
gprs_llgmm_unassign(llme);
|
||||
}
|
||||
|
||||
static void sgsn_llme_check_cb(void *data_)
|
||||
{
|
||||
struct gprs_llc_llme *llme, *llme_tmp;
|
||||
struct timespec now_tp;
|
||||
time_t now, age;
|
||||
time_t max_age = gprs_max_time_to_idle();
|
||||
|
||||
int rc;
|
||||
|
||||
rc = osmo_clock_gettime(CLOCK_MONOTONIC, &now_tp);
|
||||
OSMO_ASSERT(rc >= 0);
|
||||
now = now_tp.tv_sec;
|
||||
|
||||
LOGP(DGPRS, LOGL_DEBUG,
|
||||
"Checking for inactive LLMEs, time = %u\n", (unsigned)now);
|
||||
|
||||
llist_for_each_entry_safe(llme, llme_tmp, &gprs_llc_llmes, list) {
|
||||
if (llme->age_timestamp == GPRS_LLME_RESET_AGE)
|
||||
llme->age_timestamp = now;
|
||||
|
||||
age = now - llme->age_timestamp;
|
||||
|
||||
if (age > max_age || age < 0) {
|
||||
LOGP(DGPRS, LOGL_INFO,
|
||||
"Inactivity timeout for TLLI 0x%08x, age %d\n",
|
||||
llme->tlli, (int)age);
|
||||
sgsn_llme_cleanup_free(llme);
|
||||
}
|
||||
}
|
||||
|
||||
osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
|
||||
}
|
||||
|
||||
struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx)
|
||||
{
|
||||
struct sgsn_instance *inst;
|
||||
inst = talloc_zero(talloc_ctx, struct sgsn_instance);
|
||||
inst->cfg.gtp_statedir = talloc_strdup(inst, "./");
|
||||
inst->cfg.auth_policy = SGSN_AUTH_POLICY_CLOSED;
|
||||
inst->cfg.require_authentication = true; /* only applies if auth_policy is REMOTE */
|
||||
inst->cfg.gsup_server_port = OSMO_GSUP_PORT;
|
||||
return inst;
|
||||
}
|
||||
|
||||
void sgsn_inst_init(struct sgsn_instance *sgsn)
|
||||
{
|
||||
osmo_timer_setup(&sgsn->llme_timer, sgsn_llme_check_cb, NULL);
|
||||
osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
/* 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/crypt/gprs_cipher.h>
|
||||
#include <osmocom/crypt/utran_cipher.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.gea_encryption_mask = (1 << GPRS_ALGO_GEA0); /* no encryption */
|
||||
inst->cfg.uea_encryption_mask = (1 << OSMO_UTRAN_UEA2) | (1 << OSMO_UTRAN_UEA1);
|
||||
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;
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "bscconfig.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/select.h>
|
||||
|
@ -45,9 +45,9 @@
|
|||
#include <osmocom/sgsn/signal.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_gb.h>
|
||||
#include <osmocom/sgsn/gprs_ns.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
#include <osmocom/sgsn/mmctx.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_sm.h>
|
||||
#include <osmocom/sgsn/gprs_subscriber.h>
|
||||
|
@ -55,6 +55,11 @@
|
|||
#include <osmocom/sgsn/gprs_ranap.h>
|
||||
#include <osmocom/sgsn/gprs_gmm_fsm.h>
|
||||
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
|
||||
#include <osmocom/sgsn/gtp_ggsn.h>
|
||||
#include <osmocom/sgsn/gtp_mme.h>
|
||||
#include <osmocom/sgsn/sgsn_rim.h>
|
||||
#include <osmocom/sgsn/gprs_bssgp.h>
|
||||
#include <osmocom/sgsn/pdpctx.h>
|
||||
|
||||
#include <gtp.h>
|
||||
#include <pdp.h>
|
||||
|
@ -226,18 +231,11 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
|
|||
qos = TLVP_VAL(tp, OSMO_IE_GSM_REQ_QOS);
|
||||
}
|
||||
|
||||
if (qos_len <= 3) {
|
||||
pdp->qos_req.l = qos_len + 1;
|
||||
if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
|
||||
pdp->qos_req.l = sizeof(pdp->qos_req.v);
|
||||
pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */
|
||||
memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1);
|
||||
} else {
|
||||
pdp->qos_req.l = qos_len;
|
||||
if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
|
||||
pdp->qos_req.l = sizeof(pdp->qos_req.v);
|
||||
memcpy(pdp->qos_req.v, qos, pdp->qos_req.l);
|
||||
}
|
||||
pdp->qos_req.l = qos_len + 1;
|
||||
if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
|
||||
pdp->qos_req.l = sizeof(pdp->qos_req.v);
|
||||
pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */
|
||||
memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1);
|
||||
|
||||
/* charging characteristics if present */
|
||||
if (TLVP_LEN(tp, OSMO_IE_GSM_CHARG_CHAR) >= sizeof(pdp->cch_pdp))
|
||||
|
@ -419,7 +417,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
|||
}
|
||||
|
||||
/* Check for cause value if it was really successful */
|
||||
if (cause != GTPCAUSE_ACC_REQ) {
|
||||
if (!gtp_cause_successful(cause)) {
|
||||
reject_cause = cause_map(gtp2sm_cause_map, cause,
|
||||
GSM_CAUSE_ACT_REJ_GGSN);
|
||||
goto reject;
|
||||
|
@ -479,6 +477,70 @@ void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc)
|
|||
gtp_echo_req(ggc->gsn, ggc->gtp_version, ggc, &ggc->remote_addr);
|
||||
}
|
||||
|
||||
int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu)
|
||||
{
|
||||
char ri_src_str[64], ri_dest_str[64];
|
||||
int ri_len;
|
||||
struct msgb *msg;
|
||||
struct bssgp_normal_hdr *bgph;
|
||||
int rc;
|
||||
uint8_t ri_buf[64];
|
||||
uint8_t *ri_ptr = &ri_buf[0];
|
||||
struct sockaddr_in sk_in = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htons(GTP1C_PORT),
|
||||
.sin_addr = mme->remote_addr,
|
||||
};
|
||||
|
||||
msg = bssgp_encode_rim_pdu(pdu);
|
||||
if (!msg) {
|
||||
LOGMME(mme, DRIM, LOGL_ERROR, "Tx GTP RAN Information Relay: failed to encode pdu\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
|
||||
DEBUGP(DLBSSGP, "Tx GTP RAN Information Relay: RIM-PDU:%s, src=%s, dest=%s\n",
|
||||
bssgp_pdu_str(bgph->pdu_type),
|
||||
bssgp_rim_ri_name_buf(ri_src_str, sizeof(ri_src_str), &pdu->routing_info_src),
|
||||
bssgp_rim_ri_name_buf(ri_dest_str, sizeof(ri_dest_str), &pdu->routing_info_dest));
|
||||
|
||||
if ((ri_len = bssgp_create_rim_ri(ri_ptr, &pdu->routing_info_dest)) < 0) {
|
||||
ri_ptr = NULL;
|
||||
ri_len = 0;
|
||||
}
|
||||
|
||||
rc = gtp_ran_info_relay_req(mme->sgsn->gsn, &sk_in, msgb_data(msg), msgb_length(msg),
|
||||
ri_ptr, ri_len, pdu->routing_info_dest.discr);
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Confirmation of a PDP Context Update */
|
||||
static int update_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
{
|
||||
struct sgsn_pdp_ctx *pctx = cbp;
|
||||
int rc;
|
||||
|
||||
LOGPDPCTXP(LOGL_INFO, pctx, "Received Update PDP CTX CONF, cause=%d(%s)\n",
|
||||
cause, get_value_string(gtp_cause_strs, cause));
|
||||
|
||||
/* 3GPP TS 29.060 "7.3.4":
|
||||
* "If the SGSN receives an Update PDP Context Response with a Cause
|
||||
* value other than "Request accepted", it shall abort the update of the
|
||||
* PDP context.""
|
||||
* "If the SGSN receives an Update PDP Context Response with
|
||||
* a Cause value "Non-existent", it shall delete the PDP Context."
|
||||
*/
|
||||
if (cause != GTPCAUSE_NON_EXIST)
|
||||
return 0; /* Nothing to do */
|
||||
|
||||
LOGPDPCTXP(LOGL_INFO, pctx, "PDP CTX we tried to update doesn't exist in "
|
||||
"the GGSN anymore, deleting it locally.\n");
|
||||
|
||||
rc = gtp_freepdp(pctx->ggsn->gsn, pctx->lib);
|
||||
/* related mmctx is torn down in cb_delete_context called by gtp_freepdp() */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Confirmation of a PDP Context Delete */
|
||||
static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
{
|
||||
|
@ -534,12 +596,12 @@ static int echo_conf(void *cbp, bool timeout)
|
|||
}
|
||||
|
||||
/* Any message received by GGSN contains a recovery IE */
|
||||
static int cb_recovery2(struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery)
|
||||
static int cb_recovery3(struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery)
|
||||
{
|
||||
struct sgsn_ggsn_ctx *ggsn;
|
||||
struct sgsn_pdp_ctx *pctx = NULL;
|
||||
|
||||
ggsn = sgsn_ggsn_ctx_by_addr(&peer->sin_addr);
|
||||
ggsn = sgsn_ggsn_ctx_by_addr(sgsn, &peer->sin_addr);
|
||||
if (!ggsn) {
|
||||
LOGP(DGPRS, LOGL_NOTICE, "Received Recovery IE for unknown GGSN\n");
|
||||
return -EINVAL;
|
||||
|
@ -577,6 +639,8 @@ static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp)
|
|||
return echo_conf(cbp, cause == EOF);
|
||||
case GTP_CREATE_PDP_REQ:
|
||||
return create_pdp_conf(pdp, cbp, cause);
|
||||
case GTP_UPDATE_PDP_REQ:
|
||||
return update_pdp_conf(pdp, cbp, cause);
|
||||
case GTP_DELETE_PDP_REQ:
|
||||
return delete_pdp_conf(pdp, cbp, cause);
|
||||
default:
|
||||
|
@ -619,6 +683,74 @@ static int cb_extheader_ind(struct sockaddr_in *peer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cb_gtp_ran_info_relay_ind(struct sockaddr_in *peer, union gtpie_member **ie)
|
||||
{
|
||||
char addrbuf[INET_ADDRSTRLEN];
|
||||
struct sgsn_mme_ctx *mme = sgsn_mme_ctx_by_addr(sgsn, &peer->sin_addr);
|
||||
if (!mme) {
|
||||
LOGP(DGTP, LOGL_NOTICE, "Rx GTP RAN Information Relay from unknown MME %s\n",
|
||||
inet_ntop(AF_INET, &peer->sin_addr, addrbuf, sizeof(addrbuf)));
|
||||
return -ECONNREFUSED;
|
||||
}
|
||||
|
||||
LOGMME(mme, DGTP, LOGL_INFO, "Rx GTP RAN Information Relay\n");
|
||||
|
||||
int rc;
|
||||
unsigned int len = 0;
|
||||
struct msgb *msg = bssgp_msgb_alloc();
|
||||
|
||||
uint8_t rim_ra_encoded[256];
|
||||
unsigned int rim_ra_encoded_len = 0;
|
||||
struct bssgp_rim_routing_info rim_ra;
|
||||
|
||||
unsigned int rim_ra_discr_encoded_len = 0;
|
||||
uint8_t rim_ra_discr;
|
||||
|
||||
/* Read RIM Routing Address Discriminator (optional) */
|
||||
rc = gtpie_gettlv(ie, GTPIE_RIM_RA_DISCR, 0, &rim_ra_discr_encoded_len, &rim_ra_discr,
|
||||
sizeof(rim_ra_discr));
|
||||
if (rc || rim_ra_discr_encoded_len <= 0) {
|
||||
LOGMME(mme, DGTP, LOGL_NOTICE, "Rx GTP RAN Information Relay: No RIM Routing Address Discriminator IE found!\n");
|
||||
|
||||
/* It is not an error when the RIM ROUTING ADDRESS DISCRIMINATOR IE is missing. The RIM ROUTING ADDRESS
|
||||
* DISCRIMINATOR IE is an optional IE. When it is missing, the RIM Routing Address shall be processed
|
||||
* as an RNC address ("0001") See also: 3GPP TS 29.060 */
|
||||
rim_ra_discr = BSSGP_RIM_ROUTING_INFO_UTRAN;
|
||||
}
|
||||
|
||||
/* Read RIM Routing Address (optional) */
|
||||
rc = gtpie_gettlv(ie, GTPIE_RIM_ROUT_ADDR, 0, &rim_ra_encoded_len, rim_ra_encoded, sizeof(rim_ra_encoded));
|
||||
if (rc || rim_ra_encoded_len <= 0) {
|
||||
LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: No RIM Routing Address IE found!\n");
|
||||
|
||||
/* TODO: The (usually included) RIM ROUTING ADDRESS field is an optional field. However, we cannot
|
||||
* proceed without a destination address. A possible way to fix this would be a default route that
|
||||
* can be configured via the VTY. */
|
||||
goto ret_error;
|
||||
} else {
|
||||
rc = bssgp_parse_rim_ra(&rim_ra, rim_ra_encoded, rim_ra_encoded_len, rim_ra_discr);
|
||||
if (rc < 0) {
|
||||
LOGMME(mme, DGTP, LOGL_ERROR,
|
||||
"Rx GTP RAN Information Relay: Failed parsing RIM Routing Address/RIM Routing Address Discriminator IE!\n");
|
||||
goto ret_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (gtpie_gettlv(ie, GTPIE_RAN_T_CONTAIN, 0, &len, msgb_data(msg), 4096) || len <= 0) {
|
||||
LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: No Transparent Container IE found!\n");
|
||||
goto ret_error;
|
||||
}
|
||||
msgb_put(msg, len);
|
||||
msgb_bssgph(msg) = msg->data;
|
||||
msgb_nsei(msg) = 0;
|
||||
|
||||
return sgsn_rim_rx_from_gtp(msg, &rim_ra);
|
||||
|
||||
ret_error:
|
||||
msgb_free(msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Called whenever we receive a DATA packet */
|
||||
static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
||||
{
|
||||
|
@ -671,15 +803,24 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
|||
msgb_free(msg);
|
||||
return -1;
|
||||
case ST_GMM_REGISTERED_NORMAL:
|
||||
OSMO_ASSERT(mm->gb.mm_state_fsm->state != ST_MM_IDLE);
|
||||
if (mm->gb.mm_state_fsm->state == ST_MM_STANDBY) {
|
||||
switch (mm->gb.mm_state_fsm->state) {
|
||||
case ST_MM_IDLE:
|
||||
LOGP(DGPRS, LOGL_ERROR, "Dropping DL packet for MS in MM state %s\n",
|
||||
osmo_fsm_inst_state_name(mm->gb.mm_state_fsm));
|
||||
msgb_free(msg);
|
||||
return -1;
|
||||
case ST_MM_READY:
|
||||
/* Go ahead */
|
||||
break;
|
||||
case ST_MM_STANDBY:
|
||||
LOGMMCTXP(LOGL_INFO, mm, "Paging MS in GMM state %s, MM state %s\n",
|
||||
osmo_fsm_inst_state_name(mm->gmm_fsm),
|
||||
osmo_fsm_inst_state_name(mm->gb.mm_state_fsm));
|
||||
gprs_gb_page_ps_ra(mm);
|
||||
}
|
||||
sgsn_bssgp_page_ps_ra(mm);
|
||||
|
||||
/* FIXME: queue the packet we received from GTP */
|
||||
/* FIXME: queue the packet we received from GTP */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state "
|
||||
|
@ -688,20 +829,20 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
|||
return -1;
|
||||
}
|
||||
|
||||
rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_OUT]);
|
||||
rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_OUT], len);
|
||||
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_UDATA_OUT]);
|
||||
rate_ctr_add(&mm->ctrg->ctr[GMM_CTR_BYTES_UDATA_OUT], len);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_PKTS_UDATA_OUT));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_BYTES_UDATA_OUT), len);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_PKTS_UDATA_OUT));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(mm->ctrg, GMM_CTR_BYTES_UDATA_OUT), len);
|
||||
|
||||
/* It is easier to have a global count */
|
||||
pdp->cdr_bytes_out += len;
|
||||
|
||||
return sndcp_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi],
|
||||
return sndcp_sn_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi],
|
||||
pdp->nsapi, mm);
|
||||
}
|
||||
|
||||
/* Called by SNDCP when it has received/re-assembled a N-PDU */
|
||||
int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
|
||||
int sgsn_gtp_data_req(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
|
||||
struct msgb *msg, uint32_t npdu_len, uint8_t *npdu)
|
||||
{
|
||||
struct sgsn_mm_ctx *mmctx;
|
||||
|
@ -726,10 +867,10 @@ int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_IN]);
|
||||
rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_IN], npdu_len);
|
||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_UDATA_IN]);
|
||||
rate_ctr_add(&mmctx->ctrg->ctr[GMM_CTR_BYTES_UDATA_IN], npdu_len);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_PKTS_UDATA_IN));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(pdp->ctrg, PDP_CTR_BYTES_UDATA_IN), npdu_len);
|
||||
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_UDATA_IN));
|
||||
rate_ctr_add(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_BYTES_UDATA_IN), npdu_len);
|
||||
|
||||
/* It is easier to have a global count */
|
||||
pdp->cdr_bytes_in += npdu_len;
|
||||
|
@ -804,10 +945,11 @@ int sgsn_gtp_init(struct sgsn_instance *sgi)
|
|||
/* Register callbackcs with libgtp */
|
||||
gtp_set_cb_delete_context(gsn, cb_delete_context);
|
||||
gtp_set_cb_conf(gsn, cb_conf);
|
||||
gtp_set_cb_recovery2(gsn, cb_recovery2);
|
||||
gtp_set_cb_recovery3(gsn, cb_recovery3);
|
||||
gtp_set_cb_data_ind(gsn, cb_data_ind);
|
||||
gtp_set_cb_unsup_ind(gsn, cb_unsup_ind);
|
||||
gtp_set_cb_extheader_ind(gsn, cb_extheader_ind);
|
||||
gtp_set_cb_ran_info_relay_ind(gsn, cb_gtp_ran_info_relay_ind);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -59,17 +59,18 @@
|
|||
#include <osmocom/sgsn/vty.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_llc.h>
|
||||
#include <osmocom/sgsn/gprs_sndcp.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_ranap.h>
|
||||
#include <osmocom/sgsn/gprs_gb.h>
|
||||
|
||||
#include <osmocom/ctrl/control_if.h>
|
||||
#include <osmocom/ctrl/ports.h>
|
||||
#include <osmocom/sgsn/gprs_ns.h>
|
||||
#include <osmocom/sgsn/gprs_bssgp.h>
|
||||
#include <osmocom/sgsn/gprs_subscriber.h>
|
||||
#include <osmocom/sgsn/gtp.h>
|
||||
|
||||
#include <gtp.h>
|
||||
#include <osmocom/sgsn/sgsn_rim.h>
|
||||
|
||||
#include "../../bscconfig.h"
|
||||
#include "../../config.h"
|
||||
|
||||
#if BUILD_IU
|
||||
#include <osmocom/sigtran/osmo_ss7.h>
|
||||
|
@ -81,7 +82,6 @@
|
|||
#include <getopt.h>
|
||||
|
||||
void *tall_sgsn_ctx;
|
||||
struct ctrl_handle *g_ctrlh;
|
||||
|
||||
struct gprs_ns2_inst *sgsn_nsi;
|
||||
static int daemonize = 0;
|
||||
|
@ -97,34 +97,11 @@ const char *openbsc_copyright =
|
|||
|
||||
struct sgsn_instance *sgsn;
|
||||
|
||||
/* call-back function for the BSSGP protocol */
|
||||
/* call-back function for the BSSGP protocol.
|
||||
* Must be left here so that we can add a new one in tests/sgsn_test */
|
||||
int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
|
||||
{
|
||||
struct osmo_bssgp_prim *bp;
|
||||
bp = container_of(oph, struct osmo_bssgp_prim, oph);
|
||||
|
||||
switch (oph->sap) {
|
||||
case SAP_BSSGP_LL:
|
||||
switch (oph->primitive) {
|
||||
case PRIM_BSSGP_UL_UD:
|
||||
return gprs_llc_rcvmsg(oph->msg, bp->tp);
|
||||
}
|
||||
break;
|
||||
case SAP_BSSGP_GMM:
|
||||
switch (oph->primitive) {
|
||||
case PRIM_BSSGP_GMM_SUSPEND:
|
||||
return gprs_gmm_rx_suspend(bp->ra_id, bp->tlli);
|
||||
case PRIM_BSSGP_GMM_RESUME:
|
||||
return gprs_gmm_rx_resume(bp->ra_id, bp->tlli,
|
||||
bp->u.resume.suspend_ref);
|
||||
}
|
||||
break;
|
||||
case SAP_BSSGP_NM:
|
||||
break;
|
||||
case SAP_BSSGP_RIM:
|
||||
return sgsn_rim_rx(bp, oph->msg);
|
||||
}
|
||||
return 0;
|
||||
return sgsn_bssgp_rx_prim(oph);
|
||||
}
|
||||
|
||||
static void signal_handler(int signum)
|
||||
|
@ -162,15 +139,36 @@ static void signal_handler(int signum)
|
|||
}
|
||||
}
|
||||
|
||||
static int sgsn_vty_go_parent(struct vty *vty)
|
||||
{
|
||||
switch (vty->node) {
|
||||
case SGSN_NODE:
|
||||
vty->node = CONFIG_NODE;
|
||||
break;
|
||||
case MME_NODE:
|
||||
vty->node = SGSN_NODE;
|
||||
vty->index = NULL;
|
||||
break;
|
||||
default:
|
||||
#if BUILD_IU
|
||||
osmo_ss7_vty_go_parent(vty);
|
||||
#else
|
||||
vty->node = CONFIG_NODE;
|
||||
vty->index = NULL;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
return vty->node;
|
||||
}
|
||||
|
||||
/* NSI that BSSGP uses when transmitting on NS */
|
||||
extern struct gprs_ns_inst *bssgp_nsi;
|
||||
|
||||
static struct vty_app_info vty_info = {
|
||||
.name = "OsmoSGSN",
|
||||
.version = PACKAGE_VERSION,
|
||||
#if BUILD_IU
|
||||
.go_parent_cb = osmo_ss7_vty_go_parent,
|
||||
#endif
|
||||
.go_parent_cb = sgsn_vty_go_parent,
|
||||
};
|
||||
|
||||
static void print_help(void)
|
||||
|
@ -310,11 +308,6 @@ static struct log_info_cat gprs_categories[] = {
|
|||
.description = "GPRS Packet Service",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DNS] = {
|
||||
.name = "DNS",
|
||||
.description = "GPRS Network Service (NS)",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DLLC] = {
|
||||
.name = "DLLC",
|
||||
.description = "GPRS Logical Link Control Protocol (LLC)",
|
||||
|
@ -410,6 +403,7 @@ int main(int argc, char **argv)
|
|||
rate_ctr_init(tall_sgsn_ctx);
|
||||
|
||||
logging_vty_add_deprecated_subsys(tall_sgsn_ctx, "bssgp");
|
||||
logging_vty_add_deprecated_subsys(tall_sgsn_ctx, "ns");
|
||||
|
||||
sgsn_nsi = gprs_ns2_instantiate(tall_sgsn_ctx, &gprs_ns_prim_cb, NULL);
|
||||
if (!sgsn_nsi) {
|
||||
|
@ -417,19 +411,12 @@ int main(int argc, char **argv)
|
|||
exit(1);
|
||||
}
|
||||
sgsn->cfg.nsi = sgsn_nsi;
|
||||
bssgp_set_bssgp_callback(gprs_gb_send_cb, sgsn_nsi);
|
||||
|
||||
gprs_llc_init("/usr/local/lib/osmocom/crypt/");
|
||||
sgsn_rate_ctr_init();
|
||||
sgsn_inst_init(sgsn);
|
||||
|
||||
bssgp_set_bssgp_callback(sgsn_bssgp_dispatch_ns_unitdata_req_cb, sgsn_nsi);
|
||||
|
||||
gprs_ns2_vty_init(sgsn_nsi);
|
||||
bssgp_vty_init();
|
||||
gprs_llc_vty_init();
|
||||
gprs_sndcp_vty_init();
|
||||
sgsn_auth_init(sgsn);
|
||||
sgsn_cdr_init(sgsn);
|
||||
|
||||
handle_options(argc, argv);
|
||||
|
||||
|
@ -455,25 +442,11 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
/* start telnet after reading config for vty_get_bind_addr() */
|
||||
rc = telnet_init_dynif(tall_sgsn_ctx, NULL,
|
||||
vty_get_bind_addr(), OSMO_VTY_PORT_SGSN);
|
||||
rc = telnet_init_default(tall_sgsn_ctx, NULL, OSMO_VTY_PORT_SGSN);
|
||||
if (rc < 0)
|
||||
exit(1);
|
||||
|
||||
/* start control interface after reading config for
|
||||
* ctrl_vty_get_bind_addr() */
|
||||
g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(),
|
||||
OSMO_CTRL_PORT_SGSN, NULL);
|
||||
if (!g_ctrlh) {
|
||||
LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (sgsn_ctrl_cmds_install() != 0) {
|
||||
LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gprs_llc_init(sgsn->cfg.crypt_cipher_plugin_path);
|
||||
|
||||
rc = sgsn_gtp_init(sgsn);
|
||||
if (rc) {
|
||||
|
@ -482,9 +455,9 @@ int main(int argc, char **argv)
|
|||
} else
|
||||
LOGP(DGPRS, LOGL_NOTICE, "libGTP v%s initialized\n", gtp_version());
|
||||
|
||||
rc = gprs_subscr_init(sgsn);
|
||||
rc = sgsn_inst_init(sgsn);
|
||||
if (rc < 0) {
|
||||
LOGP(DGPRS, LOGL_FATAL, "Cannot set up subscriber management\n");
|
||||
LOGP(DGPRS, LOGL_FATAL, "Cannot set up SGSN\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,57 +11,117 @@
|
|||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
#include <osmocom/gprs/gprs_bssgp_rim.h>
|
||||
#include <osmocom/sgsn/sgsn_rim.h>
|
||||
#include <osmocom/sgsn/gtp_mme.h>
|
||||
#include <osmocom/sgsn/gtp.h>
|
||||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
|
||||
/* Find an NSEI for the destination cell, this function works only for GERAN! */
|
||||
static int find_dest_nsei_geran(struct bssgp_rim_routing_info *dest_rim_ri, uint16_t nsei)
|
||||
static int sgsn_bssgp_fwd_rim_to_geran(const struct bssgp_ran_information_pdu *pdu)
|
||||
{
|
||||
struct bssgp_bvc_ctx *bvc_ctx;
|
||||
OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_GERAN);
|
||||
|
||||
OSMO_ASSERT(dest_rim_ri->discr == BSSGP_RIM_ROUTING_INFO_GERAN);
|
||||
|
||||
bvc_ctx = btsctx_by_raid_cid(&dest_rim_ri->geran.raid, dest_rim_ri->geran.cid);
|
||||
/* 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, "BSSGP RIM (NSEI=%u) cannot find NSEI for destination cell\n", nsei);
|
||||
LOGP(DRIM, LOGL_ERROR, "Unable to find NSEI for destination cell %s\n",
|
||||
bssgp_rim_ri_name(&pdu->routing_info_dest));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return bvc_ctx->nsei;
|
||||
/* Forward PDU to the NSEI of the resolved BVC context */
|
||||
return bssgp_tx_rim(pdu, bvc_ctx->nsei);
|
||||
}
|
||||
|
||||
int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg)
|
||||
static int sgsn_bssgp_fwd_rim_to_geran_encoded(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address)
|
||||
{
|
||||
struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;
|
||||
int d_nsei;
|
||||
uint16_t nsei = msgb_nsei(msg);
|
||||
struct bssgp_bvc_ctx *bvc_ctx;
|
||||
OSMO_ASSERT(rim_routing_address->discr == BSSGP_RIM_ROUTING_INFO_GERAN);
|
||||
|
||||
/* At the moment we only support GERAN, so we block all other network
|
||||
* types here. */
|
||||
if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
|
||||
LOGP(DRIM, LOGL_ERROR,
|
||||
"BSSGP RIM (NSEI=%u) only GERAN supported, destination cell is not a GERAN cell -- rejected.\n",
|
||||
nsei);
|
||||
/* At the moment we can only handle GERAN addresses, any other
|
||||
* type of address will be consideres as an invalid address.
|
||||
* see also: 3GPP TS 48.018, section 8c.3.1.3 */
|
||||
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
|
||||
/* 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;
|
||||
OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_EUTRAN);
|
||||
|
||||
mme = sgsn_mme_ctx_by_route(sgsn, &pdu->routing_info_dest.eutran.tai);
|
||||
if (!mme) { /* See if we have a default route configured */
|
||||
mme = sgsn_mme_ctx_by_default_route(sgsn);
|
||||
if (!mme) {
|
||||
LOGP(DRIM, LOGL_ERROR, "Unable to find MME for destination cell %s\n",
|
||||
bssgp_rim_ri_name(&pdu->routing_info_dest));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return sgsn_mme_ran_info_req(mme, pdu);
|
||||
}
|
||||
|
||||
/* Receive a RIM PDU from BSSGP (GERAN) */
|
||||
int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg)
|
||||
{
|
||||
uint16_t nsei = msgb_nsei(msg);
|
||||
struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;
|
||||
|
||||
if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
|
||||
LOGP(DRIM, LOGL_ERROR,
|
||||
"BSSGP RIM (NSEI=%u) only GERAN supported, source cell is not a GERAN cell -- rejected.\n", nsei);
|
||||
/* See comment above */
|
||||
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
|
||||
"Rx BSSGP RIM (NSEI=%u): Expected src %s, got %s\n", nsei,
|
||||
bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN),
|
||||
bssgp_rim_routing_info_discr_str(pdu->routing_info_src.discr));
|
||||
goto err;
|
||||
}
|
||||
|
||||
d_nsei = find_dest_nsei_geran(&pdu->routing_info_dest, nsei);
|
||||
if (d_nsei < 0) {
|
||||
LOGP(DRIM, LOGL_NOTICE, "BSSGP RIM (NSEI=%u) Cell %s unknown to this sgsn\n",
|
||||
nsei, bssgp_rim_ri_name(&pdu->routing_info_dest));
|
||||
/* In case of an invalid destination address we respond with
|
||||
* a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */
|
||||
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
|
||||
switch (pdu->routing_info_dest.discr) {
|
||||
case BSSGP_RIM_ROUTING_INFO_GERAN:
|
||||
return sgsn_bssgp_fwd_rim_to_geran(pdu);
|
||||
case BSSGP_RIM_ROUTING_INFO_EUTRAN:
|
||||
return sgsn_bssgp_fwd_rim_to_eutran(pdu);
|
||||
default:
|
||||
/* At the moment we can only handle GERAN/EUTRAN addresses, any
|
||||
* other type of address will be considered as an invalid
|
||||
* address. see also: 3GPP TS 48.018, section 8c.3.1.3
|
||||
*/
|
||||
LOGP(DRIM, LOGL_ERROR,
|
||||
"Rx BSSGP RIM (NSEI=%u): Unsupported dst %s\n", nsei,
|
||||
bssgp_rim_routing_info_discr_str(pdu->routing_info_dest.discr));
|
||||
}
|
||||
|
||||
/* Forward PDU as it is to the correct interface */
|
||||
return bssgp_tx_rim(pdu, (uint16_t) d_nsei);
|
||||
LOGP(DRIM, LOGL_INFO, "Rx BSSGP RIM (NSEI=%u): for dest cell %s\n", nsei,
|
||||
bssgp_rim_ri_name(&pdu->routing_info_dest));
|
||||
|
||||
err:
|
||||
/* In case of an invalid destination address we respond with
|
||||
* a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */
|
||||
bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Receive a RIM PDU from GTPv1C (EUTRAN) */
|
||||
int sgsn_rim_rx_from_gtp(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address)
|
||||
{
|
||||
/* TODO: In this code path, we currently only support RIM message forwarding to GERAN (BSSGP). However, it
|
||||
* technically also be possible to route a message back to GTP (BSSGP_RIM_ROUTING_INFO_EUTRAN) or to
|
||||
* IuPS (BSSGP_RIM_ROUTING_INFO_UTRAN) */
|
||||
if (rim_routing_address->discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
|
||||
LOGP(DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected dst %s, got %s\n",
|
||||
bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN),
|
||||
bssgp_rim_routing_info_discr_str(rim_routing_address->discr));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOGP(DRIM, LOGL_INFO, "Rx GTP RAN Information Relay for dest cell %s\n",
|
||||
bssgp_rim_ri_name(rim_routing_address));
|
||||
|
||||
return sgsn_bssgp_fwd_rim_to_geran_encoded(msg, rim_routing_address);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
@ -35,9 +37,14 @@
|
|||
#include <osmocom/sgsn/debug.h>
|
||||
#include <osmocom/sgsn/sgsn.h>
|
||||
#include <osmocom/gprs/gprs_ns2.h>
|
||||
#include <osmocom/sgsn/gprs_ns.h>
|
||||
#include <osmocom/sgsn/gprs_gmm.h>
|
||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||
#include <osmocom/sgsn/gprs_bssgp.h>
|
||||
#include <osmocom/sgsn/mmctx.h>
|
||||
#include <osmocom/sgsn/gtp_ggsn.h>
|
||||
#include <osmocom/sgsn/gtp_mme.h>
|
||||
#include <osmocom/sgsn/vty.h>
|
||||
#include <osmocom/sgsn/pdpctx.h>
|
||||
#include <osmocom/gsupclient/gsup_client.h>
|
||||
|
||||
#include <osmocom/vty/tdef_vty.h>
|
||||
|
@ -45,6 +52,7 @@
|
|||
#include <osmocom/vty/vty.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
#include <osmocom/crypt/gprs_cipher.h>
|
||||
#include <osmocom/crypt/utran_cipher.h>
|
||||
#include <osmocom/abis/ipa.h>
|
||||
|
||||
#include <osmocom/gprs/gprs_bssgp.h>
|
||||
|
@ -52,14 +60,12 @@
|
|||
#include <pdp.h>
|
||||
#include <gtp.h>
|
||||
|
||||
#include "../../bscconfig.h"
|
||||
#include "../../config.h"
|
||||
|
||||
#ifdef BUILD_IU
|
||||
#include <osmocom/ranap/iu_client.h>
|
||||
#endif
|
||||
|
||||
extern void *tall_sgsn_ctx;
|
||||
|
||||
static struct sgsn_config *g_cfg = NULL;
|
||||
|
||||
const struct value_string sgsn_auth_pol_strs[] = {
|
||||
|
@ -94,7 +100,7 @@ const struct value_string sgsn_auth_pol_strs[] = {
|
|||
#define NONSPEC_X1001_SECS 5 /* wait for a RANAP Release Complete */
|
||||
|
||||
|
||||
static struct osmo_tdef sgsn_T_defs[] = {
|
||||
struct osmo_tdef sgsn_T_defs[] = {
|
||||
{ .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" },
|
||||
{ .T=3313, .default_val=GSM0408_T3313_SECS, .desc="Waiting for paging response timer (s)" },
|
||||
{ .T=3314, .default_val=GSM0408_T3314_SECS, .desc="READY timer. Force to STANDBY on expiry timer (s)" },
|
||||
|
@ -110,7 +116,6 @@ static struct osmo_tdef sgsn_T_defs[] = {
|
|||
/* non spec timers */
|
||||
{ .T=-1001, .default_val=NONSPEC_X1001_SECS, .desc="RANAP Release timeout. Wait for RANAP Release Complete."
|
||||
"On expiry release Iu connection (s)" },
|
||||
{ .T=-3314, .default_val=GSM0408_T3314_SECS, .desc="Iu User inactivity timer. On expiry release Iu connection (s)" },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -134,7 +139,27 @@ DEFUN(cfg_sgsn_timer, cfg_sgsn_timer_cmd,
|
|||
return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs, argv);
|
||||
}
|
||||
|
||||
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
|
||||
DEFUN(show_timer_gtp, show_timer_gtp_cmd,
|
||||
"show timer gtp " OSMO_TDEF_VTY_ARG_T_OPTIONAL,
|
||||
SHOW_STR "Show timers\n" "GTP (libgtp) timers\n"
|
||||
OSMO_TDEF_VTY_DOC_T)
|
||||
{
|
||||
const char *T_arg = argc > 0 ? argv[0] : NULL;
|
||||
return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs_gtp, T_arg, NULL);
|
||||
}
|
||||
|
||||
DEFUN(cfg_sgsn_timer_gtp, cfg_sgsn_timer_gtp_cmd,
|
||||
"timer gtp " OSMO_TDEF_VTY_ARG_SET_OPTIONAL,
|
||||
"Configure or show timers\n" "GTP (libgtp) timers\n"
|
||||
OSMO_TDEF_VTY_DOC_SET)
|
||||
{
|
||||
/* If any arguments are missing, redirect to 'show' */
|
||||
if (argc < 2)
|
||||
return show_timer(self, vty, argc, argv);
|
||||
return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs_gtp, argv);
|
||||
}
|
||||
|
||||
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6)
|
||||
{
|
||||
static char str[INET6_ADDRSTRLEN + 10];
|
||||
|
||||
|
@ -147,15 +172,28 @@ char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len)
|
|||
case PDP_TYPE_N_IETF_IPv4:
|
||||
if (len < 2 + 4)
|
||||
break;
|
||||
strcpy(str, "IPv4 ");
|
||||
osmo_strlcpy(str, "IPv4 ", sizeof(str));
|
||||
inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
|
||||
return str;
|
||||
case PDP_TYPE_N_IETF_IPv6:
|
||||
if (len < 2 + 8)
|
||||
break;
|
||||
strcpy(str, "IPv6 ");
|
||||
osmo_strlcpy(str, "IPv6 ", sizeof(str));
|
||||
inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5);
|
||||
return str;
|
||||
case PDP_TYPE_N_IETF_IPv4v6:
|
||||
if (len < 2 + 20)
|
||||
break;
|
||||
if (return_ipv6) {
|
||||
/* The IPv6 token, (rightmost four fields) is a duplicate of
|
||||
* the site prefix + subnetID (leftmost fields) in pdpa here */
|
||||
osmo_strlcpy(str, "IPv6 ", sizeof(str));
|
||||
inet_ntop(AF_INET6, pdpa+6, str+5, sizeof(str)-5);
|
||||
return str;
|
||||
}
|
||||
osmo_strlcpy(str, "IPv4 ", sizeof(str));
|
||||
inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5);
|
||||
return str;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -177,12 +215,36 @@ static struct cmd_node sgsn_node = {
|
|||
1,
|
||||
};
|
||||
|
||||
static struct cmd_node mme_node = {
|
||||
MME_NODE,
|
||||
"%s(config-sgsn-mme)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
static void config_write_mme(struct vty *vty, const struct sgsn_mme_ctx *mme, const char *prefix)
|
||||
{
|
||||
struct mme_rim_route *rt;
|
||||
|
||||
vty_out(vty, "%smme %s%s", prefix, mme->name, VTY_NEWLINE);
|
||||
|
||||
vty_out(vty, "%s gtp remote-ip %s%s", prefix, inet_ntoa(mme->remote_addr), VTY_NEWLINE);
|
||||
if (mme->default_route)
|
||||
vty_out(vty, "%s gtp ran-info-relay default%s", prefix, VTY_NEWLINE);
|
||||
llist_for_each_entry(rt, &mme->routes, list) {
|
||||
vty_out(vty, "%s gtp ran-info-relay %s %s %u%s", prefix,
|
||||
osmo_mcc_name(rt->tai.mcc), osmo_mnc_name(rt->tai.mnc, rt->tai.mnc_3_digits),
|
||||
rt->tai.tac, VTY_NEWLINE);
|
||||
}
|
||||
}
|
||||
|
||||
static int config_write_sgsn(struct vty *vty)
|
||||
{
|
||||
struct sgsn_ggsn_ctx *gctx;
|
||||
struct imsi_acl_entry *acl;
|
||||
struct apn_ctx *actx;
|
||||
struct ares_addr_node *server;
|
||||
struct sgsn_mme_ctx *mme;
|
||||
int i;
|
||||
|
||||
vty_out(vty, "sgsn%s", VTY_NEWLINE);
|
||||
|
||||
|
@ -191,7 +253,7 @@ static int config_write_sgsn(struct vty *vty)
|
|||
vty_out(vty, " gtp local-ip %s%s",
|
||||
inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
|
||||
|
||||
llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) {
|
||||
llist_for_each_entry(gctx, &sgsn->ggsn_list, list) {
|
||||
if (gctx->id == UINT32_MAX)
|
||||
continue;
|
||||
|
||||
|
@ -213,10 +275,26 @@ static int config_write_sgsn(struct vty *vty)
|
|||
for (server = sgsn->ares_servers; server; server = server->next)
|
||||
vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
|
||||
|
||||
if (g_cfg->cipher != GPRS_ALGO_GEA0)
|
||||
vty_out(vty, " encryption %s%s",
|
||||
get_value_string(gprs_cipher_names, g_cfg->cipher),
|
||||
VTY_NEWLINE);
|
||||
if (g_cfg->gea_encryption_mask != 0) {
|
||||
vty_out(vty, " encryption gea");
|
||||
|
||||
for (i = 0; i < _GPRS_ALGO_NUM; i++)
|
||||
if (g_cfg->gea_encryption_mask >> i & 1)
|
||||
vty_out(vty, " %u", i);
|
||||
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
}
|
||||
if (g_cfg->uea_encryption_mask != 0) {
|
||||
vty_out(vty, " encryption uea");
|
||||
|
||||
for (i = 0; i < _OSMO_UTRAN_UEA_NUM; i++)
|
||||
if (g_cfg->uea_encryption_mask >> i & 1)
|
||||
vty_out(vty, " %u", i);
|
||||
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
}
|
||||
if (g_cfg->crypt_cipher_plugin_path)
|
||||
vty_out(vty, " encryption cipher-plugin-path %s%s", g_cfg->crypt_cipher_plugin_path, VTY_NEWLINE);
|
||||
if (g_cfg->sgsn_ipa_name)
|
||||
vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);
|
||||
if (g_cfg->gsup_server_addr.sin_addr.s_addr)
|
||||
|
@ -245,9 +323,9 @@ static int config_write_sgsn(struct vty *vty)
|
|||
llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
|
||||
vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
|
||||
|
||||
if (llist_empty(&sgsn_apn_ctxts))
|
||||
if (llist_empty(&sgsn->apn_list))
|
||||
vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE);
|
||||
llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
|
||||
llist_for_each_entry(actx, &sgsn->apn_list, list) {
|
||||
if (strlen(actx->imsi_prefix) > 0)
|
||||
vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s",
|
||||
actx->name, actx->imsi_prefix, actx->ggsn->id,
|
||||
|
@ -268,6 +346,7 @@ static int config_write_sgsn(struct vty *vty)
|
|||
vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE);
|
||||
|
||||
osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer ");
|
||||
osmo_tdef_vty_write(vty, g_cfg->T_defs_gtp, " timer gtp ");
|
||||
|
||||
if (g_cfg->pcomp_rfc1144.active) {
|
||||
vty_out(vty, " compression rfc1144 active slots %d%s",
|
||||
|
@ -297,6 +376,10 @@ static int config_write_sgsn(struct vty *vty)
|
|||
} else
|
||||
vty_out(vty, " no compression v42bis%s", VTY_NEWLINE);
|
||||
|
||||
llist_for_each_entry(mme, &sgsn->mme_list, list) {
|
||||
config_write_mme(vty, mme, " ");
|
||||
}
|
||||
|
||||
#ifdef BUILD_IU
|
||||
vty_out(vty, " cs7-instance-iu %u%s", g_cfg->iu.cs7_instance,
|
||||
VTY_NEWLINE);
|
||||
|
@ -323,6 +406,11 @@ DEFUN(cfg_sgsn_state_dir, cfg_sgsn_state_dir_cmd,
|
|||
"Set the directory for the GTP State file\n"
|
||||
"Local Directory\n")
|
||||
{
|
||||
if (mkdir(argv[0], 0755) == -1 && errno != EEXIST) {
|
||||
vty_out(vty, "%% Failed to create state-dir: %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
osmo_talloc_replace_string(sgsn, &sgsn->cfg.gtp_statedir, argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
|
@ -351,7 +439,7 @@ DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd,
|
|||
"IPv4 Address\n")
|
||||
{
|
||||
uint32_t id = atoi(argv[0]);
|
||||
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
|
||||
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
|
||||
|
||||
inet_aton(argv[1], &ggc->remote_addr);
|
||||
|
||||
|
@ -376,7 +464,7 @@ DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd,
|
|||
"Version 0\n" "Version 1\n")
|
||||
{
|
||||
uint32_t id = atoi(argv[0]);
|
||||
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
|
||||
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
|
||||
|
||||
if (atoi(argv[1]))
|
||||
ggc->gtp_version = 1;
|
||||
|
@ -394,7 +482,7 @@ DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd,
|
|||
"Interval between echo requests in seconds.\n")
|
||||
{
|
||||
uint32_t id = atoi(argv[0]);
|
||||
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
|
||||
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
|
||||
|
||||
ggc->echo_interval = atoi(argv[1]);
|
||||
|
||||
|
@ -413,7 +501,7 @@ DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd,
|
|||
NO_STR "Send an echo request to this static GGSN every interval.\n")
|
||||
{
|
||||
uint32_t id = atoi(argv[0]);
|
||||
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id);
|
||||
struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id);
|
||||
|
||||
ggc->echo_interval = 0;
|
||||
sgsn_ggsn_ctx_check_echo_timer(ggc);
|
||||
|
@ -454,7 +542,7 @@ static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str,
|
|||
struct apn_ctx *actx;
|
||||
struct sgsn_ggsn_ctx *ggsn;
|
||||
|
||||
ggsn = sgsn_ggsn_ctx_by_id(ggsn_id);
|
||||
ggsn = sgsn_ggsn_ctx_by_id(sgsn, ggsn_id);
|
||||
if (ggsn == NULL) {
|
||||
vty_out(vty, "%% a GGSN with id %d has not been defined%s",
|
||||
ggsn_id, VTY_NEWLINE);
|
||||
|
@ -518,8 +606,13 @@ static void vty_dump_pdp(struct vty *vty, const char *pfx,
|
|||
osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, "%s PDP Address: %s%s", pfx,
|
||||
gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l),
|
||||
gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, false),
|
||||
VTY_NEWLINE);
|
||||
if (pdp->lib->eua.v[1] == PDP_TYPE_N_IETF_IPv4v6) {
|
||||
vty_out(vty, "%s PDP Address: %s%s", pfx,
|
||||
gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, true),
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version,
|
||||
sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own);
|
||||
vty_out(vty, "Data(%s / TEID: 0x%08x)%s",
|
||||
|
@ -627,7 +720,7 @@ DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd,
|
|||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0);
|
||||
vty_dump_mmctx(vty, "", mm, (argc > 1) ? 1 : 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -636,9 +729,8 @@ DEFUN(swow_mmctx_all, show_mmctx_all_cmd,
|
|||
SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR)
|
||||
{
|
||||
struct sgsn_mm_ctx *mm;
|
||||
|
||||
llist_for_each_entry(mm, &sgsn_mm_ctxts, list)
|
||||
vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0);
|
||||
llist_for_each_entry(mm, &sgsn->mm_list, list)
|
||||
vty_dump_mmctx(vty, "", mm, (argc > 0) ? 1 : 0);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
@ -649,7 +741,7 @@ DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
|
|||
{
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
|
||||
llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list)
|
||||
llist_for_each_entry(pdp, &sgsn->pdp_list, g_list)
|
||||
vty_dump_pdp(vty, "", pdp);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
|
@ -695,15 +787,19 @@ DEFUN(imsi_acl, cfg_imsi_acl_cmd,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_encrypt, cfg_encrypt_cmd,
|
||||
DEFUN_DEPRECATED(cfg_encrypt, cfg_encrypt_cmd,
|
||||
"encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",
|
||||
"Set encryption algorithm for SGSN\n"
|
||||
"Use GEA0 (no encryption)\n"
|
||||
"Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")
|
||||
{
|
||||
enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);
|
||||
|
||||
if (strcmp(argv[0], "gea") == 0)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
if (c != GPRS_ALGO_GEA0) {
|
||||
if (!gprs_cipher_supported(c)) {
|
||||
if (gprs_cipher_supported(c) <= 0) {
|
||||
vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
@ -715,11 +811,73 @@ DEFUN(cfg_encrypt, cfg_encrypt_cmd,
|
|||
}
|
||||
}
|
||||
|
||||
g_cfg->cipher = c;
|
||||
g_cfg->gea_encryption_mask |= (1 << c);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define ENCRYPTION_STR "Set encryption algorithms for SGSN\n"
|
||||
|
||||
DEFUN(cfg_encrypt2, cfg_encrypt2_cmd,
|
||||
"encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>]",
|
||||
ENCRYPTION_STR
|
||||
"GPRS Encryption Algorithm\n"
|
||||
"GEAn Algorithm Number\n"
|
||||
"GEAn Algorithm Number\n"
|
||||
"GEAn Algorithm Number\n"
|
||||
"GEAn Algorithm Number\n"
|
||||
"GEAn Algorithm Number\n")
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
g_cfg->gea_encryption_mask = 0;
|
||||
for (i = 0; i < argc; i++)
|
||||
g_cfg->gea_encryption_mask |= (1 << atoi(argv[i]));
|
||||
|
||||
for (i = 0; i < _GPRS_ALGO_NUM; i++) {
|
||||
if (g_cfg->gea_encryption_mask >> i & 1) {
|
||||
|
||||
if (i == GPRS_ALGO_GEA0)
|
||||
continue;
|
||||
|
||||
if (gprs_cipher_supported(i) <= 0) {
|
||||
vty_out(vty, "%% cipher %d is unsupported in current version%s", i, VTY_NEWLINE);
|
||||
return CMD_ERR_INCOMPLETE;
|
||||
}
|
||||
|
||||
if (!g_cfg->require_authentication) {
|
||||
vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",
|
||||
argv[i], VTY_NEWLINE);
|
||||
return CMD_ERR_INCOMPLETE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_encrypt_cipher_plugin_path, cfg_encrypt_cipher_plugin_path_cmd,
|
||||
"encryption cipher-plugin-path PATH",
|
||||
ENCRYPTION_STR
|
||||
"Path to gprs encryption cipher plugin directory\n"
|
||||
"Plugin path\n")
|
||||
{
|
||||
osmo_talloc_replace_string(sgsn, &sgsn->cfg.crypt_cipher_plugin_path, argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_encrypt_cipher_plugin_path, cfg_no_encrypt_cipher_plugin_path_cmd,
|
||||
"no encryption cipher-plugin-path PATH",
|
||||
NO_STR ENCRYPTION_STR
|
||||
"Path to gprs encryption cipher plugin directory\n"
|
||||
"Plugin path\n")
|
||||
{
|
||||
TALLOC_FREE(sgsn->cfg.crypt_cipher_plugin_path);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_authentication, cfg_authentication_cmd,
|
||||
"authentication (optional|required)",
|
||||
"Whether to enforce MS authentication in GERAN (only with auth-policy remote)\n"
|
||||
|
@ -741,6 +899,23 @@ DEFUN(cfg_authentication, cfg_authentication_cmd,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_encryption_uea, cfg_encryption_uea_cmd,
|
||||
"encryption uea <0-2> [<0-2>] [<0-2>]",
|
||||
ENCRYPTION_STR
|
||||
"UTRAN (3G) encryption algorithms to allow: 0 = UEA0 (no encryption), 1 = UEA1, 2 = UEA2.\n"
|
||||
"UEAn Algorithm Number\n"
|
||||
"UEAn Algorithm Number\n"
|
||||
"UEAn Algorithm Number\n")
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
g_cfg->uea_encryption_mask = 0;
|
||||
for (i = 0; i < argc; i++)
|
||||
g_cfg->uea_encryption_mask |= (1 << atoi(argv[i]));
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_auth_policy, cfg_auth_policy_cmd,
|
||||
"auth-policy (accept-all|closed|acl-only|remote)",
|
||||
"Configure the Authorization policy of the SGSN. This setting determines which subscribers are"
|
||||
|
@ -822,8 +997,17 @@ static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int
|
|||
}
|
||||
|
||||
llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
|
||||
vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'",
|
||||
pdp->context_id, pdp->pdp_type, pdp->apn_str);
|
||||
char ip_str[INET6_ADDRSTRLEN] = { 0 };
|
||||
|
||||
vty_out(vty, " PDP info: Id: %d, Addr(Org: 0x%02x Type: 0x%02x",
|
||||
pdp->context_id, pdp->pdp_type_org, pdp->pdp_type_nr);
|
||||
|
||||
if (pdp->pdp_address[0].u.sa.sa_family != AF_UNSPEC)
|
||||
vty_out(vty, " Addr[0]: %s", osmo_sockaddr_ntop(&pdp->pdp_address[0].u.sa, ip_str));
|
||||
if (pdp->pdp_address[0].u.sa.sa_family != AF_UNSPEC)
|
||||
vty_out(vty, " Addr[1]: %s", osmo_sockaddr_ntop(&pdp->pdp_address[1].u.sa, ip_str));
|
||||
|
||||
vty_out(vty, ") APN: '%s'", pdp->apn_str);
|
||||
|
||||
if (pdp->qos_subscribed_len)
|
||||
vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len));
|
||||
|
@ -870,7 +1054,7 @@ DEFUN_HIDDEN(reset_sgsn_state,
|
|||
struct gprs_subscr *subscr, *tmp_subscr;
|
||||
struct sgsn_mm_ctx *mm, *tmp_mm;
|
||||
|
||||
llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list)
|
||||
llist_for_each_entry_safe(mm, tmp_mm, &sgsn->mm_list, list)
|
||||
{
|
||||
gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE);
|
||||
}
|
||||
|
@ -1134,6 +1318,25 @@ DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(page_subscr, page_subscr_info_cmd,
|
||||
"page imsi IMSI",
|
||||
"Send a PS paging request to subscriber\n"
|
||||
"Use the IMSI to select the subscriber\n"
|
||||
"The IMSI\n")
|
||||
{
|
||||
const char *imsi = argv[0];
|
||||
struct sgsn_mm_ctx *mm;
|
||||
|
||||
mm = sgsn_mm_ctx_by_imsi(imsi);
|
||||
if (!mm) {
|
||||
vty_out(vty, "No MM context for IMSI %s%s", imsi, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
sgsn_bssgp_page_ps_ra(mm);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_gsup_ipa_name,
|
||||
cfg_gsup_ipa_name_cmd,
|
||||
"gsup ipa-name NAME",
|
||||
|
@ -1424,13 +1627,165 @@ DEFUN(cfg_sgsn_cs7_instance_iu,
|
|||
}
|
||||
#endif
|
||||
|
||||
DEFUN(cfg_sgsn_mme, cfg_sgsn_mme_cmd,
|
||||
"mme NAME",
|
||||
"Configure an MME peer\n"
|
||||
"Name identifying the MME peer\n")
|
||||
{
|
||||
struct sgsn_mme_ctx *mme;
|
||||
|
||||
mme = sgsn_mme_ctx_find_alloc(sgsn, argv[0]);
|
||||
if (!mme)
|
||||
return CMD_WARNING;
|
||||
|
||||
vty->node = MME_NODE;
|
||||
vty->index = mme;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_sgsn_no_mme, cfg_sgsn_no_mme_cmd,
|
||||
"no mme NAME",
|
||||
NO_STR "Delete an MME peer configuration\n"
|
||||
"Name identifying the MME peer\n")
|
||||
{
|
||||
struct sgsn_mme_ctx *mme;
|
||||
|
||||
mme = sgsn_mme_ctx_by_name(sgsn, argv[0]);
|
||||
if (!mme) {
|
||||
vty_out(vty, "%% MME %s doesn't exist.%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
sgsn_mme_ctx_free(mme);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define GTP_STR "Configure GTP connection\n"
|
||||
|
||||
DEFUN(cfg_mme_remote_ip, cfg_mme_remote_ip_cmd,
|
||||
"gtp remote-ip A.B.C.D",
|
||||
GTP_STR "Set Remote GTP IP address\n" IP_STR)
|
||||
{
|
||||
struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
|
||||
|
||||
inet_aton(argv[0], &mme->remote_addr);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define RAN_INFO_STR "Configure RAN Information Relay routing\n"
|
||||
#define TAI_DOC "MCC\n" "MNC\n" "TAC\n"
|
||||
|
||||
DEFUN(cfg_mme_ran_info_relay_tai, cfg_mme_ran_info_relay_tai_cmd,
|
||||
"gtp ran-info-relay <0-999> <0-999> <0-65535>",
|
||||
GTP_STR RAN_INFO_STR TAI_DOC)
|
||||
{
|
||||
struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
|
||||
struct sgsn_mme_ctx *mme_tmp;
|
||||
struct osmo_eutran_tai tai;
|
||||
|
||||
const char *mcc = argv[0];
|
||||
const char *mnc = argv[1];
|
||||
const char *tac = argv[2];
|
||||
|
||||
if (osmo_mcc_from_str(mcc, &tai.mcc)) {
|
||||
vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
|
||||
vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
tai.tac = atoi(tac);
|
||||
|
||||
if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
|
||||
if (mme_tmp != mme) {
|
||||
vty_out(vty, "%% Another MME %s already contains this route%s",
|
||||
mme_tmp->name, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
/* else: NO-OP, return */
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
sgsn_mme_ctx_route_add(mme, &tai);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mme_no_ran_info_relay_tai, cfg_mme_no_ran_info_relay_tai_cmd,
|
||||
"no gtp ran-info-relay <0-999> <0-999> <0-65535>",
|
||||
NO_STR GTP_STR RAN_INFO_STR TAI_DOC)
|
||||
{
|
||||
struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
|
||||
struct sgsn_mme_ctx *mme_tmp;
|
||||
struct osmo_eutran_tai tai;
|
||||
|
||||
const char *mcc = argv[0];
|
||||
const char *mnc = argv[1];
|
||||
const char *tac = argv[2];
|
||||
|
||||
if (osmo_mcc_from_str(mcc, &tai.mcc)) {
|
||||
vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (osmo_mnc_from_str(mnc, &tai.mnc, &tai.mnc_3_digits)) {
|
||||
vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
tai.tac = atoi(tac);
|
||||
|
||||
if ((mme_tmp = sgsn_mme_ctx_by_route(sgsn, &tai))) {
|
||||
if (mme_tmp != mme) {
|
||||
vty_out(vty, "%% Another MME %s contains this route%s",
|
||||
mme_tmp->name, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
sgsn_mme_ctx_route_del(mme, &tai);
|
||||
return CMD_SUCCESS;
|
||||
} else {
|
||||
vty_out(vty, "%% This route doesn't exist in current MME %s%s",
|
||||
mme->name, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN(cfg_mme_ran_info_relay_default, cfg_mme_ran_info_relay_default_cmd,
|
||||
"gtp ran-info-relay default",
|
||||
GTP_STR RAN_INFO_STR "Set as default route")
|
||||
{
|
||||
struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
|
||||
struct sgsn_mme_ctx *default_mme;
|
||||
|
||||
if (mme->default_route)
|
||||
return CMD_SUCCESS; /* NO-OP */
|
||||
|
||||
if ((default_mme = sgsn_mme_ctx_by_default_route(sgsn))) {
|
||||
vty_out(vty, "%% Another MME %s is already set as default route, "
|
||||
"remove it before setting it here.%s",
|
||||
default_mme->name, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
mme->default_route = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mme_no_ran_info_relay_default, cfg_mme_no_ran_info_relay_default_cmd,
|
||||
"no gtp ran-info-relay default",
|
||||
NO_STR GTP_STR RAN_INFO_STR "Set as default route")
|
||||
{
|
||||
struct sgsn_mme_ctx *mme = (struct sgsn_mme_ctx *) vty->index;
|
||||
mme->default_route = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
int sgsn_vty_init(struct sgsn_config *cfg)
|
||||
{
|
||||
g_cfg = cfg;
|
||||
|
||||
g_cfg->T_defs = sgsn_T_defs;
|
||||
osmo_tdefs_reset(g_cfg->T_defs);
|
||||
|
||||
install_element_ve(&show_sgsn_cmd);
|
||||
//install_element_ve(&show_mmctx_tlli_cmd);
|
||||
install_element_ve(&show_mmctx_imsi_cmd);
|
||||
|
@ -1438,6 +1793,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
|
|||
install_element_ve(&show_pdpctx_all_cmd);
|
||||
install_element_ve(&show_subscr_cache_cmd);
|
||||
install_element_ve(&show_timer_cmd);
|
||||
install_element_ve(&show_timer_gtp_cmd);
|
||||
|
||||
install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
|
||||
install_element(ENABLE_NODE, &update_subscr_create_cmd);
|
||||
|
@ -1445,6 +1801,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
|
|||
install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
|
||||
install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
|
||||
install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
|
||||
install_element(ENABLE_NODE, &page_subscr_info_cmd);
|
||||
install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_sgsn_cmd);
|
||||
|
@ -1459,7 +1816,14 @@ int sgsn_vty_init(struct sgsn_config *cfg)
|
|||
install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
|
||||
install_element(SGSN_NODE, &cfg_auth_policy_cmd);
|
||||
install_element(SGSN_NODE, &cfg_authentication_cmd);
|
||||
|
||||
/* order matters here: ensure we attempt to parse our new command first! */
|
||||
install_element(SGSN_NODE, &cfg_encrypt2_cmd);
|
||||
install_element(SGSN_NODE, &cfg_encrypt_cmd);
|
||||
install_element(SGSN_NODE, &cfg_encryption_uea_cmd);
|
||||
install_element(SGSN_NODE, &cfg_encrypt_cipher_plugin_path_cmd);
|
||||
install_element(SGSN_NODE, &cfg_no_encrypt_cipher_plugin_path_cmd);
|
||||
|
||||
install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd);
|
||||
install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
|
||||
install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
|
||||
|
@ -1479,6 +1843,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
|
|||
install_element(SGSN_NODE, &cfg_grx_ggsn_cmd);
|
||||
|
||||
install_element(SGSN_NODE, &cfg_sgsn_timer_cmd);
|
||||
install_element(SGSN_NODE, &cfg_sgsn_timer_gtp_cmd);
|
||||
|
||||
install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd);
|
||||
install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd);
|
||||
|
@ -1487,6 +1852,15 @@ int sgsn_vty_init(struct sgsn_config *cfg)
|
|||
install_element(SGSN_NODE, &cfg_comp_v42bis_cmd);
|
||||
install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd);
|
||||
|
||||
install_element(SGSN_NODE, &cfg_sgsn_mme_cmd);
|
||||
install_element(SGSN_NODE, &cfg_sgsn_no_mme_cmd);
|
||||
install_node(&mme_node, NULL);
|
||||
install_element(MME_NODE, &cfg_mme_remote_ip_cmd);
|
||||
install_element(MME_NODE, &cfg_mme_ran_info_relay_default_cmd);
|
||||
install_element(MME_NODE, &cfg_mme_no_ran_info_relay_default_cmd);
|
||||
install_element(MME_NODE, &cfg_mme_ran_info_relay_tai_cmd);
|
||||
install_element(MME_NODE, &cfg_mme_no_ran_info_relay_tai_cmd);
|
||||
|
||||
#ifdef BUILD_IU
|
||||
install_element(SGSN_NODE, &cfg_sgsn_cs7_instance_iu_cmd);
|
||||
ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = \
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue