mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
synced 2025-11-02 13:13:29 +00:00
Compare commits
20 Commits
1.4.0
...
neels/dgsm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1971b6731a | ||
|
|
b3c1726fb9 | ||
|
|
81ac78dfac | ||
|
|
dd73ccfc99 | ||
|
|
40d3a96f9d | ||
|
|
1e635ab550 | ||
|
|
43d5cfc13b | ||
|
|
61917ed51d | ||
|
|
43de5efb3d | ||
|
|
c992d85068 | ||
|
|
d29b2f236f | ||
|
|
647c106d1c | ||
|
|
a75d1c2c94 | ||
|
|
32cc07ad06 | ||
|
|
bf8b614c0e | ||
|
|
bcb5dca1c9 | ||
|
|
f6c8f04c79 | ||
|
|
82112ea835 | ||
|
|
0d28d85168 | ||
|
|
b2553ebb4a |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -26,7 +26,6 @@ m4
|
||||
*.m4
|
||||
missing
|
||||
.deps
|
||||
*~
|
||||
|
||||
*.pc
|
||||
.libs
|
||||
@@ -68,5 +67,3 @@ doc/manuals/generated/
|
||||
doc/manuals/osmomsc-usermanual.xml
|
||||
doc/manuals/common
|
||||
doc/manuals/build
|
||||
|
||||
contrib/osmo-hlr.spec
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
AUTOMAKE_OPTIONS = foreign dist-bzip2
|
||||
|
||||
SUBDIRS = \
|
||||
doc \
|
||||
src \
|
||||
include \
|
||||
doc \
|
||||
sql \
|
||||
contrib \
|
||||
tests \
|
||||
@@ -11,8 +11,6 @@ SUBDIRS = \
|
||||
|
||||
EXTRA_DIST = \
|
||||
.version \
|
||||
contrib/osmo-hlr.spec.in \
|
||||
debian \
|
||||
$(NULL)
|
||||
|
||||
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||
|
||||
66
README.md
66
README.md
@@ -1,66 +0,0 @@
|
||||
osmo-hlr - Osmocom HLR Implementation
|
||||
=====================================
|
||||
|
||||
This repository contains a C-language implementation of a GSM Home
|
||||
Location Register (HLR). It is part of the
|
||||
[Osmocom](https://osmocom.org/) Open Source Mobile Communications
|
||||
project.
|
||||
|
||||
Warning: While the HLR logical functionality is implemented, OsmoHLR
|
||||
does not use the ETSI/3GPP TCAP/MAP protocol stack. Instead, a much
|
||||
simpler custom protocol (GSUP) is used. This means, OsmoHLR is of
|
||||
no use outside the context of an Osmocom core network. You can use
|
||||
it with OsmoMSC, OsmoSGSN etc. - but not with third party components.
|
||||
|
||||
Homepage
|
||||
--------
|
||||
|
||||
The official homepage of the project is
|
||||
https://osmocom.org/projects/osmo-hlr/wiki
|
||||
|
||||
GIT Repository
|
||||
--------------
|
||||
|
||||
You can clone from the official osmo-hlr.git repository using
|
||||
|
||||
git clone git://git.osmocom.org/osmo-hlr.git
|
||||
git clone https://git.osmocom.org/osmo-hlr.git
|
||||
|
||||
There is a cgit interface at https://git.osmocom.org/osmo-hlr/
|
||||
|
||||
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/osmohlr-usermanual.pdf)
|
||||
as well as the VTY reference manuals
|
||||
* [VTY Reference Manual for osmo-hlr](https://ftp.osmocom.org/docs/latest/osmohlr-vty-reference.pdf)
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
|
||||
Discussions related to osmo-hlr are happening on the
|
||||
openbsc@lists.osmocom.org mailing list, please see
|
||||
https://lists.osmocom.org/mailman/listinfo/openbsc 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.
|
||||
|
||||
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-hlr can be seen at
|
||||
https://gerrit.osmocom.org/#/q/project:osmo-hlr+status:open
|
||||
@@ -1,9 +0,0 @@
|
||||
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
|
||||
# according to https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
|
||||
# In short:
|
||||
# LIBVERSION=c:r:a
|
||||
# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
|
||||
# If any interfaces have been added, removed, or changed since the last update: c + 1:0:0.
|
||||
# If any interfaces have been added since the last public release: c:r:a + 1.
|
||||
# If any interfaces have been removed or changed since the last public release: c:r:0.
|
||||
#library what description / commit summary line
|
||||
17
configure.ac
17
configure.ac
@@ -12,8 +12,6 @@ AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip 1.9])
|
||||
|
||||
AC_CONFIG_TESTDIR(tests)
|
||||
|
||||
CFLAGS="$CFLAGS -std=gnu11"
|
||||
|
||||
dnl kernel style compile messages
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
@@ -27,7 +25,7 @@ AC_PROG_MKDIR_P
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
|
||||
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
|
||||
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
|
||||
AS_CASE(["$LD"],[*clang*],
|
||||
[AS_CASE(["${host_os}"],
|
||||
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
|
||||
@@ -41,11 +39,11 @@ PKG_PROG_PKG_CONFIG([0.20])
|
||||
|
||||
PKG_CHECK_MODULES(TALLOC, [talloc >= 2.0.1])
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.3.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.3.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.3.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.3.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0)
|
||||
|
||||
PKG_CHECK_MODULES(SQLITE3, sqlite3)
|
||||
|
||||
@@ -188,6 +186,7 @@ AC_OUTPUT(
|
||||
Makefile
|
||||
doc/Makefile
|
||||
doc/examples/Makefile
|
||||
doc/sequence_charts/Makefile
|
||||
src/Makefile
|
||||
src/gsupclient/Makefile
|
||||
src/mslookup/Makefile
|
||||
@@ -202,10 +201,10 @@ AC_OUTPUT(
|
||||
contrib/Makefile
|
||||
contrib/systemd/Makefile
|
||||
contrib/dgsm/Makefile
|
||||
contrib/osmo-hlr.spec
|
||||
tests/Makefile
|
||||
tests/auc/Makefile
|
||||
tests/auc/gen_ts_55_205_test_sets/Makefile
|
||||
tests/gsup_server/Makefile
|
||||
tests/gsup/Makefile
|
||||
tests/db/Makefile
|
||||
tests/db_upgrade/Makefile
|
||||
|
||||
@@ -2,13 +2,3 @@ SUBDIRS = \
|
||||
systemd \
|
||||
dgsm \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = osmo-hlr-post-upgrade.sh
|
||||
|
||||
install-data-hook:
|
||||
install -Dm755 $(srcdir)/osmo-hlr-post-upgrade.sh \
|
||||
-t $(DESTDIR)$(datadir)/osmocom/
|
||||
|
||||
uninstall-hook:
|
||||
@$(PRE_UNINSTALL)
|
||||
$(RM) $(DESTDIR)$(datadir)/osmocom/osmo-hlr-post-upgrade.sh
|
||||
|
||||
@@ -35,6 +35,7 @@ osmo-build-dep.sh libosmo-abis
|
||||
# Additional configure options and depends
|
||||
CONFIG=""
|
||||
if [ "$WITH_MANUALS" = "1" ]; then
|
||||
osmo-build-dep.sh osmo-gsm-manuals
|
||||
CONFIG="--enable-manuals"
|
||||
fi
|
||||
|
||||
@@ -56,11 +57,11 @@ autoreconf --install --force
|
||||
$CONFIG
|
||||
$MAKE $PARALLEL_MAKE
|
||||
$MAKE check || cat-testlogs.sh
|
||||
DISTCHECK_CONFIGURE_FLAGS="$CONFIG" $MAKE $PARALLEL_MAKE distcheck || cat-testlogs.sh
|
||||
DISTCHECK_CONFIGURE_FLAGS="$CONFIG" $MAKE distcheck || cat-testlogs.sh
|
||||
|
||||
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
|
||||
make -C "$base/doc/manuals" publish
|
||||
fi
|
||||
|
||||
$MAKE $PARALLEL_MAKE maintainer-clean
|
||||
$MAKE maintainer-clean
|
||||
osmo-clean-workspace.sh
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# Copyright 2021 sysmocom s.f.m.c GmbH <info@sysmocom.de>
|
||||
#
|
||||
# Packagers are supposed to call this script in post-upgrade, so it can safely
|
||||
# upgrade the database scheme if required.
|
||||
|
||||
DB="/var/lib/osmocom/hlr.db"
|
||||
IS_ACTIVE=0
|
||||
|
||||
msg() {
|
||||
echo "osmo-hlr-post-upgrade: $@"
|
||||
}
|
||||
|
||||
err() {
|
||||
msg "ERROR: $@"
|
||||
}
|
||||
|
||||
open_db() {
|
||||
# Attempt to open the database with osmo-hlr-db-tool, it will fail if
|
||||
# upgrading the schema is required
|
||||
osmo-hlr-db-tool -s -l "$DB" create
|
||||
}
|
||||
|
||||
check_upgrade_required() {
|
||||
if ! [ -e "$DB" ]; then
|
||||
msg "nothing to do (no existing database)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if open_db 2>/dev/null; then
|
||||
msg "nothing to do (database version is up to date)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
msg "database upgrade is required"
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
if systemctl is-active -q osmo-hlr; then
|
||||
IS_ACTIVE=1
|
||||
msg "stopping osmo-hlr service"
|
||||
systemctl stop osmo-hlr
|
||||
|
||||
# Verify that it stopped
|
||||
for i in $(seq 1 100); do
|
||||
if ! systemctl is-active -q osmo-hlr; then
|
||||
return
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
err "failed to stop osmo-hlr service"
|
||||
exit 1
|
||||
else
|
||||
msg "osmo-hlr service is not running"
|
||||
fi
|
||||
}
|
||||
|
||||
create_backup() {
|
||||
backup="$DB.$(date +%Y%m%d%H%M%S).bak"
|
||||
msg "creating backup: $backup"
|
||||
if [ -e "$backup" ]; then
|
||||
err "backup already exists: $backup"
|
||||
exit 1
|
||||
fi
|
||||
cp "$DB" "$backup"
|
||||
}
|
||||
|
||||
upgrade() {
|
||||
msg "performing database upgrade"
|
||||
osmo-hlr-db-tool -s -U -l "$DB" create
|
||||
|
||||
if ! open_db 2>/dev/null; then
|
||||
err "failed to open the database after upgrade"
|
||||
err "osmo-hlr-db-tool output:"
|
||||
open_db
|
||||
# exit because of "set -e"
|
||||
fi
|
||||
|
||||
msg "database upgrade successful"
|
||||
}
|
||||
|
||||
start_service() {
|
||||
if [ "$IS_ACTIVE" = "1" ]; then
|
||||
msg "starting osmo-hlr service"
|
||||
systemctl start osmo-hlr
|
||||
fi
|
||||
}
|
||||
|
||||
check_upgrade_required
|
||||
stop_service
|
||||
create_backup
|
||||
upgrade
|
||||
start_service
|
||||
@@ -1,195 +0,0 @@
|
||||
#
|
||||
# spec file for package osmo-hlr
|
||||
#
|
||||
# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
|
||||
# Copyright (c) 2016, 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.
|
||||
|
||||
Name: osmo-hlr
|
||||
Version: @VERSION@
|
||||
Release: 0
|
||||
Summary: Osmocom Home Location Register for GSUP protocol towards OsmoSGSN and OsmoCSCN
|
||||
License: AGPL-3.0-or-later AND GPL-2.0-or-later
|
||||
Group: Productivity/Telephony/Servers
|
||||
URL: https://osmocom.org/projects/osmo-hlr
|
||||
Source: %{name}-%{version}.tar.xz
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: automake
|
||||
BuildRequires: libtool
|
||||
BuildRequires: pkgconfig >= 0.20
|
||||
BuildRequires: python3
|
||||
%if 0%{?suse_version}
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%endif
|
||||
BuildRequires: pkgconfig(libosmoabis) >= 1.1.0
|
||||
BuildRequires: pkgconfig(libosmocore) >= 1.5.0
|
||||
BuildRequires: pkgconfig(libosmoctrl) >= 1.5.0
|
||||
BuildRequires: pkgconfig(libosmogsm) >= 1.5.0
|
||||
BuildRequires: pkgconfig(libosmovty) >= 1.5.0
|
||||
BuildRequires: pkgconfig(sqlite3)
|
||||
BuildRequires: pkgconfig(talloc) >= 2.0.1
|
||||
# only needed for populate_hlr_db.pl
|
||||
Requires: libdbi-drivers-dbd-sqlite3
|
||||
%{?systemd_requires}
|
||||
|
||||
%description
|
||||
The GSUP HLR is a stand-alone HLR (Home Location Register) for SIM
|
||||
and USIM based subscribers which exposes the GSUP protocol towards
|
||||
its users. OsmoSGSN supports this protocol.
|
||||
|
||||
osmo-gsup-hlr is still very simplistic. It is a single-threaded
|
||||
architecture and uses only sqlite3 tables as back-end. It is suitable
|
||||
for installations of the scale that OsmoNITB was able to handle. It
|
||||
also lacks various features like fine-grained control of subscribed
|
||||
services (like supplementary services).
|
||||
|
||||
%package -n libosmo-gsup-client0
|
||||
Summary: Osmocom GSUP (General Subscriber Update Protocol) client library
|
||||
License: GPL-2.0-or-later
|
||||
Group: System/Libraries
|
||||
|
||||
%description -n libosmo-gsup-client0
|
||||
This is a shared library that can be used to implement client programs for
|
||||
the GSUP protocol. The typical GSUP server is OsmoHLR, with OsmoMSC, OsmoSGSN
|
||||
and External USSD Entities (EUSEs) using this library to implement clients.
|
||||
|
||||
%package -n libosmo-gsup-client-devel
|
||||
Summary: Development files for the Osmocom GSUP client library
|
||||
License: GPL-2.0-or-later
|
||||
Group: Development/Libraries/C and C++
|
||||
Requires: libosmo-gsup-client0 = %{version}
|
||||
|
||||
%description -n libosmo-gsup-client-devel
|
||||
This is a shared library that can be used to implement client programs for
|
||||
the GSUP protocol. The typical GSUP server is OsmoHLR, with OsmoMSC, OsmoSGSN
|
||||
and External USSD Entities (EUSEs) using this library to implement clients.
|
||||
|
||||
This subpackage contains libraries and header files for developing
|
||||
applications that want to make use of libosmo-gsup-client.
|
||||
|
||||
%package -n libosmo-mslookup0
|
||||
Summary: Osmocom MS lookup library
|
||||
License: GPL-2.0-or-later
|
||||
Group: System/Libraries
|
||||
|
||||
%description -n libosmo-mslookup0
|
||||
This shared library contains routines for looking up mobile subscribers.
|
||||
|
||||
%package -n libosmo-mslookup-devel
|
||||
Summary: Development files for the Osmocom MS lookup library
|
||||
License: GPL-2.0-or-later
|
||||
Group: Development/Libraries/C and C++
|
||||
Requires: libosmo-mslookup0 = %{version}
|
||||
|
||||
%description -n libosmo-mslookup-devel
|
||||
This shared library contains routines for looking up mobile subscribers.
|
||||
|
||||
This subpackage contains libraries and header files for developing
|
||||
applications that want to make use of libosmo-mslookup.
|
||||
|
||||
|
||||
%package -n osmo-mslookup-client
|
||||
Summary: Standalone program using libosmo-mslookup
|
||||
License: GPL-2.0-or-later
|
||||
Group: Development/Libraries/C and C++
|
||||
|
||||
%description -n osmo-mslookup-client
|
||||
Standalone program using libosmo-mslookup to easily integrate with programs
|
||||
that want to connect services (SIP, SMS,...) to the current location of a
|
||||
subscriber.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
echo "%{version}" >.tarball-version
|
||||
autoreconf -fi
|
||||
%configure \
|
||||
--docdir="%{_docdir}/%{name}" \
|
||||
--with-systemdsystemunitdir=%{_unitdir} \
|
||||
--enable-shared \
|
||||
--disable-static
|
||||
make V=1 %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
%make_install
|
||||
install -d "%{buildroot}/%{_localstatedir}/lib/osmocom"
|
||||
find %{buildroot} -type f -name "*.la" -delete -print
|
||||
|
||||
%check
|
||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
|
||||
|
||||
%if 0%{?suse_version}
|
||||
%preun
|
||||
%service_del_preun %{name}.service
|
||||
|
||||
%postun
|
||||
%service_del_postun %{name}.service
|
||||
|
||||
%pre
|
||||
%service_add_pre %{name}.service
|
||||
%endif
|
||||
|
||||
%post
|
||||
%if 0%{?suse_version}
|
||||
%service_add_post %{name}.service
|
||||
%endif
|
||||
/usr/share/osmocom/osmo-hlr-post-upgrade.sh
|
||||
|
||||
%post -n libosmo-gsup-client0 -p /sbin/ldconfig
|
||||
%postun -n libosmo-gsup-client0 -p /sbin/ldconfig
|
||||
%post -n libosmo-mslookup0 -p /sbin/ldconfig
|
||||
%postun -n libosmo-mslookup0 -p /sbin/ldconfig
|
||||
|
||||
%files
|
||||
%license COPYING
|
||||
%dir %{_docdir}/%{name}
|
||||
%dir %{_docdir}/%{name}/examples
|
||||
%{_docdir}/%{name}/examples/osmo-hlr.cfg
|
||||
%{_docdir}/%{name}/examples/osmo-hlr-dgsm.cfg
|
||||
%dir %{_docdir}/%{name}/sql
|
||||
%{_docdir}/%{name}/sql/hlr.sql
|
||||
%{_docdir}/%{name}/sql//hlr_data.sql
|
||||
%dir %{_sysconfdir}/osmocom
|
||||
%dir %{_localstatedir}/lib/osmocom
|
||||
%{_bindir}/osmo-hlr
|
||||
%{_bindir}/osmo-hlr-db-tool
|
||||
%dir %{_sysconfdir}/osmocom
|
||||
%config %{_sysconfdir}/osmocom/osmo-hlr.cfg
|
||||
%{_unitdir}/osmo-hlr.service
|
||||
%dir %{_datadir}/osmocom
|
||||
%{_datadir}/osmocom/osmo-hlr-post-upgrade.sh
|
||||
|
||||
%files -n libosmo-gsup-client0
|
||||
%{_libdir}/libosmo-gsup-client.so.0*
|
||||
|
||||
%files -n libosmo-gsup-client-devel
|
||||
%{_bindir}/osmo-euse-demo
|
||||
%dir %{_includedir}/osmocom
|
||||
%dir %{_includedir}/osmocom/gsupclient
|
||||
%{_includedir}/osmocom/gsupclient/*.h
|
||||
%{_libdir}/libosmo-gsup-client.so
|
||||
%{_libdir}/pkgconfig/libosmo-gsup-client.pc
|
||||
|
||||
%files -n libosmo-mslookup0
|
||||
%{_libdir}/libosmo-mslookup.so.0*
|
||||
|
||||
%files -n libosmo-mslookup-devel
|
||||
%dir %{_includedir}/osmocom
|
||||
%dir %{_includedir}/osmocom/mslookup
|
||||
%{_includedir}/osmocom/mslookup/*.h
|
||||
%{_libdir}/libosmo-mslookup.so
|
||||
%{_libdir}/pkgconfig/libosmo-mslookup.pc
|
||||
|
||||
%files -n osmo-mslookup-client
|
||||
%{_bindir}/osmo-mslookup-client
|
||||
|
||||
%changelog
|
||||
121
debian/changelog
vendored
121
debian/changelog
vendored
@@ -1,124 +1,3 @@
|
||||
osmo-hlr (1.4.0) unstable; urgency=medium
|
||||
|
||||
[ Keith ]
|
||||
* Correct configuration written from vty
|
||||
* vty: enable show subscribers filtered by IMEI
|
||||
|
||||
[ Harald Welte ]
|
||||
* add README.md file as customary for cgit, github, gitlab, etc.
|
||||
|
||||
[ Oliver Smith ]
|
||||
* Add post-upgrade script for automatic db upgrade
|
||||
* debian/control: remove dh-systemd build-depend
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* db: Avoid use uninitialized rc if running 0 statements
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* db v6: determine 3G AUC IND from VLR name
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 16 Nov 2021 14:56:41 +0100
|
||||
|
||||
osmo-hlr (1.3.0) unstable; urgency=medium
|
||||
|
||||
[ Alexander Couzens ]
|
||||
* hlr: respect the num_auth_vectors requested
|
||||
* hlr: remove unused internal USSD list
|
||||
|
||||
[ Oliver Smith ]
|
||||
* add libosmo-mslookup abstract client
|
||||
* add mDNS lookup method to libosmo-mslookup
|
||||
* Makefile.am: fix pkgconfig_DATA
|
||||
* add mDNS lookup method to libosmo-mslookup (#2)
|
||||
* contrib/dgsm/ add example esme and dialplan
|
||||
* mslookup_client.c: fix dereferencing null pointer
|
||||
* mdns_msg.c: always call va_end
|
||||
* mslookup_client_mdns.c: fix dereferencing null
|
||||
* osmo-mslookup-client.c: fix dereferencing null
|
||||
* osmo-mslookup-client: fix dereferencing null
|
||||
* mdns_sock.c: fix resource leak of sock
|
||||
* mdns_rfc.c: fix possible access of uninit. mem
|
||||
* mslookup_client_mdns_test: disable by default
|
||||
* mslookup_client_mdns_test: no automatic skip
|
||||
* Cosmetic: mention OS#4491 in location cancel code
|
||||
* hlr_vty_subscr: prettier output for last LU seen
|
||||
* contrib: import RPM spec
|
||||
* contrib: integrate RPM spec
|
||||
* Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
|
||||
* contrib/jenkins: don't build osmo-gsm-manuals
|
||||
* configure.ac: set -std=gnu11
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* add osmo-mslookup-client program
|
||||
* add osmo-mslookup-client program (#2)
|
||||
* fix missing braces in LOGP_GSUP_FWD
|
||||
* gsup_client.c: fix deprecation for client create func
|
||||
* 1/2: refactor: add and use lu_fsm, osmo_gsup_req, osmo_ipa_name
|
||||
* 2/2: wrap ipa_name in osmo_cni_peer_id with type enum and union
|
||||
* gsup client: add up_down_cb(), add osmo_gsup_client_create3()
|
||||
* db v5: prep for D-GSM: add vlr_via_proxy and sgsn_via_proxy
|
||||
* enlarge the GSUP message headroom
|
||||
* test_nodes.vty: remove cruft
|
||||
* D-GSM 1/n: add mslookup server in osmo-hlr
|
||||
* D-GSM 2/n: implement mDNS method of mslookup server
|
||||
* D-GSM 3/n: implement roaming by mslookup in osmo-hlr
|
||||
* gsup_server: send routing error back to the correct peer
|
||||
* adoc: add D-GSM chapter to osmohlr-usermanual
|
||||
* drop error log for when a subscriber does not exist
|
||||
* vty: show subscriber: change format of 'last LU seen'
|
||||
* vty: show subscriber: show lu d,h,m,s ago, not just seconds
|
||||
* auc3g: officially wrap IND around IND_bitlen space
|
||||
* make osmo_cni_peer_id_cmp() NULL safe
|
||||
* osmo_gsup_req_new(): require from_peer != NULL
|
||||
* gsup_server.c: properly handle negative rc from osmo_gsup_conn_ccm_get()
|
||||
* osmo_mslookup_server_mdns_rx(): handle read() rc == 0
|
||||
* hlr_subscr_nam(): fix condition to fix nam=false notifications
|
||||
* esme_dgsm.py: add --always-fail option for debugging SMPP
|
||||
* osmo-mslookup-client: fix segfault for respond_error() caller
|
||||
* manual: describe subscriber import by SQL
|
||||
|
||||
[ Harald Welte ]
|
||||
* Revert "add osmo-mslookup-client program"
|
||||
* Revert "add mDNS lookup method to libosmo-mslookup"
|
||||
* Use OSMO_FD_* instead of deprecated BSC_FD_*
|
||||
* support the XOR algorithm for UMTS AKA
|
||||
* auc_test.c: Add some comments on what the test cases actually do
|
||||
* main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
|
||||
* manuals: generate vty reference xml at build time
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* db: fix possible SQLite3 allocated memory leak in db_open()
|
||||
* gsup_server: fix typo: s/omso_gsup_message/osmo_gsup_message/
|
||||
* debian/control: change maintainer to the Osmocom team / mailing list
|
||||
* cosmetic: fix spelling in logging message: existAnt -> existEnt
|
||||
* doc/manuals: fix s/There/The/ in 'USSD Configuration'
|
||||
* doc/manuals: re-organize description of internal USSD handlers
|
||||
* USSD: fix handle_ussd(): do not free() unconditionally
|
||||
* USSD: add special 'idle' handler to IUSE for testing
|
||||
|
||||
[ Eric ]
|
||||
* configure.ac: fix libtool issue with clang and sanitizer
|
||||
|
||||
[ Philipp Maier ]
|
||||
* doc: do not use loglevel info for log category ss
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* configure.ac: Fix trailing whitespace
|
||||
* doc: Update VTY reference xml file
|
||||
* Support setting rt-prio and cpu-affinity mask through VTY
|
||||
* Set TCP NODELAY sockopt to GSUP cli and srv connections
|
||||
* contrib/jenkins: Enable parallel make in make distcheck
|
||||
* .gitignore: Ignore new autofoo tmp files
|
||||
* tests: Replace deprecated API log_set_print_filename
|
||||
|
||||
[ Keith ]
|
||||
* osmo-hlr-db-tool: Make import from osmo-nitb less "lossy"
|
||||
* Correct vty inline help for show subscriber
|
||||
* Add vty command to show summary of all or filtered subscribers
|
||||
* Fix Coverity Warnings
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 23 Feb 2021 18:13:53 +0100
|
||||
|
||||
osmo-hlr (1.2.0) unstable; urgency=medium
|
||||
|
||||
[ Ruben Undheim ]
|
||||
|
||||
11
debian/control
vendored
11
debian/control
vendored
@@ -1,18 +1,19 @@
|
||||
Source: osmo-hlr
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||
Maintainer: Max Suraev <msuraev@sysmocom.de>
|
||||
Build-Depends: debhelper (>= 9),
|
||||
pkg-config,
|
||||
dh-autoreconf,
|
||||
dh-systemd (>= 1.5),
|
||||
autotools-dev,
|
||||
python3-minimal,
|
||||
libosmocore-dev (>= 1.5.0),
|
||||
libosmo-abis-dev (>= 1.1.0),
|
||||
libosmo-netif-dev (>= 1.1.0),
|
||||
libosmocore-dev,
|
||||
libosmo-abis-dev,
|
||||
libosmo-netif-dev,
|
||||
libsqlite3-dev,
|
||||
sqlite3,
|
||||
osmo-gsm-manuals-dev (>= 1.1.0)
|
||||
osmo-gsm-manuals-dev
|
||||
Standards-Version: 3.9.6
|
||||
Vcs-Browser: http://cgit.osmocom.org/osmo-hlr
|
||||
Vcs-Git: git://git.osmocom.org/osmo-hlr
|
||||
|
||||
1
debian/osmo-hlr.install
vendored
1
debian/osmo-hlr.install
vendored
@@ -5,5 +5,4 @@
|
||||
/usr/share/doc/osmo-hlr/sql/hlr.sql
|
||||
/usr/share/doc/osmo-hlr/sql/hlr_data.sql
|
||||
/usr/share/doc/osmo-hlr/examples/osmo-hlr.cfg
|
||||
/usr/share/osmocom/osmo-hlr-post-upgrade.sh
|
||||
/var/lib/osmocom
|
||||
|
||||
5
debian/postinst
vendored
5
debian/postinst
vendored
@@ -1,5 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
# Debian's postinst script is called on both installation and upgrade. Call the
|
||||
# post-upgrade script in both cases, it won't do anything if there is nothing
|
||||
# to do.
|
||||
/usr/share/osmocom/osmo-hlr-post-upgrade.sh
|
||||
@@ -1,4 +1,5 @@
|
||||
SUBDIRS = \
|
||||
examples \
|
||||
manuals \
|
||||
sequence_charts \
|
||||
$(NULL)
|
||||
|
||||
@@ -12,7 +12,7 @@ log stderr
|
||||
logging level main notice
|
||||
logging level db notice
|
||||
logging level auc notice
|
||||
logging level ss notice
|
||||
logging level ss info
|
||||
logging level linp error
|
||||
!
|
||||
line vty
|
||||
|
||||
@@ -4,22 +4,21 @@ EXTRA_DIST = example_subscriber_add_update_delete.vty \
|
||||
osmohlr-usermanual.adoc \
|
||||
osmohlr-usermanual-docinfo.xml \
|
||||
osmohlr-vty-reference.xml \
|
||||
chapters/proxy_cache_attach.msc \
|
||||
chapters/proxy_cache_more_tuples.msc \
|
||||
chapters/proxy_cache_periodic_lu.msc \
|
||||
chapters/proxy_cache_tuple_cache_dry.msc \
|
||||
chapters/proxy_cache_umts_aka_resync.msc \
|
||||
regen_doc.sh \
|
||||
chapters \
|
||||
vty
|
||||
|
||||
if BUILD_MANUALS
|
||||
ASCIIDOC = osmohlr-usermanual.adoc
|
||||
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc $(srcdir)/*.vty $(srcdir)/*.ctrl
|
||||
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc $(srcdir)/*.vty $(srcdir)/*.ctrl $(srcdir)/chapters/*.msc
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
|
||||
|
||||
VTY_REFERENCE = osmohlr-vty-reference.xml
|
||||
|
||||
BUILT_REFERENCE_XML = $(builddir)/vty/hlr_vty_reference.xml
|
||||
$(builddir)/vty/hlr_vty_reference.xml: $(top_builddir)/src/osmo-hlr
|
||||
mkdir -p $(builddir)/vty
|
||||
$(top_builddir)/src/osmo-hlr --vty-ref-xml > $@
|
||||
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
||||
|
||||
OSMO_REPOSITORY = osmo-hlr
|
||||
|
||||
20
doc/manuals/chapters/Makefile
Normal file
20
doc/manuals/chapters/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
all: \
|
||||
proxy_cache_attach.msc \
|
||||
proxy_cache_more_tuples.msc \
|
||||
proxy_cache_tuple_cache_dry.msc \
|
||||
proxy_cache_periodic_lu.msc \
|
||||
proxy_cache_umts_aka_resync.msc \
|
||||
$(NULL)
|
||||
|
||||
png: \
|
||||
proxy_cache.png \
|
||||
proxy_cache_unused.png \
|
||||
lu_attach_and_periodic.png \
|
||||
$(NULL)
|
||||
|
||||
%.png: %.msc
|
||||
mscgen -T png -o $@ $<
|
||||
|
||||
%.msc: %.ladder
|
||||
@which ladder_to_msc.py || (echo 'PLEASE POINT YOUR $$PATH AT libosmocore/contrib/ladder_to_msc.py' && false)
|
||||
ladder_to_msc.py -i $< -o $@
|
||||
333
doc/manuals/chapters/proxy_cache.adoc
Normal file
333
doc/manuals/chapters/proxy_cache.adoc
Normal file
@@ -0,0 +1,333 @@
|
||||
== Distributed GSM / GSUP Proxy Cache: Remedy Temporary Link Failure to Home HLR
|
||||
|
||||
The aim of the Proxy Cache is to still provide service to roaming subscribers even if the GSUP link to the home HLR is
|
||||
temporarily down or unresponsive.
|
||||
|
||||
If a subscriber from a remote site is currently roaming at this local site, and the link to the subscriber's home HLR
|
||||
has succeeded before, the GSUP proxy cache can try to bridge the time of temporary link failure to that home HLR.
|
||||
|
||||
Tasks to take over from an unreachable home HLR:
|
||||
|
||||
- Cache and send auth tuples on Send Auth Info Request.
|
||||
- Acknowledge periodic Location Updating.
|
||||
- ...?
|
||||
|
||||
=== Design Considerations
|
||||
|
||||
==== Authentication
|
||||
|
||||
The most critical role of the home HLR is providing the Authentication and Key Agreement (AKA) tuples. If the home HLR
|
||||
is not reachable, the lack of fresh authentication challenges would normally cause the subscriber to be rejected. To
|
||||
avoid that, a proxying HLR needs to be able to provide AKA tuples on behalf of the home HLR.
|
||||
|
||||
In short, the strategy of the D-GSM proxy cache is:
|
||||
|
||||
- Try to keep a certain number of unused full UMTS AKA tuples in the proxy cache at all times.
|
||||
- When the MSC requests more tuples, dispense some from the cache, and fill it back up later on, as soon as a good link
|
||||
is available.
|
||||
- When the tuple cache in the proxy HLR runs dry, 3G RAN becomes unusable. But 2G RAN may fall back to GSM AKA, if the
|
||||
proxy HLR configuration permits it: resend previously used GSM AKA auth tuples to the MSC, omitting UMTS AKA items
|
||||
from the Send Auth Info Result, to force the MSC to send a GSM AKA challenge on 2G.
|
||||
|
||||
The remaining part of this section provides detailed reasoning for this strategy.
|
||||
|
||||
The aim is to attach a subscriber without immediate access to the authentication key data.
|
||||
|
||||
Completely switching off authentication would be an option on GERAN (2G), but this would mean complete lack of
|
||||
encryption on the air interface, and is not recommended. On 3G and later, authentication is always mandatory.
|
||||
|
||||
The key data is known only to the USIM and the home HLR. The HLR generates distinct authentication tuples, each
|
||||
containing a cryptographic challenge (RAND, AUTN) and its expected response (SRES, XRES). The MSC consumes one tuple
|
||||
per authentication: it sends the challenge to the subscriber, and compares the response received.
|
||||
|
||||
The proxy could generate fresh tuples if the cryptographic key data (Ki,K,OP/OPC) from the home HLR was shared with the
|
||||
proxy HLR. Distributed GSM does not do this, because:
|
||||
|
||||
- The key data is cryptographically very valuable. If it were leaked, any and all authentication challenges would be
|
||||
fully compromised.
|
||||
|
||||
- In D-GSM, each home site shall retain exclusive authority over the user data. It should not be necessary to share the
|
||||
secret keys with any remote site.
|
||||
|
||||
So, how about resending already used auth tuples to the MSC when no fresh ones are available? Resending identical
|
||||
authentication challenges makes the system vulnerable to relatively trivial replay-attacks, but this may be an
|
||||
acceptable fallback in situations of failing links, if it means being able to provide reliable roaming.
|
||||
|
||||
But, even if a proxying HLR is willing to compromise cryptographic security to improve service, this can only work with
|
||||
GSM AKA:
|
||||
|
||||
- In GSM AKA (so-called 2G auth), tuples may be re-used any amount of times without a strict need to generate more
|
||||
authentication challenges. The SIM will merely calculate the (same) SRES response again, and authentication will
|
||||
succeed. It is bad security to do so, but it is a choice the core network is free to make.
|
||||
|
||||
- UMTS AKA (Milenage or so-called 3G auth, but also used on 2G GERAN) adds mutual authentication, i.e. the core network
|
||||
must prove that it is authentic. Specifically to thwart replay-attacks that would spoof a core network, UMTS AKA
|
||||
contains an ongoing sequence number (SQN) that is woven into the authentication challenge. An SQN may skip forward by
|
||||
a certain number of counts, but it can never move backwards. If a USIM detects a stale SQN, it will request an
|
||||
authentication re-synchronisation (by passing AUTS in an Authentication Failure message), after which a freshly
|
||||
generated UMTS AKA challenge is strictly required -- not possible with an unresponsive home HLR.
|
||||
|
||||
Post-R99 (1999) 2G GERAN networks are capable of UMTS AKA, so, not only 3G, but also the vast majority of 2G networks
|
||||
today use UMTS AKA -- and so does Osmocom, typically. Hence it is desirable to fully support UMTS AKA in D-GSM.
|
||||
|
||||
[options="header"]
|
||||
|===
|
||||
| RAN | authentication is... 2+| available AKA types
|
||||
| GERAN (2G) | optional | GSM AKA | UMTS AKA
|
||||
| UTRAN (3G) | mandatory | - | UMTS AKA
|
||||
|===
|
||||
|
||||
UMTS AKA will not allow re-sending previously used authentication tuples. But a UMTS capable SIM will fall back to GSM
|
||||
AKA if the network sent only a GSM AKA challenge. If the proxy HLR sends only GSM AKA tuples, then the MSC will request
|
||||
GSM authentication, and re-sending old tuples is again possible. However, a USIM will only fall back to GSM AKA if the
|
||||
phone is attaching on a 2G network. For 3G RAN and later, UMTS AKA is mandatory. So, as soon as a site uses 3G or newer
|
||||
RAN technology, there is simply no way to resend previously used authentication tuples.
|
||||
|
||||
The only way to have unused UMTS AKA tuples in the proxy HLR is to already have them stored from an earlier time. The
|
||||
idea is to request more auth tuples in advance whenever the link is available, and cache them in the proxy. When the MSC
|
||||
uses up some tuples from the proxy HLR, the proxy cache can fill up again in its own time, by requesting more tuples
|
||||
from the home HLR at a time of good link. Then, the next time the subscriber needs immediate action, it does not matter
|
||||
whether the home HLR is directly reachable or not.
|
||||
|
||||
In an aside, since OsmoMSC already caches a number of authentication tuples, one option would be to implement this in
|
||||
OsmoMSC, and not in the proxy HLR: the MSC could request new tuples long before its tuple cache runs dry. However, the
|
||||
OsmoMSC VLR state is volatile, and a power cycle of the system would lose the tuple cache; if the home HLR is
|
||||
unreachable at the same time of the power cycle, roaming service would be interrupted. The proxy cache in the HLR is
|
||||
persistent, so roaming can continue immediately after a power cycle, even if the home HLR link is down.
|
||||
|
||||
==== Location Updating
|
||||
|
||||
Any attached subscriber periodically repeats a Location Updating procedure, typically every 15 minutes. If a home HLR is
|
||||
unreachable at the time of the periodic Location Updating, a roaming subscriber would assume that it is detached from
|
||||
the network, even though the local site it is roaming at is still fully operational.
|
||||
|
||||
The aim of D-GSM is to keep subscribers attached even if the remote home HLR is temporarily unreachable. The simplest
|
||||
way to achieve that is by directly responding with a Update Location Result to the MSC.
|
||||
|
||||
In addition to accepting an Update Location, a proxy HLR should also start an Insert Subscriber Data procedure, as a
|
||||
home HLR would do. For a periodic Location Updating, the MSC should already know all of the information that an Insert
|
||||
Subscriber Data would convey (i.e. the MSISDN), and there would be no strict need to resend this data. But if a
|
||||
subscriber quickly detaches and re-attaches (e.g. the device rebooted), the MSC has discarded the subscriber info from
|
||||
the VLR, and hence the proxy HLR should also always perform an Insert Subscriber Data. (On the GSUP wire, a periodic LU
|
||||
is indistinguishable from an IMSI-Attach LU.)
|
||||
|
||||
Furthermore, the longer the proxy HLR's cache keeps a roaming subscriber's data after an IMSI Detach, the longer it is
|
||||
possible for the subscriber to immediately re-attach despite the home HLR being temporarily unreachable.
|
||||
|
||||
If a subscriber has carried out a GSUP Update Location with the proxy HLR while the home HLR was unreachable, it is not
|
||||
strictly necessary to repeat that Update Location message to the home HLR later. The home HLR does keep a timestamped
|
||||
record of an Update Location from a proxy HLR if seen, but that has no visible effect on serving the subscriber:
|
||||
|
||||
- If the home HLR still thinks that the subscriber is currently attached at the home site, it will respond to mslookup
|
||||
requests. But the actual site the subscriber is roaming at will have a younger age, and its mslookup responses will
|
||||
win.
|
||||
|
||||
- If the home HLR has no record of the subscriber being attached recently, or has a record of being attached at another
|
||||
remote site, it does not respond to mslookup requests for that subscriber. If it records the new proxy LU, it still
|
||||
does not respond to mslookup requests since the subscriber is attached remotely, i.e. there is no difference.
|
||||
|
||||
It is thinkable to always handle an Update Location in the proxy HLR, and never even attempt to involve the home HLR in
|
||||
case the proxy cache already has data for a given subscriber, but then the proxy HLR would never notice a changed MSISDN
|
||||
or authorization status for this subscriber. It is best practice to involve the home HLR whenever possible.
|
||||
|
||||
==== IMSI Detach
|
||||
|
||||
If a GSUP client reports a detaching IMSI when the home HLR is not reachable, simply respond with an ack.
|
||||
|
||||
It is not required to signal the home HLR with a detach once the link is back up. A home HLR anyway flags a remotely
|
||||
roaming subscriber as attached-at-a-proxy, and there is literally no difference between telling a home HLR about a
|
||||
detach or not.
|
||||
|
||||
(TODO: is there even a GSUP message that a VLR should send on IMSI Detach? see OS#4374)
|
||||
|
||||
[[proxy_cache_umts_aka_resync]]
|
||||
==== UMTS AKA Resync
|
||||
|
||||
When the SQN between USIM and AUC (subscriber and home HLR) have diverged, the Send Authentication Info Request from the
|
||||
MSC contains an AUTS IE. This means that a resynchronization between USIM and AUC (the home HLR) is necessary. All of
|
||||
the UMTS AKA tuples in the proxy cache are now unusable, and the home HLR must respond with fresh tuples after doing a
|
||||
resync. This also means that either the home HLR must be reachable immediately, or GSM AKA fallback must be allowed for
|
||||
the subscriber to remain in roaming service.
|
||||
|
||||
In short:
|
||||
|
||||
- A UMTS AKA resync is handled similarly to the attaching of a so far unknown subscriber.
|
||||
- With the exception that previous GSM AKA tuples may be available to try a fallback to re-using older tuples.
|
||||
|
||||
Needless to say that avoiding the need for UMTS AKA resynchronization is an important aspect of D-GSM's resilience
|
||||
against unreliable links.
|
||||
|
||||
In UMTS AKA, there is not one single SQN, but there are a number SQN slots, called IND slots or IND buckets. The IND
|
||||
bitlen configured on the USIM determines the amount of slots available. The IND bitlen is usually 5, i.e. 2^5^ = 32
|
||||
slots. Monotonously rising SQN are only strictly enforced within each slot, so that each site should maintain a
|
||||
different IND slot. OsmoHLR determines distinct IND slots based on the IPA unit name. As soon as more than 16 sites
|
||||
(with an MSC and SGSN each) are maintained, IND slots may be shared between distinct sites, and administrative care
|
||||
should be taken to choose wisely which sites share the same slots: those that least share a common user group.
|
||||
|
||||
On 2G RAN, it may be possible to fall back to GSM AKA after a UMTS AKA resync request.
|
||||
TODO: test this
|
||||
|
||||
Either way, the AUTS that was received from the MSC definitely needs to find its way to the home HLR, and, ideally, the
|
||||
immediately returned auth tuples from the home HLR should be used to attach the subscriber.
|
||||
|
||||
=== CS and PS
|
||||
|
||||
Each subscriber may have multiple HLR subscriptions from distinct CN Domain VLRs at any time: Circuit Switched (MSC) and
|
||||
Packet Switched (SGSN) attach separately and perform Update Location Requests that are completely orthogonal, as far as
|
||||
the HLR is concerned.
|
||||
|
||||
Particularly the UMTS AKA tuples, which use distinct IND slots per VLR, need to be cached separately per CN Domain.
|
||||
|
||||
Hence it is not enough to maintain one cache per subscriber. A separate auth tuple cache and Mobility Management state
|
||||
has to be kept for each VLR that is requesting roaming service for a given subscriber.
|
||||
|
||||
=== Intercepting GSUP Conversations
|
||||
|
||||
Taking over GSUP conversations in the proxy HLR is not as trivial as it may sound. Here are potential problems and how
|
||||
to fix them.
|
||||
|
||||
[[proxy_cache_gsup_mm_messages]]
|
||||
==== Which GSUP Conversations to Intercept
|
||||
|
||||
For the purpose of providing highly available roaming despite unreliable links to the home HLR, it suffices to intercept
|
||||
Mobility Management (MM) related GSUP messages, only:
|
||||
|
||||
- Send Auth Info Request / Result
|
||||
- Update Location Request / Result
|
||||
- Insert Subscriber Data Request / Result
|
||||
- PurgeMS Request / Result (?)
|
||||
|
||||
An interesting feature would be to also intercept specific USSD requests, like returning the own MSISDN or IMSI more
|
||||
reliably, or handling services that only make sense when served by the local site. At the time of writing, this is seen
|
||||
as a future extension of D-GSM and not considered for implementation.
|
||||
|
||||
==== Determining Whether a Home HLR is Responsive
|
||||
|
||||
Normally, all GSUP messages are merely routed via the proxy HLR and are handled by the home HLR. The idea is that the
|
||||
proxy HLR jumps in and saves a GSUP conversation when the home HLR is not answering properly.
|
||||
|
||||
The simplest method to decide whether a home HLR is currently connected would be to look at the GSUP client state.
|
||||
However, a local flag that indicates an established GSUP connection does not necessarily mean a reliable link.
|
||||
There are keep-alive messages on the GSUP/IPA link, and a lost connection should reflect in the client state, so that a
|
||||
lost GSUP link definitely indicates an unresponsive home HLR. But for various reasons (e.g. packet loss), the link might
|
||||
look intact, but still a given GSUP message fails to get a response from the home HLR.
|
||||
|
||||
A more resilient method to decide whether a home HLR is responsive is to keep track of every MM related GSUP
|
||||
conversation for each subscriber, and to jump in and take over the GSUP conversation as soon as the response is taking
|
||||
too long to arrive. However, choosing an inadequate timeout period would either mean responding after the MSC has
|
||||
already timed out (too slow), or completely cutting off all responses from a high-latency home HLR (too fast).
|
||||
|
||||
Also, if the proxy HLR has already responded to the MSC, but a slow home HLR's response arrives shortly after,
|
||||
forwarding this late message to the MSC on top of the earlier response to the same request would confuse the GSUP
|
||||
conversation.
|
||||
|
||||
So, the proxy HLR just jumping into the GSUP conversation when a specific delay has passed is fairly complex and error
|
||||
prone. A better idea is to always intercept MM related GSUP conversations:
|
||||
|
||||
[[proxy_cache_gsup_conversations]]
|
||||
==== Solution: Distinct GSUP Conversations
|
||||
|
||||
A solution that avoids all of the above problems is to *always* take over *all* MM related conversations (see
|
||||
<<proxy_cache_gsup_mm_messages>>), as soon as the proxy has sufficient data to service them by itself; at the same time,
|
||||
the proxy HLR should also relay the same requests to the home HLR, and acknowledge its responses, after the fact.
|
||||
|
||||
If the proxy cache already has a complete record of a subscriber, the proxy HLR can always directly accept an Update
|
||||
Location Request, including an Insert Subscriber Data. A prompt response ensures that the MSC does not timeout its GSUP
|
||||
request, and reduces waiting time for the subscriber.
|
||||
|
||||
To ensure that the proxy HLR's data on the subscriber doesn't become stale and diverge from the home HLR, the proxy
|
||||
asynchronously also forwards an Update Location Request to the home HLR. In most normal cases, there will be no
|
||||
surprises, and the home HLR will continue with an Insert Subscriber Data Request containing already known data, and an
|
||||
Update Location Result accepting the LU.
|
||||
|
||||
If the home HLR does not respond, the proxy HLR ignores that fact -- the home HLR is not reachable, and the aim is to
|
||||
continue to service the subscriber for the time being.
|
||||
|
||||
But, should the home HLR's Insert Subscriber Data Request send different data than the proxy cache sees on record, the
|
||||
proxy HLR can trigger another Insert Subscriber Data Request to the MSC, to correct the stale data sent before.
|
||||
|
||||
Similarly, if the home HLR rejects the Update Location Request completely, the proxy HLR can tell the MSC to detach the
|
||||
subscriber with a Cancel Location Request message, as soon as it notices the rejection.
|
||||
|
||||
Note that a UMTS AKA resynchronization request invalidates the entire auth tuple cache and needs to either be sent to
|
||||
the home HLR immediately, if available, or the AUTS from the USIM must later reach the home HLR to obtain fresh UMTS AKA
|
||||
tuples for the cache. See <<proxy_cache_umts_aka_resync>>.
|
||||
|
||||
=== Message Sequences
|
||||
|
||||
==== Normal Roaming Attach
|
||||
|
||||
On first attaching via a proxy HLR, when there is no proxy state for the subscriber yet, the home HLR must be reachable.
|
||||
|
||||
The normal procedure takes place without modification, except that he proxy HLR keeps a copy of the first auth tuples it
|
||||
forwards from the home HLR back to the MSC (marked as used) (1). This is to have auth tuples available for resending
|
||||
already used tuples in a fallback to GSM AKA, in case this is enabled in the proxy HLR config.
|
||||
|
||||
After the Location Updating has completed successfully, the proxy HLR fills up its auth tuple cache by additional Send
|
||||
Auth Info Requests (2). As soon as unused auth tuples become available, the proxy HLR can discard already used tuples
|
||||
from (1).
|
||||
|
||||
.Normal attaching of a subscriber that is roaming here
|
||||
["mscgen"]
|
||||
----
|
||||
include::proxy_cache_attach.msc[]
|
||||
----
|
||||
|
||||
==== MSC Requests More Auth Tuples
|
||||
|
||||
As soon as the MSC has run out of fresh auth tuples, it will ask the HLR proxy for more. Without proxy caching, this
|
||||
request would be directly forwarded to the home HLR. Instead, the proxy HLR finds unused auth tuples in the cache and
|
||||
directly sends those (3). Even if there is a reliable link, the home HLR is not contacted at this point.
|
||||
|
||||
Directly after completing the Send Auth Info Result, the proxy HLR finds that less tuples than requested by the D-GSM
|
||||
configuration are cached, and asks the home HLR for more tuples, to fill up the cache (4). If there currently is no
|
||||
reliable link, this will fail, and the proxy HLR will retry periodically (5) / upon GSUP reconnect.
|
||||
|
||||
.When the MSC has used up all of its auth tuples, but the proxy HLR still has unused auth tuples in the cache
|
||||
["mscgen"]
|
||||
----
|
||||
include::proxy_cache_more_tuples.msc[]
|
||||
----
|
||||
|
||||
==== Running Out of Auth Tuples
|
||||
|
||||
When all fresh tuples from the proxy HLR have been used up, and the home HLR remains unreachable, the proxy HLR normally
|
||||
fails and rejects the subscriber (default configuration).
|
||||
|
||||
If explicitly enabled in the configuration, the proxy HLR will attempt to fall back to GSM AKA and resend already spent
|
||||
tuples, deliberately omitting UMTS AKA parts (6).
|
||||
|
||||
Note that an attempt to refill the tuple cache in the proxy HLR always happens asynchronously. If there are no tuples,
|
||||
that means the link to the home HLR is currently broken, and there is no point in trying to contact it now. Tuples will
|
||||
be obtained as soon as the link is established again.
|
||||
|
||||
.When the MSC has used up all of its auth tuples and the proxy HLR tuple cache is dry
|
||||
["mscgen"]
|
||||
----
|
||||
include::proxy_cache_tuple_cache_dry.msc[]
|
||||
----
|
||||
|
||||
==== Periodic Location Updating
|
||||
|
||||
Each subscriber performs periodic Location Updating to ensure that it is not implicitly detached from the network. When
|
||||
the proxy HLR already has a proxy cache for this subscriber, all information to complete the periodic Location Updating
|
||||
is already known in the proxy HLR. If the link to the home HLR is unresponsive, the proxy HLR mimicks the Insert
|
||||
Subscriber Data Request that the home HLR would normally send, using the cached MSISDN, and then sends the Update
|
||||
Location Result. The subscriber remains attached without a responsive link to the home HLR being required.
|
||||
|
||||
.Periodic Location Updating when the MSC still has unused auth tuples
|
||||
["mscgen"]
|
||||
----
|
||||
include::proxy_cache_periodic_lu.msc[]
|
||||
----
|
||||
|
||||
==== UMTS AKA Resync
|
||||
|
||||
The AUTS from a UMTS AKA resync needs to reach the home HLR sooner or later, and a resync renders all UMTS AKA tuples in
|
||||
the cache stale.
|
||||
|
||||
.Cached tuples become unusable from a UMTS AKA resynchronisation request from the USIM.
|
||||
["mscgen"]
|
||||
----
|
||||
include::proxy_cache_umts_aka_resync.msc[]
|
||||
----
|
||||
39
doc/manuals/chapters/proxy_cache_attach.ladder
Normal file
39
doc/manuals/chapters/proxy_cache_attach.ladder
Normal file
@@ -0,0 +1,39 @@
|
||||
{hscale=2}
|
||||
ms = MS,BSS
|
||||
msc = MSC
|
||||
hlr = HLR proxy
|
||||
home = Home HLR
|
||||
|
||||
ms -> msc Location Updating Request (IMSI Attach)
|
||||
msc -> hlr Send Auth Info Request
|
||||
hlr <> hlr No proxy cache data available for this subscriber
|
||||
hlr () home mslookup finds the home HLR
|
||||
hlr -> home Send Auth Info Request
|
||||
hlr <- home Send Auth Info Result
|
||||
with 5 auth tuples
|
||||
hlr () . (1) Keep a copy of the auth tuples
|
||||
msc <- hlr Send Auth Info Result
|
||||
msc () . MSC stores 5 auth tuples,
|
||||
uses the first one now,
|
||||
and keeps the rest for later requests
|
||||
ms () msc Authentication
|
||||
msc -> hlr Update Location Request
|
||||
hlr -> home Update Location Request
|
||||
hlr <- home Insert Subscriber Data Request
|
||||
(with subscriber's MSISDN)
|
||||
hlr () . proxy HLR caches the MSISDN
|
||||
msc <- hlr Insert Subscriber Data Request
|
||||
msc -> hlr Insert Subscriber Data Result
|
||||
hlr -> home Insert Subscriber Data Result
|
||||
hlr <- home Update Location Result
|
||||
msc <- hlr Update Location Result
|
||||
ms <- msc Location Updating Accept
|
||||
hlr <> . After successful Update Location, check the cache
|
||||
hlr () . (2) Ask for more auth tuples to cache
|
||||
(amount of tuples configurable)
|
||||
hlr -> home Send Auth Info Request
|
||||
hlr <- home Send Auth Info Result
|
||||
hlr () . store 5 more tuples
|
||||
hlr -> home Send Auth Info Request
|
||||
hlr <- home Send Auth Info Result
|
||||
hlr () . store yet 5 more tuples
|
||||
33
doc/manuals/chapters/proxy_cache_attach.msc
Normal file
33
doc/manuals/chapters/proxy_cache_attach.msc
Normal file
@@ -0,0 +1,33 @@
|
||||
msc {
|
||||
hscale="2";
|
||||
ms[label="MS,BSS"],__msc[label="MSC"],hlr[label="HLR proxy"],home[label="Home HLR"];
|
||||
|
||||
ms => __msc [label="Location Updating Request (IMSI Attach)"];
|
||||
__msc => hlr [label="Send Auth Info Request"];
|
||||
hlr abox hlr [label="No proxy cache data available for this subscriber"];
|
||||
hlr rbox home [label="mslookup finds the home HLR"];
|
||||
hlr => home [label="Send Auth Info Request"];
|
||||
hlr <= home [label="Send Auth Info Result\nwith 5 auth tuples"];
|
||||
hlr rbox hlr [label="(1) Keep a copy of the auth tuples"];
|
||||
__msc <= hlr [label="Send Auth Info Result"];
|
||||
__msc rbox __msc [label="MSC stores 5 auth tuples,\nuses the first one now,\nand keeps the rest for later requests"];
|
||||
ms rbox __msc [label="Authentication"];
|
||||
__msc => hlr [label="Update Location Request"];
|
||||
hlr => home [label="Update Location Request"];
|
||||
hlr <= home [label="Insert Subscriber Data Request\n(with subscriber's MSISDN)"];
|
||||
hlr rbox hlr [label="proxy HLR caches the MSISDN"];
|
||||
__msc <= hlr [label="Insert Subscriber Data Request"];
|
||||
__msc => hlr [label="Insert Subscriber Data Result"];
|
||||
hlr => home [label="Insert Subscriber Data Result"];
|
||||
hlr <= home [label="Update Location Result"];
|
||||
__msc <= hlr [label="Update Location Result"];
|
||||
ms <= __msc [label="Location Updating Accept"];
|
||||
hlr abox hlr [label="After successful Update Location, check the cache"];
|
||||
hlr rbox hlr [label="(2) Ask for more auth tuples to cache\n(amount of tuples configurable)"];
|
||||
hlr => home [label="Send Auth Info Request"];
|
||||
hlr <= home [label="Send Auth Info Result"];
|
||||
hlr rbox hlr [label="store 5 more tuples"];
|
||||
hlr => home [label="Send Auth Info Request"];
|
||||
hlr <= home [label="Send Auth Info Result"];
|
||||
hlr rbox hlr [label="store yet 5 more tuples"];
|
||||
}
|
||||
31
doc/manuals/chapters/proxy_cache_more_tuples.ladder
Normal file
31
doc/manuals/chapters/proxy_cache_more_tuples.ladder
Normal file
@@ -0,0 +1,31 @@
|
||||
{hscale=2}
|
||||
ms = MS,BSS
|
||||
msc = MSC
|
||||
hlr = HLR proxy
|
||||
home = Home HLR
|
||||
|
||||
ms -> msc CM Service Request / Paging Response
|
||||
msc -> hlr Send Auth Info Request
|
||||
hlr () . Use already set up proxy path
|
||||
hlr <> . there still are unsent auth tuples
|
||||
in the cache
|
||||
hlr () . (3) Send cached, fresh tuples
|
||||
msc <- hlr Send Auth Info Result
|
||||
containing auth tuples
|
||||
from the proxy cache
|
||||
ms () msc Authentication
|
||||
ms () msc Continue the CM Service / Paging action
|
||||
hlr <> . Note that there are no/few unused tuples in the cache, fill up again
|
||||
hlr () . (4) Ask for more auth tuples to cache
|
||||
hlr -> home Send Auth Info Request
|
||||
--- If the home HLR link is not working
|
||||
hlr <> . no link
|
||||
or
|
||||
response timeout
|
||||
hlr () . (5) Set up a timer to retry SAI
|
||||
(a few minutes?)
|
||||
hlr <> . Timer triggers
|
||||
hlr -> home Send Auth Info Request
|
||||
--- If the home HLR link is functional
|
||||
hlr <- home Send Auth Info Result
|
||||
hlr () . store 5 more tuples
|
||||
24
doc/manuals/chapters/proxy_cache_more_tuples.msc
Normal file
24
doc/manuals/chapters/proxy_cache_more_tuples.msc
Normal file
@@ -0,0 +1,24 @@
|
||||
msc {
|
||||
hscale="2";
|
||||
ms[label="MS,BSS"],__msc[label="MSC"],hlr[label="HLR proxy"],home[label="Home HLR"];
|
||||
|
||||
ms => __msc [label="CM Service Request / Paging Response"];
|
||||
__msc => hlr [label="Send Auth Info Request"];
|
||||
hlr rbox hlr [label="Use already set up proxy path"];
|
||||
hlr abox hlr [label="there still are unsent auth tuples\nin the cache"];
|
||||
hlr rbox hlr [label="(3) Send cached, fresh tuples"];
|
||||
__msc <= hlr [label="Send Auth Info Result\ncontaining auth tuples\nfrom the proxy cache"];
|
||||
ms rbox __msc [label="Authentication"];
|
||||
ms rbox __msc [label="Continue the CM Service / Paging action"];
|
||||
hlr abox hlr [label="Note that there are no/few unused tuples in the cache, fill up again"];
|
||||
hlr rbox hlr [label="(4) Ask for more auth tuples to cache"];
|
||||
hlr => home [label="Send Auth Info Request"];
|
||||
--- [label="If the home HLR link is not working"];
|
||||
hlr abox hlr [label="no link\nor\nresponse timeout"];
|
||||
hlr rbox hlr [label="(5) Set up a timer to retry SAI\n(a few minutes?)"];
|
||||
hlr abox hlr [label="Timer triggers"];
|
||||
hlr => home [label="Send Auth Info Request"];
|
||||
--- [label="If the home HLR link is functional"];
|
||||
hlr <= home [label="Send Auth Info Result"];
|
||||
hlr rbox hlr [label="store 5 more tuples"];
|
||||
}
|
||||
47
doc/manuals/chapters/proxy_cache_periodic_lu.ladder
Normal file
47
doc/manuals/chapters/proxy_cache_periodic_lu.ladder
Normal file
@@ -0,0 +1,47 @@
|
||||
{hscale=2}
|
||||
ms = MS,BSS
|
||||
msc = MSC
|
||||
hlr = HLR proxy
|
||||
home = Home HLR
|
||||
|
||||
ms -> msc Location Updating Request (Periodic)
|
||||
ms () msc Authentication,
|
||||
using the next of 5 auth tuples the MSC has stored
|
||||
msc -> hlr Update Location Request
|
||||
hlr () . Use already set up proxy path
|
||||
hlr <> . (8) proxy cache already has all information to answer
|
||||
msc <- hlr Insert Subscriber Data Request
|
||||
msc -> hlr Insert Subscriber Data Result
|
||||
msc <- hlr Update Location Result
|
||||
ms <- msc Location Updating Accept
|
||||
hlr () . (9) Verify Update Location with home HLR
|
||||
|||
|
||||
--- if the home HLR has no changes and accepts
|
||||
hlr -> home Update Location Request
|
||||
hlr <- home Insert Subscriber Data Request
|
||||
hlr -> home Insert Subscriber Data Result
|
||||
hlr <> . Notice identical MSISDN
|
||||
hlr <- home Update Location Result
|
||||
|||
|
||||
--- if the home HLR is unreachable
|
||||
hlr -> home Update Location Request
|
||||
hlr <> . no link
|
||||
or
|
||||
response timeout
|
||||
hlr () . Don't care, carry on
|
||||
|||
|
||||
--- if the home HLR has a modified MSISDN, and accepts
|
||||
hlr -> home Update Location Request
|
||||
hlr <- home Insert Subscriber Data Request
|
||||
hlr -> home Insert Subscriber Data Result
|
||||
hlr <> . Notice changed MSISDN
|
||||
msc <- hlr Insert Subscriber Data Request
|
||||
msc -> hlr Insert Subscriber Data Result
|
||||
hlr <- home Update Location Result
|
||||
|||
|
||||
--- if the home HLR rejects
|
||||
hlr -> home Update Location Request
|
||||
hlr <- home Update Location Error
|
||||
msc <- hlr Cancel Location Request
|
||||
msc -> hlr Cancel Location Result
|
||||
hlr () . Clear subscriber cache
|
||||
43
doc/manuals/chapters/proxy_cache_periodic_lu.msc
Normal file
43
doc/manuals/chapters/proxy_cache_periodic_lu.msc
Normal file
@@ -0,0 +1,43 @@
|
||||
msc {
|
||||
hscale="2";
|
||||
ms[label="MS,BSS"],__msc[label="MSC"],hlr[label="HLR proxy"],home[label="Home HLR"];
|
||||
|
||||
ms => __msc [label="Location Updating Request (Periodic)"];
|
||||
ms rbox __msc [label="Authentication,\nusing the next of 5 auth tuples the MSC has stored"];
|
||||
__msc => hlr [label="Update Location Request"];
|
||||
hlr rbox hlr [label="Use already set up proxy path"];
|
||||
hlr abox hlr [label="(8) proxy cache already has all information to answer"];
|
||||
__msc <= hlr [label="Insert Subscriber Data Request"];
|
||||
__msc => hlr [label="Insert Subscriber Data Result"];
|
||||
__msc <= hlr [label="Update Location Result"];
|
||||
ms <= __msc [label="Location Updating Accept"];
|
||||
hlr rbox hlr [label="(9) Verify Update Location with home HLR"];
|
||||
|||;
|
||||
--- [label="if the home HLR has no changes and accepts"];
|
||||
hlr => home [label="Update Location Request"];
|
||||
hlr <= home [label="Insert Subscriber Data Request"];
|
||||
hlr => home [label="Insert Subscriber Data Result"];
|
||||
hlr abox hlr [label="Notice identical MSISDN"];
|
||||
hlr <= home [label="Update Location Result"];
|
||||
|||;
|
||||
--- [label="if the home HLR is unreachable"];
|
||||
hlr => home [label="Update Location Request"];
|
||||
hlr abox hlr [label="no link\nor\nresponse timeout"];
|
||||
hlr rbox hlr [label="Don't care, carry on"];
|
||||
|||;
|
||||
--- [label="if the home HLR has a modified MSISDN, and accepts"];
|
||||
hlr => home [label="Update Location Request"];
|
||||
hlr <= home [label="Insert Subscriber Data Request"];
|
||||
hlr => home [label="Insert Subscriber Data Result"];
|
||||
hlr abox hlr [label="Notice changed MSISDN"];
|
||||
__msc <= hlr [label="Insert Subscriber Data Request"];
|
||||
__msc => hlr [label="Insert Subscriber Data Result"];
|
||||
hlr <= home [label="Update Location Result"];
|
||||
|||;
|
||||
--- [label="if the home HLR rejects"];
|
||||
hlr => home [label="Update Location Request"];
|
||||
hlr <= home [label="Update Location Error"];
|
||||
__msc <= hlr [label="Cancel Location Request"];
|
||||
__msc => hlr [label="Cancel Location Result"];
|
||||
hlr rbox hlr [label="Clear subscriber cache"];
|
||||
}
|
||||
21
doc/manuals/chapters/proxy_cache_tuple_cache_dry.ladder
Normal file
21
doc/manuals/chapters/proxy_cache_tuple_cache_dry.ladder
Normal file
@@ -0,0 +1,21 @@
|
||||
{hscale=2}
|
||||
ms = MS,BSS
|
||||
msc = MSC
|
||||
hlr = HLR proxy
|
||||
home = Home HLR
|
||||
|
||||
ms -> msc CM Service Request / Paging Response
|
||||
msc -> hlr Send Auth Info Request
|
||||
hlr () . Use already set up proxy path
|
||||
hlr <> . All cached auth tuples have been sent to the MSC before
|
||||
--- If no GSM AKA fallback is allowed
|
||||
msc <- hlr Send Auth Info Error
|
||||
ms () msc Detach
|
||||
--- If GSM AKA fallback is allowed
|
||||
hlr () . (6) Resend only GSM AKA tuples, already sent earlier
|
||||
msc <- hlr Send Auth Info Result
|
||||
containing GSM AKA auth tuples
|
||||
from the proxy cache
|
||||
ms () msc 2G: Authentication
|
||||
3G: Detach
|
||||
ms () msc Continue the CM Service / Paging action
|
||||
17
doc/manuals/chapters/proxy_cache_tuple_cache_dry.msc
Normal file
17
doc/manuals/chapters/proxy_cache_tuple_cache_dry.msc
Normal file
@@ -0,0 +1,17 @@
|
||||
msc {
|
||||
hscale="2";
|
||||
ms[label="MS,BSS"],__msc[label="MSC"],hlr[label="HLR proxy"],home[label="Home HLR"];
|
||||
|
||||
ms => __msc [label="CM Service Request / Paging Response"];
|
||||
__msc => hlr [label="Send Auth Info Request"];
|
||||
hlr rbox hlr [label="Use already set up proxy path"];
|
||||
hlr abox hlr [label="All cached auth tuples have been sent to the MSC before"];
|
||||
--- [label="If no GSM AKA fallback is allowed"];
|
||||
__msc <= hlr [label="Send Auth Info Error"];
|
||||
ms rbox __msc [label="Detach"];
|
||||
--- [label="If GSM AKA fallback is allowed"];
|
||||
hlr rbox hlr [label="(6) Resend only GSM AKA tuples, already sent earlier"];
|
||||
__msc <= hlr [label="Send Auth Info Result\ncontaining GSM AKA auth tuples\nfrom the proxy cache"];
|
||||
ms rbox __msc [label="2G: Authentication\n3G: Detach"];
|
||||
ms rbox __msc [label="Continue the CM Service / Paging action"];
|
||||
}
|
||||
55
doc/manuals/chapters/proxy_cache_umts_aka_resync.ladder
Normal file
55
doc/manuals/chapters/proxy_cache_umts_aka_resync.ladder
Normal file
@@ -0,0 +1,55 @@
|
||||
{hscale=2}
|
||||
ms = MS,BSS
|
||||
msc = MSC
|
||||
hlr = HLR proxy
|
||||
home = Home HLR
|
||||
|
||||
ms -> msc CM Service Request / Paging Response
|
||||
msc -> hlr Send Auth Info Request
|
||||
hlr <> . there still are unsent auth tuples
|
||||
in the cache
|
||||
hlr () . Send cached, fresh tuples
|
||||
msc <- hlr Send Auth Info Result
|
||||
containing auth tuples
|
||||
from the proxy cache
|
||||
ms <- msc Authentication Request
|
||||
ms -> msc USIM requests UMTS AKA resync
|
||||
Auth Failure with AUTS
|
||||
msc -> hlr Send Auth Info Request
|
||||
containing AUTS IE
|
||||
hlr () . Mark all UMTS AKA tuples as stale
|
||||
--- If the home HLR responds in time
|
||||
hlr -> home Send Auth Info Request
|
||||
hlr <- home Send Auth Info Result
|
||||
with 5 auth tuples
|
||||
hlr () . clear tuple cache, store new tuples
|
||||
msc <- hlr Send Auth Info Result
|
||||
ms () msc Authentication
|
||||
hlr () . fill up the tuple cache as necessary
|
||||
hlr -> home Send Auth Info Request
|
||||
hlr <- home Send Auth Info Result
|
||||
...
|
||||
--- If the home HLR is unreachable
|
||||
hlr -> home Send Auth Info Request
|
||||
hlr <> . no link
|
||||
or
|
||||
response timeout
|
||||
hlr () . Store the AUTS received earlier,
|
||||
and set up a timer to retry SAI
|
||||
(a few minutes?)
|
||||
--- If no GSM AKA fallback is allowed
|
||||
msc <- hlr Send Auth Info Error
|
||||
ms () msc Detach
|
||||
--- If GSM AKA fallback is allowed
|
||||
hlr () . Resend only GSM AKA tuples, already sent earlier
|
||||
msc <- hlr Send Auth Info Result
|
||||
containing GSM AKA auth tuples
|
||||
from the proxy cache
|
||||
ms () msc 2G: Authentication
|
||||
3G: Detach
|
||||
---
|
||||
hlr <> . AUTS timer triggers
|
||||
hlr -> home Send Auth Info Request
|
||||
hlr <- home Send Auth Info Result
|
||||
hlr () . clear tuple cache, store new tuples
|
||||
hlr () . continue to fill up the cache as necessary
|
||||
41
doc/manuals/chapters/proxy_cache_umts_aka_resync.msc
Normal file
41
doc/manuals/chapters/proxy_cache_umts_aka_resync.msc
Normal file
@@ -0,0 +1,41 @@
|
||||
msc {
|
||||
hscale="2";
|
||||
ms[label="MS,BSS"],__msc[label="MSC"],hlr[label="HLR proxy"],home[label="Home HLR"];
|
||||
|
||||
ms => __msc [label="CM Service Request / Paging Response"];
|
||||
__msc => hlr [label="Send Auth Info Request"];
|
||||
hlr abox hlr [label="there still are unsent auth tuples\nin the cache"];
|
||||
hlr rbox hlr [label="Send cached, fresh tuples"];
|
||||
__msc <= hlr [label="Send Auth Info Result\ncontaining auth tuples\nfrom the proxy cache"];
|
||||
ms <= __msc [label="Authentication Request"];
|
||||
ms => __msc [label="USIM requests UMTS AKA resync\nAuth Failure with AUTS"];
|
||||
__msc => hlr [label="Send Auth Info Request\ncontaining AUTS IE"];
|
||||
hlr rbox hlr [label="Mark all UMTS AKA tuples as stale"];
|
||||
--- [label="If the home HLR responds in time"];
|
||||
hlr => home [label="Send Auth Info Request"];
|
||||
hlr <= home [label="Send Auth Info Result\nwith 5 auth tuples"];
|
||||
hlr rbox hlr [label="clear tuple cache, store new tuples"];
|
||||
__msc <= hlr [label="Send Auth Info Result"];
|
||||
ms rbox __msc [label="Authentication"];
|
||||
hlr rbox hlr [label="fill up the tuple cache as necessary"];
|
||||
hlr => home [label="Send Auth Info Request"];
|
||||
hlr <= home [label="Send Auth Info Result"];
|
||||
...;
|
||||
--- [label="If the home HLR is unreachable"];
|
||||
hlr => home [label="Send Auth Info Request"];
|
||||
hlr abox hlr [label="no link\nor\nresponse timeout"];
|
||||
hlr rbox hlr [label="Store the AUTS received earlier,\nand set up a timer to retry SAI\n(a few minutes?)"];
|
||||
--- [label="If no GSM AKA fallback is allowed"];
|
||||
__msc <= hlr [label="Send Auth Info Error"];
|
||||
ms rbox __msc [label="Detach"];
|
||||
--- [label="If GSM AKA fallback is allowed"];
|
||||
hlr rbox hlr [label="Resend only GSM AKA tuples, already sent earlier"];
|
||||
__msc <= hlr [label="Send Auth Info Result\ncontaining GSM AKA auth tuples\nfrom the proxy cache"];
|
||||
ms rbox __msc [label="2G: Authentication\n3G: Detach"];
|
||||
---;
|
||||
hlr abox hlr [label="AUTS timer triggers"];
|
||||
hlr => home [label="Send Auth Info Request"];
|
||||
hlr <= home [label="Send Auth Info Result"];
|
||||
hlr rbox hlr [label="clear tuple cache, store new tuples"];
|
||||
hlr rbox hlr [label="continue to fill up the cache as necessary"];
|
||||
}
|
||||
@@ -54,7 +54,7 @@ this database file will be created in the current working directory.
|
||||
|
||||
Alternatively, you may use the `osmo-hlr-db-tool`, which is installed along
|
||||
with `osmo-hlr`, to bootstrap an empty database, or to migrate subscriber data
|
||||
from an old 'OsmoNITB' database. See <<db_import_nitb>>.
|
||||
from an old 'OsmoNITB' database. See `osmo-hlr-db-tool --help`.
|
||||
|
||||
=== Multiple instances
|
||||
|
||||
|
||||
@@ -127,83 +127,3 @@ OsmoHLR# subscriber imei 35761300444848 show
|
||||
----
|
||||
<1> Randomly generated 5 digit MSISDN
|
||||
<2> Disabled CS and PS NAM prevent the subscriber from accessing the network
|
||||
|
||||
|
||||
=== Import Subscriber Data
|
||||
|
||||
==== Scripted Import
|
||||
|
||||
WARNING: It is not generally a good idea to depend on the HLR database's internal table structure, but in the lack of an
|
||||
automated import procedure, this example is provided as an ad-hoc method to aid automated subscriber import. This is not
|
||||
guaranteed to remain valid.
|
||||
|
||||
NOTE: We may add CSV and other import methods to the `osmo-hlr-db-tool`, but so far that is not implemented. Contact the
|
||||
community if you are interested in such a feature being implemented.
|
||||
|
||||
NOTE: `sqlite3` is available from your distribution packages or `sqlite.org`.
|
||||
|
||||
Currently, probably the easiest way to automatically import subscribers to OsmoHLR is to write out a text file with SQL
|
||||
commands per subscriber, and feed that to `sqlite3`, as described below.
|
||||
|
||||
A difficulty is to always choose subscriber IDs that are not yet in use. For an initial import, the subscriber ID may be
|
||||
incremented per subscriber record. If adding more subscribers to an existing database, it is necessary to choose
|
||||
subscriber IDs that are not yet in use. Get the highest ID in use with:
|
||||
|
||||
----
|
||||
sqlite3 hlr.db 'select max(id) from subscriber'
|
||||
----
|
||||
|
||||
A full SQL example of adding a single subscriber with id 23, IMSI 001010123456789, MSISDN 1234, Ki for COMP128v1, and K
|
||||
and OPC for Milenage:
|
||||
|
||||
----
|
||||
INSERT subscriber (id, imsi, msisdn) VALUES (23, '001010123456789', '1234');
|
||||
|
||||
INSERT INTO auc_2g (subscriber_id, algo_id_2g, ki)
|
||||
VALUES(23, 1, '0123456789abcdef0123456789abcdef');
|
||||
|
||||
INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, op, opc)
|
||||
VALUES(23, 5, '0123456789abcdef0123456789abcdef',NULL,'0123456789abcdef0123456789abcdef');
|
||||
----
|
||||
|
||||
Table entries to `auc_2g` and/or `auc_3g` may be omitted if no such key material is required.
|
||||
|
||||
UMTS Milenage auth (on both 2G and 3G RAN) is configured by the `auc_3g` table. `algo_id_3g` must currently always be 5
|
||||
(MILENAGE).
|
||||
|
||||
The algorithm IDs for `algo_id_2g` and `algo_id_3g` are:
|
||||
|
||||
.Algorithm IDs in OsmoHLR's database
|
||||
[options="header",width="50%",cols="40%,60%"]
|
||||
|===
|
||||
|`algo_id_2g` / `algo_id_3g` | Authentication Algorithm
|
||||
| 1 | COMP128v1
|
||||
| 2 | COMP128v2
|
||||
| 3 | COMP128v3
|
||||
| 4 | XOR
|
||||
| 5 | MILENAGE
|
||||
|===
|
||||
|
||||
Create an empty HLR database with
|
||||
|
||||
----
|
||||
osmo-hlr-db-tool -l hlr.db create
|
||||
----
|
||||
|
||||
Repeat above SQL commands per subscriber, incrementing the subscriber ID for each block, then feed the SQL commands for
|
||||
the subscribers to be imported to the `sqlite3` command line tool:
|
||||
|
||||
----
|
||||
sqlite3 hlr.db < subscribers.sql
|
||||
----
|
||||
|
||||
[[db_import_nitb]]
|
||||
==== Import OsmoNITB database
|
||||
|
||||
To upgrade from old OsmoNITB to OsmoHLR, use `osmo-hlr-db-tool`:
|
||||
|
||||
----
|
||||
osmo-hlr-db-tool -l hlr.db import-nitb-db nitb.db
|
||||
----
|
||||
|
||||
Be aware that the import is lossy, only the IMSI, MSISDN, nam_cs/ps and 2G auth data are set.
|
||||
|
||||
@@ -50,29 +50,15 @@ prefix route to the named EUSE. All USSD short codes starting with *123 will be
|
||||
routed to the named EUSE.
|
||||
|
||||
`ussd route prefix *#100# internal own-msisdn` installs a prefix route
|
||||
to the named internal USSD handler. The above command will restore
|
||||
to the named internal USSD handler. There above command will restore
|
||||
the old behavior, in which *#100# will return a text message containing
|
||||
the subscribers own phone number. More information on internal USSD
|
||||
handlers can be found in <<iuse_handlers>>.
|
||||
the subscribers own phone number. There is one other handler called
|
||||
`own-imsi` which will return the IMSI instead of the MSISDN.
|
||||
|
||||
`ussd default-route external foobar-00-00-00-00-00-00` installs a
|
||||
default route to the named EUSE. This means that all USSD codes for
|
||||
which no more specific route exists will be routed to the named EUSE.
|
||||
|
||||
[[iuse_handlers]]
|
||||
=== Built-in USSD handlers
|
||||
|
||||
OsmoHLR has an Internal USSD Entity (IUSE) that allows to handle some
|
||||
USSD requests internally. It features a set of simple handlers, which
|
||||
can be assigned to one or more USSD request prefixes:
|
||||
|
||||
* `own-msisdn` returns subscriber's MSISDN (if assigned);
|
||||
* `own-imsi` returns subscriber's IMSI;
|
||||
* `test-idle` keeps the session idle until the MS terminates it, or
|
||||
the guard timer expires (may be useful for testing).
|
||||
|
||||
Additional handlers can be added on request.
|
||||
|
||||
=== Example EUSE program
|
||||
|
||||
We have provided an example EUSE developed in C language using existing
|
||||
|
||||
@@ -26,9 +26,9 @@ include::./common/chapters/control_if.adoc[]
|
||||
|
||||
include::{srcdir}/chapters/dgsm.adoc[]
|
||||
|
||||
include::./common/chapters/gsup.adoc[]
|
||||
include::{srcdir}/chapters/proxy_cache.adoc[]
|
||||
|
||||
include::./common/chapters/vty_cpu_sched.adoc[]
|
||||
include::./common/chapters/gsup.adoc[]
|
||||
|
||||
include::./common/chapters/port_numbers.adoc[]
|
||||
|
||||
@@ -37,3 +37,4 @@ include::./common/chapters/bibliography.adoc[]
|
||||
include::./common/chapters/glossary.adoc[]
|
||||
|
||||
include::./common/chapters/gfdl.adoc[]
|
||||
|
||||
|
||||
1431
doc/manuals/vty/hlr_vty_reference.xml
Normal file
1431
doc/manuals/vty/hlr_vty_reference.xml
Normal file
File diff suppressed because it is too large
Load Diff
39
doc/sequence_charts/Makefile.am
Normal file
39
doc/sequence_charts/Makefile.am
Normal file
@@ -0,0 +1,39 @@
|
||||
all:
|
||||
echo "built only on manual invocation, needs mscgen and dot (graphviz) programs: invoke 'make charts'"
|
||||
|
||||
charts: msc dot
|
||||
|
||||
EXTRA_DIST = \
|
||||
proxy_cache.dot \
|
||||
proxy_cache__mm_fsm.dot \
|
||||
proxy_cache__to_home_hlr_fsm.dot \
|
||||
$(NULL)
|
||||
|
||||
CLEANFILES = \
|
||||
proxy_cache.png \
|
||||
proxy_cache__mm_fsm.png \
|
||||
proxy_cache__to_home_hlr_fsm.png \
|
||||
$(NULL)
|
||||
|
||||
msc: \
|
||||
$(NULL)
|
||||
|
||||
dot: \
|
||||
$(builddir)/proxy_cache.png \
|
||||
$(builddir)/proxy_cache__mm_fsm.png \
|
||||
$(builddir)/proxy_cache__to_home_hlr_fsm.png \
|
||||
$(NULL)
|
||||
|
||||
$(builddir)/%.png: %.msc
|
||||
mscgen -T png -o $@ $<
|
||||
|
||||
$(builddir)/%.msc: $(srcdir)/%.ladder
|
||||
@which ladder_to_msc.py || (echo 'PLEASE POINT YOUR $$PATH AT libosmocore/contrib/ladder_to_msc.py' && false)
|
||||
ladder_to_msc.py -i $< -o $@
|
||||
|
||||
$(builddir)/%.png: $(srcdir)/%.dot
|
||||
dot -Tpng $< > $@
|
||||
|
||||
.PHONY: poll
|
||||
poll:
|
||||
while true; do $(MAKE) msc dot; sleep 1; done
|
||||
19
doc/sequence_charts/proxy_cache.dot
Normal file
19
doc/sequence_charts/proxy_cache.dot
Normal file
@@ -0,0 +1,19 @@
|
||||
digraph G {
|
||||
rankdir=LR
|
||||
labelloc=t;
|
||||
|
||||
msc [label="MS/BSS/MSC"]
|
||||
subgraph cluster_proxy {
|
||||
label="HLR Proxy"
|
||||
proxy_mm [label="Proxy Mobility Management FSM",shape=box3d]
|
||||
proxy_home [label="Proxy to Home HLR FSM",shape=box3d]
|
||||
proxy [label="GSUP Proxy"]
|
||||
proxy_mm -> proxy_home [constraint=false,dir=both,label="(FSM events)"]
|
||||
}
|
||||
hlr [label="Home HLR"]
|
||||
|
||||
msc -> proxy_mm [dir=both,label="MM related GSUP\n (immediate response\n if possible)"]
|
||||
proxy_home -> hlr [dir=both,label="MM related GSUP\n (delayed)"]
|
||||
|
||||
msc -> proxy -> hlr [dir=both,label="non-MM GSUP",style=dashed]
|
||||
}
|
||||
78
doc/sequence_charts/proxy_cache__mm_fsm.dot
Normal file
78
doc/sequence_charts/proxy_cache__mm_fsm.dot
Normal file
@@ -0,0 +1,78 @@
|
||||
digraph G {
|
||||
rankdir=TB
|
||||
labelloc=t; label="HLR Proxy MM FSM"
|
||||
|
||||
top,top2,top3[shape=invtriangle,label="(1)"]
|
||||
|
||||
top -> READY
|
||||
|
||||
new [label="proxy_cache_subscr_new()\n/ proxy_cache_subscr_from_db()",shape=box]
|
||||
READY [style=bold]
|
||||
HIBERNATE [shape=note,label="Hibernate\n (keep in DB)"]
|
||||
CLEAR [shape=box,label="Clear DB entry\n (discard completely)"]
|
||||
WAIT_AUTH_TUPLES [style=bold]
|
||||
WAIT_SUBSCR_DATA [style=bold]
|
||||
WAIT_GSUP_ISD_RESULT [style=bold]
|
||||
|
||||
home_fsm [label="Proxy to Home HLR FSM",shape=box3d]
|
||||
{rank=same;READY,home_fsm}
|
||||
|
||||
|
||||
new -> {READY,home_fsm}
|
||||
|
||||
READY -> {event_lu_req,event_auth_info_req} [arrowhead=none]
|
||||
|
||||
event_auth_info_req [shape=rarrow,label="Rx GSUP\nSend Auth Info Request\nfrom MSC"]
|
||||
event_auth_info_req -> junction_send_auth_info_req
|
||||
junction_send_auth_info_req [shape=diamond,label="Unused\nauth tuples\navailable?"]
|
||||
junction_send_auth_info_req -> action_send_auth_info [label="yes"]
|
||||
junction_send_auth_info_req -> emit_need_tuples [label="no"]
|
||||
emit_need_tuples [shape=lpromoter,label="emit\n HOME_EV_CHECK_TUPLES\n to Home FSM"]
|
||||
emit_need_tuples->WAIT_AUTH_TUPLES
|
||||
WAIT_AUTH_TUPLES -> rx_ev_rx_auth_tuples [arrowhead=none]
|
||||
rx_ev_rx_auth_tuples [shape=rpromoter,label="receive\n MM_EV_RX_AUTH_TUPLES"]
|
||||
rx_ev_rx_auth_tuples -> action_send_auth_info
|
||||
action_send_auth_info [shape=larrow,label="Tx GSUP\nSend Auth Info Result\nwith fresh auth tuples\n to MSC"]
|
||||
action_send_auth_info -> emit_check_tuples
|
||||
emit_check_tuples [shape=lpromoter,label="emit\n HOME_EV_CHECK_TUPLES\n to Home FSM"]
|
||||
emit_check_tuples -> top2
|
||||
WAIT_AUTH_TUPLES -> junction_check_auth_fallback [label="Timeout",style=dashed]
|
||||
junction_check_auth_fallback -> action_do_auth_fallback [label="yes",style=dashed]
|
||||
action_do_auth_fallback [shape=larrow,label="Tx GSUP\nSend Auth Info Result\nwith recycled auth tuple\n(GSM AKA only)"]
|
||||
junction_check_auth_fallback [shape=diamond,label="Re-usable\nauth tuples\navailable?"]
|
||||
junction_check_auth_fallback -> action_fail_auth [label="no",style=dashed]
|
||||
action_fail_auth [shape=larrow,label="Tx GSUP\nSend Auth Info Error\npending re-connection to\nthe home HLR"]
|
||||
{action_do_auth_fallback,action_fail_auth} -> top2 [style=dashed]
|
||||
|
||||
event_lu_req [shape=rarrow,label="Rx GSUP\nUpdate Location Request\nfrom MSC"]
|
||||
event_lu_req -> emit_lu_req
|
||||
emit_lu_req [shape=lpromoter,label="emit\n HOME_EV_CONFIRM_LU"];
|
||||
emit_lu_req -> junction_check_subscriber_data
|
||||
junction_check_subscriber_data [shape=diamond,label="Subscriber\nData\nknown?"]
|
||||
junction_check_subscriber_data -> WAIT_SUBSCR_DATA [label=no]
|
||||
WAIT_SUBSCR_DATA -> rx_ev_subscr_data [arrowhead=none]
|
||||
rx_ev_subscr_data [shape=rpromoter,label="receive\n MM_EV_RX_SUBSCR_DATA"];
|
||||
rx_ev_subscr_data -> action_subscr_data_req
|
||||
junction_check_subscriber_data -> action_subscr_data_req [label="yes"]
|
||||
action_subscr_data_req [shape=larrow,label="Tx GSUP\n Insert Subscriber Data\n Request to MSC"]
|
||||
action_subscr_data_req -> WAIT_GSUP_ISD_RESULT
|
||||
WAIT_GSUP_ISD_RESULT -> tx_gsup_isd_res [arrowhead=none]
|
||||
tx_gsup_isd_res [shape=rarrow,label="Rx GSUP\n Insert Subscriber Data Result\nfrom MSC"]
|
||||
tx_gsup_isd_res -> top3
|
||||
|
||||
{WAIT_GSUP_ISD_RESULT,WAIT_SUBSCR_DATA} -> action_lu_reject [label="Timeout",style=dashed]
|
||||
action_lu_reject [shape=larrow,label="Tx GSUP\nUpdate Location Error\nto MSC\npending reconnect of home HLR"]
|
||||
action_lu_reject -> top3 [style=dashed]
|
||||
|
||||
READY -> HIBERNATE [label="Timeout"]
|
||||
READY -> rx_ev_subscr_invalid [arrowhead=none]
|
||||
rx_ev_subscr_invalid[shape=rpromoter,label="receive\n MM_EV_SUBSCR_INVALID"]
|
||||
rx_ev_subscr_invalid -> tx_purge_req
|
||||
tx_purge_req [shape=larrow,label="Tx GSUP\nPurge MS Request"]
|
||||
tx_purge_req -> note_purge [style=dotted]
|
||||
note_purge [shape=note,label="Don't care about\nPurge MS Result"]
|
||||
tx_purge_req -> CLEAR
|
||||
{CLEAR,HIBERNATE} -> TERM
|
||||
TERM[shape=octagon][style=bold]
|
||||
|
||||
}
|
||||
97
doc/sequence_charts/proxy_cache__to_home_hlr_fsm.dot
Normal file
97
doc/sequence_charts/proxy_cache__to_home_hlr_fsm.dot
Normal file
@@ -0,0 +1,97 @@
|
||||
digraph G {
|
||||
rankdir=TB
|
||||
labelloc=t; label="HLR Proxy to Home HLR FSM"
|
||||
|
||||
top,to_top1,to_top2,to_top3,to_top4,to_top5[shape=invtriangle,label="(A)"]
|
||||
top->junction_resolve_home_hlr
|
||||
|
||||
at_clear,to_clear1,to_clear2 [shape=invtriangle,label="(X)"]
|
||||
|
||||
mm_fsm [shape=box3d,label="Proxy MM FSM"]
|
||||
mm_fsm -> junction_resolve_home_hlr [style=invisible,arrowhead=none]
|
||||
|
||||
WAIT_HOME_HLR_RESOLVED [style=bold]
|
||||
WAIT_UPDATE_LOCATION_RESULT [style=bold]
|
||||
WAIT_SEND_AUTH_INFO_RESULT [style=bold]
|
||||
IDLE [style=bold]
|
||||
CLEAR [style=bold]
|
||||
|
||||
new [label="proxy_cache_subscr_new()\n/ proxy_cache_subscr_from_db()",shape=box]
|
||||
{
|
||||
rank=same;
|
||||
junction_resolve_home_hlr [shape=diamond,label="Home HLR\n known?"]
|
||||
junction_confirm_home_hlr [shape=diamond,label="mslookup\n for home HLR\n very old?"]
|
||||
junction_update_location [shape=diamond,label="Did MM FSM emit another\n HOME_EV_CONFIRM_LU?"]
|
||||
junction_auth_info [shape=diamond,label="Auth tuple\ncache full of\nfresh tuples?"]
|
||||
}
|
||||
|
||||
new -> {junction_resolve_home_hlr, mm_fsm}
|
||||
|
||||
junction_resolve_home_hlr -> junction_confirm_home_hlr [label="known"]
|
||||
junction_resolve_home_hlr -> action_mslookup [label="wat"]
|
||||
action_mslookup [shape=larrow,label="start mslookup"]
|
||||
action_mslookup -> WAIT_HOME_HLR_RESOLVED
|
||||
WAIT_HOME_HLR_RESOLVED -> rx_mslookup_res [arrowhead=none]
|
||||
rx_mslookup_res [shape=rarrow,label="home HLR\n resolved"]
|
||||
rx_mslookup_res -> to_top1
|
||||
WAIT_HOME_HLR_RESOLVED -> CLEAR [style=dashed,label=Timeout]
|
||||
|
||||
junction_update_location -> action_lu_req [label="need data\n/\nneed to confirm LU"]
|
||||
action_lu_req [shape=larrow,label="Tx GSUP Update Location Req\nto home HLR"]
|
||||
action_lu_req -> WAIT_UPDATE_LOCATION_RESULT
|
||||
WAIT_UPDATE_LOCATION_RESULT->rx_isd [arrowhead=none]
|
||||
rx_isd [shape=rarrow,label="Rx GSUP\n Insert Subscriber\n Data Request\nfrom home HLR"]
|
||||
rx_isd -> emit_rx_subscr_data
|
||||
emit_rx_subscr_data [shape=lpromoter,label="emit\n MM_EV_RX_SUBSCR_DATA"]
|
||||
emit_rx_subscr_data->action_tx_isd_res
|
||||
action_tx_isd_res -> WAIT_UPDATE_LOCATION_RESULT
|
||||
action_tx_isd_res [shape=larrow,label="Tx GSUP Insert Subscriber Data Result\nto home HLR"]
|
||||
WAIT_UPDATE_LOCATION_RESULT -> rx_lu_res [arrowhead=none]
|
||||
rx_lu_res [shape=rarrow,label="Rx GSUP Update\n Location Result\nfrom home HLR"]
|
||||
rx_lu_res -> to_top2
|
||||
junction_update_location -> junction_auth_info [label="data known,\nLU confirmed"]
|
||||
WAIT_UPDATE_LOCATION_RESULT->junction_lu_failed [label="Timeout "]
|
||||
junction_lu_failed [shape=diamond,label="has home HLR\never confirmed\na LU before?"];
|
||||
junction_lu_failed -> to_clear2 [label="never\nconfirmed",style=dashed]
|
||||
junction_lu_failed -> note_lu_failed [label="has\nconfirmed\nbefore"]
|
||||
note_lu_failed [shape=note,label="Home HLR is\ntemporarily unreachable,\n just carry on."]
|
||||
note_lu_failed -> to_top3
|
||||
|
||||
junction_confirm_home_hlr -> action_mslookup_confirm [label="very old"]
|
||||
junction_confirm_home_hlr -> junction_update_location [label="fair enough"]
|
||||
action_mslookup_confirm [shape=larrow,label="start mslookup"]
|
||||
note_mslookup_confirm [shape=note,label="Result evaluated in IDLE state.\nIf no mslookup result comes\n back, the home HLR is\ntemporarily unreachable:\ncontinue anyway.\nThis is sanity checking for\na *modified* home HLR"]
|
||||
action_mslookup_confirm -> note_mslookup_confirm [arrowhead=none,style=dotted]
|
||||
action_mslookup_confirm -> junction_update_location
|
||||
|
||||
junction_auth_info -> action_sai_req [label="need more tuples"]
|
||||
junction_auth_info -> set_idle_timeout [label="cache is fresh"]
|
||||
action_sai_req [shape=larrow,label="Tx GSUP\n Send Auth Info Request\n to home HLR"]
|
||||
action_sai_req -> WAIT_SEND_AUTH_INFO_RESULT
|
||||
WAIT_SEND_AUTH_INFO_RESULT->rx_sai_res[arrowhead=none]
|
||||
rx_sai_res[shape=rarrow,label="Rx GSUP\n Send Auth Info\n Result\nfrom home HLR"]
|
||||
rx_sai_res -> emit_rx_tuples
|
||||
emit_rx_tuples [shape=lpromoter,label="emit\n MM_EV_RX_AUTH_TUPLES"]
|
||||
emit_rx_tuples -> to_top4
|
||||
WAIT_SEND_AUTH_INFO_RESULT->set_idle_timeout[label="Timeout",style=dashed]
|
||||
set_idle_timeout [shape=diamond,label="Select IDLE\n timeout:\nmin(\nretry tuples,\n confirm mslookup)"]
|
||||
set_idle_timeout -> IDLE
|
||||
|
||||
IDLE -> rx_mslookup_confirm_res [arrowhead=none]
|
||||
rx_mslookup_confirm_res [shape=rarrow,label="Rx mslookup result"]
|
||||
rx_mslookup_confirm_res -> junction_compare_home_hlr
|
||||
junction_compare_home_hlr [shape=diamond,label="mslookup result\n matches home HLR\n on record?"]
|
||||
junction_compare_home_hlr -> set_idle_timeout [label="matches"]
|
||||
junction_compare_home_hlr -> to_clear1 [label="mismatch",style=dashed]
|
||||
|
||||
IDLE -> to_top5 [label="Timeout"]
|
||||
IDLE -> {rx_ev_check_tuples,rx_ev_confirm_lu} [arrowhead=none]
|
||||
rx_ev_check_tuples [shape=rpromoter,label="receive\n HOME_EV_CHECK_TUPLES"]
|
||||
rx_ev_confirm_lu [shape=rpromoter,label="receive\n HOME_EV_CONFIRM_LU"]
|
||||
{rx_ev_check_tuples,rx_ev_confirm_lu} -> to_top5
|
||||
|
||||
at_clear -> CLEAR
|
||||
CLEAR -> emit_subscr_invalid -> TERM
|
||||
emit_subscr_invalid [shape=lpromoter,label="emit\n MM_EV_SUBSCR_INVALID"]
|
||||
TERM[shape=octagon][style=bold]
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
SUBDIRS = osmocom
|
||||
|
||||
nobase_include_HEADERS = \
|
||||
osmocom/gsupclient/cni_peer_id.h \
|
||||
osmocom/gsupclient/gsup_peer_id.h \
|
||||
osmocom/gsupclient/gsup_client.h \
|
||||
osmocom/gsupclient/gsup_req.h \
|
||||
osmocom/mslookup/mdns.h \
|
||||
|
||||
@@ -32,35 +32,35 @@ struct osmo_ipa_name {
|
||||
uint8_t val[128];
|
||||
};
|
||||
|
||||
bool osmo_ipa_name_is_empty(const struct osmo_ipa_name *ipa_name);
|
||||
bool osmo_ipa_name_is_empty(struct osmo_ipa_name *ipa_name);
|
||||
int osmo_ipa_name_set(struct osmo_ipa_name *ipa_name, const uint8_t *val, size_t len);
|
||||
int osmo_ipa_name_set_str(struct osmo_ipa_name *ipa_name, const char *str_fmt, ...);
|
||||
int osmo_ipa_name_cmp(const struct osmo_ipa_name *a, const struct osmo_ipa_name *b);
|
||||
const char *osmo_ipa_name_to_str_c(void *ctx, const struct osmo_ipa_name *ipa_name);
|
||||
const char *osmo_ipa_name_to_str(const struct osmo_ipa_name *ipa_name);
|
||||
|
||||
enum osmo_cni_peer_id_type {
|
||||
OSMO_CNI_PEER_ID_EMPTY=0,
|
||||
OSMO_CNI_PEER_ID_IPA_NAME,
|
||||
/* OSMO_CNI_PEER_ID_GLOBAL_TITLE, <-- currently not implemented, but likely future possibility */
|
||||
enum osmo_gsup_peer_id_type {
|
||||
OSMO_GSUP_PEER_ID_EMPTY=0,
|
||||
OSMO_GSUP_PEER_ID_IPA_NAME,
|
||||
/* OSMO_GSUP_PEER_ID_GLOBAL_TITLE, <-- currently not implemented, but likely future possibility */
|
||||
};
|
||||
|
||||
extern const struct value_string osmo_cni_peer_id_type_names[];
|
||||
static inline const char *osmo_cni_peer_id_type_name(enum osmo_cni_peer_id_type val)
|
||||
{ return get_value_string(osmo_cni_peer_id_type_names, val); }
|
||||
extern const struct value_string osmo_gsup_peer_id_type_names[];
|
||||
static inline const char *osmo_gsup_peer_id_type_name(enum osmo_gsup_peer_id_type val)
|
||||
{ return get_value_string(osmo_gsup_peer_id_type_names, val); }
|
||||
|
||||
struct osmo_cni_peer_id {
|
||||
enum osmo_cni_peer_id_type type;
|
||||
struct osmo_gsup_peer_id {
|
||||
enum osmo_gsup_peer_id_type type;
|
||||
union {
|
||||
struct osmo_ipa_name ipa_name;
|
||||
};
|
||||
};
|
||||
|
||||
bool osmo_cni_peer_id_is_empty(const struct osmo_cni_peer_id *cni_peer_id);
|
||||
int osmo_cni_peer_id_set(struct osmo_cni_peer_id *cni_peer_id, enum osmo_cni_peer_id_type type,
|
||||
bool osmo_gsup_peer_id_is_empty(struct osmo_gsup_peer_id *gsup_peer_id);
|
||||
int osmo_gsup_peer_id_set(struct osmo_gsup_peer_id *gsup_peer_id, enum osmo_gsup_peer_id_type type,
|
||||
const uint8_t *val, size_t len);
|
||||
int osmo_cni_peer_id_set_str(struct osmo_cni_peer_id *cni_peer_id, enum osmo_cni_peer_id_type type,
|
||||
int osmo_gsup_peer_id_set_str(struct osmo_gsup_peer_id *gsup_peer_id, enum osmo_gsup_peer_id_type type,
|
||||
const char *str_fmt, ...);
|
||||
int osmo_cni_peer_id_cmp(const struct osmo_cni_peer_id *a, const struct osmo_cni_peer_id *b);
|
||||
const char *osmo_cni_peer_id_to_str(const struct osmo_cni_peer_id *cni_peer_id);
|
||||
const char *osmo_cni_peer_id_to_str_c(void *ctx, const struct osmo_cni_peer_id *cni_peer_id);
|
||||
int osmo_gsup_peer_id_cmp(const struct osmo_gsup_peer_id *a, const struct osmo_gsup_peer_id *b);
|
||||
const char *osmo_gsup_peer_id_to_str(const struct osmo_gsup_peer_id *gsup_peer_id);
|
||||
const char *osmo_gsup_peer_id_to_str_c(void *ctx, const struct osmo_gsup_peer_id *gsup_peer_id);
|
||||
@@ -19,14 +19,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
|
||||
struct osmo_gsup_req;
|
||||
|
||||
#define LOG_GSUP_REQ_CAT_SRC(req, subsys, level, file, line, fmt, args...) \
|
||||
LOGPSRC(subsys, level, file, line, "GSUP %u: %s: IMSI-%s %s: " fmt, \
|
||||
(req) ? (req)->nr : 0, \
|
||||
(req) ? osmo_cni_peer_id_to_str(&(req)->source_name) : "NULL", \
|
||||
(req) ? osmo_gsup_peer_id_to_str(&(req)->source_name) : "NULL", \
|
||||
(req) ? (req)->gsup.imsi : "NULL", \
|
||||
(req) ? osmo_gsup_message_type_name((req)->gsup.message_type) : "NULL", \
|
||||
##args)
|
||||
@@ -56,11 +56,11 @@ struct osmo_gsup_req {
|
||||
/* The ultimate source of this message: the source_name form the GSUP message, or, if not present, then the
|
||||
* immediate GSUP peer. GSUP messages going via a proxy reflect the initial source in the source_name.
|
||||
* This source_name is implicitly added to the routes for the conn the message was received on. */
|
||||
struct osmo_cni_peer_id source_name;
|
||||
struct osmo_gsup_peer_id source_name;
|
||||
|
||||
/* If the source_name is not an immediate GSUP peer, this is set to the closest intermediate peer between here
|
||||
* and source_name. */
|
||||
struct osmo_cni_peer_id via_proxy;
|
||||
struct osmo_gsup_peer_id via_proxy;
|
||||
|
||||
/* Identify this request by number, for logging. */
|
||||
unsigned int nr;
|
||||
@@ -82,28 +82,24 @@ struct osmo_gsup_req {
|
||||
struct msgb *msg;
|
||||
};
|
||||
|
||||
struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id *from_peer, struct msgb *msg,
|
||||
struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_gsup_peer_id *from_peer, struct msgb *msg,
|
||||
osmo_gsup_req_send_response_t send_response_cb, void *cb_data,
|
||||
struct llist_head *add_to_list);
|
||||
void osmo_gsup_req_free(struct osmo_gsup_req *req);
|
||||
|
||||
/*! See _osmo_gsup_req_respond() for details.
|
||||
* Call _osmo_gsup_req_respond(), passing the caller's source file and line for logging. */
|
||||
/*! Call _osmo_gsup_req_respond() to convey the sender's source file and line in the logs. */
|
||||
#define osmo_gsup_req_respond(REQ, RESPONSE, ERROR, FINAL_RESPONSE) \
|
||||
_osmo_gsup_req_respond(REQ, RESPONSE, ERROR, FINAL_RESPONSE, __FILE__, __LINE__)
|
||||
int _osmo_gsup_req_respond(struct osmo_gsup_req *req, struct osmo_gsup_message *response,
|
||||
bool error, bool final_response, const char *file, int line);
|
||||
|
||||
/*! See _osmo_gsup_req_respond_msgt() for details.
|
||||
* Call _osmo_gsup_req_respond_msgt(), passing the caller's source file and line for logging. */
|
||||
/*! Call _osmo_gsup_req_respond_msgt() to convey the sender's source file and line in the logs. */
|
||||
#define osmo_gsup_req_respond_msgt(REQ, MESSAGE_TYPE, FINAL_RESPONSE) \
|
||||
_osmo_gsup_req_respond_msgt(REQ, MESSAGE_TYPE, FINAL_RESPONSE, __FILE__, __LINE__)
|
||||
int _osmo_gsup_req_respond_msgt(struct osmo_gsup_req *req, enum osmo_gsup_message_type message_type,
|
||||
bool final_response, const char *file, int line);
|
||||
|
||||
/*! See _osmo_gsup_req_respond_err() for details.
|
||||
* Log an error message, and call _osmo_gsup_req_respond_err(), passing the caller's source file and line for logging.
|
||||
*/
|
||||
/*! Log an error message, and call _osmo_gsup_req_respond() to convey the sender's source file and line in the logs. */
|
||||
#define osmo_gsup_req_respond_err(REQ, CAUSE, FMT, args...) do { \
|
||||
LOG_GSUP_REQ(REQ, LOGL_ERROR, "%s: " FMT "\n", \
|
||||
get_value_string(gsm48_gmm_cause_names, CAUSE), ##args); \
|
||||
|
||||
@@ -14,6 +14,8 @@ noinst_HEADERS = \
|
||||
mslookup_server.h \
|
||||
mslookup_server_mdns.h \
|
||||
proxy.h \
|
||||
proxy_mm.h \
|
||||
proxy_db.h \
|
||||
rand.h \
|
||||
remote_hlr.h \
|
||||
timestamp.h \
|
||||
|
||||
@@ -3,19 +3,12 @@
|
||||
#include <stdbool.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
|
||||
struct hlr;
|
||||
|
||||
enum stmt_idx {
|
||||
DB_STMT_SEL_ALL,
|
||||
DB_STMT_SEL_ALL_ORDER_LAST_SEEN,
|
||||
DB_STMT_SEL_FILTER_MSISDN,
|
||||
DB_STMT_SEL_FILTER_IMSI,
|
||||
DB_STMT_SEL_FILTER_IMEI,
|
||||
DB_STMT_SEL_FILTER_CS,
|
||||
DB_STMT_SEL_FILTER_PS,
|
||||
DB_STMT_SEL_BY_IMSI,
|
||||
DB_STMT_SEL_BY_MSISDN,
|
||||
DB_STMT_SEL_BY_ID,
|
||||
@@ -159,9 +152,6 @@ int db_subscr_update_imei_by_imsi(struct db_context *dbc, const char* imsi, cons
|
||||
int db_subscr_exists_by_imsi(struct db_context *dbc, const char *imsi);
|
||||
int db_subscr_exists_by_msisdn(struct db_context *dbc, const char *msisdn);
|
||||
|
||||
int db_subscrs_get(struct db_context *dbc, const char *filter_type, const char *filter,
|
||||
void (*get_cb)(struct hlr_subscriber *subscr, void *data), void *data,
|
||||
int *count, const char **err);
|
||||
int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
|
||||
struct hlr_subscriber *subscr);
|
||||
int db_subscr_get_by_msisdn(struct db_context *dbc, const char *msisdn,
|
||||
@@ -177,8 +167,8 @@ int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
|
||||
int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
|
||||
bool purge_val, bool is_ps);
|
||||
|
||||
int db_ind(struct db_context *dbc, const struct osmo_cni_peer_id *vlr, unsigned int *ind);
|
||||
int db_ind_del(struct db_context *dbc, const struct osmo_cni_peer_id *vlr);
|
||||
int db_ind(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr, unsigned int *ind);
|
||||
int db_ind_del(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr);
|
||||
|
||||
/*! Call sqlite3_column_text() and copy result to a char[].
|
||||
* \param[out] buf A char[] used as sizeof() arg(!) and osmo_strlcpy() target.
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <osmocom/mslookup/mslookup.h>
|
||||
#include <osmocom/hlr/gsup_server.h>
|
||||
#include <osmocom/hlr/logging.h>
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_req.h>
|
||||
|
||||
#define LOG_DGSM(imsi, level, fmt, args...) \
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <osmocom/abis/ipa.h>
|
||||
#include <osmocom/abis/ipaccess.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_req.h>
|
||||
|
||||
#ifndef OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN
|
||||
@@ -42,6 +42,8 @@ struct osmo_gsup_conn {
|
||||
//struct oap_state oap_state;
|
||||
struct tlv_parsed ccm;
|
||||
|
||||
unsigned int auc_3g_ind; /*!< IND index used for UMTS AKA SQN */
|
||||
|
||||
/* Set when Location Update is received: */
|
||||
bool supports_cs; /* client supports OSMO_GSUP_CN_DOMAIN_CS */
|
||||
bool supports_ps; /* client supports OSMO_GSUP_CN_DOMAIN_PS */
|
||||
@@ -72,5 +74,5 @@ int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup,
|
||||
uint8_t *msisdn_enc, size_t msisdn_enc_size,
|
||||
uint8_t *apn_buf, size_t apn_buf_size,
|
||||
enum osmo_gsup_cn_domain cn_domain);
|
||||
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_cni_peer_id *to_peer,
|
||||
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_gsup_peer_id *to_peer,
|
||||
struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
#include <osmocom/mslookup/mslookup.h>
|
||||
|
||||
struct osmo_mslookup_query;
|
||||
|
||||
@@ -20,9 +20,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
||||
#include <osmocom/core/sockaddr_str.h>
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
#include <osmocom/hlr/timestamp.h>
|
||||
|
||||
struct osmo_gsup_req;
|
||||
@@ -65,6 +68,8 @@ struct proxy_subscr {
|
||||
char msisdn[GSM23003_MSISDN_MAX_DIGITS+1];
|
||||
struct osmo_sockaddr_str remote_hlr_addr;
|
||||
struct proxy_subscr_domain_state cs, ps;
|
||||
struct osmo_fsm_inst *mm_fi;
|
||||
struct osmo_fsm_inst *to_home_fi;
|
||||
};
|
||||
|
||||
void proxy_init(struct osmo_gsup_server *gsup_server_to_vlr);
|
||||
|
||||
37
include/osmocom/hlr/proxy_broken_link_cache.h
Normal file
37
include/osmocom/hlr/proxy_broken_link_cache.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright 2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* Author: Neels Hofmeyr <neels@hofmeyr.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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* If a subscriber from a remote site has successfully attached at this local site, and the link to the subscriber's
|
||||
* home HLR has succeeded, this will try to bridge the time of temporary link failure to that home HLR.
|
||||
* Tasks to take over from the unreachable home HLR:
|
||||
* - Resend known auth tuples on OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST.
|
||||
* - ...?
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* Data stored per subscriber */
|
||||
struct proxy_broken_link_cache {
|
||||
struct osmo_auth_vector auth_vectors[OSMO_GSUP_MAX_NUM_AUTH_INFO];
|
||||
size_t num_auth_vectors;
|
||||
|
||||
timestamp_t last_update;
|
||||
};
|
||||
54
include/osmocom/hlr/proxy_mm.h
Normal file
54
include/osmocom/hlr/proxy_mm.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/hlr/proxy.h>
|
||||
|
||||
enum proxy_mm_fsm_event {
|
||||
PROXY_MM_EV_SUBSCR_INVALID,
|
||||
PROXY_MM_EV_RX_GSUP_LU,
|
||||
PROXY_MM_EV_RX_GSUP_SAI,
|
||||
PROXY_MM_EV_RX_SUBSCR_DATA,
|
||||
PROXY_MM_EV_RX_GSUP_ISD_RESULT,
|
||||
PROXY_MM_EV_RX_AUTH_TUPLES,
|
||||
};
|
||||
|
||||
enum proxy_to_home_fsm_event {
|
||||
PROXY_TO_HOME_EV_HOME_HLR_RESOLVED,
|
||||
PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ,
|
||||
PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT,
|
||||
PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT,
|
||||
PROXY_TO_HOME_EV_CHECK_TUPLES,
|
||||
PROXY_TO_HOME_EV_CONFIRM_LU,
|
||||
};
|
||||
|
||||
extern struct llist_head proxy_mm_list;
|
||||
|
||||
struct proxy_mm_auth_cache {
|
||||
struct llist_head entry;
|
||||
uint64_t db_id;
|
||||
struct osmo_auth_vector auth_vectors[OSMO_GSUP_MAX_NUM_AUTH_INFO];
|
||||
size_t num_auth_vectors;
|
||||
unsigned int sent_to_vlr_count;
|
||||
};
|
||||
|
||||
struct proxy_mm {
|
||||
struct llist_head entry;
|
||||
struct osmo_gsup_peer_id vlr_name;
|
||||
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
|
||||
bool is_ps;
|
||||
struct osmo_fsm_inst *mm_fi;
|
||||
struct osmo_fsm_inst *to_home_fi;
|
||||
struct llist_head auth_cache;
|
||||
};
|
||||
|
||||
struct proxy_mm *proxy_mm_alloc(const struct osmo_gsup_peer_id *vlr_name,
|
||||
bool is_ps,
|
||||
const char *imsi);
|
||||
|
||||
void proxy_mm_add_auth_vectors(struct proxy_mm *proxy_mm,
|
||||
const struct osmo_auth_vector *auth_vectors, size_t num_auth_vectors);
|
||||
struct proxy_mm_auth_cache *proxy_mm_get_auth_vectors(struct proxy_mm *proxy_mm);
|
||||
void proxy_mm_use_auth_vectors(struct proxy_mm *proxy_mm, struct proxy_mm_auth_cache *ac);
|
||||
void proxy_mm_discard_auth_vectors(struct proxy_mm *proxy_mm, struct proxy_mm_auth_cache *ac);
|
||||
|
||||
bool proxy_mm_subscriber_data_known(const struct proxy_mm *proxy_mm);
|
||||
21
sql/hlr.sql
21
sql/hlr.sql
@@ -87,6 +87,27 @@ CREATE TABLE ind (
|
||||
UNIQUE (vlr)
|
||||
);
|
||||
|
||||
CREATE TABLE proxy_auth_cache {
|
||||
id INTEGER PRIMARY KEY,
|
||||
vlr TEXT NOT NULL,
|
||||
imsi TEXT NOT NULL,
|
||||
sent_count INTEGER
|
||||
};
|
||||
|
||||
CREATE TABLE proxy_auth_cache_vector {
|
||||
-- belongs to this proxy_auth_cache entry
|
||||
proxy_auth_cache_id INTEGER,
|
||||
rand VARCHAR(32),
|
||||
autn VARCHAR(32),
|
||||
ck VARCHAR(32),
|
||||
ik VARCHAR(32),
|
||||
res VARCHAR(32),
|
||||
kc[8] VARCHAR(16),
|
||||
sres[4] VARCHAR(8),
|
||||
-- enum osmo_sub_auth_type bitmask
|
||||
auth_types INTEGER
|
||||
};
|
||||
|
||||
CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi);
|
||||
|
||||
-- Set HLR database schema version number
|
||||
|
||||
@@ -54,6 +54,9 @@ osmo_hlr_SOURCES = \
|
||||
gsup_send.c \
|
||||
hlr_ussd.c \
|
||||
proxy.c \
|
||||
proxy_mm.c \
|
||||
proxy_to_home.c \
|
||||
proxy_db.c \
|
||||
dgsm.c \
|
||||
remote_hlr.c \
|
||||
lu_fsm.c \
|
||||
@@ -82,7 +85,7 @@ osmo_hlr_db_tool_SOURCES = \
|
||||
logging.c \
|
||||
rand_urandom.c \
|
||||
dbd_decode_binary.c \
|
||||
$(srcdir)/gsupclient/cni_peer_id.c \
|
||||
$(srcdir)/gsupclient/gsup_peer_id.c \
|
||||
$(NULL)
|
||||
|
||||
osmo_hlr_db_tool_LDADD = \
|
||||
|
||||
10
src/db.c
10
src/db.c
@@ -51,14 +51,6 @@
|
||||
"sgsn_via_proxy"
|
||||
|
||||
static const char *stmt_sql[] = {
|
||||
[DB_STMT_SEL_ALL] = "SELECT " SEL_COLUMNS " FROM subscriber;",
|
||||
[DB_STMT_SEL_ALL_ORDER_LAST_SEEN] = "SELECT " SEL_COLUMNS " FROM subscriber "
|
||||
"WHERE last_lu_seen IS NOT NULL ORDER BY last_lu_seen;",
|
||||
[DB_STMT_SEL_FILTER_MSISDN] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE msisdn LIKE $search ORDER BY msisdn",
|
||||
[DB_STMT_SEL_FILTER_IMSI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imsi LIKE $search ORDER BY imsi",
|
||||
[DB_STMT_SEL_FILTER_IMEI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imei LIKE $search ORDER BY imei",
|
||||
[DB_STMT_SEL_FILTER_CS] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE nam_cs = $search ORDER BY last_lu_seen",
|
||||
[DB_STMT_SEL_FILTER_PS] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE nam_ps = $search ORDER BY last_lu_seen",
|
||||
[DB_STMT_SEL_BY_IMSI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imsi = ?",
|
||||
[DB_STMT_SEL_BY_MSISDN] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE msisdn = ?",
|
||||
[DB_STMT_SEL_BY_ID] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE id = ?",
|
||||
@@ -237,7 +229,7 @@ void db_close(struct db_context *dbc)
|
||||
|
||||
static int db_run_statements(struct db_context *dbc, const char **statements, size_t statements_count)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc;
|
||||
int i;
|
||||
for (i = 0; i < statements_count; i++) {
|
||||
const char *stmt_str = statements[i];
|
||||
|
||||
104
src/db_hlr.c
104
src/db_hlr.c
@@ -37,7 +37,7 @@
|
||||
#include <osmocom/hlr/logging.h>
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
|
||||
#define LOGHLR(imsi, level, fmt, args ...) LOGP(DAUC, level, "IMSI='%s': " fmt, imsi, ## args)
|
||||
|
||||
@@ -264,11 +264,11 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
|
||||
switch (aud->algo) {
|
||||
case OSMO_AUTH_ALG_NONE:
|
||||
case OSMO_AUTH_ALG_MILENAGE:
|
||||
case OSMO_AUTH_ALG_XOR:
|
||||
break;
|
||||
case OSMO_AUTH_ALG_COMP128v1:
|
||||
case OSMO_AUTH_ALG_COMP128v2:
|
||||
case OSMO_AUTH_ALG_COMP128v3:
|
||||
case OSMO_AUTH_ALG_XOR:
|
||||
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
||||
" auth algo not suited for 3G: %s\n",
|
||||
osmo_auth_alg_name(aud->algo));
|
||||
@@ -625,94 +625,6 @@ int db_subscr_get_by_msisdn(struct db_context *dbc, const char *msisdn,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! Retrieve subscriber data from the HLR database.
|
||||
* \param[in,out] dbc database context.
|
||||
* \param[in] filter_type ASCII string of identifier type to search.
|
||||
* \param[in] filter ASCII string to search.
|
||||
* \param[in] get_cb pointer to call back function for data.
|
||||
* \param[in,out] data pointer to pass to callback function.
|
||||
* \param[in,out] count counter for number of matched subscribers.
|
||||
* \param[in,our] err
|
||||
* \returns 0 on success, -ENOENT if no subscriber was found, -EIO on
|
||||
* database error.
|
||||
*/
|
||||
int db_subscrs_get(struct db_context *dbc, const char *filter_type, const char *filter,
|
||||
void (*get_cb)(struct hlr_subscriber *subscr, void *data), void *data,
|
||||
int *count, const char **err)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
char search[256];
|
||||
int rc;
|
||||
struct hlr_subscriber subscr;
|
||||
bool show_ls = false;
|
||||
|
||||
if (!filter_type) {
|
||||
stmt = dbc->stmt[DB_STMT_SEL_ALL];
|
||||
} else if (strcmp(filter_type, "imei") == 0) {
|
||||
stmt = dbc->stmt[DB_STMT_SEL_FILTER_IMEI];
|
||||
} else if (strcmp(filter_type, "imsi") == 0) {
|
||||
stmt = dbc->stmt[DB_STMT_SEL_FILTER_IMSI];
|
||||
} else if (strcmp(filter_type, "msisdn") == 0) {
|
||||
stmt = dbc->stmt[DB_STMT_SEL_FILTER_MSISDN];
|
||||
} else if (strcmp(filter_type, "cs") == 0) {
|
||||
stmt = dbc->stmt[DB_STMT_SEL_FILTER_CS];
|
||||
} else if (strcmp(filter_type, "ps") == 0) {
|
||||
stmt = dbc->stmt[DB_STMT_SEL_FILTER_PS];
|
||||
} else if (strcmp(filter_type, "last_lu_seen") == 0) {
|
||||
show_ls = true;
|
||||
stmt = dbc->stmt[DB_STMT_SEL_ALL_ORDER_LAST_SEEN];
|
||||
} else {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (filter_type && filter && strcmp(filter_type, "last_lu_seen") != 0) {
|
||||
if (strcmp(filter, "on") == 0) {
|
||||
sprintf(search, "%s", "1");
|
||||
} else if (strcmp(filter, "off") == 0) {
|
||||
sprintf(search, "%s", "0");
|
||||
} else {
|
||||
sprintf(search, "%%%s%%", filter);
|
||||
}
|
||||
if (!db_bind_text(stmt, "$search", search)) {
|
||||
*err = sqlite3_errmsg(dbc->db);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
|
||||
if (rc == SQLITE_DONE) {
|
||||
db_remove_reset(stmt);
|
||||
*err = "No matching subscriber(s)";
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
while (rc == SQLITE_ROW) {
|
||||
subscr = (struct hlr_subscriber){
|
||||
.id = sqlite3_column_int64(stmt, 0),};
|
||||
copy_sqlite3_text_to_buf(subscr.imsi, stmt, 1);
|
||||
copy_sqlite3_text_to_buf(subscr.msisdn, stmt, 2);
|
||||
copy_sqlite3_text_to_buf(subscr.imei, stmt, 3);
|
||||
subscr.nam_cs = sqlite3_column_int(stmt, 9);
|
||||
subscr.nam_ps = sqlite3_column_int(stmt, 10);
|
||||
if (show_ls)
|
||||
parse_last_lu_seen(&subscr.last_lu_seen, (const char *)sqlite3_column_text(stmt, 14),
|
||||
subscr.imsi, "CS");
|
||||
get_cb(&subscr, data);
|
||||
rc = sqlite3_step(stmt);
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
db_remove_reset(stmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
*err = sqlite3_errmsg(dbc->db);
|
||||
LOGP(DAUC, LOGL_ERROR, "Cannot read subscribers from db:: %s\n", *err);
|
||||
return rc;
|
||||
}
|
||||
*err = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Retrieve subscriber data from the HLR database.
|
||||
* \param[in,out] dbc database context.
|
||||
* \param[in] id ID of the subscriber in the HLR db.
|
||||
@@ -1027,14 +939,14 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _db_ind(struct db_context *dbc, const struct osmo_cni_peer_id *vlr,
|
||||
int _db_ind(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr,
|
||||
unsigned int *ind, bool del)
|
||||
{
|
||||
const char *vlr_name = NULL;
|
||||
int rc;
|
||||
|
||||
switch (vlr->type) {
|
||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
||||
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||
if (vlr->ipa_name.len < 2 || vlr->ipa_name.val[vlr->ipa_name.len - 1] != '\0') {
|
||||
LOGP(DDB, LOGL_ERROR, "Expecting VLR ipa_name to be zero terminated; found %s\n",
|
||||
osmo_ipa_name_to_str(&vlr->ipa_name));
|
||||
@@ -1043,8 +955,8 @@ int _db_ind(struct db_context *dbc, const struct osmo_cni_peer_id *vlr,
|
||||
vlr_name = (const char*)vlr->ipa_name.val;
|
||||
break;
|
||||
default:
|
||||
LOGP(DDB, LOGL_ERROR, "Unsupported osmo_cni_peer_id type: %s\n",
|
||||
osmo_cni_peer_id_type_name(vlr->type));
|
||||
LOGP(DDB, LOGL_ERROR, "Unsupported osmo_gsup_peer_id type: %s\n",
|
||||
osmo_gsup_peer_id_type_name(vlr->type));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -1066,12 +978,12 @@ int _db_ind(struct db_context *dbc, const struct osmo_cni_peer_id *vlr,
|
||||
return _db_ind_get(dbc, vlr_name, ind);
|
||||
}
|
||||
|
||||
int db_ind(struct db_context *dbc, const struct osmo_cni_peer_id *vlr, unsigned int *ind)
|
||||
int db_ind(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr, unsigned int *ind)
|
||||
{
|
||||
return _db_ind(dbc, vlr, ind, false);
|
||||
}
|
||||
|
||||
int db_ind_del(struct db_context *dbc, const struct osmo_cni_peer_id *vlr)
|
||||
int db_ind_del(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr)
|
||||
{
|
||||
return _db_ind(dbc, vlr, NULL, true);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <osmocom/mslookup/mslookup_client.h>
|
||||
#include <osmocom/mslookup/mslookup_client_mdns.h>
|
||||
#include <osmocom/gsupclient/gsup_client.h>
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
#include <osmocom/hlr/logging.h>
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <osmocom/hlr/hlr_vty.h>
|
||||
#include <osmocom/hlr/mslookup_server.h>
|
||||
#include <osmocom/hlr/mslookup_server_mdns.h>
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
|
||||
struct cmd_node mslookup_node = {
|
||||
MSLOOKUP_NODE,
|
||||
@@ -442,7 +442,7 @@ int config_write_mslookup(struct vty *vty)
|
||||
|
||||
msc = mslookup_server_msc_get(&mslookup_server_msc_wildcard, false);
|
||||
if (msc)
|
||||
config_write_msc_services(vty, " ", msc);
|
||||
config_write_msc_services(vty, " ", msc);
|
||||
|
||||
llist_for_each_entry(msc, &g_hlr->mslookup.server.local_site_services, entry) {
|
||||
if (!osmo_ipa_name_cmp(&mslookup_server_msc_wildcard, &msc->name))
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
@@ -67,13 +65,13 @@ int osmo_gsup_conn_send(struct osmo_gsup_conn *conn, struct msgb *msg)
|
||||
static void gsup_server_send_req_response(struct osmo_gsup_req *req, struct osmo_gsup_message *response)
|
||||
{
|
||||
struct osmo_gsup_server *server = req->cb_data;
|
||||
struct osmo_cni_peer_id *routing;
|
||||
struct osmo_gsup_peer_id *routing;
|
||||
struct osmo_gsup_conn *conn = NULL;
|
||||
struct msgb *msg = osmo_gsup_msgb_alloc("GSUP Tx");
|
||||
int rc;
|
||||
|
||||
if (response->message_type == OSMO_GSUP_MSGT_ROUTING_ERROR
|
||||
&& !osmo_cni_peer_id_is_empty(&req->via_proxy)) {
|
||||
&& !osmo_gsup_peer_id_is_empty(&req->via_proxy)) {
|
||||
/* If a routing error occured, we need to route back via the immediate sending peer, not via the
|
||||
* intended final recipient -- because one source of routing errors is a duplicate name for a recipient.
|
||||
* If we resolve to req->source_name, we may send to a completely unrelated recipient. */
|
||||
@@ -82,12 +80,12 @@ static void gsup_server_send_req_response(struct osmo_gsup_req *req, struct osmo
|
||||
routing = &req->source_name;
|
||||
}
|
||||
switch (routing->type) {
|
||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
||||
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||
conn = gsup_route_find_by_ipa_name(server, &routing->ipa_name);
|
||||
break;
|
||||
default:
|
||||
LOG_GSUP_REQ(req, LOGL_ERROR, "GSUP peer id kind not supported: %s\n",
|
||||
osmo_cni_peer_id_type_name(routing->type));
|
||||
osmo_gsup_peer_id_type_name(routing->type));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -113,22 +111,22 @@ static void gsup_server_send_req_response(struct osmo_gsup_req *req, struct osmo
|
||||
struct osmo_gsup_req *osmo_gsup_conn_rx(struct osmo_gsup_conn *conn, struct msgb *msg)
|
||||
{
|
||||
struct osmo_gsup_req *req;
|
||||
struct osmo_cni_peer_id cpi = {
|
||||
.type = OSMO_CNI_PEER_ID_IPA_NAME,
|
||||
struct osmo_gsup_peer_id gpi = {
|
||||
.type = OSMO_GSUP_PEER_ID_IPA_NAME,
|
||||
.ipa_name = conn->peer_name,
|
||||
};
|
||||
|
||||
req = osmo_gsup_req_new(conn->server, &cpi, msg, gsup_server_send_req_response, conn->server, NULL);
|
||||
req = osmo_gsup_req_new(conn->server, &gpi, msg, gsup_server_send_req_response, conn->server, NULL);
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
||||
if (!osmo_cni_peer_id_is_empty(&req->via_proxy)) {
|
||||
if (!osmo_gsup_peer_id_is_empty(&req->via_proxy)) {
|
||||
switch (req->via_proxy.type) {
|
||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
||||
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||
break;
|
||||
default:
|
||||
LOG_GSUP_REQ(req, LOGL_ERROR, "GSUP peer id kind not supported: %s\n",
|
||||
osmo_cni_peer_id_type_name(req->source_name.type));
|
||||
osmo_gsup_peer_id_type_name(req->source_name.type));
|
||||
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);
|
||||
return NULL;
|
||||
}
|
||||
@@ -139,7 +137,7 @@ struct osmo_gsup_req *osmo_gsup_conn_rx(struct osmo_gsup_conn *conn, struct msgb
|
||||
LOG_GSUP_REQ(req, LOGL_ERROR,
|
||||
"GSUP message received from %s via peer %s, but there already exists a"
|
||||
" different route to this source, message is not routable\n",
|
||||
osmo_cni_peer_id_to_str(&req->source_name),
|
||||
osmo_gsup_peer_id_to_str(&req->source_name),
|
||||
osmo_ipa_name_to_str(&conn->peer_name));
|
||||
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);
|
||||
return NULL;
|
||||
@@ -276,7 +274,7 @@ static int osmo_gsup_server_ccm_cb(struct ipa_server_conn *conn,
|
||||
{
|
||||
struct osmo_gsup_conn *clnt = (struct osmo_gsup_conn *)conn->data;
|
||||
uint8_t *addr = NULL;
|
||||
int addr_len;
|
||||
size_t addr_len;
|
||||
|
||||
LOGP(DLGSUP, LOGL_INFO, "CCM Callback\n");
|
||||
|
||||
@@ -317,17 +315,41 @@ static int osmo_gsup_server_closed_cb(struct ipa_server_conn *conn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update_fd_settings(int fd)
|
||||
/* Add conn to the clients list in a way that conn->auc_3g_ind takes the lowest
|
||||
* unused integer and the list of clients remains sorted by auc_3g_ind.
|
||||
* Keep this function non-static to allow linking in a unit test. */
|
||||
void osmo_gsup_server_add_conn(struct llist_head *clients,
|
||||
struct osmo_gsup_conn *conn)
|
||||
{
|
||||
int ret;
|
||||
int val;
|
||||
struct osmo_gsup_conn *c;
|
||||
struct osmo_gsup_conn *prev_conn;
|
||||
|
||||
/*TODO: Set keepalive settings here. See OS#4312 */
|
||||
c = llist_first_entry_or_null(clients, struct osmo_gsup_conn, list);
|
||||
|
||||
val = 1;
|
||||
ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||
if (ret < 0)
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
|
||||
/* Is the first index, 0, unused? */
|
||||
if (!c || c->auc_3g_ind > 0) {
|
||||
conn->auc_3g_ind = 0;
|
||||
llist_add(&conn->list, clients);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Look for a gap later on */
|
||||
prev_conn = NULL;
|
||||
llist_for_each_entry(c, clients, list) {
|
||||
/* skip first item, we know it has auc_3g_ind == 0. */
|
||||
if (!prev_conn) {
|
||||
prev_conn = c;
|
||||
continue;
|
||||
}
|
||||
if (c->auc_3g_ind > prev_conn->auc_3g_ind + 1)
|
||||
break;
|
||||
prev_conn = c;
|
||||
}
|
||||
|
||||
OSMO_ASSERT(prev_conn);
|
||||
|
||||
conn->auc_3g_ind = prev_conn->auc_3g_ind + 1;
|
||||
llist_add(&conn->list, &prev_conn->list);
|
||||
}
|
||||
|
||||
/* a client has connected to the server socket and we have accept()ed it */
|
||||
@@ -349,11 +371,10 @@ static int osmo_gsup_server_accept_cb(struct ipa_server_link *link, int fd)
|
||||
|
||||
/* link data structure with server structure */
|
||||
conn->server = gsups;
|
||||
llist_add_tail(&conn->list, &gsups->clients);
|
||||
osmo_gsup_server_add_conn(&gsups->clients, conn);
|
||||
|
||||
LOGP(DLGSUP, LOGL_INFO, "New GSUP client %s:%d\n", conn->conn->addr, conn->conn->port);
|
||||
|
||||
update_fd_settings(fd);
|
||||
LOGP(DLGSUP, LOGL_INFO, "New GSUP client %s:%d (IND=%u)\n",
|
||||
conn->conn->addr, conn->conn->port, conn->auc_3g_ind);
|
||||
|
||||
/* request the identity of the client */
|
||||
rc = ipa_ccm_send_id_req(fd);
|
||||
@@ -440,7 +461,7 @@ int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
|
||||
|
||||
/**
|
||||
* Populate a gsup message structure with an Insert Subscriber Data Message.
|
||||
* All required memory buffers for data pointed to by pointers in struct osmo_gsup_message
|
||||
* All required memory buffers for data pointed to by pointers in struct omso_gsup_message
|
||||
* must be allocated by the caller and should have the same lifetime as the gsup parameter.
|
||||
*
|
||||
* \param[out] gsup The gsup message to populate.
|
||||
@@ -493,7 +514,7 @@ int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_cni_peer_id *to_peer,
|
||||
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_gsup_peer_id *to_peer,
|
||||
struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup)
|
||||
{
|
||||
int rc;
|
||||
@@ -502,22 +523,22 @@ int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struc
|
||||
* is required to return this as gsup->destination_name so that the reply gets routed to the original sender. */
|
||||
struct osmo_gsup_message forward = *(modified_gsup? : &req->gsup);
|
||||
|
||||
if (req->source_name.type != OSMO_CNI_PEER_ID_IPA_NAME) {
|
||||
if (req->source_name.type != OSMO_GSUP_PEER_ID_IPA_NAME) {
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",
|
||||
osmo_cni_peer_id_type_name(req->source_name.type));
|
||||
osmo_gsup_peer_id_type_name(req->source_name.type));
|
||||
rc = -ENOTSUP;
|
||||
goto routing_error;
|
||||
}
|
||||
forward.source_name = req->source_name.ipa_name.val;
|
||||
forward.source_name_len = req->source_name.ipa_name.len;
|
||||
|
||||
if (to_peer->type != OSMO_CNI_PEER_ID_IPA_NAME) {
|
||||
if (to_peer->type != OSMO_GSUP_PEER_ID_IPA_NAME) {
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",
|
||||
osmo_cni_peer_id_type_name(to_peer->type));
|
||||
osmo_gsup_peer_id_type_name(to_peer->type));
|
||||
rc = -ENOTSUP;
|
||||
goto routing_error;
|
||||
}
|
||||
LOG_GSUP_REQ(req, LOGL_INFO, "Forwarding to %s\n", osmo_cni_peer_id_to_str(to_peer));
|
||||
LOG_GSUP_REQ(req, LOGL_INFO, "Forwarding to %s\n", osmo_gsup_peer_id_to_str(to_peer));
|
||||
rc = osmo_gsup_enc_send_to_ipa_name(server, &to_peer->ipa_name, &forward);
|
||||
if (rc)
|
||||
goto routing_error;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# This is _NOT_ the library release version, it's an API version.
|
||||
# Please read chapter "Library interface versions" of the libtool documentation
|
||||
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
|
||||
LIBVERSION=1:0:1
|
||||
LIBVERSION=0:0:0
|
||||
|
||||
AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include \
|
||||
$(TALLOC_CFLAGS) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOABIS_CFLAGS)
|
||||
@@ -9,7 +9,7 @@ AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/incl
|
||||
lib_LTLIBRARIES = libosmo-gsup-client.la
|
||||
|
||||
libosmo_gsup_client_la_SOURCES = \
|
||||
cni_peer_id.c \
|
||||
gsup_peer_id.c \
|
||||
gsup_client.c \
|
||||
gsup_req.c \
|
||||
$(NULL)
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
static void start_test_procedure(struct osmo_gsup_client *gsupc);
|
||||
|
||||
@@ -131,19 +129,6 @@ static void gsup_client_oap_register(struct osmo_gsup_client *gsupc)
|
||||
client_send(gsupc, IPAC_PROTO_EXT_OAP, msg_tx);
|
||||
}
|
||||
|
||||
static void update_fd_settings(int fd)
|
||||
{
|
||||
int ret;
|
||||
int val;
|
||||
|
||||
/*TODO: Set keepalive settings here. See OS#4312 */
|
||||
|
||||
val = 1;
|
||||
ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||
if (ret < 0)
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
static void gsup_client_updown_cb(struct ipa_client_conn *link, int up)
|
||||
{
|
||||
struct osmo_gsup_client *gsupc = link->data;
|
||||
@@ -154,7 +139,6 @@ static void gsup_client_updown_cb(struct ipa_client_conn *link, int up)
|
||||
gsupc->is_connected = up;
|
||||
|
||||
if (up) {
|
||||
update_fd_settings(link->ofd->fd);
|
||||
start_test_procedure(gsupc);
|
||||
|
||||
if (gsupc->oap_state.state == OSMO_OAP_INITIALIZED)
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
|
||||
bool osmo_ipa_name_is_empty(const struct osmo_ipa_name *ipa_name)
|
||||
bool osmo_ipa_name_is_empty(struct osmo_ipa_name *ipa_name)
|
||||
{
|
||||
return (!ipa_name) || (!ipa_name->len);
|
||||
}
|
||||
@@ -107,44 +107,44 @@ const char *osmo_ipa_name_to_str_c(void *ctx, const struct osmo_ipa_name *ipa_na
|
||||
return osmo_escape_str_c(ctx, (char*)ipa_name->val, len);
|
||||
}
|
||||
|
||||
bool osmo_cni_peer_id_is_empty(const struct osmo_cni_peer_id *cni_peer_id)
|
||||
bool osmo_gsup_peer_id_is_empty(struct osmo_gsup_peer_id *gsup_peer_id)
|
||||
{
|
||||
if (!cni_peer_id)
|
||||
if (!gsup_peer_id)
|
||||
return true;
|
||||
switch (cni_peer_id->type) {
|
||||
case OSMO_CNI_PEER_ID_EMPTY:
|
||||
switch (gsup_peer_id->type) {
|
||||
case OSMO_GSUP_PEER_ID_EMPTY:
|
||||
return true;
|
||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
||||
return osmo_ipa_name_is_empty(&cni_peer_id->ipa_name);
|
||||
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||
return osmo_ipa_name_is_empty(&gsup_peer_id->ipa_name);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int osmo_cni_peer_id_set(struct osmo_cni_peer_id *cni_peer_id, enum osmo_cni_peer_id_type type,
|
||||
int osmo_gsup_peer_id_set(struct osmo_gsup_peer_id *gsup_peer_id, enum osmo_gsup_peer_id_type type,
|
||||
const uint8_t *val, size_t len)
|
||||
{
|
||||
cni_peer_id->type = type;
|
||||
gsup_peer_id->type = type;
|
||||
switch (type) {
|
||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
||||
return osmo_ipa_name_set(&cni_peer_id->ipa_name, val, len);
|
||||
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||
return osmo_ipa_name_set(&gsup_peer_id->ipa_name, val, len);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int osmo_cni_peer_id_set_str(struct osmo_cni_peer_id *cni_peer_id, enum osmo_cni_peer_id_type type,
|
||||
int osmo_gsup_peer_id_set_str(struct osmo_gsup_peer_id *gsup_peer_id, enum osmo_gsup_peer_id_type type,
|
||||
const char *str_fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
*cni_peer_id = (struct osmo_cni_peer_id){};
|
||||
*gsup_peer_id = (struct osmo_gsup_peer_id){};
|
||||
|
||||
switch (type) {
|
||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
||||
cni_peer_id->type = OSMO_CNI_PEER_ID_IPA_NAME;
|
||||
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||
gsup_peer_id->type = OSMO_GSUP_PEER_ID_IPA_NAME;
|
||||
va_start(ap, str_fmt);
|
||||
rc = osmo_ipa_name_set_str_va(&cni_peer_id->ipa_name, str_fmt, ap);
|
||||
rc = osmo_ipa_name_set_str_va(&gsup_peer_id->ipa_name, str_fmt, ap);
|
||||
va_end(ap);
|
||||
return rc;
|
||||
default:
|
||||
@@ -152,42 +152,36 @@ int osmo_cni_peer_id_set_str(struct osmo_cni_peer_id *cni_peer_id, enum osmo_cni
|
||||
}
|
||||
}
|
||||
|
||||
int osmo_cni_peer_id_cmp(const struct osmo_cni_peer_id *a, const struct osmo_cni_peer_id *b)
|
||||
int osmo_gsup_peer_id_cmp(const struct osmo_gsup_peer_id *a, const struct osmo_gsup_peer_id *b)
|
||||
{
|
||||
if (a == b)
|
||||
return 0;
|
||||
if (!a)
|
||||
return -1;
|
||||
if (!b)
|
||||
return 1;
|
||||
if (a->type != b->type)
|
||||
return OSMO_CMP(a->type, b->type);
|
||||
switch (a->type) {
|
||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
||||
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||
return osmo_ipa_name_cmp(&a->ipa_name, &b->ipa_name);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
const struct value_string osmo_cni_peer_id_type_names[] = {
|
||||
{ OSMO_CNI_PEER_ID_IPA_NAME, "IPA-name" },
|
||||
const struct value_string osmo_gsup_peer_id_type_names[] = {
|
||||
{ OSMO_GSUP_PEER_ID_IPA_NAME, "IPA-name" },
|
||||
{}
|
||||
};
|
||||
|
||||
/* Call osmo_cni_peer_id_to_str_c with OTC_SELECT */
|
||||
const char *osmo_cni_peer_id_to_str(const struct osmo_cni_peer_id *cpi)
|
||||
/* Call osmo_gsup_peer_id_to_str_c with OTC_SELECT */
|
||||
const char *osmo_gsup_peer_id_to_str(const struct osmo_gsup_peer_id *gpi)
|
||||
{
|
||||
return osmo_cni_peer_id_to_str_c(OTC_SELECT, cpi);
|
||||
return osmo_gsup_peer_id_to_str_c(OTC_SELECT, gpi);
|
||||
}
|
||||
|
||||
/* Return an unquoted string, not including the terminating zero. Used for writing VTY config. */
|
||||
const char *osmo_cni_peer_id_to_str_c(void *ctx, const struct osmo_cni_peer_id *cpi)
|
||||
const char *osmo_gsup_peer_id_to_str_c(void *ctx, const struct osmo_gsup_peer_id *gpi)
|
||||
{
|
||||
switch (cpi->type) {
|
||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
||||
return osmo_ipa_name_to_str_c(ctx, &cpi->ipa_name);
|
||||
switch (gpi->type) {
|
||||
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||
return osmo_ipa_name_to_str_c(ctx, &gpi->ipa_name);
|
||||
default:
|
||||
return talloc_strdup(ctx, osmo_cni_peer_id_type_name(cpi->type));
|
||||
return talloc_strdup(ctx, osmo_gsup_peer_id_type_name(gpi->type));
|
||||
}
|
||||
}
|
||||
@@ -25,81 +25,26 @@
|
||||
#include <osmocom/gsupclient/gsup_req.h>
|
||||
|
||||
/*! Create a new osmo_gsup_req record, decode GSUP and add to a provided list of requests.
|
||||
*
|
||||
* Rationales:
|
||||
*
|
||||
* - osmo_gsup_req makes it easy to handle GSUP requests asynchronously. Before this, a GSUP message struct would be
|
||||
* valid only within a read callback function, and would not survive asynchronous handling, because the struct often
|
||||
* points directly into the received msgb. An osmo_gsup_req takes ownership of the msgb and ensures that the data
|
||||
* remains valid, so that it can easily be queued for later handling.
|
||||
* - osmo_gsup_req unifies the composition of response messages to ensure that all IEs that identify it to belong to
|
||||
* the initial request are preserved / derived, like the source_name, destination_name, session_id, etc (see
|
||||
* osmo_gsup_make_response() for details).
|
||||
* - Deallocation of an osmo_gsup_req is implicit upon sending a response. The idea is that msgb memory leaks are a
|
||||
* recurring source of bugs. By enforcing a request-response relation with implicit deallocation, osmo_gsup_req aims
|
||||
* to help avoid most such memory leaks implicitly.
|
||||
*
|
||||
* The typical GSUP message sequence is:
|
||||
* -> rx request,
|
||||
* <- tx response.
|
||||
*
|
||||
* With osmo_gsup_req we can easily expand to:
|
||||
* -> rx request,
|
||||
* ... wait asynchronously,
|
||||
* <- tx response.
|
||||
*
|
||||
* Only few GSUP conversations go beyond a 1:1 request-response match. But some have a session (e.g. USSD) or more
|
||||
* negotiation may happen before the initial request is completed (e.g. Update Location with interleaved Insert
|
||||
* Subscriber Data), so osmo_gsup_req also allows passing non-final responses.
|
||||
* The final_response flag allows for:
|
||||
* -> rx request,
|
||||
* ... wait async,
|
||||
* <- tx intermediate message to same peer (final_response = false, req remains open),
|
||||
* ... wait async,
|
||||
* -> rx intermediate response,
|
||||
* ... wait async,
|
||||
* <- tx final response (final_response = true, req is deallocated).
|
||||
*
|
||||
* This function takes ownership of the msgb, which will, on success, be owned by the returned osmo_gsup_req instance
|
||||
* until osmo_gsup_req_free(). If a decoding error occurs, send an error response immediately, and return NULL.
|
||||
*
|
||||
* The original CNI entity that sent the message is found in req->source_name. If the message was passed on by an
|
||||
* intermediate CNI peer, then req->via_proxy is set to the immediate peer, and it is the responsibility of the caller
|
||||
* to add req->source_name to the GSUP routes that are serviced by req->via_proxy (usually not relevant for clients with
|
||||
* a single GSUP conn).
|
||||
* Examples:
|
||||
*
|
||||
* "msc" ---> here
|
||||
* source_name = "msc"
|
||||
* via_proxy = <empty>
|
||||
*
|
||||
* "msc" ---> "proxy-HLR" ---> here (e.g. home HLR)
|
||||
* source_name = "msc"
|
||||
* via_proxy = "proxy-HLR"
|
||||
*
|
||||
* "msc" ---> "proxy-HLR" ---> "home-HLR" ---> here (e.g. EUSE)
|
||||
* source_name = "msc"
|
||||
* via_proxy = "home-HLR"
|
||||
*
|
||||
* An osmo_gsup_req must be concluded (and deallocated) by calling one of the osmo_gsup_req_respond* functions.
|
||||
* When this function returns, the original sender is found in req->source_name. If this is not the immediate peer name,
|
||||
* then req->via_proxy is set to the immediate peer, and it is the responsibility of the caller to add req->source_name
|
||||
* to the GSUP routes that are serviced by req->via_proxy (usually not relevant for clients with a single GSUP conn).
|
||||
*
|
||||
* Note: osmo_gsup_req API makes use of OTC_SELECT to allocate volatile buffers for logging. Use of
|
||||
* osmo_select_main_ctx() is mandatory when using osmo_gsup_req.
|
||||
*
|
||||
* \param[in] ctx Talloc context for allocation of the new request.
|
||||
* \param[in] from_peer The IPA unit name of the immediate GSUP peer from which this msgb was received.
|
||||
* \param[in] msg The message buffer containing the received GSUP message, where msgb_l2() shall point to the GSUP
|
||||
* message start. The caller no longer owns the msgb when it is passed to this function: on error, the
|
||||
* msgb is freed immediately, and on success, the msgb is owned by the returned osmo_gsup_req.
|
||||
* \param[in] msg The GSUP message buffer.
|
||||
* \param[in] send_response_cb User specific method to send a GSUP response message, invoked upon
|
||||
* osmo_gsup_req_respond*() functions. Typically this invokes encoding and transmitting the
|
||||
* GSUP message over a network socket. See for example gsup_server_send_req_response().
|
||||
* osmo_gsup_req_respond*() functions.
|
||||
* \param[inout] cb_data Context data to be used freely by the caller.
|
||||
* \param[inout] add_to_list List to which to append this request, or NULL for no list.
|
||||
* \return a newly allocated osmo_gsup_req, or NULL on error. If NULL is returned, an error response has already been
|
||||
* dispatched to the send_response_cb.
|
||||
* \return a newly allocated osmo_gsup_req, or NULL on error.
|
||||
*/
|
||||
struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id *from_peer, struct msgb *msg,
|
||||
struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_gsup_peer_id *from_peer, struct msgb *msg,
|
||||
osmo_gsup_req_send_response_t send_response_cb, void *cb_data,
|
||||
struct llist_head *add_to_list)
|
||||
{
|
||||
@@ -107,15 +52,9 @@ struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id
|
||||
struct osmo_gsup_req *req;
|
||||
int rc;
|
||||
|
||||
if (!from_peer) {
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from NULL peer is not allowed\n");
|
||||
msgb_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!msgb_l2(msg) || !msgb_l2len(msg)) {
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from %s: missing or empty L2 data\n",
|
||||
osmo_cni_peer_id_to_str(from_peer));
|
||||
osmo_gsup_peer_id_to_str(from_peer));
|
||||
msgb_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
@@ -127,10 +66,11 @@ struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id
|
||||
req->msg = msg;
|
||||
req->send_response_cb = send_response_cb;
|
||||
req->cb_data = cb_data;
|
||||
req->source_name = *from_peer;
|
||||
if (from_peer)
|
||||
req->source_name = *from_peer;
|
||||
rc = osmo_gsup_decode(msgb_l2(req->msg), msgb_l2len(req->msg), (struct osmo_gsup_message*)&req->gsup);
|
||||
if (rc < 0) {
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from %s: cannot decode (rc=%d)\n", osmo_cni_peer_id_to_str(from_peer), rc);
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from %s: cannot decode (rc=%d)\n", osmo_gsup_peer_id_to_str(from_peer), rc);
|
||||
osmo_gsup_req_free(req);
|
||||
return NULL;
|
||||
}
|
||||
@@ -138,18 +78,18 @@ struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id
|
||||
LOG_GSUP_REQ(req, LOGL_DEBUG, "new request: {%s}\n", osmo_gsup_message_to_str_c(OTC_SELECT, &req->gsup));
|
||||
|
||||
if (req->gsup.source_name_len) {
|
||||
if (osmo_cni_peer_id_set(&req->source_name, OSMO_CNI_PEER_ID_IPA_NAME,
|
||||
if (osmo_gsup_peer_id_set(&req->source_name, OSMO_GSUP_PEER_ID_IPA_NAME,
|
||||
req->gsup.source_name, req->gsup.source_name_len)) {
|
||||
LOGP(DLGSUP, LOGL_ERROR,
|
||||
"Rx GSUP from %s: failed to decode source_name, message is not routable\n",
|
||||
osmo_cni_peer_id_to_str(from_peer));
|
||||
osmo_gsup_peer_id_to_str(from_peer));
|
||||
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The source of the GSUP message is not the immediate GSUP peer; the peer is our proxy for that source.
|
||||
*/
|
||||
if (osmo_cni_peer_id_cmp(&req->source_name, from_peer))
|
||||
if (osmo_gsup_peer_id_cmp(&req->source_name, from_peer))
|
||||
req->via_proxy = *from_peer;
|
||||
}
|
||||
|
||||
@@ -164,8 +104,6 @@ struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id
|
||||
return req;
|
||||
}
|
||||
|
||||
/*! Free an osmo_gsup_req and its msgb -- this is usually implicit in osmo_gsup_req_resond_*(), it should not be
|
||||
* necessary to call this directly. */
|
||||
void osmo_gsup_req_free(struct osmo_gsup_req *req)
|
||||
{
|
||||
LOG_GSUP_REQ(req, LOGL_DEBUG, "free\n");
|
||||
@@ -176,25 +114,6 @@ void osmo_gsup_req_free(struct osmo_gsup_req *req)
|
||||
talloc_free(req);
|
||||
}
|
||||
|
||||
/*! Send a response to a GSUP request.
|
||||
*
|
||||
* Ensure that the response message contains all GSUP IEs that identify it as a response for the request req, by calling
|
||||
* osmo_gsup_make_response().
|
||||
*
|
||||
* The final complete response message is passed to req->send_response_cb() to take care of the transmission.
|
||||
*
|
||||
* \param req Request as previously initialized by osmo_gsup_req_new().
|
||||
* \param response Buffer to compose the response, possibly with some pre-configured IEs.
|
||||
* Any missing IEs are added via osmo_gsup_make_response().
|
||||
* Must not be NULL. Does not need to remain valid memory beyond the function call,
|
||||
* i.e. this can just be a local variable in the calling function.
|
||||
* \param error True when the response message indicates an error response (error message type).
|
||||
* \param final_response True when the request is concluded by this response, which deallocates the req.
|
||||
* False when the request should remain open after this response.
|
||||
* For most plain request->response GSUP messages, this should be True.
|
||||
* \param file Source file for logging as in __FILE__, added by osmo_gsup_req_respond() macro.
|
||||
* \param line Source line for logging as in __LINE__, added by osmo_gsup_req_respond() macro.
|
||||
*/
|
||||
int _osmo_gsup_req_respond(struct osmo_gsup_req *req, struct osmo_gsup_message *response,
|
||||
bool error, bool final_response, const char *file, int line)
|
||||
{
|
||||
@@ -225,18 +144,6 @@ exit_cleanup:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! Shorthand for _osmo_gsup_req_respond() with no additional IEs and a fixed message type.
|
||||
* Set the message type in a local osmo_gsup_message and feed it to _osmo_gsup_req_respond().
|
||||
* That will ensure to add all IEs that identify it as a response to req.
|
||||
*
|
||||
* \param req Request as previously initialized by osmo_gsup_req_new().
|
||||
* \param message_type The GSUP message type discriminator to respond with.
|
||||
* \param final_response True when the request is concluded by this response, which deallocates the req.
|
||||
* False when the request should remain open after this response.
|
||||
* For most plain request->response GSUP messages, this should be True.
|
||||
* \param file Source file for logging as in __FILE__, added by osmo_gsup_req_respond_msgt() macro.
|
||||
* \param line Source line for logging as in __LINE__, added by osmo_gsup_req_respond_msgt() macro.
|
||||
*/
|
||||
int _osmo_gsup_req_respond_msgt(struct osmo_gsup_req *req, enum osmo_gsup_message_type message_type,
|
||||
bool final_response, const char *file, int line)
|
||||
{
|
||||
@@ -247,17 +154,6 @@ int _osmo_gsup_req_respond_msgt(struct osmo_gsup_req *req, enum osmo_gsup_messag
|
||||
file, line);
|
||||
}
|
||||
|
||||
/*! Shorthand for _osmo_gsup_req_respond() with an error cause IEs and using the req's matched error message type.
|
||||
* Set the error cause in a local osmo_gsup_message and feed it to _osmo_gsup_req_respond().
|
||||
* That will ensure to add all IEs that identify it as a response to req.
|
||||
*
|
||||
* Responding with an error always implies a final response: req is implicitly deallocated.
|
||||
*
|
||||
* \param req Request as previously initialized by osmo_gsup_req_new().
|
||||
* \param cause The error cause to include in a OSMO_GSUP_CAUSE_IE.
|
||||
* \param file Source file for logging as in __FILE__, added by osmo_gsup_req_respond_err() macro.
|
||||
* \param line Source line for logging as in __LINE__, added by osmo_gsup_req_respond_err() macro.
|
||||
*/
|
||||
void _osmo_gsup_req_respond_err(struct osmo_gsup_req *req, enum gsm48_gmm_cause cause,
|
||||
const char *file, int line)
|
||||
{
|
||||
|
||||
48
src/hlr.c
48
src/hlr.c
@@ -31,7 +31,6 @@
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/telnet_interface.h>
|
||||
#include <osmocom/vty/ports.h>
|
||||
#include <osmocom/vty/cpu_sched_vty.h>
|
||||
#include <osmocom/ctrl/control_vty.h>
|
||||
#include <osmocom/gsm/apn.h>
|
||||
#include <osmocom/gsm/gsm48_ie.h>
|
||||
@@ -39,7 +38,7 @@
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
#include <osmocom/mslookup/mslookup_client.h>
|
||||
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/ctrl.h>
|
||||
@@ -269,9 +268,9 @@ int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val,
|
||||
if (nam_val)
|
||||
return 0;
|
||||
|
||||
if (subscr->vlr_number[0] && !osmo_ipa_name_set_str(&vlr_name, subscr->vlr_number))
|
||||
if (subscr->vlr_number && osmo_ipa_name_set_str(&vlr_name, subscr->vlr_number))
|
||||
osmo_gsup_enc_send_to_ipa_name(g_hlr->gs, &vlr_name, &gsup_del_data);
|
||||
if (subscr->sgsn_number[0] && !osmo_ipa_name_set_str(&vlr_name, subscr->sgsn_number))
|
||||
if (subscr->sgsn_number && osmo_ipa_name_set_str(&vlr_name, subscr->sgsn_number))
|
||||
osmo_gsup_enc_send_to_ipa_name(g_hlr->gs, &vlr_name, &gsup_del_data);
|
||||
return 0;
|
||||
}
|
||||
@@ -304,7 +303,7 @@ static int rx_send_auth_info(struct osmo_gsup_req *req)
|
||||
LOG_GSUP_REQ(req, LOGL_ERROR,
|
||||
"Unable to determine 3G auth IND for source %s (rc=%d),"
|
||||
" generating tuples with IND = 0\n",
|
||||
osmo_cni_peer_id_to_str(&req->source_name), rc);
|
||||
osmo_gsup_peer_id_to_str(&req->source_name), rc);
|
||||
auc_3g_ind = 0;
|
||||
}
|
||||
|
||||
@@ -586,10 +585,6 @@ static void print_help()
|
||||
printf(" -U --db-upgrade Allow HLR database schema upgrades.\n");
|
||||
printf(" -C --db-check Quit after opening (and upgrading) the database.\n");
|
||||
printf(" -V --version Print the version of OsmoHLR.\n");
|
||||
|
||||
printf("\nVTY reference generation:\n");
|
||||
printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n");
|
||||
printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
|
||||
}
|
||||
|
||||
static struct {
|
||||
@@ -605,37 +600,10 @@ static struct {
|
||||
.db_upgrade = false,
|
||||
};
|
||||
|
||||
static void handle_long_options(const char *prog_name, const int long_option)
|
||||
{
|
||||
static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
|
||||
|
||||
switch (long_option) {
|
||||
case 1:
|
||||
vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
|
||||
if (vty_ref_mode < 0) {
|
||||
fprintf(stderr, "%s: Unknown VTY reference generation "
|
||||
"mode '%s'\n", prog_name, optarg);
|
||||
exit(2);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
|
||||
get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
|
||||
get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
|
||||
vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
|
||||
exit(0);
|
||||
default:
|
||||
fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void handle_options(int argc, char **argv)
|
||||
{
|
||||
while (1) {
|
||||
int option_index = 0, c;
|
||||
static int long_option = 0;
|
||||
static struct option long_options[] = {
|
||||
{"help", 0, 0, 'h'},
|
||||
{"config-file", 1, 0, 'c'},
|
||||
@@ -648,8 +616,6 @@ static void handle_options(int argc, char **argv)
|
||||
{"db-upgrade", 0, 0, 'U' },
|
||||
{"db-check", 0, 0, 'C' },
|
||||
{"version", 0, 0, 'V' },
|
||||
{"vty-ref-mode", 1, &long_option, 1},
|
||||
{"vty-ref-xml", 0, &long_option, 2},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@@ -659,9 +625,6 @@ static void handle_options(int argc, char **argv)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 0:
|
||||
handle_long_options(argv[0], long_option);
|
||||
break;
|
||||
case 'h':
|
||||
print_usage();
|
||||
print_help();
|
||||
@@ -775,10 +738,9 @@ int main(int argc, char **argv)
|
||||
osmo_stats_init(hlr_ctx);
|
||||
vty_init(&vty_info);
|
||||
ctrl_vty_init(hlr_ctx);
|
||||
handle_options(argc, argv);
|
||||
hlr_vty_init();
|
||||
dgsm_vty_init();
|
||||
osmo_cpu_sched_vty_init(hlr_ctx);
|
||||
handle_options(argc, argv);
|
||||
|
||||
rc = vty_read_config_file(cmdline_opts.config_file, NULL);
|
||||
if (rc < 0) {
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/application.h>
|
||||
@@ -71,9 +70,8 @@ static void print_help()
|
||||
printf(" (All commands imply this if none exists yet.)\n");
|
||||
printf("\n");
|
||||
printf(" import-nitb-db <nitb.db> Add OsmoNITB db's subscribers to OsmoHLR db.\n");
|
||||
printf(" Be aware that the import is somewhat lossy, only the IMSI,\n");
|
||||
printf(" MSISDN, IMEI, nam_cs/ps, 2G auth data and last seen LU are set.\n");
|
||||
printf(" The most recently associated IMEI from the Equipment table is used.\n");
|
||||
printf(" Be aware that the import is lossy, only the\n");
|
||||
printf(" IMSI, MSISDN, nam_cs/ps and 2G auth data are set.\n");
|
||||
}
|
||||
|
||||
static void print_version(int print_copyright)
|
||||
@@ -214,15 +212,9 @@ enum nitb_stmt {
|
||||
|
||||
static const char *nitb_stmt_sql[] = {
|
||||
[NITB_SELECT_SUBSCR] =
|
||||
"SELECT s.imsi, s.id, s.extension, s.authorized,"
|
||||
" SUBSTR(e.imei,0,15), STRFTIME('%s', s.expire_lu)"
|
||||
" FROM Subscriber s LEFT JOIN"
|
||||
" (SELECT imei, subscriber_id, MAX(Equipment.updated) AS updated"
|
||||
" FROM Equipment,EquipmentWatch"
|
||||
" WHERE Equipment.id = EquipmentWatch.equipment_id"
|
||||
" GROUP BY EquipmentWatch.subscriber_id) e"
|
||||
" ON e.subscriber_id = s.id"
|
||||
" ORDER by s.id",
|
||||
"SELECT imsi, id, extension, authorized"
|
||||
" FROM Subscriber"
|
||||
" ORDER BY id",
|
||||
[NITB_SELECT_AUTH_KEYS] =
|
||||
"SELECT algorithm_id, a3a8_ki from authkeys"
|
||||
" WHERE subscriber_id = $subscr_id",
|
||||
@@ -230,65 +222,8 @@ static const char *nitb_stmt_sql[] = {
|
||||
|
||||
sqlite3_stmt *nitb_stmt[ARRAY_SIZE(nitb_stmt_sql)] = {};
|
||||
|
||||
enum hlr_db_stmt {
|
||||
HLR_DB_STMT_SET_IMPLICIT_LU_BY_IMSI,
|
||||
};
|
||||
|
||||
static const char *hlr_db_stmt_sql[] = {
|
||||
[HLR_DB_STMT_SET_IMPLICIT_LU_BY_IMSI] =
|
||||
"UPDATE subscriber SET last_lu_seen = datetime($last_lu, 'unixepoch') WHERE imsi = $imsi",
|
||||
};
|
||||
|
||||
sqlite3_stmt *hlr_db_stmt[ARRAY_SIZE(hlr_db_stmt_sql)] = {};
|
||||
|
||||
size_t _dbd_decode_binary(const unsigned char *in, unsigned char *out);
|
||||
|
||||
/*! Set a subscriber's LU timestamp in the HLR database.
|
||||
* In normal operations there is never any need to explicitly
|
||||
* update the value of last_lu_seen, so this function can live here.
|
||||
*
|
||||
* \param[in,out] dbc database context.
|
||||
* \param[in] imsi ASCII string of IMSI digits
|
||||
* \param[in] imei ASCII string of identifier digits, or NULL to remove the IMEI.
|
||||
* \returns 0 on success, -ENOENT when the given subscriber does not exist,
|
||||
* -EIO on database errors.
|
||||
*/
|
||||
int db_subscr_update_lu_by_imsi(struct db_context *dbc, const char* imsi, const int last_lu)
|
||||
{
|
||||
int rc, ret = 0;
|
||||
|
||||
sqlite3_stmt *stmt = hlr_db_stmt[HLR_DB_STMT_SET_IMPLICIT_LU_BY_IMSI];
|
||||
|
||||
if (!db_bind_text(stmt, "$imsi", imsi))
|
||||
return -EIO;
|
||||
if (last_lu && !db_bind_int(stmt, "$last_lu", last_lu))
|
||||
return -EIO;
|
||||
|
||||
/* execute the statement */
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Update last_lu_seen for subscriber IMSI='%s': SQL Error: %s\n", imsi,
|
||||
sqlite3_errmsg(dbc->db));
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* verify execution result */
|
||||
rc = sqlite3_changes(dbc->db);
|
||||
if (!rc) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Cannot update last_lu_seen for subscriber IMSI='%s': no such subscriber\n", imsi);
|
||||
ret = -ENOENT;
|
||||
} else if (rc != 1) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Update last_lu_seen for subscriber IMSI='%s': SQL modified %d rows (expected 1)\n",
|
||||
imsi, rc);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
out:
|
||||
db_remove_reset(stmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void import_nitb_subscr_aud(sqlite3 *nitb_db, const char *imsi, int64_t nitb_id, int64_t hlr_id)
|
||||
{
|
||||
int rc;
|
||||
@@ -362,7 +297,6 @@ void import_nitb_subscr(sqlite3 *nitb_db, sqlite3_stmt *stmt)
|
||||
int64_t imsi;
|
||||
char imsi_str[32];
|
||||
bool authorized;
|
||||
int last_lu_int;
|
||||
|
||||
imsi = sqlite3_column_int64(stmt, 0);
|
||||
|
||||
@@ -381,18 +315,8 @@ void import_nitb_subscr(sqlite3 *nitb_db, sqlite3_stmt *stmt)
|
||||
nitb_id = sqlite3_column_int64(stmt, 1);
|
||||
copy_sqlite3_text_to_buf(subscr.msisdn, stmt, 2);
|
||||
authorized = sqlite3_column_int(stmt, 3) ? true : false;
|
||||
copy_sqlite3_text_to_buf(subscr.imei, stmt, 4);
|
||||
/* Default periodic LU was 30 mins and the expire_lu
|
||||
* was twice that + 1 min
|
||||
*/
|
||||
last_lu_int = sqlite3_column_int(stmt, 5) - 3660;
|
||||
|
||||
db_subscr_update_msisdn_by_imsi(dbc, imsi_str, subscr.msisdn);
|
||||
/* In case the subscriber was somehow never seen, invent an IMEI */
|
||||
if (strlen(subscr.imei) == 14)
|
||||
db_subscr_update_imei_by_imsi(dbc, imsi_str, subscr.imei);
|
||||
db_subscr_update_lu_by_imsi(dbc, imsi_str, last_lu_int);
|
||||
|
||||
db_subscr_nam(dbc, imsi_str, authorized, true);
|
||||
db_subscr_nam(dbc, imsi_str, authorized, false);
|
||||
|
||||
@@ -437,17 +361,6 @@ int import_nitb_db(void)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hlr_db_stmt_sql); i++) {
|
||||
sql = hlr_db_stmt_sql[i];
|
||||
rc = sqlite3_prepare_v2(g_hlr_db_tool_ctx->dbc->db, hlr_db_stmt_sql[i], -1,
|
||||
&hlr_db_stmt[i], NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOGP(DDB, LOGL_ERROR, "OsmoHLR DB: Unable to prepare SQL statement '%s'\n", sql);
|
||||
ret = -1;
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
|
||||
stmt = nitb_stmt[NITB_SELECT_SUBSCR];
|
||||
|
||||
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||
@@ -474,7 +387,6 @@ int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
int (*main_action)(void);
|
||||
int i;
|
||||
main_action = NULL;
|
||||
|
||||
g_hlr_db_tool_ctx = talloc_zero(NULL, struct hlr_db_tool_ctx);
|
||||
@@ -518,11 +430,6 @@ int main(int argc, char **argv)
|
||||
if (main_action)
|
||||
rc = (*main_action)();
|
||||
|
||||
/* db_close will only finalize statments in g_hlr_db_tool_ctx->dbc->stmt
|
||||
* it is ok to call finalize on NULL */
|
||||
for (i = 0; i < ARRAY_SIZE(hlr_db_stmt); i++) {
|
||||
sqlite3_finalize(hlr_db_stmt[i]);
|
||||
}
|
||||
db_close(g_hlr_db_tool_ctx->dbc);
|
||||
log_fini();
|
||||
exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
|
||||
@@ -279,20 +279,19 @@ static int ss_gsup_send_to_ms(struct ss_session *ss, struct osmo_gsup_server *gs
|
||||
}
|
||||
|
||||
static int ss_tx_to_ms(struct ss_session *ss, enum osmo_gsup_message_type gsup_msg_type,
|
||||
struct msgb *ss_msg)
|
||||
bool final, struct msgb *ss_msg)
|
||||
|
||||
{
|
||||
struct osmo_gsup_message resp;
|
||||
struct osmo_gsup_message resp = {0};
|
||||
int rc;
|
||||
|
||||
resp = (struct osmo_gsup_message) {
|
||||
.message_type = gsup_msg_type,
|
||||
.session_id = ss->session_id,
|
||||
.session_state = ss->state,
|
||||
};
|
||||
|
||||
resp.message_type = gsup_msg_type;
|
||||
OSMO_STRLCPY_ARRAY(resp.imsi, ss->imsi);
|
||||
|
||||
if (final)
|
||||
resp.session_state = OSMO_GSUP_SESSION_STATE_END;
|
||||
else
|
||||
resp.session_state = OSMO_GSUP_SESSION_STATE_CONTINUE;
|
||||
resp.session_id = ss->session_id;
|
||||
if (ss_msg) {
|
||||
resp.ss_info = msgb_data(ss_msg);
|
||||
resp.ss_info_len = msgb_length(ss_msg);
|
||||
@@ -312,8 +311,7 @@ static int ss_tx_reject(struct ss_session *ss, int invoke_id, uint8_t problem_ta
|
||||
LOGPSS(ss, LOGL_NOTICE, "Tx Reject(%u, 0x%02x, 0x%02x)\n", invoke_id,
|
||||
problem_tag, problem_code);
|
||||
OSMO_ASSERT(msg);
|
||||
ss->state = OSMO_GSUP_SESSION_STATE_END;
|
||||
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, msg);
|
||||
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, true, msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -322,16 +320,15 @@ static int ss_tx_to_ms_error(struct ss_session *ss, uint8_t invoke_id, uint8_t e
|
||||
struct msgb *msg = gsm0480_gen_return_error(invoke_id, error_code);
|
||||
LOGPSS(ss, LOGL_NOTICE, "Tx ReturnError(%u, 0x%02x)\n", invoke_id, error_code);
|
||||
OSMO_ASSERT(msg);
|
||||
ss->state = OSMO_GSUP_SESSION_STATE_END;
|
||||
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, msg);
|
||||
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, true, msg);
|
||||
}
|
||||
|
||||
static int ss_tx_to_ms_ussd_7bit(struct ss_session *ss, uint8_t invoke_id, const char *text)
|
||||
static int ss_tx_to_ms_ussd_7bit(struct ss_session *ss, bool final, uint8_t invoke_id, const char *text)
|
||||
{
|
||||
struct msgb *msg = gsm0480_gen_ussd_resp_7bit(invoke_id, text);
|
||||
LOGPSS(ss, LOGL_INFO, "Tx USSD '%s'\n", text);
|
||||
OSMO_ASSERT(msg);
|
||||
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, msg);
|
||||
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, final, msg);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
@@ -347,8 +344,6 @@ static int handle_ussd_own_msisdn(struct ss_session *ss,
|
||||
char buf[GSM0480_USSD_7BIT_STRING_LEN+1];
|
||||
int rc;
|
||||
|
||||
ss->state = OSMO_GSUP_SESSION_STATE_END;
|
||||
|
||||
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
@@ -356,7 +351,7 @@ static int handle_ussd_own_msisdn(struct ss_session *ss,
|
||||
snprintf(buf, sizeof(buf), "You have no MSISDN!");
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "Your extension is %s", subscr.msisdn);
|
||||
ss_tx_to_ms_ussd_7bit(ss, req->invoke_id, buf);
|
||||
ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id, buf);
|
||||
break;
|
||||
case -ENOENT:
|
||||
ss_tx_to_ms_error(ss, req->invoke_id, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||
@@ -374,21 +369,7 @@ static int handle_ussd_own_imsi(struct ss_session *ss,
|
||||
{
|
||||
char buf[GSM0480_USSD_7BIT_STRING_LEN+1];
|
||||
snprintf(buf, sizeof(buf), "Your IMSI is %s", ss->imsi);
|
||||
ss->state = OSMO_GSUP_SESSION_STATE_END;
|
||||
ss_tx_to_ms_ussd_7bit(ss, req->invoke_id, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This handler just keeps the session idle unless the guard timer expires. */
|
||||
static int handle_ussd_test_idle(struct ss_session *ss,
|
||||
const struct osmo_gsup_message *gsup,
|
||||
const struct ss_request *req)
|
||||
{
|
||||
char buf[GSM0480_USSD_7BIT_STRING_LEN + 1];
|
||||
snprintf(buf, sizeof(buf), "Keeping your session idle, it will expire "
|
||||
"at most in %u seconds.", g_hlr->ncss_guard_timeout);
|
||||
ss->state = OSMO_GSUP_SESSION_STATE_CONTINUE;
|
||||
ss_tx_to_ms_ussd_7bit(ss, req->invoke_id, buf);
|
||||
ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -402,10 +383,6 @@ static const struct hlr_iuse hlr_iuses[] = {
|
||||
.name = "own-imsi",
|
||||
.handle_ussd = handle_ussd_own_imsi,
|
||||
},
|
||||
{
|
||||
.name = "test-idle",
|
||||
.handle_ussd = handle_ussd_test_idle,
|
||||
},
|
||||
};
|
||||
|
||||
const struct hlr_iuse *iuse_find(const char *name)
|
||||
@@ -439,22 +416,22 @@ static bool ss_op_is_ussd(uint8_t opcode)
|
||||
}
|
||||
|
||||
/* is this GSUP connection an EUSE (true) or not (false)? */
|
||||
static bool peer_name_is_euse(const struct osmo_cni_peer_id *peer_name)
|
||||
static bool peer_name_is_euse(const struct osmo_gsup_peer_id *peer_name)
|
||||
{
|
||||
if (peer_name->type != OSMO_CNI_PEER_ID_IPA_NAME)
|
||||
if (peer_name->type != OSMO_GSUP_PEER_ID_IPA_NAME)
|
||||
return false;
|
||||
if (peer_name->ipa_name.len <= 5)
|
||||
return false;
|
||||
return strncmp((char *)(peer_name->ipa_name.val), "EUSE-", 5) == 0;
|
||||
}
|
||||
|
||||
static struct hlr_euse *euse_by_name(const struct osmo_cni_peer_id *peer_name)
|
||||
static struct hlr_euse *euse_by_name(const struct osmo_gsup_peer_id *peer_name)
|
||||
{
|
||||
if (!peer_name_is_euse(peer_name))
|
||||
return NULL;
|
||||
|
||||
/* above peer_name_is_euse() ensures this: */
|
||||
OSMO_ASSERT(peer_name->type == OSMO_CNI_PEER_ID_IPA_NAME);
|
||||
OSMO_ASSERT(peer_name->type == OSMO_GSUP_PEER_ID_IPA_NAME);
|
||||
|
||||
return euse_find(g_hlr, (const char*)(peer_name->ipa_name.val)+5);
|
||||
}
|
||||
@@ -519,9 +496,8 @@ static int handle_ussd(struct ss_session *ss, bool is_euse_originated, const str
|
||||
} else {
|
||||
/* Handle internally */
|
||||
ss->u.iuse->handle_ussd(ss, gsup, req);
|
||||
/* Release session if the handler has changed its state to END */
|
||||
if (ss->state == OSMO_GSUP_SESSION_STATE_END)
|
||||
ss_session_free(ss);
|
||||
/* Release session immediately */
|
||||
ss_session_free(ss);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,10 +521,10 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
|
||||
LOGP(DSS, LOGL_DEBUG, "%s/0x%08x: Process SS (%s)\n", gsup->imsi, gsup->session_id,
|
||||
osmo_gsup_session_state_name(gsup->session_state));
|
||||
|
||||
if (gsup_req->source_name.type != OSMO_CNI_PEER_ID_IPA_NAME) {
|
||||
if (gsup_req->source_name.type != OSMO_GSUP_PEER_ID_IPA_NAME) {
|
||||
LOGP(DSS, LOGL_ERROR, "%s/0x%082x: Unable to process SS request: Unsupported GSUP peer id type%s\n",
|
||||
gsup->imsi, gsup->session_id,
|
||||
osmo_cni_peer_id_type_name(gsup_req->source_name.type));
|
||||
osmo_gsup_peer_id_type_name(gsup_req->source_name.type));
|
||||
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_PROTO_ERR_UNSPEC, "error processing SS request");
|
||||
return;
|
||||
}
|
||||
@@ -590,7 +566,7 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
|
||||
if (!is_euse_originated) {
|
||||
ss->initial_req_from_ms = gsup_req;
|
||||
free_gsup_req = NULL;
|
||||
OSMO_ASSERT(gsup_req->source_name.type == OSMO_CNI_PEER_ID_IPA_NAME); /* checked above */
|
||||
OSMO_ASSERT(gsup_req->source_name.type == OSMO_GSUP_PEER_ID_IPA_NAME); /* checked above */
|
||||
ss->vlr_name = gsup_req->source_name.ipa_name;
|
||||
} else {
|
||||
ss->initial_req_from_euse = gsup_req;
|
||||
|
||||
@@ -102,8 +102,6 @@ static int config_write_hlr_gsup(struct vty *vty)
|
||||
vty_out(vty, " gsup%s", VTY_NEWLINE);
|
||||
if (g_hlr->gsup_bind_addr)
|
||||
vty_out(vty, " bind ip %s%s", g_hlr->gsup_bind_addr, VTY_NEWLINE);
|
||||
if (g_hlr->gsup_unit_name.serno)
|
||||
vty_out(vty, " ipa-name %s%s", g_hlr->gsup_unit_name.serno, VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -116,8 +114,8 @@ static void show_one_conn(struct vty *vty, const struct osmo_gsup_conn *conn)
|
||||
rc = osmo_gsup_conn_ccm_get(conn, (uint8_t **) &name, IPAC_IDTAG_SERNR);
|
||||
OSMO_ASSERT(rc);
|
||||
|
||||
vty_out(vty, " '%s' from %s:%5u, CS=%u, PS=%u%s",
|
||||
name, isc->addr, isc->port, conn->supports_cs, conn->supports_ps,
|
||||
vty_out(vty, " '%s' from %s:%5u, CS=%u, PS=%u, 3G_IND=%u%s",
|
||||
name, isc->addr, isc->port, conn->supports_cs, conn->supports_ps, conn->auc_3g_ind,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
@@ -176,11 +174,10 @@ DEFUN(cfg_hlr_gsup_ipa_name,
|
||||
#define UROUTE_STR "Routing Configuration\n"
|
||||
#define PREFIX_STR "Prefix-Matching Route\n" "USSD Prefix\n"
|
||||
|
||||
#define INT_CHOICE "(own-msisdn|own-imsi|test-idle)"
|
||||
#define INT_CHOICE "(own-msisdn|own-imsi)"
|
||||
#define INT_STR "Internal USSD Handler\n" \
|
||||
"Respond with subscribers' own MSISDN\n" \
|
||||
"Respond with subscribers' own IMSI\n" \
|
||||
"Keep the session idle (useful for testing)\n"
|
||||
"Respond with subscribers' own IMSI\n"
|
||||
|
||||
#define EXT_STR "External USSD Handler\n" \
|
||||
"Name of External USSD Handler (IPA CCM ID)\n"
|
||||
@@ -308,7 +305,7 @@ DEFUN(cfg_no_euse, cfg_no_euse_cmd,
|
||||
{
|
||||
struct hlr_euse *euse = euse_find(g_hlr, argv[0]);
|
||||
if (!euse) {
|
||||
vty_out(vty, "%% Cannot remove non-existent EUSE %s%s", argv[0], VTY_NEWLINE);
|
||||
vty_out(vty, "%% Cannot remove non-existant EUSE %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (g_hlr->euse_default == euse) {
|
||||
|
||||
@@ -44,14 +44,13 @@ static char *get_datestr(const time_t *t, char *buf, size_t bufsize)
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t last_lu_seen, bool only_age)
|
||||
static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t last_lu_seen)
|
||||
{
|
||||
uint32_t age;
|
||||
char datebuf[32];
|
||||
if (!last_lu_seen)
|
||||
return;
|
||||
if (!only_age)
|
||||
vty_out(vty, " last LU seen on %s: %s", domain_label, get_datestr(&last_lu_seen, datebuf, sizeof(datebuf)));
|
||||
vty_out(vty, " last LU seen on %s: %s", domain_label, get_datestr(&last_lu_seen, datebuf, sizeof(datebuf)));
|
||||
if (!timestamp_age(&last_lu_seen, &age))
|
||||
vty_out(vty, " (invalid timestamp)%s", VTY_NEWLINE);
|
||||
else {
|
||||
@@ -65,10 +64,7 @@ static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t
|
||||
UNIT_AGO("h", 60*60);
|
||||
UNIT_AGO("m", 60);
|
||||
UNIT_AGO("s", 1);
|
||||
if (!only_age)
|
||||
vty_out(vty, " ago)%s", VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " ago)");
|
||||
vty_out(vty, " ago)%s", VTY_NEWLINE);
|
||||
#undef UNIT_AGO
|
||||
}
|
||||
}
|
||||
@@ -112,8 +108,8 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
||||
vty_out(vty, " PS disabled%s", VTY_NEWLINE);
|
||||
if (subscr->ms_purged_ps)
|
||||
vty_out(vty, " PS purged%s", VTY_NEWLINE);
|
||||
dump_last_lu_seen(vty, "CS", subscr->last_lu_seen, false);
|
||||
dump_last_lu_seen(vty, "PS", subscr->last_lu_seen_ps, false);
|
||||
dump_last_lu_seen(vty, "CS", subscr->last_lu_seen);
|
||||
dump_last_lu_seen(vty, "PS", subscr->last_lu_seen_ps);
|
||||
|
||||
if (!*subscr->imsi)
|
||||
return;
|
||||
@@ -163,28 +159,6 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
||||
}
|
||||
}
|
||||
|
||||
static void subscr_dump_summary_vty(struct hlr_subscriber *subscr, void *data)
|
||||
{
|
||||
struct vty *vty = data;
|
||||
vty_out(vty, "%-5"PRIu64" %-12s %-16s", subscr->id,
|
||||
*subscr->msisdn ? subscr->msisdn : "none",
|
||||
*subscr->imsi ? subscr->imsi : "none");
|
||||
|
||||
if (*subscr->imei) {
|
||||
char checksum = osmo_luhn(subscr->imei, 14);
|
||||
if (checksum == -EINVAL)
|
||||
vty_out(vty, " %-14s (INVALID LENGTH!)", subscr->imei);
|
||||
else
|
||||
vty_out(vty, " %-14s%c", subscr->imei, checksum);
|
||||
} else {
|
||||
vty_out(vty," ------------- ");
|
||||
}
|
||||
vty_out(vty, " %-2s%-2s ", subscr->nam_cs ? "CS" : "", subscr->nam_ps ? "PS" : "");
|
||||
if (subscr->last_lu_seen)
|
||||
dump_last_lu_seen(vty, "CS", subscr->last_lu_seen, true);
|
||||
vty_out_newline(vty);
|
||||
}
|
||||
|
||||
static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id, struct hlr_subscriber *subscr)
|
||||
{
|
||||
char imei_buf[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1];
|
||||
@@ -212,52 +186,10 @@ static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dump_summary_table_vty(struct vty *vty, bool header, bool show_ls)
|
||||
{
|
||||
const char *texts = "ID MSISDN IMSI IMEI NAM";
|
||||
const char *lines = "----- ------------ ---------------- ---------------- -----";
|
||||
const char *ls_text = " LAST SEEN";
|
||||
const char *ls_line = " ------------";
|
||||
if (header) {
|
||||
if (!show_ls)
|
||||
vty_out(vty, "%s%s%s%s", texts, VTY_NEWLINE, lines, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, "%s%s%s%s%s%s", texts, ls_text, VTY_NEWLINE, lines, ls_line, VTY_NEWLINE);
|
||||
} else {
|
||||
if (!show_ls)
|
||||
vty_out(vty, "%s%s%s%s", lines, VTY_NEWLINE, texts, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, "%s%s%s%s%s%s", lines, ls_line, VTY_NEWLINE, texts, ls_text, VTY_NEWLINE);
|
||||
}
|
||||
}
|
||||
|
||||
static int get_subscrs(struct vty *vty, const char *filter_type, const char *filter)
|
||||
{
|
||||
int rc = -1;
|
||||
int count = 0;
|
||||
const char *err;
|
||||
bool show_ls = (filter_type && strcmp(filter_type, "last_lu_seen") == 0);
|
||||
dump_summary_table_vty(vty, true, show_ls);
|
||||
rc = db_subscrs_get(g_hlr->dbc, filter_type, filter, subscr_dump_summary_vty, vty, &count, &err);
|
||||
if (count > 40) {
|
||||
dump_summary_table_vty(vty, false, show_ls);
|
||||
}
|
||||
if (count > 0)
|
||||
vty_out(vty, " Subscribers Shown: %d%s", count, VTY_NEWLINE);
|
||||
if (rc)
|
||||
vty_out(vty, "%% %s%s", err, VTY_NEWLINE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#define SUBSCR_CMD "subscriber "
|
||||
#define SUBSCR_CMD_HELP "Subscriber management commands\n"
|
||||
#define SUBSCR_SHOW_HELP "Show subscriber information\n"
|
||||
#define SUBSCRS_SHOW_HELP "Show all subscribers (with filter possibility)\n"
|
||||
|
||||
#define SUBSCR_ID "(imsi|msisdn|id|imei) IDENT"
|
||||
#define SUBSCR_FILTER "(imei|imsi|msisdn) FILTER"
|
||||
|
||||
#define SUBSCR_ID_HELP \
|
||||
"Identify subscriber by IMSI\n" \
|
||||
"Identify subscriber by MSISDN (phone number)\n" \
|
||||
@@ -275,7 +207,7 @@ static int get_subscrs(struct vty *vty, const char *filter_type, const char *fil
|
||||
DEFUN(subscriber_show,
|
||||
subscriber_show_cmd,
|
||||
SUBSCR "show",
|
||||
SUBSCR_HELP SUBSCR_SHOW_HELP)
|
||||
SUBSCR_HELP "Show subscriber information\n")
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
const char *id_type = argv[0];
|
||||
@@ -290,50 +222,7 @@ DEFUN(subscriber_show,
|
||||
|
||||
ALIAS(subscriber_show, show_subscriber_cmd,
|
||||
"show " SUBSCR_CMD SUBSCR_ID,
|
||||
SHOW_STR SUBSCR_SHOW_HELP SUBSCR_ID_HELP);
|
||||
|
||||
DEFUN(show_subscriber_all,
|
||||
show_subscriber_all_cmd,
|
||||
"show subscribers all",
|
||||
SHOW_STR SUBSCRS_SHOW_HELP "Show summary of all subscribers\n")
|
||||
{
|
||||
if (get_subscrs(vty, NULL, NULL))
|
||||
return CMD_WARNING;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(show_subscriber_filtered,
|
||||
show_subscriber_filtered_cmd,
|
||||
"show subscribers " SUBSCR_FILTER,
|
||||
SHOW_STR SUBSCRS_SHOW_HELP
|
||||
"Filter Subscribers by IMEI\n" "Filter Subscribers by IMSI\n" "Filter Subscribers by MSISDN\n"
|
||||
"String to match in imei, imsi or msisdn\n")
|
||||
{
|
||||
const char *filter_type = argv[0];
|
||||
const char *filter = argv[1];
|
||||
|
||||
if (get_subscrs(vty, filter_type, filter))
|
||||
return CMD_WARNING;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
ALIAS(show_subscriber_filtered, show_subscriber_filtered_cmd2,
|
||||
"show subscribers (cs|ps) (on|off)",
|
||||
SHOW_STR SUBSCR_SHOW_HELP
|
||||
"Filter Subscribers by CS Network Access Mode\n" "Filter Subscribers by PS Network Access Mode\n"
|
||||
"Authorised\n" "Not Authorised\n");
|
||||
|
||||
DEFUN(show_subscriber_order_last_seen, show_subscriber_order_last_seen_cmd,
|
||||
"show subscribers last-seen",
|
||||
SHOW_STR SUBSCR_SHOW_HELP "Show Subscribers Ordered by Last Seen Time\n")
|
||||
{
|
||||
if (get_subscrs(vty, "last_lu_seen", NULL))
|
||||
return CMD_WARNING;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
SHOW_STR SUBSCR_CMD_HELP SUBSCR_ID_HELP);
|
||||
|
||||
DEFUN(subscriber_create,
|
||||
subscriber_create_cmd,
|
||||
@@ -662,55 +551,6 @@ DEFUN(subscriber_aud3g,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(subscriber_aud3g_xor,
|
||||
subscriber_aud3g_xor_cmd,
|
||||
SUBSCR_UPDATE "aud3g xor k K"
|
||||
" [ind-bitlen] [<0-28>]",
|
||||
SUBSCR_UPDATE_HELP
|
||||
"Set UMTS authentication data (3G, and 2G with UMTS AKA)\n"
|
||||
"Use XOR algorithm\n"
|
||||
"Set Encryption Key K\n" "K as 32 hexadecimal characters\n"
|
||||
"Set IND bit length\n" "IND bit length value (default: 5)\n")
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
int minlen = 0;
|
||||
int maxlen = 0;
|
||||
int rc;
|
||||
const char *id_type = argv[0];
|
||||
const char *id = argv[1];
|
||||
const char *k = argv[2];
|
||||
int ind_bitlen = argc > 4? atoi(argv[4]) : 5;
|
||||
struct sub_auth_data_str aud3g = {
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.u.umts = {
|
||||
.k = k,
|
||||
.opc_is_op = 0,
|
||||
.opc = "00000000000000000000000000000000",
|
||||
.ind_bitlen = ind_bitlen,
|
||||
},
|
||||
};
|
||||
|
||||
if (!auth_algo_parse("xor", &aud3g.algo, &minlen, &maxlen)) {
|
||||
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", "xor", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (!is_hexkey_valid(vty, "K", aud3g.u.umts.k, minlen, maxlen))
|
||||
return CMD_WARNING;
|
||||
|
||||
if (get_subscr_by_argv(vty, id_type, id, &subscr))
|
||||
return CMD_WARNING;
|
||||
|
||||
rc = db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud3g);
|
||||
|
||||
if (rc) {
|
||||
vty_out(vty, "%% Error: cannot set 3G auth data for IMSI='%s'%s",
|
||||
subscr.imsi, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(subscriber_imei,
|
||||
subscriber_imei_cmd,
|
||||
SUBSCR_UPDATE "imei (none|IMEI)",
|
||||
@@ -788,10 +628,6 @@ DEFUN(subscriber_nam,
|
||||
|
||||
void hlr_vty_subscriber_init(void)
|
||||
{
|
||||
install_element_ve(&show_subscriber_all_cmd);
|
||||
install_element_ve(&show_subscriber_filtered_cmd);
|
||||
install_element_ve(&show_subscriber_filtered_cmd2);
|
||||
install_element_ve(&show_subscriber_order_last_seen_cmd);
|
||||
install_element_ve(&subscriber_show_cmd);
|
||||
install_element_ve(&show_subscriber_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_create_cmd);
|
||||
@@ -801,7 +637,6 @@ void hlr_vty_subscriber_init(void)
|
||||
install_element(ENABLE_NODE, &subscriber_aud2g_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_no_aud3g_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_aud3g_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_aud3g_xor_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_imei_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_nam_cmd);
|
||||
}
|
||||
|
||||
28
src/lu_fsm.c
28
src/lu_fsm.c
@@ -26,7 +26,7 @@
|
||||
#include <osmocom/gsm/apn.h>
|
||||
#include <osmocom/gsm/gsm48_ie.h>
|
||||
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_req.h>
|
||||
#include <osmocom/hlr/logging.h>
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
@@ -52,11 +52,11 @@ struct lu {
|
||||
bool is_ps;
|
||||
|
||||
/* VLR requesting the LU. */
|
||||
struct osmo_cni_peer_id vlr_name;
|
||||
struct osmo_gsup_peer_id vlr_name;
|
||||
|
||||
/* If the LU request was received via a proxy and not immediately from a local VLR, this indicates the closest
|
||||
* peer that forwarded the GSUP message. */
|
||||
struct osmo_cni_peer_id via_proxy;
|
||||
struct osmo_gsup_peer_id via_proxy;
|
||||
};
|
||||
LLIST_HEAD(g_all_lu);
|
||||
|
||||
@@ -130,7 +130,7 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
|
||||
|
||||
osmo_fsm_inst_update_id_f_sanitize(fi, '_', "%s:IMSI-%s", lu->is_ps ? "PS" : "CS", update_location_req->gsup.imsi);
|
||||
|
||||
if (osmo_cni_peer_id_is_empty(&lu->vlr_name)) {
|
||||
if (osmo_gsup_peer_id_is_empty(&lu->vlr_name)) {
|
||||
lu_failure(lu, GMM_CAUSE_NET_FAIL, "LU without a VLR");
|
||||
return;
|
||||
}
|
||||
@@ -163,30 +163,30 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
|
||||
#endif
|
||||
|
||||
/* Store the VLR / SGSN number with the subscriber, so we know where it was last seen. */
|
||||
if (!osmo_cni_peer_id_is_empty(&lu->via_proxy)) {
|
||||
if (!osmo_gsup_peer_id_is_empty(&lu->via_proxy)) {
|
||||
LOG_GSUP_REQ(update_location_req, LOGL_DEBUG, "storing %s = %s, via proxy %s\n",
|
||||
lu->is_ps ? "SGSN number" : "VLR number",
|
||||
osmo_cni_peer_id_to_str(&lu->vlr_name),
|
||||
osmo_cni_peer_id_to_str(&lu->via_proxy));
|
||||
osmo_gsup_peer_id_to_str(&lu->vlr_name),
|
||||
osmo_gsup_peer_id_to_str(&lu->via_proxy));
|
||||
} else {
|
||||
LOG_GSUP_REQ(update_location_req, LOGL_DEBUG, "storing %s = %s\n",
|
||||
lu->is_ps ? "SGSN number" : "VLR number",
|
||||
osmo_cni_peer_id_to_str(&lu->vlr_name));
|
||||
osmo_gsup_peer_id_to_str(&lu->vlr_name));
|
||||
}
|
||||
|
||||
if (osmo_cni_peer_id_is_empty(&lu->vlr_name)
|
||||
|| (lu->vlr_name.type != OSMO_CNI_PEER_ID_IPA_NAME)) {
|
||||
if (osmo_gsup_peer_id_is_empty(&lu->vlr_name)
|
||||
|| (lu->vlr_name.type != OSMO_GSUP_PEER_ID_IPA_NAME)) {
|
||||
lu_failure(lu, GMM_CAUSE_PROTO_ERR_UNSPEC, "Unsupported GSUP peer id type for vlr_name: %s",
|
||||
osmo_cni_peer_id_type_name(lu->vlr_name.type));
|
||||
osmo_gsup_peer_id_type_name(lu->vlr_name.type));
|
||||
return;
|
||||
}
|
||||
if (!osmo_cni_peer_id_is_empty(&lu->via_proxy) && (lu->via_proxy.type != OSMO_CNI_PEER_ID_IPA_NAME)) {
|
||||
if (!osmo_gsup_peer_id_is_empty(&lu->via_proxy) && (lu->via_proxy.type != OSMO_GSUP_PEER_ID_IPA_NAME)) {
|
||||
lu_failure(lu, GMM_CAUSE_PROTO_ERR_UNSPEC, "Unsupported GSUP peer id type for via_proxy: %s",
|
||||
osmo_cni_peer_id_type_name(lu->via_proxy.type));
|
||||
osmo_gsup_peer_id_type_name(lu->via_proxy.type));
|
||||
return;
|
||||
}
|
||||
if (db_subscr_lu(g_hlr->dbc, lu->subscr.id, &lu->vlr_name.ipa_name, lu->is_ps,
|
||||
osmo_cni_peer_id_is_empty(&lu->via_proxy)? NULL : &lu->via_proxy.ipa_name)) {
|
||||
osmo_gsup_peer_id_is_empty(&lu->via_proxy)? NULL : &lu->via_proxy.ipa_name)) {
|
||||
lu_failure(lu, GMM_CAUSE_NET_FAIL, "Cannot update %s in the database",
|
||||
lu->is_ps ? "SGSN number" : "VLR number");
|
||||
return;
|
||||
|
||||
@@ -487,7 +487,7 @@ static int socket_cb(struct osmo_fd *ofd, unsigned int flags)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (flags & OSMO_FD_READ)
|
||||
if (flags & BSC_FD_READ)
|
||||
rc = socket_read_cb(ofd);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
@@ -512,7 +512,7 @@ int socket_accept(struct osmo_fd *ofd, unsigned int flags)
|
||||
c = talloc_zero(globals.ctx, struct socket_client);
|
||||
OSMO_ASSERT(c);
|
||||
c->ofd.fd = rc;
|
||||
c->ofd.when = OSMO_FD_READ;
|
||||
c->ofd.when = BSC_FD_READ;
|
||||
c->ofd.cb = socket_cb;
|
||||
c->ofd.data = c;
|
||||
|
||||
@@ -543,7 +543,7 @@ int socket_init(const char *sock_path)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ofd->when = OSMO_FD_READ;
|
||||
ofd->when = BSC_FD_READ;
|
||||
ofd->cb = socket_accept;
|
||||
|
||||
rc = osmo_fd_register(ofd);
|
||||
@@ -584,11 +584,11 @@ void respond_result(const char *query_str, const struct osmo_mslookup_result *r)
|
||||
llist_for_each_entry_safe(c, n, &globals.socket_clients, entry) {
|
||||
if (!strcmp(query_str, c->query_str)) {
|
||||
socket_client_respond_result(c, g_buf);
|
||||
if (!r || r->last)
|
||||
if (r->last)
|
||||
socket_client_close(c);
|
||||
}
|
||||
}
|
||||
if (!r || r->last)
|
||||
if (r->last)
|
||||
globals.requests_handled++;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ static int osmo_mslookup_server_mdns_rx(struct osmo_fd *osmo_fd, unsigned int wh
|
||||
|
||||
/* Parse the message and print it */
|
||||
n = read(osmo_fd->fd, buffer, sizeof(buffer));
|
||||
if (n <= 0)
|
||||
if (n < 0)
|
||||
return n;
|
||||
|
||||
ctx = talloc_named_const(server, 0, __func__);
|
||||
|
||||
26
src/proxy.c
26
src/proxy.c
@@ -263,10 +263,10 @@ static int proxy_acknowledge_gsup_to_remote_hlr(struct proxy *proxy, const struc
|
||||
bool cs;
|
||||
int rc;
|
||||
|
||||
if (req->source_name.type != OSMO_CNI_PEER_ID_IPA_NAME) {
|
||||
if (req->source_name.type != OSMO_GSUP_PEER_ID_IPA_NAME) {
|
||||
LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_ERROR,
|
||||
"Unsupported GSUP peer id type: %s\n",
|
||||
osmo_cni_peer_id_type_name(req->source_name.type));
|
||||
osmo_gsup_peer_id_type_name(req->source_name.type));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ static int proxy_acknowledge_gsup_to_remote_hlr(struct proxy *proxy, const struc
|
||||
"%s: preliminary VLR name for%s%s to %s\n",
|
||||
rc ? "failed to update" : "updated",
|
||||
cs ? " CS" : "", ps ? " PS" : "",
|
||||
osmo_cni_peer_id_to_str(&req->source_name));
|
||||
osmo_gsup_peer_id_to_str(&req->source_name));
|
||||
break;
|
||||
/* TODO: delete proxy entry in case of a Purge Request? */
|
||||
default:
|
||||
@@ -403,6 +403,18 @@ static int proxy_acknowledge_gsup_from_remote_hlr(struct proxy *proxy, const str
|
||||
);
|
||||
break;
|
||||
|
||||
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
|
||||
/* Remember the auth tuples: if the remote HLR becomes unreachable for an intermediate period, we can
|
||||
* still re-use this auth information a number of times and keep the subscriber attached (on this
|
||||
* roaming/proxy HLR). */
|
||||
#if 0
|
||||
for (i = 0; i < gsup->num_auth_vectors; i++)
|
||||
proxy_subscr_new.auth_vectors[i] = gsup->auth_vectors[i];
|
||||
proxy_subscr_new.num_auth_vectors = gsup->num_auth_vectors;
|
||||
rc = proxy_subscr_create_or_update(proxy, &proxy_subscr_new);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -483,13 +495,13 @@ int proxy_subscr_forward_to_remote_hlr(struct proxy *proxy, const struct proxy_s
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!osmo_cni_peer_id_is_empty(&req->via_proxy)) {
|
||||
if (!osmo_gsup_peer_id_is_empty(&req->via_proxy)) {
|
||||
LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_INFO, "VLR->HLR: forwarding from %s via proxy %s\n",
|
||||
osmo_cni_peer_id_to_str(&req->source_name),
|
||||
osmo_cni_peer_id_to_str(&req->via_proxy));
|
||||
osmo_gsup_peer_id_to_str(&req->source_name),
|
||||
osmo_gsup_peer_id_to_str(&req->via_proxy));
|
||||
} else {
|
||||
LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_INFO, "VLR->HLR: forwarding from %s\n",
|
||||
osmo_cni_peer_id_to_str(&req->source_name));
|
||||
osmo_gsup_peer_id_to_str(&req->source_name));
|
||||
}
|
||||
|
||||
/* We could always store in the defer queue and empty the queue if the connection is already up.
|
||||
|
||||
417
src/proxy_mm.c
Normal file
417
src/proxy_mm.c
Normal file
@@ -0,0 +1,417 @@
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
#include <osmocom/gsm/apn.h>
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/proxy_mm.h>
|
||||
#include <osmocom/hlr/proxy_db.h>
|
||||
|
||||
enum proxy_mm_fsm_state {
|
||||
PROXY_MM_ST_READY,
|
||||
PROXY_MM_ST_WAIT_SUBSCR_DATA,
|
||||
PROXY_MM_ST_WAIT_GSUP_ISD_RESULT,
|
||||
PROXY_MM_ST_WAIT_AUTH_TUPLES,
|
||||
};
|
||||
|
||||
static const struct value_string proxy_mm_fsm_event_names[] = {
|
||||
OSMO_VALUE_STRING(PROXY_MM_EV_SUBSCR_INVALID),
|
||||
OSMO_VALUE_STRING(PROXY_MM_EV_RX_GSUP_LU),
|
||||
OSMO_VALUE_STRING(PROXY_MM_EV_RX_GSUP_SAI),
|
||||
OSMO_VALUE_STRING(PROXY_MM_EV_RX_SUBSCR_DATA),
|
||||
OSMO_VALUE_STRING(PROXY_MM_EV_RX_GSUP_ISD_RESULT),
|
||||
OSMO_VALUE_STRING(PROXY_MM_EV_RX_AUTH_TUPLES),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct osmo_fsm proxy_mm_fsm;
|
||||
static struct osmo_fsm proxy_to_home_fsm;
|
||||
|
||||
struct osmo_tdef proxy_mm_tdefs[] = {
|
||||
// FIXME
|
||||
{ .T=-1, .default_val=5, .desc="proxy_mm ready timeout" },
|
||||
{ .T=-2, .default_val=5, .desc="proxy_mm wait_subscr_data timeout" },
|
||||
{ .T=-3, .default_val=5, .desc="proxy_mm wait_gsup_isd_result timeout" },
|
||||
{ .T=-4, .default_val=5, .desc="proxy_mm wait_auth_tuples timeout" },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct osmo_tdef_state_timeout proxy_mm_fsm_timeouts[32] = {
|
||||
// FIXME
|
||||
[PROXY_MM_ST_READY] = { .T=-1 },
|
||||
[PROXY_MM_ST_WAIT_SUBSCR_DATA] = { .T=-2 },
|
||||
[PROXY_MM_ST_WAIT_GSUP_ISD_RESULT] = { .T=-3 },
|
||||
[PROXY_MM_ST_WAIT_AUTH_TUPLES] = { .T=-4 },
|
||||
};
|
||||
|
||||
#define proxy_mm_fsm_state_chg(state) \
|
||||
osmo_tdef_fsm_inst_state_chg(mm_fi, state, \
|
||||
proxy_mm_fsm_timeouts, \
|
||||
proxy_mm_tdefs, \
|
||||
5)
|
||||
|
||||
LLIST_HEAD(proxy_mm_list);
|
||||
|
||||
struct proxy_mm *proxy_mm_alloc(const struct osmo_gsup_peer_id *vlr_name,
|
||||
bool is_ps,
|
||||
const char *imsi)
|
||||
{
|
||||
struct proxy_mm *proxy_mm;
|
||||
|
||||
struct osmo_fsm_inst *mm_fi = osmo_fsm_inst_alloc(&proxy_mm_fsm, g_hlr, NULL, LOGL_DEBUG, imsi);
|
||||
OSMO_ASSERT(mm_fi);
|
||||
|
||||
proxy_mm = talloc(mm_fi, struct proxy_mm);
|
||||
OSMO_ASSERT(proxy_mm);
|
||||
mm_fi->priv = proxy_mm;
|
||||
*proxy_mm = (struct proxy_mm){
|
||||
.mm_fi = mm_fi,
|
||||
.is_ps = is_ps,
|
||||
};
|
||||
OSMO_STRLCPY_ARRAY(proxy_mm->imsi, imsi);
|
||||
INIT_LLIST_HEAD(&proxy_mm->auth_cache);
|
||||
|
||||
llist_add(&proxy_mm->entry, &proxy_mm_list);
|
||||
|
||||
proxy_mm->to_home_fi = osmo_fsm_inst_alloc_child(&proxy_to_home_fsm, mm_fi, PROXY_MM_EV_SUBSCR_INVALID);
|
||||
proxy_mm->to_home_fi->priv = proxy_mm;
|
||||
|
||||
/* Do a state change to activate timeout */
|
||||
proxy_mm_fsm_state_chg(PROXY_MM_ST_READY);
|
||||
|
||||
return proxy_mm;
|
||||
}
|
||||
|
||||
void proxy_mm_add_auth_vectors(struct proxy_mm *proxy_mm,
|
||||
const struct osmo_auth_vector *auth_vectors, size_t num_auth_vectors)
|
||||
{
|
||||
struct proxy_mm_auth_cache *ac = talloc_zero(proxy_mm, struct proxy_mm_auth_cache);
|
||||
int i;
|
||||
OSMO_ASSERT(ac);
|
||||
ac->num_auth_vectors = num_auth_vectors;
|
||||
for (i = 0; i < num_auth_vectors; i++)
|
||||
ac->auth_vectors[i] = auth_vectors[i];
|
||||
if (proxy_db_add_auth_vectors(&proxy_mm->vlr_name, ac)) {
|
||||
talloc_free(ac);
|
||||
return;
|
||||
}
|
||||
llist_add(&ac->entry, &proxy_mm->auth_cache);
|
||||
}
|
||||
|
||||
struct proxy_mm_auth_cache *proxy_mm_get_auth_vectors(struct proxy_mm *proxy_mm)
|
||||
{
|
||||
struct proxy_mm_auth_cache *i;
|
||||
struct proxy_mm_auth_cache *ac = NULL;
|
||||
|
||||
llist_for_each_entry(i, &proxy_mm->auth_cache, entry) {
|
||||
if (!ac || i->sent_to_vlr_count < ac->sent_to_vlr_count) {
|
||||
ac = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* ac now points to (one of) the least used auth cache entries (or NULL if none). */
|
||||
return ac;
|
||||
}
|
||||
|
||||
void proxy_mm_discard_auth_vectors(struct proxy_mm *proxy_mm, struct proxy_mm_auth_cache *ac)
|
||||
{
|
||||
proxy_db_drop_auth_vectors(ac->db_id);
|
||||
llist_del(&ac->entry);
|
||||
talloc_free(ac);
|
||||
}
|
||||
|
||||
/* Mark given auth cache entries as sent to the VLR and clean up if necessary. */
|
||||
void proxy_mm_use_auth_vectors(struct proxy_mm *proxy_mm, struct proxy_mm_auth_cache *ac)
|
||||
{
|
||||
struct proxy_mm_auth_cache *i, *i_next;
|
||||
bool found_fresh_ac = false;
|
||||
|
||||
/* The aim is to keep at least one set of already used auth tuples in the cache. If there are still fresh ones,
|
||||
* all used auth vectors can be discarded. If there are no fresh ones left, keep only this last set. */
|
||||
|
||||
llist_for_each_entry_safe(i, i_next, &proxy_mm->auth_cache, entry) {
|
||||
if (i == ac)
|
||||
continue;
|
||||
if (i->sent_to_vlr_count) {
|
||||
/* An auth entry other than this freshly used one, which has been used before.
|
||||
* No need to keep it. */
|
||||
proxy_mm_discard_auth_vectors(proxy_mm, i);
|
||||
continue;
|
||||
}
|
||||
if (!i->sent_to_vlr_count)
|
||||
found_fresh_ac = true;
|
||||
}
|
||||
|
||||
if (found_fresh_ac) {
|
||||
/* There are still other, fresh auth vectors. */
|
||||
proxy_mm_discard_auth_vectors(proxy_mm, ac);
|
||||
} else {
|
||||
/* else, only this ac remains in the list */
|
||||
ac->sent_to_vlr_count++;
|
||||
proxy_db_auth_vectors_update_sent_count(ac);
|
||||
}
|
||||
}
|
||||
|
||||
static void proxy_mm_ready_action(struct osmo_fsm_inst *mm_fi, uint32_t event, void *data)
|
||||
{
|
||||
struct proxy *proxy = g_hlr->gs->proxy;
|
||||
struct proxy_mm *proxy_mm = mm_fi->priv;
|
||||
|
||||
switch (event) {
|
||||
|
||||
case PROXY_MM_EV_SUBSCR_INVALID:
|
||||
/* Home HLR has responded and rejected a Location Updating, or no home HLR could be found. The
|
||||
* subscriber is invalid, remove it from the cache. */
|
||||
proxy_subscr_del(proxy, proxy_mm->imsi);
|
||||
osmo_fsm_inst_term(mm_fi, OSMO_FSM_TERM_REGULAR, NULL);
|
||||
break;
|
||||
|
||||
case PROXY_MM_EV_RX_GSUP_LU:
|
||||
/* The MSC asks for a LU. If we don't know details about this subscriber, then we'll have to wait for the
|
||||
* home HLR to respond. If we already know details about the subscriber, we respond immediately (with
|
||||
* Insert Subscriber Data and accept the LU), but also ask the home HLR to confirm the LU later. */
|
||||
osmo_fsm_inst_dispatch(proxy_mm->to_home_fi, PROXY_TO_HOME_EV_CONFIRM_LU, NULL);
|
||||
|
||||
if (proxy_mm_subscriber_data_known(proxy_mm))
|
||||
proxy_mm_fsm_state_chg(PROXY_MM_ST_WAIT_GSUP_ISD_RESULT);
|
||||
else
|
||||
proxy_mm_fsm_state_chg(PROXY_MM_ST_WAIT_SUBSCR_DATA);
|
||||
break;
|
||||
|
||||
case PROXY_MM_EV_RX_GSUP_SAI:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int proxy_mm_ready_timeout(struct osmo_fsm_inst *mm_fi)
|
||||
{
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void proxy_mm_wait_subscr_data_onenter(struct osmo_fsm_inst *mm_fi, uint32_t prev_state)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = mm_fi->priv;
|
||||
// FIXME
|
||||
}
|
||||
|
||||
static void proxy_mm_wait_subscr_data_action(struct osmo_fsm_inst *mm_fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = mm_fi->priv;
|
||||
|
||||
switch (event) {
|
||||
|
||||
case PROXY_MM_EV_RX_SUBSCR_DATA:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int proxy_mm_wait_subscr_data_timeout(struct osmo_fsm_inst *mm_fi)
|
||||
{
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void proxy_mm_lu_error(struct osmo_fsm_inst *mm_fi)
|
||||
{
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_ROAMING_NOTALLOWED,
|
||||
"LU does not accept GSUP rx");
|
||||
|
||||
}
|
||||
|
||||
void proxy_mm_wait_gsup_isd_result_onenter(struct osmo_fsm_inst *mm_fi, uint32_t prev_state)
|
||||
{
|
||||
struct proxy_mm *proxy_mm = mm_fi->priv;
|
||||
struct proxy_subscr proxy_subscr;
|
||||
struct osmo_gsup_message isd_req;
|
||||
|
||||
uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];
|
||||
uint8_t apn[APN_MAXLEN];
|
||||
|
||||
isd_req.message_type = OSMO_GSUP_MSGT_INSERT_DATA_REQUEST;
|
||||
|
||||
if (proxy_subscr_get_by_imsi(&proxy_subscr, g_hlr->gs->proxy, proxy_mm->imsi)) {
|
||||
LOGPFSML(mm_fi, LOGL_ERROR,
|
||||
"Proxy: trying to send cached Subscriber Data, but there is no proxy entry\n");
|
||||
proxy_mm_lu_error(mm_fi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (proxy_subscr.msisdn[0] == '\0') {
|
||||
LOGPFSML(mm_fi, LOGL_ERROR,
|
||||
"Proxy: trying to send cached Subscriber Data, but subscriber has no MSISDN in proxy cache\n");
|
||||
proxy_mm_lu_error(mm_fi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (osmo_gsup_create_insert_subscriber_data_msg(&isd_req, proxy_mm->imsi,
|
||||
proxy_subscr->msisdn, msisdn_enc, sizeof(msisdn_enc),
|
||||
apn, sizeof(apn),
|
||||
proxy_mm->is_ps? OSMO_GSUP_CN_DOMAIN_PS : OSMO_GSUP_CN_DOMAIN_CS)) {
|
||||
LOGPFSML(mm_fi, LOGL_ERROR, "Proxy: failed to send cached Subscriber Data\n");
|
||||
proxy_mm_lu_error(mm_fi);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void proxy_mm_wait_gsup_isd_result_action(struct osmo_fsm_inst *mm_fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = mm_fi->priv;
|
||||
|
||||
switch (event) {
|
||||
|
||||
case PROXY_MM_EV_RX_GSUP_ISD_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int proxy_mm_wait_gsup_isd_result_timeout(struct osmo_fsm_inst *mm_fi)
|
||||
{
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void proxy_mm_wait_auth_tuples_onenter(struct osmo_fsm_inst *mm_fi, uint32_t prev_state)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = mm_fi->priv;
|
||||
// FIXME
|
||||
}
|
||||
|
||||
static void proxy_mm_wait_auth_tuples_action(struct osmo_fsm_inst *mm_fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = mm_fi->priv;
|
||||
|
||||
switch (event) {
|
||||
|
||||
case PROXY_MM_EV_RX_AUTH_TUPLES:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int proxy_mm_wait_auth_tuples_timeout(struct osmo_fsm_inst *mm_fi)
|
||||
{
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
static const struct osmo_fsm_state proxy_mm_fsm_states[] = {
|
||||
[PROXY_MM_ST_READY] = {
|
||||
.name = "ready",
|
||||
.in_event_mask = 0
|
||||
| S(PROXY_MM_EV_SUBSCR_INVALID)
|
||||
| S(PROXY_MM_EV_RX_GSUP_LU)
|
||||
| S(PROXY_MM_EV_RX_GSUP_SAI)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PROXY_MM_ST_READY)
|
||||
| S(PROXY_MM_ST_WAIT_SUBSCR_DATA)
|
||||
| S(PROXY_MM_ST_WAIT_GSUP_ISD_RESULT)
|
||||
| S(PROXY_MM_ST_WAIT_AUTH_TUPLES)
|
||||
,
|
||||
.action = proxy_mm_ready_action,
|
||||
},
|
||||
[PROXY_MM_ST_WAIT_SUBSCR_DATA] = {
|
||||
.name = "wait_subscr_data",
|
||||
.in_event_mask = 0
|
||||
| S(PROXY_MM_EV_RX_SUBSCR_DATA)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PROXY_MM_ST_WAIT_GSUP_ISD_RESULT)
|
||||
| S(PROXY_MM_ST_READY)
|
||||
,
|
||||
.onenter = proxy_mm_wait_subscr_data_onenter,
|
||||
.action = proxy_mm_wait_subscr_data_action,
|
||||
},
|
||||
[PROXY_MM_ST_WAIT_GSUP_ISD_RESULT] = {
|
||||
.name = "wait_gsup_isd_result",
|
||||
.in_event_mask = 0
|
||||
| S(PROXY_MM_EV_RX_GSUP_ISD_RESULT)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PROXY_MM_ST_READY)
|
||||
,
|
||||
.onenter = proxy_mm_wait_gsup_isd_result_onenter,
|
||||
.action = proxy_mm_wait_gsup_isd_result_action,
|
||||
},
|
||||
[PROXY_MM_ST_WAIT_AUTH_TUPLES] = {
|
||||
.name = "wait_auth_tuples",
|
||||
.in_event_mask = 0
|
||||
| S(PROXY_MM_EV_RX_AUTH_TUPLES)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PROXY_MM_ST_READY)
|
||||
,
|
||||
.onenter = proxy_mm_wait_auth_tuples_onenter,
|
||||
.action = proxy_mm_wait_auth_tuples_action,
|
||||
},
|
||||
};
|
||||
|
||||
static int proxy_mm_fsm_timer_cb(struct osmo_fsm_inst *mm_fi)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = mm_fi->priv;
|
||||
switch (mm_fi->state) {
|
||||
|
||||
case PROXY_MM_ST_READY:
|
||||
return proxy_mm_ready_timeout(mm_fi);
|
||||
|
||||
case PROXY_MM_ST_WAIT_SUBSCR_DATA:
|
||||
return proxy_mm_wait_subscr_data_timeout(mm_fi);
|
||||
|
||||
case PROXY_MM_ST_WAIT_GSUP_ISD_RESULT:
|
||||
return proxy_mm_wait_gsup_isd_result_timeout(mm_fi);
|
||||
|
||||
case PROXY_MM_ST_WAIT_AUTH_TUPLES:
|
||||
return proxy_mm_wait_auth_tuples_timeout(mm_fi);
|
||||
|
||||
default:
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void proxy_mm_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
|
||||
{
|
||||
struct proxy_mm *proxy_mm = fi->priv;
|
||||
llist_del(&proxy_mm->entry);
|
||||
}
|
||||
|
||||
static struct osmo_fsm proxy_mm_fsm = {
|
||||
.name = "proxy_mm",
|
||||
.states = proxy_mm_fsm_states,
|
||||
.num_states = ARRAY_SIZE(proxy_mm_fsm_states),
|
||||
.log_subsys = DLGLOBAL, // FIXME
|
||||
.event_names = proxy_mm_fsm_event_names,
|
||||
.timer_cb = proxy_mm_fsm_timer_cb,
|
||||
.cleanup = proxy_mm_fsm_cleanup,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void proxy_mm_fsm_register(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&proxy_mm_fsm) == 0);
|
||||
}
|
||||
|
||||
bool proxy_mm_subscriber_data_known(const struct proxy_mm *proxy_mm)
|
||||
{
|
||||
struct proxy_subscr proxy_subscr;
|
||||
if (proxy_subscr_get_by_imsi(&proxy_subscr, g_hlr->gs->proxy, proxy_mm->imsi))
|
||||
return false;
|
||||
return proxy_subscr.msisdn[0] != '\0';
|
||||
}
|
||||
439
src/proxy_to_home.c
Normal file
439
src/proxy_to_home.c
Normal file
@@ -0,0 +1,439 @@
|
||||
|
||||
#include <osmocom/hlr/proxy_mm.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
|
||||
enum proxy_to_home_fsm_state {
|
||||
PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED,
|
||||
PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT,
|
||||
PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT,
|
||||
PROXY_TO_HOME_ST_IDLE,
|
||||
PROXY_TO_HOME_ST_CLEAR,
|
||||
};
|
||||
|
||||
static const struct value_string proxy_to_home_fsm_event_names[] = {
|
||||
OSMO_VALUE_STRING(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED),
|
||||
OSMO_VALUE_STRING(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ),
|
||||
OSMO_VALUE_STRING(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT),
|
||||
OSMO_VALUE_STRING(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT),
|
||||
OSMO_VALUE_STRING(PROXY_TO_HOME_EV_CHECK_TUPLES),
|
||||
OSMO_VALUE_STRING(PROXY_TO_HOME_EV_CONFIRM_LU),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct osmo_fsm proxy_to_home_fsm;
|
||||
|
||||
struct osmo_tdef proxy_to_home_tdefs[] = {
|
||||
// FIXME
|
||||
{ .T=-1, .default_val=5, .desc="proxy_to_home wait_home_hlr_resolved timeout" },
|
||||
{ .T=-2, .default_val=5, .desc="proxy_to_home wait_update_location_result timeout" },
|
||||
{ .T=-3, .default_val=5, .desc="proxy_to_home wait_send_auth_info_result timeout" },
|
||||
{ .T=-4, .default_val=5, .desc="proxy_to_home idle timeout" },
|
||||
{ .T=-5, .default_val=5, .desc="proxy_to_home clear timeout" },
|
||||
{}
|
||||
};
|
||||
|
||||
#if 0
|
||||
static const struct osmo_tdef_state_timeout proxy_to_home_fsm_timeouts[32] = {
|
||||
// FIXME
|
||||
[PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED] = { .T=-1 },
|
||||
[PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT] = { .T=-2 },
|
||||
[PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT] = { .T=-3 },
|
||||
[PROXY_TO_HOME_ST_IDLE] = { .T=-4 },
|
||||
[PROXY_TO_HOME_ST_CLEAR] = { .T=-5 },
|
||||
};
|
||||
#endif
|
||||
|
||||
#define proxy_to_home_fsm_state_chg(state) \
|
||||
osmo_tdef_fsm_inst_state_chg(fi, state, \
|
||||
proxy_to_home_fsm_timeouts, \
|
||||
proxy_to_home_tdefs, \
|
||||
5)
|
||||
|
||||
void proxy_to_home_wait_home_hlr_resolved_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
// FIXME
|
||||
}
|
||||
|
||||
static void proxy_to_home_wait_home_hlr_resolved_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
|
||||
switch (event) {
|
||||
|
||||
case PROXY_TO_HOME_EV_HOME_HLR_RESOLVED:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_CHECK_TUPLES:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_CONFIRM_LU:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int proxy_to_home_wait_home_hlr_resolved_timeout(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void proxy_to_home_wait_update_location_result_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
// FIXME
|
||||
}
|
||||
|
||||
static void proxy_to_home_wait_update_location_result_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
|
||||
switch (event) {
|
||||
|
||||
case PROXY_TO_HOME_EV_HOME_HLR_RESOLVED:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_CHECK_TUPLES:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_CONFIRM_LU:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int proxy_to_home_wait_update_location_result_timeout(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void proxy_to_home_wait_send_auth_info_result_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
// FIXME
|
||||
}
|
||||
|
||||
static void proxy_to_home_wait_send_auth_info_result_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
|
||||
switch (event) {
|
||||
|
||||
case PROXY_TO_HOME_EV_HOME_HLR_RESOLVED:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_CHECK_TUPLES:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_CONFIRM_LU:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int proxy_to_home_wait_send_auth_info_result_timeout(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void proxy_to_home_idle_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
// FIXME
|
||||
}
|
||||
|
||||
static void proxy_to_home_idle_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
|
||||
switch (event) {
|
||||
|
||||
case PROXY_TO_HOME_EV_HOME_HLR_RESOLVED:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_CHECK_TUPLES:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_CONFIRM_LU:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int proxy_to_home_idle_timeout(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void proxy_to_home_clear_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
// FIXME
|
||||
}
|
||||
|
||||
static void proxy_to_home_clear_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
|
||||
switch (event) {
|
||||
|
||||
case PROXY_TO_HOME_EV_HOME_HLR_RESOLVED:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_CHECK_TUPLES:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
case PROXY_TO_HOME_EV_CONFIRM_LU:
|
||||
// FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int proxy_to_home_clear_timeout(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
static const struct osmo_fsm_state proxy_to_home_fsm_states[] = {
|
||||
[PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED] = {
|
||||
.name = "wait_home_hlr_resolved",
|
||||
.in_event_mask = 0
|
||||
| S(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED)
|
||||
| S(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ)
|
||||
| S(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT)
|
||||
| S(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT)
|
||||
| S(PROXY_TO_HOME_EV_CHECK_TUPLES)
|
||||
| S(PROXY_TO_HOME_EV_CONFIRM_LU)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED)
|
||||
| S(PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT)
|
||||
| S(PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT)
|
||||
| S(PROXY_TO_HOME_ST_IDLE)
|
||||
| S(PROXY_TO_HOME_ST_CLEAR)
|
||||
,
|
||||
.onenter = proxy_to_home_wait_home_hlr_resolved_onenter,
|
||||
.action = proxy_to_home_wait_home_hlr_resolved_action,
|
||||
},
|
||||
[PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT] = {
|
||||
.name = "wait_update_location_result",
|
||||
.in_event_mask = 0
|
||||
| S(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED)
|
||||
| S(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ)
|
||||
| S(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT)
|
||||
| S(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT)
|
||||
| S(PROXY_TO_HOME_EV_CHECK_TUPLES)
|
||||
| S(PROXY_TO_HOME_EV_CONFIRM_LU)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED)
|
||||
| S(PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT)
|
||||
| S(PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT)
|
||||
| S(PROXY_TO_HOME_ST_IDLE)
|
||||
| S(PROXY_TO_HOME_ST_CLEAR)
|
||||
,
|
||||
.onenter = proxy_to_home_wait_update_location_result_onenter,
|
||||
.action = proxy_to_home_wait_update_location_result_action,
|
||||
},
|
||||
[PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT] = {
|
||||
.name = "wait_send_auth_info_result",
|
||||
.in_event_mask = 0
|
||||
| S(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED)
|
||||
| S(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ)
|
||||
| S(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT)
|
||||
| S(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT)
|
||||
| S(PROXY_TO_HOME_EV_CHECK_TUPLES)
|
||||
| S(PROXY_TO_HOME_EV_CONFIRM_LU)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED)
|
||||
| S(PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT)
|
||||
| S(PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT)
|
||||
| S(PROXY_TO_HOME_ST_IDLE)
|
||||
| S(PROXY_TO_HOME_ST_CLEAR)
|
||||
,
|
||||
.onenter = proxy_to_home_wait_send_auth_info_result_onenter,
|
||||
.action = proxy_to_home_wait_send_auth_info_result_action,
|
||||
},
|
||||
[PROXY_TO_HOME_ST_IDLE] = {
|
||||
.name = "idle",
|
||||
.in_event_mask = 0
|
||||
| S(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED)
|
||||
| S(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ)
|
||||
| S(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT)
|
||||
| S(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT)
|
||||
| S(PROXY_TO_HOME_EV_CHECK_TUPLES)
|
||||
| S(PROXY_TO_HOME_EV_CONFIRM_LU)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED)
|
||||
| S(PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT)
|
||||
| S(PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT)
|
||||
| S(PROXY_TO_HOME_ST_IDLE)
|
||||
| S(PROXY_TO_HOME_ST_CLEAR)
|
||||
,
|
||||
.onenter = proxy_to_home_idle_onenter,
|
||||
.action = proxy_to_home_idle_action,
|
||||
},
|
||||
[PROXY_TO_HOME_ST_CLEAR] = {
|
||||
.name = "clear",
|
||||
.in_event_mask = 0
|
||||
| S(PROXY_TO_HOME_EV_HOME_HLR_RESOLVED)
|
||||
| S(PROXY_TO_HOME_EV_RX_INSERT_SUBSCRIBER_DATA_REQ)
|
||||
| S(PROXY_TO_HOME_EV_RX_UPDATE_LOCATION_RESULT)
|
||||
| S(PROXY_TO_HOME_EV_RX_SEND_AUTH_INFO_RESULT)
|
||||
| S(PROXY_TO_HOME_EV_CHECK_TUPLES)
|
||||
| S(PROXY_TO_HOME_EV_CONFIRM_LU)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED)
|
||||
| S(PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT)
|
||||
| S(PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT)
|
||||
| S(PROXY_TO_HOME_ST_IDLE)
|
||||
| S(PROXY_TO_HOME_ST_CLEAR)
|
||||
,
|
||||
.onenter = proxy_to_home_clear_onenter,
|
||||
.action = proxy_to_home_clear_action,
|
||||
},
|
||||
};
|
||||
|
||||
static int proxy_to_home_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
switch (fi->state) {
|
||||
|
||||
case PROXY_TO_HOME_ST_WAIT_HOME_HLR_RESOLVED:
|
||||
return proxy_to_home_wait_home_hlr_resolved_timeout(fi);
|
||||
|
||||
case PROXY_TO_HOME_ST_WAIT_UPDATE_LOCATION_RESULT:
|
||||
return proxy_to_home_wait_update_location_result_timeout(fi);
|
||||
|
||||
case PROXY_TO_HOME_ST_WAIT_SEND_AUTH_INFO_RESULT:
|
||||
return proxy_to_home_wait_send_auth_info_result_timeout(fi);
|
||||
|
||||
case PROXY_TO_HOME_ST_IDLE:
|
||||
return proxy_to_home_idle_timeout(fi);
|
||||
|
||||
case PROXY_TO_HOME_ST_CLEAR:
|
||||
return proxy_to_home_clear_timeout(fi);
|
||||
|
||||
default:
|
||||
/* Return 1 to terminate FSM instance, 0 to keep running */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void proxy_to_home_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
|
||||
{
|
||||
//struct proxy_mm *proxy_mm = fi->priv;
|
||||
// FIXME
|
||||
}
|
||||
|
||||
static struct osmo_fsm proxy_to_home_fsm = {
|
||||
.name = "proxy_to_home",
|
||||
.states = proxy_to_home_fsm_states,
|
||||
.num_states = ARRAY_SIZE(proxy_to_home_fsm_states),
|
||||
.log_subsys = DLGLOBAL, // FIXME
|
||||
.event_names = proxy_to_home_fsm_event_names,
|
||||
.timer_cb = proxy_to_home_fsm_timer_cb,
|
||||
.cleanup = proxy_to_home_fsm_cleanup,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void proxy_to_home_fsm_register(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&proxy_to_home_fsm) == 0);
|
||||
}
|
||||
@@ -233,9 +233,9 @@ void remote_hlr_gsup_forward_to_remote_hlr(struct remote_hlr *remote_hlr, struct
|
||||
else
|
||||
forward = req->gsup;
|
||||
|
||||
if (req->source_name.type != OSMO_CNI_PEER_ID_IPA_NAME) {
|
||||
if (req->source_name.type != OSMO_GSUP_PEER_ID_IPA_NAME) {
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",
|
||||
osmo_cni_peer_id_type_name(req->source_name.type));
|
||||
osmo_gsup_peer_id_type_name(req->source_name.type));
|
||||
return;
|
||||
}
|
||||
forward.source_name = req->source_name.ipa_name.val;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
SUBDIRS = \
|
||||
auc \
|
||||
gsup_server \
|
||||
db \
|
||||
gsup \
|
||||
db_upgrade \
|
||||
|
||||
@@ -113,7 +113,6 @@ int rand_get(uint8_t *rand, unsigned int len)
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Subscriber with 2G-only (COMP128v1) authentication data */
|
||||
static void test_gen_vectors_2g_only(void)
|
||||
{
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
@@ -175,8 +174,6 @@ static void test_gen_vectors_2g_only(void)
|
||||
comment_end();
|
||||
}
|
||||
|
||||
/* Subscriber with separate 2G (COMP128v1) and 3G (MILENAGE) authentication data,
|
||||
* reflects the default configuration of sysmoUSIM-SJS1 */
|
||||
static void test_gen_vectors_2g_plus_3g(void)
|
||||
{
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
@@ -287,9 +284,6 @@ void _test_gen_vectors_3g_only__expect_vecs(struct osmo_auth_vector vecs[3])
|
||||
);
|
||||
}
|
||||
|
||||
/* Subscriber with only 3G (MILENAGE) authentication data,
|
||||
* reflects the default configuration of sysmoISIM-SJA2. Resulting
|
||||
* tuples are suitable for both 2G and 3G authentication */
|
||||
static void test_gen_vectors_3g_only(void)
|
||||
{
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
@@ -460,55 +454,6 @@ static void test_gen_vectors_3g_only(void)
|
||||
comment_end();
|
||||
}
|
||||
|
||||
/* Subscriber with only 3G (XOR) authentication data,
|
||||
* reflects the default configuration of sysmoTSIM-SJAx as well
|
||||
* as many "Test USIM" cards. Resulting tuples are suitable for both
|
||||
* 2G and 3G authentication */
|
||||
static void test_gen_vectors_3g_xor(void)
|
||||
{
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
struct osmo_sub_auth_data aud3g;
|
||||
struct osmo_auth_vector vec;
|
||||
int rc;
|
||||
|
||||
comment_start();
|
||||
|
||||
aud2g = (struct osmo_sub_auth_data){ 0 };
|
||||
|
||||
aud3g = (struct osmo_sub_auth_data){
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.algo = OSMO_AUTH_ALG_XOR,
|
||||
.u.umts.sqn = 0,
|
||||
};
|
||||
|
||||
osmo_hexparse("000102030405060708090a0b0c0d0e0f",
|
||||
aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
|
||||
osmo_hexparse("00000000000000000000000000000000",
|
||||
aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
|
||||
next_rand("b5039c57e4a75051551d1a390a71ce48", true);
|
||||
|
||||
vec = (struct osmo_auth_vector){ {0} };
|
||||
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 0, "%"PRIu64);
|
||||
rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
|
||||
VERBOSE_ASSERT(rc, == 1, "%d");
|
||||
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 0, "%"PRIu64);
|
||||
|
||||
VEC_IS(&vec,
|
||||
" rand: b5039c57e4a75051551d1a390a71ce48\n"
|
||||
" autn: 54e0a256565d0000b5029e54e0a25656\n"
|
||||
" ck: 029e54e0a256565d141032067cc047b5\n"
|
||||
" ik: 9e54e0a256565d141032067cc047b502\n"
|
||||
" res: b5029e54e0a256565d141032067cc047\n"
|
||||
" res_len: 10\n"
|
||||
" kc: 98e880384887f9fe\n"
|
||||
" sres: 0ec81877\n"
|
||||
" auth_types: 03000000\n"
|
||||
);
|
||||
|
||||
comment_end();
|
||||
}
|
||||
|
||||
/* Test a variety of invalid authentication data combinations */
|
||||
void test_gen_vectors_bad_args()
|
||||
{
|
||||
struct osmo_auth_vector vec;
|
||||
@@ -668,20 +613,15 @@ int main(int argc, char **argv)
|
||||
void *tall_ctx = talloc_named_const(NULL, 1, "auc_test");
|
||||
|
||||
osmo_init_logging2(tall_ctx, &hlr_log_info);
|
||||
log_set_print_filename2(osmo_stderr_target,
|
||||
cmdline_opts.verbose ?
|
||||
LOG_FILENAME_BASENAME :
|
||||
LOG_FILENAME_NONE);
|
||||
log_set_print_filename(osmo_stderr_target, cmdline_opts.verbose);
|
||||
log_set_print_timestamp(osmo_stderr_target, 0);
|
||||
log_set_use_color(osmo_stderr_target, 0);
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
log_set_print_category(osmo_stderr_target, 1);
|
||||
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
|
||||
|
||||
test_gen_vectors_2g_only();
|
||||
test_gen_vectors_2g_plus_3g();
|
||||
test_gen_vectors_3g_only();
|
||||
test_gen_vectors_3g_xor();
|
||||
test_gen_vectors_bad_args();
|
||||
|
||||
printf("Done\n");
|
||||
|
||||
@@ -217,29 +217,6 @@ DAUC vector [2]: auth_types = 0x3
|
||||
===== test_gen_vectors_3g_only: SUCCESS
|
||||
|
||||
|
||||
===== test_gen_vectors_3g_xor
|
||||
aud3g.u.umts.sqn == 0
|
||||
DAUC Computing 1 auth vector: 3G only (2G derived from 3G keys)
|
||||
DAUC 3G: k = 000102030405060708090a0b0c0d0e0f
|
||||
DAUC 3G: opc = 00000000000000000000000000000000
|
||||
DAUC 3G: for sqn ind 0, previous sqn was 0
|
||||
DAUC vector [0]: rand = b5039c57e4a75051551d1a390a71ce48
|
||||
DAUC vector [0]: sqn = 0
|
||||
DAUC vector [0]: autn = 54e0a256565d0000b5029e54e0a25656
|
||||
DAUC vector [0]: ck = 029e54e0a256565d141032067cc047b5
|
||||
DAUC vector [0]: ik = 9e54e0a256565d141032067cc047b502
|
||||
DAUC vector [0]: res = b5029e54e0a256565d141032067cc047
|
||||
DAUC vector [0]: res_len = 16
|
||||
DAUC vector [0]: deriving 2G from 3G
|
||||
DAUC vector [0]: kc = 98e880384887f9fe
|
||||
DAUC vector [0]: sres = 0ec81877
|
||||
DAUC vector [0]: auth_types = 0x3
|
||||
rc == 1
|
||||
aud3g.u.umts.sqn == 0
|
||||
vector matches expectations
|
||||
===== test_gen_vectors_3g_xor: SUCCESS
|
||||
|
||||
|
||||
===== test_gen_vectors_bad_args
|
||||
|
||||
- no auth data (a)
|
||||
|
||||
@@ -106,10 +106,9 @@ int main()
|
||||
void *tall_ctx = talloc_named_const(NULL, 1, "test");
|
||||
msgb_talloc_ctx_init(tall_ctx, 0);
|
||||
osmo_init_logging2(tall_ctx, &hlr_log_info);
|
||||
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
log_set_print_timestamp(osmo_stderr_target, 0);
|
||||
log_set_use_color(osmo_stderr_target, 0);
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
log_set_print_category(osmo_stderr_target, 1);
|
||||
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ db_test_LDADD = \
|
||||
$(top_builddir)/src/db_auc.o \
|
||||
$(top_builddir)/src/db_hlr.o \
|
||||
$(top_builddir)/src/db.o \
|
||||
$(top_builddir)/src/cni_peer_id.o \
|
||||
$(top_builddir)/src/gsup_peer_id.o \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
#include <osmocom/hlr/logging.h>
|
||||
|
||||
@@ -924,16 +924,16 @@ static void test_ind()
|
||||
|
||||
#define ASSERT_IND(VLR, IND) do { \
|
||||
unsigned int ind; \
|
||||
struct osmo_cni_peer_id vlr; \
|
||||
OSMO_ASSERT(!osmo_cni_peer_id_set_str(&vlr, OSMO_CNI_PEER_ID_IPA_NAME, VLR)); \
|
||||
struct osmo_gsup_peer_id vlr; \
|
||||
OSMO_ASSERT(!osmo_gsup_peer_id_set_str(&vlr, OSMO_GSUP_PEER_ID_IPA_NAME, VLR)); \
|
||||
ASSERT_RC(db_ind(dbc, &vlr, &ind), 0); \
|
||||
fprintf(stderr, "%s ind = %u\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len), ind); \
|
||||
if (ind != (IND)) \
|
||||
fprintf(stderr, " ERROR: expected " #IND "\n"); \
|
||||
} while (0)
|
||||
#define IND_DEL(VLR) do { \
|
||||
struct osmo_cni_peer_id vlr; \
|
||||
OSMO_ASSERT(!osmo_cni_peer_id_set_str(&vlr, OSMO_CNI_PEER_ID_IPA_NAME, VLR)); \
|
||||
struct osmo_gsup_peer_id vlr; \
|
||||
OSMO_ASSERT(!osmo_gsup_peer_id_set_str(&vlr, OSMO_GSUP_PEER_ID_IPA_NAME, VLR)); \
|
||||
ASSERT_RC(db_ind_del(dbc, &vlr), 0); \
|
||||
fprintf(stderr, "%s ind deleted\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len)); \
|
||||
} while (0)
|
||||
@@ -1024,13 +1024,9 @@ int main(int argc, char **argv)
|
||||
handle_options(argc, argv);
|
||||
|
||||
osmo_init_logging2(ctx, &hlr_log_info);
|
||||
log_set_print_filename2(osmo_stderr_target,
|
||||
cmdline_opts.verbose ?
|
||||
LOG_FILENAME_BASENAME :
|
||||
LOG_FILENAME_NONE);
|
||||
log_set_print_filename(osmo_stderr_target, cmdline_opts.verbose);
|
||||
log_set_print_timestamp(osmo_stderr_target, 0);
|
||||
log_set_use_color(osmo_stderr_target, 0);
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
log_set_print_category(osmo_stderr_target, 1);
|
||||
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
ctx = talloc_named_const(NULL, 0, "gsup_test");
|
||||
osmo_init_logging2(ctx, &info);
|
||||
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
log_set_print_timestamp(osmo_stderr_target, 0);
|
||||
log_set_use_color(osmo_stderr_target, 0);
|
||||
log_set_print_category(osmo_stderr_target, 1);
|
||||
|
||||
44
tests/gsup_server/Makefile.am
Normal file
44
tests/gsup_server/Makefile.am
Normal file
@@ -0,0 +1,44 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-ggdb3 \
|
||||
-I$(top_srcdir)/include \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
-no-install \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
gsup_server_test.ok \
|
||||
gsup_server_test.err \
|
||||
$(NULL)
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
gsup_server_test \
|
||||
$(NULL)
|
||||
|
||||
gsup_server_test_SOURCES = \
|
||||
gsup_server_test.c \
|
||||
$(NULL)
|
||||
|
||||
gsup_server_test_LDADD = \
|
||||
$(top_srcdir)/src/gsup_server.c \
|
||||
$(top_srcdir)/src/gsup_router.c \
|
||||
$(top_srcdir)/src/gsup_send.c \
|
||||
$(top_srcdir)/src/gsupclient/gsup_peer_id.c \
|
||||
$(top_srcdir)/src/gsupclient/gsup_req.c \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
.PHONY: update_exp
|
||||
update_exp:
|
||||
$(builddir)/gsup_server_test >"$(srcdir)/gsup_server_test.ok" 2>"$(srcdir)/gsup_server_test.err"
|
||||
145
tests/gsup_server/gsup_server_test.c
Normal file
145
tests/gsup_server/gsup_server_test.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/* (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Author: Neels Hofmeyr <nhofmeyr@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 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 <stdio.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/hlr/gsup_server.h>
|
||||
|
||||
#define comment_start() printf("\n===== %s\n", __func__)
|
||||
#define comment_end() printf("===== %s: SUCCESS\n\n", __func__)
|
||||
#define btw(fmt, args...) printf("\n" fmt "\n", ## args)
|
||||
|
||||
#define VERBOSE_ASSERT(val, expect_op, fmt) \
|
||||
do { \
|
||||
printf(#val " == " fmt "\n", (val)); \
|
||||
OSMO_ASSERT((val) expect_op); \
|
||||
} while (0)
|
||||
|
||||
void osmo_gsup_server_add_conn(struct llist_head *clients,
|
||||
struct osmo_gsup_conn *conn);
|
||||
|
||||
static void test_add_conn(void)
|
||||
{
|
||||
struct llist_head _list;
|
||||
struct llist_head *clients = &_list;
|
||||
struct osmo_gsup_conn conn_inst[23] = {};
|
||||
struct osmo_gsup_conn *conn;
|
||||
unsigned int i;
|
||||
|
||||
comment_start();
|
||||
|
||||
INIT_LLIST_HEAD(clients);
|
||||
|
||||
btw("Add 10 items");
|
||||
for (i = 0; i < 10; i++) {
|
||||
osmo_gsup_server_add_conn(clients, &conn_inst[i]);
|
||||
printf("conn_inst[%u].auc_3g_ind == %u\n", i, conn_inst[i].auc_3g_ind);
|
||||
OSMO_ASSERT(clients->next == &conn_inst[0].list);
|
||||
}
|
||||
|
||||
btw("Expecting a list of 0..9");
|
||||
i = 0;
|
||||
llist_for_each_entry(conn, clients, list) {
|
||||
printf("conn[%u].auc_3g_ind == %u\n", i, conn->auc_3g_ind);
|
||||
OSMO_ASSERT(conn->auc_3g_ind == i);
|
||||
OSMO_ASSERT(conn == &conn_inst[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
btw("Punch two holes in the sequence in arbitrary order,"
|
||||
" a larger one from 2..4 and a single one at 7.");
|
||||
llist_del(&conn_inst[4].list);
|
||||
llist_del(&conn_inst[2].list);
|
||||
llist_del(&conn_inst[3].list);
|
||||
llist_del(&conn_inst[7].list);
|
||||
|
||||
btw("Expecting a list of 0,1, 5,6, 8,9");
|
||||
i = 0;
|
||||
llist_for_each_entry(conn, clients, list) {
|
||||
printf("conn[%u].auc_3g_ind == %u\n", i, conn->auc_3g_ind);
|
||||
i++;
|
||||
}
|
||||
|
||||
btw("Add conns, expecting them to take the open slots");
|
||||
osmo_gsup_server_add_conn(clients, &conn_inst[12]);
|
||||
VERBOSE_ASSERT(conn_inst[12].auc_3g_ind, == 2, "%u");
|
||||
|
||||
osmo_gsup_server_add_conn(clients, &conn_inst[13]);
|
||||
VERBOSE_ASSERT(conn_inst[13].auc_3g_ind, == 3, "%u");
|
||||
|
||||
osmo_gsup_server_add_conn(clients, &conn_inst[14]);
|
||||
VERBOSE_ASSERT(conn_inst[14].auc_3g_ind, == 4, "%u");
|
||||
|
||||
osmo_gsup_server_add_conn(clients, &conn_inst[17]);
|
||||
VERBOSE_ASSERT(conn_inst[17].auc_3g_ind, == 7, "%u");
|
||||
|
||||
osmo_gsup_server_add_conn(clients, &conn_inst[18]);
|
||||
VERBOSE_ASSERT(conn_inst[18].auc_3g_ind, == 10, "%u");
|
||||
|
||||
btw("Expecting a list of 0..10");
|
||||
i = 0;
|
||||
llist_for_each_entry(conn, clients, list) {
|
||||
printf("conn[%u].auc_3g_ind == %u\n", i, conn->auc_3g_ind);
|
||||
OSMO_ASSERT(conn->auc_3g_ind == i);
|
||||
i++;
|
||||
}
|
||||
|
||||
btw("Does it also work for the first item?");
|
||||
llist_del(&conn_inst[0].list);
|
||||
|
||||
btw("Expecting a list of 1..10");
|
||||
i = 0;
|
||||
llist_for_each_entry(conn, clients, list) {
|
||||
printf("conn[%u].auc_3g_ind == %u\n", i, conn->auc_3g_ind);
|
||||
OSMO_ASSERT(conn->auc_3g_ind == i + 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
btw("Add another conn, should take auc_3g_ind == 0");
|
||||
osmo_gsup_server_add_conn(clients, &conn_inst[20]);
|
||||
VERBOSE_ASSERT(conn_inst[20].auc_3g_ind, == 0, "%u");
|
||||
|
||||
btw("Expecting a list of 0..10");
|
||||
i = 0;
|
||||
llist_for_each_entry(conn, clients, list) {
|
||||
printf("conn[%u].auc_3g_ind == %u\n", i, conn->auc_3g_ind);
|
||||
OSMO_ASSERT(conn->auc_3g_ind == i);
|
||||
i++;
|
||||
}
|
||||
|
||||
btw("If a client reconnects, it will (likely) get the same auc_3g_ind");
|
||||
VERBOSE_ASSERT(conn_inst[5].auc_3g_ind, == 5, "%u");
|
||||
llist_del(&conn_inst[5].list);
|
||||
conn_inst[5].auc_3g_ind = 423;
|
||||
osmo_gsup_server_add_conn(clients, &conn_inst[5]);
|
||||
VERBOSE_ASSERT(conn_inst[5].auc_3g_ind, == 5, "%u");
|
||||
|
||||
comment_end();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("test_gsup_server.c\n");
|
||||
|
||||
test_add_conn();
|
||||
|
||||
printf("Done\n");
|
||||
return 0;
|
||||
}
|
||||
0
tests/gsup_server/gsup_server_test.err
Normal file
0
tests/gsup_server/gsup_server_test.err
Normal file
94
tests/gsup_server/gsup_server_test.ok
Normal file
94
tests/gsup_server/gsup_server_test.ok
Normal file
@@ -0,0 +1,94 @@
|
||||
test_gsup_server.c
|
||||
|
||||
===== test_add_conn
|
||||
|
||||
Add 10 items
|
||||
conn_inst[0].auc_3g_ind == 0
|
||||
conn_inst[1].auc_3g_ind == 1
|
||||
conn_inst[2].auc_3g_ind == 2
|
||||
conn_inst[3].auc_3g_ind == 3
|
||||
conn_inst[4].auc_3g_ind == 4
|
||||
conn_inst[5].auc_3g_ind == 5
|
||||
conn_inst[6].auc_3g_ind == 6
|
||||
conn_inst[7].auc_3g_ind == 7
|
||||
conn_inst[8].auc_3g_ind == 8
|
||||
conn_inst[9].auc_3g_ind == 9
|
||||
|
||||
Expecting a list of 0..9
|
||||
conn[0].auc_3g_ind == 0
|
||||
conn[1].auc_3g_ind == 1
|
||||
conn[2].auc_3g_ind == 2
|
||||
conn[3].auc_3g_ind == 3
|
||||
conn[4].auc_3g_ind == 4
|
||||
conn[5].auc_3g_ind == 5
|
||||
conn[6].auc_3g_ind == 6
|
||||
conn[7].auc_3g_ind == 7
|
||||
conn[8].auc_3g_ind == 8
|
||||
conn[9].auc_3g_ind == 9
|
||||
|
||||
Punch two holes in the sequence in arbitrary order, a larger one from 2..4 and a single one at 7.
|
||||
|
||||
Expecting a list of 0,1, 5,6, 8,9
|
||||
conn[0].auc_3g_ind == 0
|
||||
conn[1].auc_3g_ind == 1
|
||||
conn[2].auc_3g_ind == 5
|
||||
conn[3].auc_3g_ind == 6
|
||||
conn[4].auc_3g_ind == 8
|
||||
conn[5].auc_3g_ind == 9
|
||||
|
||||
Add conns, expecting them to take the open slots
|
||||
conn_inst[12].auc_3g_ind == 2
|
||||
conn_inst[13].auc_3g_ind == 3
|
||||
conn_inst[14].auc_3g_ind == 4
|
||||
conn_inst[17].auc_3g_ind == 7
|
||||
conn_inst[18].auc_3g_ind == 10
|
||||
|
||||
Expecting a list of 0..10
|
||||
conn[0].auc_3g_ind == 0
|
||||
conn[1].auc_3g_ind == 1
|
||||
conn[2].auc_3g_ind == 2
|
||||
conn[3].auc_3g_ind == 3
|
||||
conn[4].auc_3g_ind == 4
|
||||
conn[5].auc_3g_ind == 5
|
||||
conn[6].auc_3g_ind == 6
|
||||
conn[7].auc_3g_ind == 7
|
||||
conn[8].auc_3g_ind == 8
|
||||
conn[9].auc_3g_ind == 9
|
||||
conn[10].auc_3g_ind == 10
|
||||
|
||||
Does it also work for the first item?
|
||||
|
||||
Expecting a list of 1..10
|
||||
conn[0].auc_3g_ind == 1
|
||||
conn[1].auc_3g_ind == 2
|
||||
conn[2].auc_3g_ind == 3
|
||||
conn[3].auc_3g_ind == 4
|
||||
conn[4].auc_3g_ind == 5
|
||||
conn[5].auc_3g_ind == 6
|
||||
conn[6].auc_3g_ind == 7
|
||||
conn[7].auc_3g_ind == 8
|
||||
conn[8].auc_3g_ind == 9
|
||||
conn[9].auc_3g_ind == 10
|
||||
|
||||
Add another conn, should take auc_3g_ind == 0
|
||||
conn_inst[20].auc_3g_ind == 0
|
||||
|
||||
Expecting a list of 0..10
|
||||
conn[0].auc_3g_ind == 0
|
||||
conn[1].auc_3g_ind == 1
|
||||
conn[2].auc_3g_ind == 2
|
||||
conn[3].auc_3g_ind == 3
|
||||
conn[4].auc_3g_ind == 4
|
||||
conn[5].auc_3g_ind == 5
|
||||
conn[6].auc_3g_ind == 6
|
||||
conn[7].auc_3g_ind == 7
|
||||
conn[8].auc_3g_ind == 8
|
||||
conn[9].auc_3g_ind == 9
|
||||
conn[10].auc_3g_ind == 10
|
||||
|
||||
If a client reconnects, it will (likely) get the same auc_3g_ind
|
||||
conn_inst[5].auc_3g_ind == 5
|
||||
conn_inst[5].auc_3g_ind == 5
|
||||
===== test_add_conn: SUCCESS
|
||||
|
||||
Done
|
||||
@@ -583,7 +583,7 @@ int main()
|
||||
void *ctx = talloc_named_const(NULL, 0, "main");
|
||||
osmo_init_logging2(ctx, NULL);
|
||||
|
||||
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
log_set_print_level(osmo_stderr_target, 1);
|
||||
log_set_print_category(osmo_stderr_target, 1);
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
|
||||
@@ -233,7 +233,7 @@ int main()
|
||||
ctx = talloc_named_const(NULL, 0, "main");
|
||||
osmo_init_logging2(ctx, NULL);
|
||||
|
||||
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
log_set_print_level(osmo_stderr_target, 0);
|
||||
log_set_print_category(osmo_stderr_target, 0);
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
|
||||
@@ -174,7 +174,7 @@ int main()
|
||||
ctx = talloc_named_const(NULL, 0, "main");
|
||||
osmo_init_logging2(ctx, NULL);
|
||||
|
||||
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
log_set_print_level(osmo_stderr_target, 0);
|
||||
log_set_print_category(osmo_stderr_target, 0);
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
|
||||
@@ -73,7 +73,7 @@ int main()
|
||||
ctx = talloc_named_const(NULL, 0, "main");
|
||||
osmo_init_logging2(ctx, NULL);
|
||||
|
||||
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
log_set_print_level(osmo_stderr_target, 0);
|
||||
log_set_print_category(osmo_stderr_target, 0);
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
|
||||
@@ -13,14 +13,9 @@ OsmoHLR> ?
|
||||
OsmoHLR> list
|
||||
...
|
||||
show gsup-connections
|
||||
show subscribers all
|
||||
show subscribers (imei|imsi|msisdn) FILTER
|
||||
show subscribers (cs|ps) (on|off)
|
||||
show subscribers last-seen
|
||||
subscriber (imsi|msisdn|id|imei) IDENT show
|
||||
show subscriber (imsi|msisdn|id|imei) IDENT
|
||||
show mslookup services
|
||||
...
|
||||
|
||||
OsmoHLR> enable
|
||||
OsmoHLR# ?
|
||||
@@ -30,15 +25,12 @@ OsmoHLR# ?
|
||||
OsmoHLR# configure terminal
|
||||
OsmoHLR(config)# ?
|
||||
...
|
||||
hlr Configure the HLR
|
||||
mslookup Configure Distributed GSM mslookup
|
||||
...
|
||||
|
||||
hlr Configure the HLR
|
||||
mslookup Configure Distributed GSM mslookup
|
||||
OsmoHLR(config)# list
|
||||
...
|
||||
hlr
|
||||
mslookup
|
||||
...
|
||||
|
||||
OsmoHLR(config)# hlr
|
||||
OsmoHLR(config-hlr)# ?
|
||||
@@ -55,7 +47,7 @@ OsmoHLR(config-hlr)# list
|
||||
database PATH
|
||||
euse NAME
|
||||
no euse NAME
|
||||
ussd route prefix PREFIX internal (own-msisdn|own-imsi|test-idle)
|
||||
ussd route prefix PREFIX internal (own-msisdn|own-imsi)
|
||||
ussd route prefix PREFIX external EUSE
|
||||
no ussd route prefix PREFIX
|
||||
ussd default-route external EUSE
|
||||
@@ -97,7 +89,7 @@ log stderr
|
||||
logging level main notice
|
||||
logging level db notice
|
||||
logging level auc notice
|
||||
logging level ss notice
|
||||
logging level ss info
|
||||
logging level mslookup notice
|
||||
logging level lu notice
|
||||
logging level dgsm notice
|
||||
@@ -107,7 +99,6 @@ hlr
|
||||
database hlr_vty_test.db
|
||||
gsup
|
||||
bind ip 127.0.0.1
|
||||
ipa-name unnamed-HLR
|
||||
ussd route prefix *#100# internal own-msisdn
|
||||
ussd route prefix *#101# internal own-imsi
|
||||
end
|
||||
@@ -346,9 +337,9 @@ OsmoHLR(config-mslookup-server-msc)# show running-config
|
||||
mslookup
|
||||
server
|
||||
mdns bind 239.192.23.42 4266
|
||||
service foo.bar at 123.45.67.89 1011
|
||||
service baz.bar at 121.31.41.5 1617
|
||||
service baz.bar at a:b:c::d 1819
|
||||
service foo.bar at 123.45.67.89 1011
|
||||
service baz.bar at 121.31.41.5 1617
|
||||
service baz.bar at a:b:c::d 1819
|
||||
msc MSC-1
|
||||
msc msc-901-70-23
|
||||
service foo.bar at 76.54.32.10 1234
|
||||
@@ -402,8 +393,8 @@ OsmoHLR(config-mslookup-client)# show running-config
|
||||
mslookup
|
||||
server
|
||||
mdns bind 239.192.23.42 4266
|
||||
service foo.bar at 123.45.67.89 1011
|
||||
service baz.bar at 121.31.41.5 1617
|
||||
service foo.bar at 123.45.67.89 1011
|
||||
service baz.bar at 121.31.41.5 1617
|
||||
msc MSC-1
|
||||
msc msc-901-70-23
|
||||
service foo.bar at 76.54.32.10 1234
|
||||
@@ -434,9 +425,9 @@ OsmoHLR(config-mslookup-server)# show running-config
|
||||
mslookup
|
||||
server
|
||||
mdns bind 239.192.23.42 4266
|
||||
service foo.bar at 123.45.67.89 1011
|
||||
service baz.bar at 121.31.41.5 1617
|
||||
service gsup.hlr at 23.42.17.11 4223
|
||||
service foo.bar at 123.45.67.89 1011
|
||||
service baz.bar at 121.31.41.5 1617
|
||||
service gsup.hlr at 23.42.17.11 4223
|
||||
msc MSC-1
|
||||
msc msc-901-70-23
|
||||
service foo.bar at 76.54.32.10 1234
|
||||
|
||||
@@ -11,11 +11,9 @@ OsmoHLR# list
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor) ki KI
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update aud3g none
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>]
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update aud3g xor k K [ind-bitlen] [<0-28>]
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update imei (none|IMEI)
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update network-access-mode (none|cs|ps|cs+ps)
|
||||
show mslookup services
|
||||
...
|
||||
|
||||
OsmoHLR# subscriber?
|
||||
subscriber Subscriber management commands
|
||||
@@ -269,7 +267,6 @@ OsmoHLR# subscriber id 101 show
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g ?
|
||||
none Delete 3G authentication data
|
||||
milenage Use Milenage algorithm
|
||||
xor Use XOR algorithm
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage ?
|
||||
k Set Encryption Key K
|
||||
|
||||
@@ -22,6 +22,13 @@ cat $abs_srcdir/gsup/gsup_test.err > experr
|
||||
AT_CHECK([$abs_top_builddir/tests/gsup/gsup_test], [], [expout], [experr])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([gsup_server])
|
||||
AT_KEYWORDS([gsup_server])
|
||||
cat $abs_srcdir/gsup_server/gsup_server_test.ok > expout
|
||||
cat $abs_srcdir/gsup_server/gsup_server_test.err > experr
|
||||
AT_CHECK([$abs_top_builddir/tests/gsup_server/gsup_server_test], [], [expout], [experr])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([db])
|
||||
AT_KEYWORDS([db])
|
||||
cat $abs_srcdir/db/db_test.ok > expout
|
||||
|
||||
Reference in New Issue
Block a user