mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
synced 2025-11-01 12:43:50 +00:00
Compare commits
114 Commits
osmith/rel
...
rhizomatic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
945cc067b3 | ||
|
|
ff058aac73 | ||
|
|
caee387b7e | ||
|
|
7dbe2b1fa4 | ||
|
|
081990e4ff | ||
|
|
b8fbb709fa | ||
|
|
b3f6229953 | ||
|
|
9e2beaffc2 | ||
|
|
1c84633350 | ||
|
|
5225de1474 | ||
|
|
d4b4548589 | ||
|
|
bb7d5b2a61 | ||
|
|
1a71e73fdc | ||
|
|
bb8591dfab | ||
|
|
521fe02d41 | ||
|
|
74e413c014 | ||
|
|
b08796d279 | ||
|
|
35d4c5b376 | ||
|
|
558160be4b | ||
|
|
e9dc7eaeda | ||
|
|
19929d873b | ||
|
|
ada985a0ea | ||
|
|
6b5616fd36 | ||
|
|
96dab5f886 | ||
|
|
db2f1f65da | ||
|
|
0451b13e0d | ||
|
|
26c82ba2be | ||
|
|
e1aed27178 | ||
|
|
7c06eea5b2 | ||
|
|
d4693f652a | ||
|
|
c819234a42 | ||
|
|
bae137d9eb | ||
|
|
413f5e3670 | ||
|
|
6b771e34bd | ||
|
|
a005ad6495 | ||
|
|
e391c4c58d | ||
|
|
a26abc6aa8 | ||
|
|
da4fc0eab9 | ||
|
|
507315eed8 | ||
|
|
72f92e28c9 | ||
|
|
ac1365fddf | ||
|
|
be8bcd30eb | ||
|
|
947e137918 | ||
|
|
e513c43857 | ||
|
|
f6a303c669 | ||
|
|
786ec5b91c | ||
|
|
ff7c7ea085 | ||
|
|
fa6af8872f | ||
|
|
d052f076e3 | ||
|
|
37f0b3a8f3 | ||
|
|
7a763aa012 | ||
|
|
626f5eb740 | ||
|
|
5800f3add5 | ||
|
|
f8b73f0682 | ||
|
|
f4223f5b53 | ||
|
|
1c23f304d1 | ||
|
|
f4159bd54c | ||
|
|
a854b48762 | ||
|
|
91150802f8 | ||
|
|
8f3fa656e7 | ||
|
|
829713a69d | ||
|
|
5edf387353 | ||
|
|
2989873a68 | ||
|
|
390f6fcf13 | ||
|
|
d10c2ef366 | ||
|
|
974aed9c04 | ||
|
|
cf535dbcbd | ||
|
|
a55e63b087 | ||
|
|
62e5c1b2c7 | ||
|
|
ed939154f8 | ||
|
|
268a33e58b | ||
|
|
8804a2335a | ||
|
|
c27bc90ae6 | ||
|
|
f80ab768d0 | ||
|
|
5decd49713 | ||
|
|
c5f034b13d | ||
|
|
01155eaee6 | ||
|
|
e4143234c8 | ||
|
|
6263cf350a | ||
|
|
63eefabdde | ||
|
|
7a4765325d | ||
|
|
53f6067e97 | ||
|
|
8023d246f2 | ||
|
|
00aea9e0d9 | ||
|
|
023c6524a2 | ||
|
|
1d02b51a68 | ||
|
|
78a9f92fda | ||
|
|
ad8866e86e | ||
|
|
6156950634 | ||
|
|
65f51535d0 | ||
|
|
386381662c | ||
|
|
777860ddb5 | ||
|
|
1d0a030aa4 | ||
|
|
3ca9a1fd4f | ||
|
|
b74769f1b4 | ||
|
|
140dffd8f7 | ||
|
|
d63ec88dba | ||
|
|
e427bb299f | ||
|
|
d456fced21 | ||
|
|
c772e525ef | ||
|
|
83a41471da | ||
|
|
b4f25a0d1a | ||
|
|
b246580900 | ||
|
|
0c13953ed0 | ||
|
|
77a1bf66e6 | ||
|
|
37a5b70195 | ||
|
|
4d7cbfcc9a | ||
|
|
bfeea69cab | ||
|
|
3f9d1977df | ||
|
|
608e2e483f | ||
|
|
60673e7f77 | ||
|
|
ca8e6efca6 | ||
|
|
ed2e36316b | ||
|
|
649c335602 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
open_collective: osmocom
|
||||
18
.gitignore
vendored
18
.gitignore
vendored
@@ -70,3 +70,21 @@ doc/manuals/common
|
||||
doc/manuals/build
|
||||
|
||||
contrib/osmo-hlr.spec
|
||||
/debian/.debhelper/
|
||||
/debian/libosmo-gsup-client-dev/
|
||||
/debian/files
|
||||
/debian/autoreconf.after
|
||||
/debian/autoreconf.before
|
||||
/debian/libosmo-gsup-client0/
|
||||
/debian/libosmo-mslookup0/
|
||||
/debian/osmo-hlr-dbg/
|
||||
/debian/tmp/
|
||||
/doc/manuals/vty/hlr_vty_reference.xml
|
||||
/debian/libosmo-mslookup-dev/
|
||||
/debian/osmo-hlr-doc/
|
||||
/debian/osmo-hlr/
|
||||
/debian/osmo-mslookup-utils/
|
||||
/debian/*.log
|
||||
/debian/*.substvars
|
||||
|
||||
include/osmocom/*/version.h
|
||||
|
||||
@@ -11,8 +11,9 @@ SUBDIRS = \
|
||||
|
||||
EXTRA_DIST = \
|
||||
.version \
|
||||
contrib/osmo-hlr.spec.in \
|
||||
README.md \
|
||||
debian \
|
||||
git-version-gen \
|
||||
$(NULL)
|
||||
|
||||
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||
|
||||
80
README.md
Normal file
80
README.md
Normal file
@@ -0,0 +1,80 @@
|
||||
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](https://osmocom.org/projects/osmomsc/wiki),
|
||||
[OsmoSGSN](https://osmocom.org/projects/osmosgsn/wiki) etc. -
|
||||
but not directly 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 https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr
|
||||
|
||||
There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr>
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
User Manuals and VTY reference manuals are [optionally] built in PDF form
|
||||
as part of the build process.
|
||||
|
||||
Pre-rendered PDF versions of the current `master` can be found at
|
||||
|
||||
* [User Manual](https://ftp.osmocom.org/docs/latest/osmohlr-usermanual.pdf)
|
||||
* [VTY Reference Manual for osmo-hlr](https://ftp.osmocom.org/docs/latest/osmohlr-vty-reference.pdf)
|
||||
|
||||
Forum
|
||||
-----
|
||||
|
||||
We welcome any osmo-hlr related discussions in the
|
||||
[Cellular Network Infrastructure -> 2G/3G Core Network](https://discourse.osmocom.org/c/cni/2g-3g-cn)
|
||||
section of the osmocom discourse (web based Forum).
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
|
||||
Discussions related to osmo-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.
|
||||
|
||||
Issue Tracker
|
||||
-------------
|
||||
|
||||
We use the [issue tracker of the osmo-hlr project on osmocom.org](https://osmocom.org/projects/osmo-hlr/issues) for
|
||||
tracking the state of bug reports and feature requests. Feel free to submit any issues you may find, or help
|
||||
us out by resolving existing issues.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Our coding standards are described at
|
||||
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
|
||||
|
||||
We use 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 +1,9 @@
|
||||
# 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:
|
||||
# according to https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
|
||||
# In short: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
|
||||
# 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, removed, or changed since the last update: c + 1:0:a.
|
||||
# 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
|
||||
#library what description / commit summary line
|
||||
|
||||
15
configure.ac
15
configure.ac
@@ -41,11 +41,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.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 2.0.0)
|
||||
|
||||
PKG_CHECK_MODULES(SQLITE3, sqlite3)
|
||||
|
||||
@@ -93,6 +93,7 @@ AC_ARG_ENABLE(werror,
|
||||
if test x"$werror" = x"yes"
|
||||
then
|
||||
WERROR_FLAGS="-Werror"
|
||||
WERROR_FLAGS+=" -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition"
|
||||
WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
|
||||
WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
|
||||
CFLAGS="$CFLAGS $WERROR_FLAGS"
|
||||
@@ -107,7 +108,7 @@ if test "x$enable_ext_tests" = "xyes" ; then
|
||||
AM_PATH_PYTHON
|
||||
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
|
||||
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
|
||||
AC_MSG_ERROR([Please install git://osmocom.org/python/osmo-python-tests to run the VTY/CTRL tests.])
|
||||
AC_MSG_ERROR([Please install https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests to run the VTY/CTRL tests.])
|
||||
fi
|
||||
fi
|
||||
AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
|
||||
@@ -202,11 +203,9 @@ 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,3 +2,13 @@ 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
|
||||
|
||||
@@ -29,7 +29,8 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
export LD_LIBRARY_PATH="$inst/lib"
|
||||
export PATH="$inst/bin:$PATH"
|
||||
|
||||
osmo-build-dep.sh libosmocore "" ac_cv_path_DOXYGEN=false
|
||||
osmo-build-dep.sh libosmocore "" --disable-doxygen
|
||||
osmo-build-dep.sh libosmo-netif "" --disable-doxygen
|
||||
osmo-build-dep.sh libosmo-abis
|
||||
|
||||
# Additional configure options and depends
|
||||
|
||||
95
contrib/osmo-hlr-post-upgrade.sh
Normal file
95
contrib/osmo-hlr-post-upgrade.sh
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/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,190 +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
|
||||
|
||||
%post
|
||||
%service_add_post %{name}.service
|
||||
%endif
|
||||
|
||||
%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
|
||||
|
||||
%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
|
||||
@@ -1,12 +1,19 @@
|
||||
[Unit]
|
||||
Description=Osmocom Home Location Register (OsmoHLR)
|
||||
Documentation=https://osmocom.org/projects/osmo-hlr/wiki/OsmoHLR
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
StateDirectory=osmocom
|
||||
WorkingDirectory=%S/osmocom
|
||||
User=osmocom
|
||||
Group=osmocom
|
||||
ExecStart=/usr/bin/osmo-hlr -c /etc/osmocom/osmo-hlr.cfg -l /var/lib/osmocom/hlr.db
|
||||
RestartSec=2
|
||||
ProtectHome=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
190
debian/changelog
vendored
190
debian/changelog
vendored
@@ -1,8 +1,194 @@
|
||||
osmo-hlr (1.3.1) unstable; urgency=medium
|
||||
osmo-hlr (1.9.1) unstable; urgency=medium
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* Drop use of deprecated vty is_config_node() cb
|
||||
|
||||
[ Oliver Smith ]
|
||||
* db: flush after changing schema version
|
||||
|
||||
-- Oliver Smith <osmith@sysmocom.de> Wed, 02 Apr 2025 15:12:35 +0200
|
||||
|
||||
osmo-hlr (1.9.0) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* subscriber-create-on-demand: rework configuration
|
||||
* subscriber-create-on-demand: add mode for MSISDN=IMSI
|
||||
|
||||
[ Alexander Couzens ]
|
||||
* gsupclient: Introduce gsup_client_mux
|
||||
* gsupclient: add missing SPDX line
|
||||
* debian/copyright: add gsup_client under GPLv2+
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* gsup: Replace deprecated ipa_msg_push_header()
|
||||
* jenkins.sh: libosmo-netif no longer depends on libosmo-abis
|
||||
* Drop use of libosmo-abis osmocom/abis/ipaccess.h
|
||||
* gsup_client: Add new APIs to avoid users accessing struct fields
|
||||
* gsup_client: Avoid double memset 0
|
||||
* Drop unneeded use of abis/ipa.h header
|
||||
* jenkins.sh: Use --disable-doxygen configure param
|
||||
|
||||
[ Mychaela N. Falconia ]
|
||||
* vty: always emit reject-cause lines in saved config
|
||||
* change default reject cause to plmn-not-allowed
|
||||
* change default no-proxy reject cause to net-fail
|
||||
|
||||
-- Oliver Smith <osmith@sysmocom.de> Wed, 12 Feb 2025 12:17:52 +0100
|
||||
|
||||
osmo-hlr (1.8.0) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* hlr_vty.c: drop redundant include of hlr_ussd.h
|
||||
* build: include {README.md,git-version-gen} into the release tarball
|
||||
* README.md: cosmetic: fix a typo
|
||||
|
||||
[ Mychaela N. Falconia ]
|
||||
* SMS over GSUP: implement vty config of SMSC routing
|
||||
* SMS over GSUP: implement forwarding of MO SMS
|
||||
* SMS over GSUP: implement forwarding of MT SMS
|
||||
* SMS over GSUP: handle READY-FOR-SM.req from MSCs
|
||||
* ctrl: add subscriber.by-*.imsi GET-able variable
|
||||
|
||||
[ Andreas Eversberg ]
|
||||
* Use uniform log format for default config files
|
||||
|
||||
[ Harald Welte ]
|
||||
* Add funding link to github mirror
|
||||
* README.md: Improve mark-down formatting
|
||||
* README.md: Add Forum and Issue Tracker sections
|
||||
|
||||
[ Max ]
|
||||
* .deb/.rpm: add osmocom user during package install
|
||||
|
||||
[ Oliver Smith ]
|
||||
* .deb/.rpm: various fixes related to non-root
|
||||
* contrib: remove rpm spec file
|
||||
* debian/postinst: add checks, be verbose
|
||||
* mslookup: don't ignore return value of write()
|
||||
|
||||
-- Oliver Smith <osmith@sysmocom.de> Wed, 24 Jul 2024 15:29:12 +0200
|
||||
|
||||
osmo-hlr (1.7.0) unstable; urgency=medium
|
||||
|
||||
[ Oliver Smith ]
|
||||
* Run struct_endianness.py
|
||||
* tests/db/db_test.err: adjust to XOR-3G rename
|
||||
* debian: set compat level to 10
|
||||
* systemd: depend on networking-online.target
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* mslookup: Call osmo_fd_unregister() before closing and changing bfd->fd
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* tests/auc/Makefile.am: put object files to LDADD
|
||||
* tests/*/Makefile.am: move -I to AM_CPPFLAGS
|
||||
* lu_fsm: fix memleak in lu_fsm_wait_insert_data_result()
|
||||
* ussd: fix GSUP memleaks in rx_proc_ss_{req,error}()
|
||||
* gsup_server: fix msgb memleak in osmo_gsup_server_read_cb()
|
||||
* USSD: fix handling of ussd-DataCodingScheme != 0x0f
|
||||
|
||||
[ Alexander Couzens ]
|
||||
* hlr: use talloc for memory allocation in osmo_gsup_create_insert_subscriber_data_msg
|
||||
* Add support for multiple APN profiles for subscriber data
|
||||
|
||||
[ Harald Welte ]
|
||||
* Introduce support for XOR-2G algorithm
|
||||
* cosmetic: gen_ts_55_205_test_sets/func_template.c: Use tab-indent
|
||||
* cosmetic: gen_ts_55_205_test_sets/main_template tabs istead of spaces
|
||||
* Port to new libosmogsm 'struct osmo_sub_auth_data2'
|
||||
* src/db.c: Switch from "const char *statements" to "const char * const"
|
||||
* db: extend database schema to support 256bit K and/or OP[c] values
|
||||
* Add VTY support for TUAK algorithm
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 14:41:33 +0200
|
||||
|
||||
osmo-hlr (1.6.0) unstable; urgency=medium
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* db_auc: hexparse_stmt(): check value returned by osmo_hexparse()
|
||||
|
||||
[ Max ]
|
||||
* Set working directory in systemd service file
|
||||
* Ignore .deb build byproducts
|
||||
* Debian: bump copyright year to match current
|
||||
* Debian: reformat package description
|
||||
* systemd: enable basic hardening
|
||||
* Debian: install osmo-hlr-dgsm.cfg as example config
|
||||
* hlr_vty.c: fix typo
|
||||
* ctrl: take both address and port from vty config
|
||||
|
||||
[ Harald Welte ]
|
||||
* Support building with -Werror=strict-prototypes / -Werror=old-style-definition
|
||||
* Add -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition
|
||||
|
||||
[ arehbein ]
|
||||
* osmo-hlr: Transition to use of 'telnet_init_default'
|
||||
|
||||
[ Oliver Smith ]
|
||||
* osmo_mdns_rfc_record_decode: check ret of talloc
|
||||
* osmo_mdns_rfc_record_decode: proper free on err
|
||||
* mslookup: use apn functions from libosmocore
|
||||
* osmo_mdns_rfc_record/question_encode: remove ctx
|
||||
|
||||
[ Keith ]
|
||||
* Vty: Fixup config shown/written from vty
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* fix memleak of proxy_subscr_listentry
|
||||
|
||||
[ Alexander Couzens ]
|
||||
* Add vty `reject-cause` to set the reject cause
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 16:49:14 +0100
|
||||
|
||||
osmo-hlr (1.5.0) unstable; urgency=medium
|
||||
|
||||
[ Oliver Smith ]
|
||||
* treewide: remove FSF address
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* fixup: debian: remove unneeded dependency libdbd-sqlite3
|
||||
* debian: add new 'osmo-mslookup-utils' package
|
||||
* tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* ctrl: Mark function as static
|
||||
* tests: Allow specyfing specific ctrl test to run
|
||||
* tests/ctrl: Move ERROR test scenario to proper file
|
||||
* Fix db_subscr_create() not returning -EEXIST expected by VTY subscriber create cmd
|
||||
* ctrl: Introduce cmd SET subscriber.create <imsi>
|
||||
* ctrl: Introduce CTRL command subscriber.by-*.msisdn
|
||||
* cosmetic: hlr_vty_subscr.c: Fix trailing whitespace
|
||||
* ctrl: Introduce cmd SET subscriber.delete <imsi>
|
||||
* ctrl: Introduce CTRL command subscriber.by-*.aud2g <algo[,ki]>
|
||||
* ctrl: Introduce CTRL command subscriber.by-*.aud3g <algo[,KI,(op|opc),OP_C[,ind_bitlen]]>
|
||||
* doc: Document new subscriber CTRL commands
|
||||
|
||||
[ Harald Welte ]
|
||||
* update git URLs (git -> https; gitea)
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 28 Jun 2022 18:38:31 +0200
|
||||
|
||||
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
|
||||
|
||||
-- Oliver Smith <osmith@sysmocom.de> Mon, 06 Sep 2021 15:48:52 +0200
|
||||
[ 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
|
||||
|
||||
|
||||
2
debian/compat
vendored
2
debian/compat
vendored
@@ -1 +1 @@
|
||||
9
|
||||
10
|
||||
|
||||
35
debian/control
vendored
35
debian/control
vendored
@@ -2,28 +2,29 @@ Source: osmo-hlr
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||
Build-Depends: debhelper (>= 9),
|
||||
Build-Depends: debhelper (>= 10),
|
||||
pkg-config,
|
||||
dh-autoreconf,
|
||||
autotools-dev,
|
||||
python3-minimal,
|
||||
libosmocore-dev (>= 1.5.0),
|
||||
libosmo-abis-dev (>= 1.1.0),
|
||||
libosmo-netif-dev (>= 1.1.0),
|
||||
libosmocore-dev (>= 1.11.0),
|
||||
libosmo-abis-dev (>= 2.0.0),
|
||||
libosmo-netif-dev (>= 1.6.0),
|
||||
libsqlite3-dev,
|
||||
sqlite3,
|
||||
osmo-gsm-manuals-dev (>= 1.1.0)
|
||||
osmo-gsm-manuals-dev (>= 1.6.0)
|
||||
Standards-Version: 3.9.6
|
||||
Vcs-Browser: http://cgit.osmocom.org/osmo-hlr
|
||||
Vcs-Git: git://git.osmocom.org/osmo-hlr
|
||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr
|
||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr
|
||||
Homepage: https://projects.osmocom.org/projects/osmo-hlr
|
||||
|
||||
Package: osmo-hlr
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libdbd-sqlite3
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Osmocom Home Location Register
|
||||
OsmoHLR is a Osmocom implementation of HLR (Home Location Registrar) which works over GSUP
|
||||
protocol. The subscribers are store in sqlite DB. It supports both 2G and 3G authentication.
|
||||
OsmoHLR is a Osmocom implementation of HLR (Home Location Registrar) which
|
||||
works over GSUP protocol. The subscribers are store in sqlite DB.
|
||||
It supports both 2G and 3G authentication.
|
||||
|
||||
Package: osmo-hlr-dbg
|
||||
Architecture: any
|
||||
@@ -58,7 +59,7 @@ Description: Development headers of Osmocom GSUP client library
|
||||
.
|
||||
This package contains the development headers.
|
||||
|
||||
Package: libosmo-mslookup0
|
||||
Package: libosmo-mslookup1
|
||||
Section: libs
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
@@ -72,7 +73,7 @@ Package: libosmo-mslookup-dev
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Depends: ${misc:Depends},
|
||||
libosmo-mslookup0 (= ${binary:Version}),
|
||||
libosmo-mslookup1 (= ${binary:Version}),
|
||||
libosmocore-dev
|
||||
Pre-Depends: ${misc:Pre-Depends}
|
||||
Description: Development headers of Osmocom MS lookup library
|
||||
@@ -80,6 +81,16 @@ Description: Development headers of Osmocom MS lookup library
|
||||
.
|
||||
This package contains the development headers.
|
||||
|
||||
Package: osmo-mslookup-utils
|
||||
Architecture: any
|
||||
Section: utils
|
||||
Depends: ${shlibs:Depends},
|
||||
libosmo-mslookup1 (= ${binary:Version}),
|
||||
${misc:Depends}
|
||||
Multi-Arch: same
|
||||
Description: Utilities for Osmocom MS lookup
|
||||
This package contains a simple MS lookup client utility.
|
||||
|
||||
Package: osmo-hlr-doc
|
||||
Architecture: all
|
||||
Section: doc
|
||||
|
||||
20
debian/copyright
vendored
20
debian/copyright
vendored
@@ -3,9 +3,13 @@ Upstream-Name: OsmoHLR
|
||||
Source: http://cgit.osmocom.org/osmo-hlr/
|
||||
|
||||
Files: *
|
||||
Copyright: 2016-2017 Sysmocom s. f. m. c. GmbH <info@sysmocom.de>
|
||||
Copyright: 2016-2022 Sysmocom s. f. m. c. GmbH <info@sysmocom.de>
|
||||
License: AGPL-3+
|
||||
|
||||
Files: src/gsupclient/*
|
||||
Copyright: 2014-2016,2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
License: GPL-2+
|
||||
|
||||
License: AGPL-3+
|
||||
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
|
||||
@@ -19,3 +23,17 @@ License: AGPL-3+
|
||||
|
||||
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/>.
|
||||
|
||||
License: GPL-2+
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
3
debian/osmo-hlr.install
vendored
3
debian/osmo-hlr.install
vendored
@@ -5,4 +5,5 @@
|
||||
/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
|
||||
/var/lib/osmocom
|
||||
/usr/share/doc/osmo-hlr/examples/osmo-hlr-dgsm.cfg
|
||||
/usr/share/osmocom/osmo-hlr-post-upgrade.sh
|
||||
|
||||
1
debian/osmo-mslookup-utils.install
vendored
Normal file
1
debian/osmo-mslookup-utils.install
vendored
Normal file
@@ -0,0 +1 @@
|
||||
usr/bin/osmo-mslookup-client
|
||||
43
debian/postinst
vendored
Executable file
43
debian/postinst
vendored
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/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
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
# Create the osmocom group and user (if it doesn't exist yet)
|
||||
if ! getent group osmocom >/dev/null; then
|
||||
groupadd --system osmocom
|
||||
fi
|
||||
if ! getent passwd osmocom >/dev/null; then
|
||||
useradd \
|
||||
--system \
|
||||
--gid osmocom \
|
||||
--home-dir /var/lib/osmocom \
|
||||
--shell /sbin/nologin \
|
||||
--comment "Open Source Mobile Communications" \
|
||||
osmocom
|
||||
fi
|
||||
|
||||
# Fix permissions of previous (root-owned) install (OS#4107)
|
||||
if dpkg --compare-versions "$2" le "1.8.0"; then
|
||||
if [ -e /etc/osmocom/osmo-hlr.cfg ]; then
|
||||
chown -v osmocom:osmocom /etc/osmocom/osmo-hlr.cfg
|
||||
chmod -v 0660 /etc/osmocom/osmo-hlr.cfg
|
||||
fi
|
||||
|
||||
if [ -d /etc/osmocom ]; then
|
||||
chown -v root:osmocom /etc/osmocom
|
||||
chmod -v 2775 /etc/osmocom
|
||||
fi
|
||||
|
||||
mkdir -p /var/lib/osmocom
|
||||
chown -R -v osmocom:osmocom /var/lib/osmocom
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb(1) will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
#DEBHELPER#
|
||||
@@ -1,4 +1,12 @@
|
||||
# OsmoHLR example configuration for Distributed GSM (mslookup)
|
||||
log stderr
|
||||
logging color 1
|
||||
logging print category-hex 0
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print level 1
|
||||
|
||||
hlr
|
||||
gsup
|
||||
# For D-GSM roaming, osmo-hlr's GSUP must listen on a public IP:
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
log stderr
|
||||
logging filter all 1
|
||||
logging color 1
|
||||
logging print category 1
|
||||
logging print category-hex 0
|
||||
logging print level 1
|
||||
logging print category 1
|
||||
logging timestamp 0
|
||||
logging print file basename last
|
||||
logging print extended-timestamp 1
|
||||
logging print level 1
|
||||
logging level main notice
|
||||
logging level db notice
|
||||
logging level auc notice
|
||||
@@ -24,3 +24,9 @@ hlr
|
||||
bind ip 127.0.0.1
|
||||
ussd route prefix *#100# internal own-msisdn
|
||||
ussd route prefix *#101# internal own-imsi
|
||||
ps
|
||||
pdp-profiles default
|
||||
profile 1
|
||||
apn internet
|
||||
profile 2
|
||||
apn *
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
EXTRA_DIST = example_subscriber_add_update_delete.vty \
|
||||
EXTRA_DIST = \
|
||||
example_subscriber_add_update_delete.vty \
|
||||
example_subscriber_aud2g.ctrl \
|
||||
example_subscriber_aud3g.ctrl \
|
||||
example_subscriber_cs_ps_enabled.ctrl \
|
||||
example_subscriber_info.ctrl \
|
||||
example_subscriber_msisdn.ctrl \
|
||||
osmohlr-usermanual.adoc \
|
||||
osmohlr-usermanual-docinfo.xml \
|
||||
osmohlr-vty-reference.xml \
|
||||
|
||||
@@ -5,6 +5,16 @@ The actual protocol is described in <<common-control-if>>, the variables common
|
||||
to all programs using it are described in <<ctrl_common_vars>>. This section
|
||||
describes the CTRL interface variables specific to OsmoHLR.
|
||||
|
||||
Subscribers can be created and deleted using the following SET commands:
|
||||
|
||||
.Subscriber management commands available on OsmoHLR's Control interface
|
||||
[options="header",width="100%",cols="35%,65%"]
|
||||
|===
|
||||
|Command|Comment
|
||||
|subscriber.create '123456'|Create a new subscriber with IMSI "123456" to the database. Returns database ID of the subscriber being created.
|
||||
|subscriber.delete '123456'|Delete subscriber with IMSI "123456" from database. Returns database ID of the subscriber being deleted.
|
||||
|===
|
||||
|
||||
All subscriber variables are available by different selectors, which are freely
|
||||
interchangeable:
|
||||
|
||||
@@ -28,6 +38,9 @@ Each of the above selectors feature all of these control variables:
|
||||
|subscriber.by-\*.*info-all*|R|No||List both 'info' and 'info-aud' in one
|
||||
|subscriber.by-\*.*cs-enabled*|RW|No|'1' or '0'|Enable/disable circuit-switched access
|
||||
|subscriber.by-\*.*ps-enabled*|RW|No|'1' or '0'|Enable/disable packet-switched access
|
||||
|subscriber.by-\*.*msisdn*|RW|No|valid MSISDN string|Get/Set assigned MSISDN
|
||||
|subscriber.by-\*.*aud2g*|RW|No|'algo[,KI]'|Get/Set 2g Authentication Data
|
||||
|subscriber.by-\*.*aud2g*|RW|No|'algo[,KI,("op"|"opc"),OP_C[,ind_bitlen]]'|Get/Set 3g Authentication Data
|
||||
|===
|
||||
|
||||
=== subscriber.by-*.info, info-aud, info-all
|
||||
@@ -104,3 +117,63 @@ commands:
|
||||
----
|
||||
include::../example_subscriber_cs_ps_enabled.ctrl[]
|
||||
----
|
||||
|
||||
=== subscriber.by-*.msisdn
|
||||
|
||||
Get or set the MSISDN currently assigned to a subscriber.
|
||||
|
||||
|
||||
This is an example transcript that illustrates use of this command:
|
||||
|
||||
----
|
||||
include::../example_subscriber_msisdn.ctrl[]
|
||||
----
|
||||
|
||||
=== subscriber.by-*.aud2g
|
||||
|
||||
Get or set the 2G Authentication data of a subscriber.
|
||||
|
||||
The information is stored/retrieved as a comma separated list of fields:
|
||||
|
||||
----
|
||||
algo[,KI]
|
||||
----
|
||||
|
||||
Where::
|
||||
* *KI* is the KI as a hexadecimal string.
|
||||
* *algo* is one of the following algorithms: _none, xor, comp128v1, comp128v2,
|
||||
comp128v3_.
|
||||
|
||||
All values are case insensitive.
|
||||
|
||||
This is an example transcript that illustrates use of this command:
|
||||
|
||||
----
|
||||
include::../example_subscriber_aud2g.ctrl[]
|
||||
----
|
||||
|
||||
=== subscriber.by-*.aud3g
|
||||
|
||||
Get or set the 3G Authentication data of a subscriber.
|
||||
|
||||
The information is stored/retrieved as a comma separated list of fields:
|
||||
|
||||
----
|
||||
algo[,KI,("op"|"opc"),OP_C[,ind_bitlen]]
|
||||
----
|
||||
|
||||
Where:
|
||||
* *KI* is the KI as a hexadecimal string.
|
||||
* *algo* is one of the following algorithms: _none, xor, milenage_.
|
||||
* "op" or "opc" indicates whether next field is an OP or OPC value.
|
||||
* *OP_C* contains an OP or OPC values as hexadecimal string, based on what the
|
||||
previous field specifies.
|
||||
* *ind_bitlen* is set to 5 by default if not provided.
|
||||
|
||||
All values are case insensitive.
|
||||
|
||||
This is an example transcript that illustrates use of this command:
|
||||
|
||||
----
|
||||
include::../example_subscriber_aud3g.ctrl[]
|
||||
----
|
||||
|
||||
14
doc/manuals/example_subscriber_aud2g.ctrl
Normal file
14
doc/manuals/example_subscriber_aud2g.ctrl
Normal file
@@ -0,0 +1,14 @@
|
||||
GET 1 subscriber.by-imsi-901991234567891.aud2g
|
||||
GET_REPLY 1 subscriber.by-imsi-901991234567891.aud2g none
|
||||
|
||||
SET 2 subscriber.by-imsi-901991234567891.aud2g xor,c01ffedc1cadaeac1d1f1edacac1ab0a
|
||||
SET_REPLY 2 subscriber.by-imsi-901991234567891.aud2g OK
|
||||
|
||||
GET 3 subscriber.by-imsi-901991234567891.aud2g
|
||||
GET_REPLY 3 subscriber.by-imsi-901991234567891.aud2g XOR,c01ffedc1cadaeac1d1f1edacac1ab0a
|
||||
|
||||
SET 4 subscriber.by-imsi-901991234567891.aud2g none
|
||||
SET_REPLY 4 subscriber.by-imsi-901991234567891.aud2g OK
|
||||
|
||||
GET 5 subscriber.by-imsi-901991234567891.aud2g
|
||||
GET_REPLY 5 subscriber.by-imsi-901991234567891.aud2g none
|
||||
20
doc/manuals/example_subscriber_aud3g.ctrl
Normal file
20
doc/manuals/example_subscriber_aud3g.ctrl
Normal file
@@ -0,0 +1,20 @@
|
||||
GET 117 subscriber.by-imsi-901991234567891.aud3g
|
||||
GET_REPLY 117 subscriber.by-imsi-901991234567891.aud3g none
|
||||
|
||||
SET 118 subscriber.by-imsi-901991234567891.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OP,FB2A3D1B360F599ABAB99DB8669F8308
|
||||
SET_REPLY 118 subscriber.by-imsi-901991234567891.aud3g OK
|
||||
|
||||
GET 119 subscriber.by-imsi-901991234567891.aud3g
|
||||
GET_REPLY 119 subscriber.by-imsi-901991234567891.aud3g MILENAGE,c01ffedc1cadaeac1d1f1edacac1ab0a,OP,fb2a3d1b360f599abab99db8669f8308,5
|
||||
|
||||
SET 120 subscriber.by-imsi-901991234567891.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,FB2A3D1B360F599ABAB99DB8669F8308,7
|
||||
SET_REPLY 120 subscriber.by-imsi-901991234567891.aud3g OK
|
||||
|
||||
GET 121 subscriber.by-imsi-901991234567891.aud3g
|
||||
GET_REPLY 121 subscriber.by-imsi-901991234567891.aud3g MILENAGE,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,fb2a3d1b360f599abab99db8669f8308,7
|
||||
|
||||
SET 122 subscriber.by-imsi-901991234567891.aud3g none
|
||||
SET_REPLY 122 subscriber.by-imsi-901991234567891.aud3g OK
|
||||
|
||||
GET 123 subscriber.by-imsi-901991234567891.aud3g
|
||||
GET_REPLY 123 subscriber.by-imsi-901991234567891.aud3g none
|
||||
8
doc/manuals/example_subscriber_msisdn.ctrl
Normal file
8
doc/manuals/example_subscriber_msisdn.ctrl
Normal file
@@ -0,0 +1,8 @@
|
||||
GET 1 subscriber.by-imsi-901991234567891.msisdn
|
||||
GET_REPLY 1 subscriber.by-imsi-901991234567891.msisdn none
|
||||
|
||||
SET 2 subscriber.by-imsi-901991234567891.msisdn 555666
|
||||
SET_REPLY 2 subscriber.by-imsi-901991234567891.msisdn OK
|
||||
|
||||
GET 3 subscriber.by-imsi-901991234567891.msisdn
|
||||
GET_REPLY 3 subscriber.by-imsi-901991234567891.msisdn 555666
|
||||
@@ -1,13 +1,25 @@
|
||||
SUBDIRS = osmocom
|
||||
|
||||
osmocom/%/version.h: osmocom/%/version.h.tpl
|
||||
$(AM_V_GEN)$(MKDIR_P) $(dir $@)
|
||||
$(AM_V_GEN)sed \
|
||||
-e "s/{{VERSION}}/$$(echo '@VERSION@' | cut -d. -f1-3)/g" \
|
||||
-e "s/{{VERSION_MAJOR}}/$$(echo '@VERSION@' | cut -d. -f1)/g" \
|
||||
-e "s/{{VERSION_MINOR}}/$$(echo '@VERSION@' | cut -d. -f2)/g" \
|
||||
-e "s/{{VERSION_PATCH}}/$$(echo '@VERSION@' | cut -d. -f3)/g" \
|
||||
$< > $@
|
||||
|
||||
nobase_include_HEADERS = \
|
||||
osmocom/gsupclient/cni_peer_id.h \
|
||||
osmocom/gsupclient/gsup_client.h \
|
||||
osmocom/gsupclient/gsup_client_mux.h \
|
||||
osmocom/gsupclient/gsup_req.h \
|
||||
osmocom/gsupclient/version.h \
|
||||
osmocom/mslookup/mdns.h \
|
||||
osmocom/mslookup/mdns_sock.h \
|
||||
osmocom/mslookup/mslookup_client_fake.h \
|
||||
osmocom/mslookup/mslookup_client.h \
|
||||
osmocom/mslookup/mslookup_client_mdns.h \
|
||||
osmocom/mslookup/mslookup.h \
|
||||
osmocom/mslookup/version.h \
|
||||
$(NULL)
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/gsm/oap_client.h>
|
||||
#include <osmocom/gsm/ipa.h>
|
||||
@@ -40,6 +43,7 @@ typedef int (*osmo_gsup_client_read_cb_t)(struct osmo_gsup_client *gsupc, struct
|
||||
|
||||
typedef bool (*osmo_gsup_client_up_down_cb_t)(struct osmo_gsup_client *gsupc, bool up);
|
||||
|
||||
/* NOTE: THIS STRUCT IS CONSIDERED PRIVATE, AVOID ACCESSING ITS FIELDS! */
|
||||
struct osmo_gsup_client {
|
||||
const char *unit_name; /* same as ipa_dev->unit_name, for backwards compat */
|
||||
|
||||
@@ -99,3 +103,12 @@ int osmo_gsup_client_enc_send(struct osmo_gsup_client *gsupc,
|
||||
const struct osmo_gsup_message *gsup_msg);
|
||||
struct msgb *osmo_gsup_client_msgb_alloc(void);
|
||||
|
||||
void *osmo_gsup_client_get_data(const struct osmo_gsup_client *gsupc);
|
||||
void osmo_gsup_client_set_data(struct osmo_gsup_client *gsupc, void *data);
|
||||
|
||||
const char *osmo_gsup_client_get_rem_addr(const struct osmo_gsup_client *gsupc);
|
||||
uint16_t osmo_gsup_client_get_rem_port(const struct osmo_gsup_client *gsupc);
|
||||
|
||||
bool osmo_gsup_client_is_connected(const struct osmo_gsup_client *gsupc);
|
||||
const struct ipaccess_unit *osmo_gsup_client_get_ipaccess_unit(const struct osmo_gsup_client *gsupc);
|
||||
|
||||
|
||||
56
include/osmocom/gsupclient/gsup_client_mux.h
Normal file
56
include/osmocom/gsupclient/gsup_client_mux.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Author: Neels Hofmeyr
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
|
||||
struct gsup_client_mux;
|
||||
struct ipaccess_unit;
|
||||
|
||||
struct gsup_client_mux_rx_cb {
|
||||
int (*func)(struct gsup_client_mux *gcm, void *data, const struct osmo_gsup_message *gsup_msg);
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* A GSUP client shared between code paths for various GSUP Message Classes.
|
||||
* The main task is to dispatch GSUP messages to code paths corresponding to the respective Message Class, i.e.
|
||||
* subscriber management, SMS, SS/USSD and inter-MSC messaging.
|
||||
* If a GSUP Message Class IE is present in the message, the received message is dispatched directly to the rx_cb entry
|
||||
* for that Message Class. Otherwise, the Message Class is determined by a switch() on the Message Type.*/
|
||||
struct gsup_client_mux {
|
||||
struct osmo_gsup_client *gsup_client;
|
||||
|
||||
/* Target clients by enum osmo_gsup_message_class */
|
||||
struct gsup_client_mux_rx_cb rx_cb[OSMO_GSUP_MESSAGE_CLASS_ARRAYSIZE];
|
||||
};
|
||||
|
||||
struct gsup_client_mux *gsup_client_mux_alloc(void *talloc_ctx);
|
||||
int gsup_client_mux_start(struct gsup_client_mux *gcm, const char *gsup_server_addr_str, uint16_t gsup_server_port,
|
||||
struct ipaccess_unit *ipa_dev);
|
||||
|
||||
int gsup_client_mux_tx(struct gsup_client_mux *gcm, const struct osmo_gsup_message *gsup_msg);
|
||||
void gsup_client_mux_tx_set_source(const struct gsup_client_mux *gcm, struct osmo_gsup_message *gsup_msg);
|
||||
void gsup_client_mux_tx_error_reply(struct gsup_client_mux *gcm, const struct osmo_gsup_message *gsup_orig,
|
||||
enum gsm48_gmm_cause cause);
|
||||
|
||||
int gsup_client_mux_rx(struct osmo_gsup_client *gsup_client, struct msgb *msg);
|
||||
16
include/osmocom/gsupclient/version.h.tpl
Normal file
16
include/osmocom/gsupclient/version.h.tpl
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#define LIBOSMO_GSUP_CLIENT_VERSION {{VERSION}}
|
||||
#define LIBOSMO_GSUP_CLIENT_VERSION_STR "{{VERSION}}"
|
||||
|
||||
#define LIBOSMO_GSUP_CLIENT_VERSION_MAJOR {{VERSION_MAJOR}}
|
||||
#define LIBOSMO_GSUP_CLIENT_VERSION_MINOR {{VERSION_MINOR}}
|
||||
#define LIBOSMO_GSUP_CLIENT_VERSION_PATCH {{VERSION_PATCH}}
|
||||
|
||||
#define LIBOSMO_GSUP_CLIENT_VERSION_GREATER_EQUAL(major, minor, patch) \
|
||||
(LIBOSMO_GSUP_CLIENT_VERSION_MAJOR > (major) || \
|
||||
(LIBOSMO_GSUP_CLIENT_VERSION_MAJOR == (major) && \
|
||||
LIBOSMO_GSUP_CLIENT_VERSION_MINOR > (minor)) || \
|
||||
(LIBOSMO_GSUP_CLIENT_VERSION_MAJOR == (major) && \
|
||||
LIBOSMO_GSUP_CLIENT_VERSION_MINOR == (minor) && \
|
||||
LIBOSMO_GSUP_CLIENT_VERSION_PATCH >= (patch)))
|
||||
@@ -6,6 +6,7 @@ noinst_HEADERS = \
|
||||
gsup_router.h \
|
||||
gsup_server.h \
|
||||
hlr.h \
|
||||
hlr_sms.h \
|
||||
hlr_ussd.h \
|
||||
hlr_vty.h \
|
||||
hlr_vty_subscr.h \
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
#include <osmocom/crypt/auth.h>
|
||||
|
||||
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||
struct osmo_sub_auth_data *aud2g,
|
||||
struct osmo_sub_auth_data *aud3g,
|
||||
struct osmo_sub_auth_data2 *aud2g,
|
||||
struct osmo_sub_auth_data2 *aud3g,
|
||||
const uint8_t *rand_auts, const uint8_t *auts);
|
||||
|
||||
@@ -30,5 +30,4 @@ enum hlr_ctrl_node {
|
||||
_LAST_CTRL_NODE_HLR
|
||||
};
|
||||
|
||||
int hlr_ctrl_cmds_install();
|
||||
struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
|
||||
struct hlr;
|
||||
|
||||
@@ -12,6 +13,7 @@ enum stmt_idx {
|
||||
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,
|
||||
@@ -38,7 +40,12 @@ enum stmt_idx {
|
||||
DB_STMT_SET_LAST_LU_SEEN,
|
||||
DB_STMT_SET_LAST_LU_SEEN_PS,
|
||||
DB_STMT_EXISTS_BY_IMSI,
|
||||
DB_STMT_EXISTS_AUTHORIZED_BY_IMSI,
|
||||
DB_STMT_IS_CREATED_ON_DEMAND_BY_IMSI,
|
||||
DB_STMT_EXISTS_BY_MSISDN,
|
||||
DB_STMT_IND_ADD,
|
||||
DB_STMT_IND_SELECT,
|
||||
DB_STMT_IND_DEL,
|
||||
_NUM_DB_STMT
|
||||
};
|
||||
|
||||
@@ -65,8 +72,8 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite3_log
|
||||
|
||||
/* obtain the authentication data for a given imsi */
|
||||
int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
||||
struct osmo_sub_auth_data *aud2g,
|
||||
struct osmo_sub_auth_data *aud3g,
|
||||
struct osmo_sub_auth_data2 *aud2g,
|
||||
struct osmo_sub_auth_data2 *aud3g,
|
||||
int64_t *subscr_id);
|
||||
|
||||
int db_update_sqn(struct db_context *dbc, int64_t id,
|
||||
@@ -116,7 +123,7 @@ struct hlr_subscriber {
|
||||
* See https://sqlite.org/lang_datefunc.html, function datetime(). */
|
||||
#define DB_LAST_LU_SEEN_FMT "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
/* Like struct osmo_sub_auth_data, but the keys are in hexdump representation.
|
||||
/* Like struct osmo_sub_auth_data2, but the keys are in hexdump representation.
|
||||
* This is useful because SQLite requires them in hexdump format, and callers
|
||||
* like the VTY and CTRL interface also have them available as hexdump to begin
|
||||
* with. In the binary format, a VTY command would first need to hexparse,
|
||||
@@ -152,6 +159,8 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
|
||||
int db_subscr_update_imei_by_imsi(struct db_context *dbc, const char* imsi, const char *imei);
|
||||
|
||||
int db_subscr_exists_by_imsi(struct db_context *dbc, const char *imsi);
|
||||
int db_subscr_authorized_by_imsi(struct db_context *dbc, const char *imsi);
|
||||
int db_subscr_is_created_on_demand_by_imsi(struct db_context *dbc, const char *imsi, unsigned int msisdn_len);
|
||||
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,
|
||||
@@ -172,6 +181,9 @@ 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);
|
||||
|
||||
/*! Call sqlite3_column_text() and copy result to a char[].
|
||||
* \param[out] buf A char[] used as sizeof() arg(!) and osmo_strlcpy() target.
|
||||
* \param[in] stmt An sqlite3_stmt*.
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_req.h>
|
||||
|
||||
#define OSMO_DGSM_DEFAULT_LOCAL_ATTACH_MAX_AGE 60 * 60
|
||||
#define OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS 2000
|
||||
#define LOG_DGSM(imsi, level, fmt, args...) \
|
||||
LOGP(DDGSM, level, "(IMSI-%s) " fmt, imsi, ##args)
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/abis/ipa.h>
|
||||
#include <osmocom/abis/ipaccess.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
#include <osmocom/gsm/protocol/ipaccess.h>
|
||||
#include <osmocom/abis/ipa.h>
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsupclient/gsup_req.h>
|
||||
|
||||
@@ -42,8 +42,6 @@ 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 */
|
||||
@@ -71,8 +69,6 @@ void osmo_gsup_server_destroy(struct osmo_gsup_server *gsups);
|
||||
int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
|
||||
uint8_t *apn_buf, size_t apn_buf_size);
|
||||
int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
|
||||
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);
|
||||
enum osmo_gsup_cn_domain cn_domain, void *talloc_ctx);
|
||||
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_cni_peer_id *to_peer,
|
||||
struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/gsm/ipa.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
@@ -38,6 +39,13 @@ enum osmo_gsup_message_type;
|
||||
|
||||
extern struct osmo_tdef g_hlr_tdefs[];
|
||||
|
||||
enum subscr_create_on_demand_mode {
|
||||
SUBSCR_COD_MODE_DISABLED = 0,
|
||||
SUBSCR_COD_MODE_NO_MSISDN,
|
||||
SUBSCR_COD_MODE_RAND_MSISDN,
|
||||
SUBSCR_COD_MODE_MSISDN_FROM_IMSI,
|
||||
};
|
||||
|
||||
struct hlr {
|
||||
/* GSUP server pointer */
|
||||
struct osmo_gsup_server *gs;
|
||||
@@ -48,7 +56,6 @@ struct hlr {
|
||||
|
||||
/* Control Interface */
|
||||
struct ctrl_handle *ctrl;
|
||||
const char *ctrl_bind_addr;
|
||||
|
||||
/* Local bind addr */
|
||||
char *gsup_bind_addr;
|
||||
@@ -57,6 +64,24 @@ struct hlr {
|
||||
struct llist_head euse_list;
|
||||
struct hlr_euse *euse_default;
|
||||
|
||||
struct {
|
||||
enum gsm48_gmm_cause cs;
|
||||
enum gsm48_gmm_cause ps;
|
||||
} reject_cause;
|
||||
struct {
|
||||
enum gsm48_gmm_cause cs;
|
||||
enum gsm48_gmm_cause ps;
|
||||
} no_proxy_reject_cause;
|
||||
|
||||
/* PS: APN default configuration used by Subscription Data on ISR */
|
||||
struct {
|
||||
struct {
|
||||
bool enabled;
|
||||
struct osmo_gsup_pdp_info pdp_infos[OSMO_GSUP_MAX_NUM_PDP_INFO];
|
||||
size_t num_pdp_infos;
|
||||
} pdp_profile;
|
||||
} ps;
|
||||
|
||||
/* NCSS (call independent) session guard timeout value */
|
||||
int ncss_guard_timeout;
|
||||
|
||||
@@ -64,12 +89,18 @@ struct hlr {
|
||||
|
||||
struct llist_head ss_sessions;
|
||||
|
||||
struct llist_head smsc_list;
|
||||
struct llist_head smsc_routes;
|
||||
struct hlr_smsc *smsc_default;
|
||||
|
||||
bool store_imei;
|
||||
|
||||
bool subscr_create_on_demand;
|
||||
/* Bitmask of DB_SUBSCR_FLAG_* */
|
||||
uint8_t subscr_create_on_demand_flags;
|
||||
unsigned int subscr_create_on_demand_rand_msisdn_len;
|
||||
struct {
|
||||
enum subscr_create_on_demand_mode mode;
|
||||
unsigned int rand_msisdn_len;
|
||||
/* Bitmask of DB_SUBSCR_FLAG_* */
|
||||
uint8_t flags;
|
||||
} subscr_create_on_demand;
|
||||
|
||||
struct {
|
||||
bool allow_startup;
|
||||
@@ -109,7 +140,10 @@ struct hlr {
|
||||
char *domain_suffix;
|
||||
struct osmo_mslookup_client_method *running;
|
||||
} mdns;
|
||||
bool subscr_create_on_demand_fallback;
|
||||
} client;
|
||||
bool auth_imsi_only;
|
||||
bool ignore_created_on_demand;
|
||||
} mslookup;
|
||||
};
|
||||
|
||||
@@ -119,3 +153,4 @@ struct hlr_subscriber;
|
||||
|
||||
void osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr);
|
||||
int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val, bool is_ps);
|
||||
void dgsm_fallback_to_hlr();
|
||||
|
||||
33
include/osmocom/hlr/hlr_sms.h
Normal file
33
include/osmocom/hlr/hlr_sms.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
|
||||
struct hlr_smsc {
|
||||
/* g_hlr->smsc_list */
|
||||
struct llist_head list;
|
||||
struct hlr *hlr;
|
||||
/* name (must match the IPA ID tag) */
|
||||
const char *name;
|
||||
/* human-readable description */
|
||||
const char *description;
|
||||
};
|
||||
|
||||
struct hlr_smsc *smsc_find(struct hlr *hlr, const char *name);
|
||||
struct hlr_smsc *smsc_alloc(struct hlr *hlr, const char *name);
|
||||
void smsc_free(struct hlr_smsc *smsc);
|
||||
|
||||
struct hlr_smsc_route {
|
||||
/* g_hlr->smsc_routes */
|
||||
struct llist_head list;
|
||||
const char *num_addr;
|
||||
struct hlr_smsc *smsc;
|
||||
};
|
||||
|
||||
struct hlr_smsc_route *smsc_route_find(struct hlr *hlr, const char *num_addr);
|
||||
struct hlr_smsc_route *smsc_route_alloc(struct hlr *hlr, const char *num_addr,
|
||||
struct hlr_smsc *smsc);
|
||||
void smsc_route_free(struct hlr_smsc_route *rt);
|
||||
|
||||
void forward_mo_sms(struct osmo_gsup_req *req);
|
||||
void forward_mt_sms(struct osmo_gsup_req *req);
|
||||
void rx_ready_for_sm_req(struct osmo_gsup_req *req);
|
||||
@@ -31,13 +31,23 @@ enum hlr_vty_node {
|
||||
HLR_NODE = _LAST_OSMOVTY_NODE + 1,
|
||||
GSUP_NODE,
|
||||
EUSE_NODE,
|
||||
SMSC_NODE,
|
||||
MSLOOKUP_NODE,
|
||||
MSLOOKUP_SERVER_NODE,
|
||||
MSLOOKUP_SERVER_MSC_NODE,
|
||||
MSLOOKUP_CLIENT_NODE,
|
||||
PS_NODE,
|
||||
PS_PDP_PROFILES_NODE,
|
||||
PS_PDP_PROFILES_PROFILE_NODE,
|
||||
};
|
||||
|
||||
int hlr_vty_is_config_node(struct vty *vty, int node);
|
||||
|
||||
#define A38_XOR_MIN_KEY_LEN 12
|
||||
#define A38_XOR_MAX_KEY_LEN 16
|
||||
#define A38_XOR2G_KEY_LEN 16
|
||||
#define A38_COMP128_KEY_LEN 16
|
||||
#define MILENAGE_KEY_LEN 16
|
||||
|
||||
int hlr_vty_go_parent(struct vty *vty);
|
||||
void hlr_vty_init(void);
|
||||
void hlr_vty_init(void *hlr_ctx);
|
||||
void dgsm_vty_init(void);
|
||||
|
||||
@@ -11,6 +11,7 @@ enum {
|
||||
DMSLOOKUP,
|
||||
DLU,
|
||||
DDGSM,
|
||||
DCTRL,
|
||||
};
|
||||
|
||||
extern const struct log_info hlr_log_info;
|
||||
|
||||
@@ -71,6 +71,8 @@ void proxy_init(struct osmo_gsup_server *gsup_server_to_vlr);
|
||||
void proxy_del(struct proxy *proxy);
|
||||
void proxy_set_gc_period(struct proxy *proxy, uint32_t gc_period);
|
||||
|
||||
struct osmo_gsup_req *proxy_deferred_gsup_req_get_by_imsi(struct proxy *proxy, const char *imsi);
|
||||
|
||||
/* The API to access / modify proxy entries keeps the implementation opaque, to make sure that we can easily move proxy
|
||||
* storage to SQLite db. */
|
||||
int proxy_subscr_get_by_imsi(struct proxy_subscr *dst, struct proxy *proxy, const char *imsi);
|
||||
|
||||
@@ -71,7 +71,7 @@ struct osmo_mdns_rfc_header {
|
||||
uint16_t nscount; /* Number of authority records */
|
||||
uint16_t arcount; /* Number of additional records */
|
||||
#elif OSMO_IS_BIG_ENDIAN
|
||||
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
|
||||
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
|
||||
uint16_t id;
|
||||
uint8_t qr:1, opcode:4, aa:1, tc:1, rd:1;
|
||||
uint8_t ra:1, z:3, rcode:4;
|
||||
@@ -99,15 +99,12 @@ struct osmo_mdns_rfc_record {
|
||||
uint8_t *rdata;
|
||||
};
|
||||
|
||||
char *osmo_mdns_rfc_qname_encode(void *ctx, const char *domain);
|
||||
char *osmo_mdns_rfc_qname_decode(void *ctx, const char *qname, size_t qname_len);
|
||||
|
||||
void osmo_mdns_rfc_header_encode(struct msgb *msg, const struct osmo_mdns_rfc_header *hdr);
|
||||
int osmo_mdns_rfc_header_decode(const uint8_t *data, size_t data_len, struct osmo_mdns_rfc_header *hdr);
|
||||
|
||||
int osmo_mdns_rfc_question_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_question *qst);
|
||||
int osmo_mdns_rfc_question_encode(struct msgb *msg, const struct osmo_mdns_rfc_question *qst);
|
||||
struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const uint8_t *data, size_t data_len);
|
||||
|
||||
int osmo_mdns_rfc_record_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_record *rec);
|
||||
int osmo_mdns_rfc_record_encode(struct msgb *msg, const struct osmo_mdns_rfc_record *rec);
|
||||
struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len,
|
||||
size_t *record_len);
|
||||
|
||||
@@ -35,6 +35,7 @@ enum osmo_mslookup_id_type {
|
||||
OSMO_MSLOOKUP_ID_NONE = 0,
|
||||
OSMO_MSLOOKUP_ID_IMSI,
|
||||
OSMO_MSLOOKUP_ID_MSISDN,
|
||||
OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED,
|
||||
};
|
||||
|
||||
extern const struct value_string osmo_mslookup_id_type_names[];
|
||||
|
||||
@@ -37,6 +37,8 @@ typedef void (*osmo_mslookup_cb_t)(struct osmo_mslookup_client *client,
|
||||
* This query handling info is not seen by the individual method implementations, to clarify that it is the
|
||||
* osmo_mslookup_client layer that takes care of these details. */
|
||||
struct osmo_mslookup_query_handling {
|
||||
bool search_all;
|
||||
|
||||
/*! Wait at least this long before returning any results.
|
||||
*
|
||||
* If nonzero, result_cb will be called as soon as this delay has elapsed, either with the so far youngest age
|
||||
|
||||
16
include/osmocom/mslookup/version.h.tpl
Normal file
16
include/osmocom/mslookup/version.h.tpl
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#define LIBOSMO_MSLOOKUP_VERSION {{VERSION}}
|
||||
#define LIBOSMO_MSLOOKUP_VERSION_STR "{{VERSION}}"
|
||||
|
||||
#define LIBOSMO_MSLOOKUP_VERSION_MAJOR {{VERSION_MAJOR}}
|
||||
#define LIBOSMO_MSLOOKUP_VERSION_MINOR {{VERSION_MINOR}}
|
||||
#define LIBOSMO_MSLOOKUP_VERSION_PATCH {{VERSION_PATCH}}
|
||||
|
||||
#define LIBOSMO_MSLOOKUP_VERSION_GREATER_EQUAL(major, minor, patch) \
|
||||
(LIBOSMO_MSLOOKUP_VERSION_MAJOR > (major) || \
|
||||
(LIBOSMO_MSLOOKUP_VERSION_MAJOR == (major) && \
|
||||
LIBOSMO_MSLOOKUP_VERSION_MINOR > (minor)) || \
|
||||
(LIBOSMO_MSLOOKUP_VERSION_MAJOR == (major) && \
|
||||
LIBOSMO_MSLOOKUP_VERSION_MINOR == (minor) && \
|
||||
LIBOSMO_MSLOOKUP_VERSION_PATCH >= (patch)))
|
||||
16
sql/hlr.sql
16
sql/hlr.sql
@@ -71,16 +71,24 @@ CREATE TABLE auc_2g (
|
||||
CREATE TABLE auc_3g (
|
||||
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
|
||||
algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value
|
||||
k VARCHAR(32) NOT NULL, -- hex string: subscriber's secret key (128bit)
|
||||
op VARCHAR(32), -- hex string: operator's secret key (128bit)
|
||||
opc VARCHAR(32), -- hex string: derived from OP and K (128bit)
|
||||
k VARCHAR(64) NOT NULL, -- hex string: subscriber's secret key (128/256bit)
|
||||
op VARCHAR(64), -- hex string: operator's secret key (128/256bit)
|
||||
opc VARCHAR(64), -- hex string: derived from OP and K (128/256bit)
|
||||
sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage
|
||||
-- nr of index bits at lower SQN end
|
||||
ind_bitlen INTEGER NOT NULL DEFAULT 5
|
||||
);
|
||||
|
||||
CREATE TABLE ind (
|
||||
-- 3G auth IND pool to be used for this VLR
|
||||
ind INTEGER PRIMARY KEY,
|
||||
-- VLR identification, usually the GSUP source_name
|
||||
vlr TEXT NOT NULL,
|
||||
UNIQUE (vlr)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi);
|
||||
|
||||
-- Set HLR database schema version number
|
||||
-- Note: This constant is currently duplicated in src/db.c and must be kept in sync!
|
||||
PRAGMA user_version = 5;
|
||||
PRAGMA user_version = 7;
|
||||
|
||||
@@ -52,6 +52,7 @@ osmo_hlr_SOURCES = \
|
||||
hlr_vty.c \
|
||||
hlr_vty_subscr.c \
|
||||
gsup_send.c \
|
||||
hlr_sms.c \
|
||||
hlr_ussd.c \
|
||||
proxy.c \
|
||||
dgsm.c \
|
||||
@@ -111,7 +112,7 @@ BOOTSTRAP_SQL = $(top_srcdir)/sql/hlr.sql
|
||||
db_bootstrap.h: $(BOOTSTRAP_SQL) $(srcdir)/db_sql2c.sed
|
||||
echo "/* DO NOT EDIT THIS FILE. It is generated from files in osmo-hlr.git/sql/ */" > "$@"
|
||||
echo "#pragma once" >> "$@"
|
||||
echo "static const char *stmt_bootstrap_sql[] = {" >> "$@"
|
||||
echo "static const char * const stmt_bootstrap_sql[] = {" >> "$@"
|
||||
cat "$(BOOTSTRAP_SQL)" \
|
||||
| sed -f "$(srcdir)/db_sql2c.sed" \
|
||||
>> "$@"
|
||||
|
||||
21
src/auc.c
21
src/auc.c
@@ -1,4 +1,4 @@
|
||||
/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
|
||||
/* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
@@ -32,8 +32,8 @@
|
||||
/* compute given number of vectors using either aud2g or aud2g or a combination
|
||||
* of both. Handles re-synchronization if rand_auts and auts are set */
|
||||
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||
struct osmo_sub_auth_data *aud2g,
|
||||
struct osmo_sub_auth_data *aud3g,
|
||||
struct osmo_sub_auth_data2 *aud2g,
|
||||
struct osmo_sub_auth_data2 *aud3g,
|
||||
const uint8_t *rand_auts, const uint8_t *auts)
|
||||
{
|
||||
unsigned int i;
|
||||
@@ -93,10 +93,10 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||
: "2G only",
|
||||
auts? ", with AUTS resync" : "");
|
||||
if (aud3g) {
|
||||
DBGP("3G: k = %s\n", hexb(aud3g->u.umts.k));
|
||||
DBGP("3G: k = %s\n", hex(aud3g->u.umts.k, aud3g->u.umts.k_len));
|
||||
DBGP("3G: %s = %s\n",
|
||||
aud3g->u.umts.opc_is_op? "OP" : "opc",
|
||||
hexb(aud3g->u.umts.opc));
|
||||
hex(aud3g->u.umts.opc, aud3g->u.umts.opc_len));
|
||||
DBGP("3G: for sqn ind %u, previous sqn was %" PRIu64 "\n",
|
||||
aud3g->u.umts.ind, aud3g->u.umts.sqn);
|
||||
}
|
||||
@@ -115,6 +115,9 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||
if (aud3g) {
|
||||
/* 3G or 3G + 2G case */
|
||||
|
||||
/* backwards-compatibiliy: We assume all RES are 8 bytes long */
|
||||
vec[i].res_len = 8;
|
||||
|
||||
/* Do AUTS only for the first vector or we would use
|
||||
* the same SQN for each following key. */
|
||||
if ((i == 0) && auts) {
|
||||
@@ -123,10 +126,10 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||
DBGP("vector [%u]: resync: rand_auts = %s\n",
|
||||
i, hex(rand_auts, 16));
|
||||
|
||||
rc = osmo_auth_gen_vec_auts(vec+i, aud3g, auts,
|
||||
rc = osmo_auth_gen_vec_auts2(vec+i, aud3g, auts,
|
||||
rand_auts, rand);
|
||||
} else {
|
||||
rc = osmo_auth_gen_vec(vec+i, aud3g, rand);
|
||||
rc = osmo_auth_gen_vec2(vec+i, aud3g, rand);
|
||||
}
|
||||
if (rc < 0) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Error in 3G vector "
|
||||
@@ -154,7 +157,7 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||
|
||||
DBGP("vector [%u]: calculating 2G separately\n", i);
|
||||
|
||||
rc = osmo_auth_gen_vec(&vtmp, aud2g, rand);
|
||||
rc = osmo_auth_gen_vec2(&vtmp, aud2g, rand);
|
||||
if (rc < 0) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Error in 2G vector"
|
||||
"generation: [%u]: rc = %d\n", i, rc);
|
||||
@@ -165,7 +168,7 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||
vec[i].auth_types |= OSMO_AUTH_TYPE_GSM;
|
||||
} else {
|
||||
/* 2G only case */
|
||||
rc = osmo_auth_gen_vec(vec+i, aud2g, rand);
|
||||
rc = osmo_auth_gen_vec2(vec+i, aud2g, rand);
|
||||
if (rc < 0) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Error in 2G vector "
|
||||
"generation: [%u]: rc = %d\n", i, rc);
|
||||
|
||||
435
src/ctrl.c
435
src/ctrl.c
@@ -1,6 +1,6 @@
|
||||
/* OsmoHLR Control Interface implementation */
|
||||
|
||||
/* (C) 2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2017-2023 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Author: Max Suraev <msuraev@sysmocom.de>
|
||||
@@ -31,12 +31,16 @@
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/ctrl.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
#include <osmocom/hlr/hlr_vty.h>
|
||||
|
||||
#define SEL_BY "by-"
|
||||
#define SEL_BY_IMSI SEL_BY "imsi-"
|
||||
#define SEL_BY_MSISDN SEL_BY "msisdn-"
|
||||
#define SEL_BY_ID SEL_BY "id-"
|
||||
|
||||
extern bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
|
||||
int *minlen, int *maxlen, int *minlen_opc, int *maxlen_opc);
|
||||
|
||||
#define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
|
||||
|
||||
static bool startswith(const char *str, const char *start)
|
||||
@@ -162,7 +166,7 @@ static void print_subscr_info(struct ctrl_cmd *cmd,
|
||||
);
|
||||
}
|
||||
|
||||
static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data *aud)
|
||||
static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data2 *aud)
|
||||
{
|
||||
if (aud->algo == OSMO_AUTH_ALG_NONE)
|
||||
return;
|
||||
@@ -174,7 +178,7 @@ static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_d
|
||||
hexdump_buf(aud->u.gsm.ki));
|
||||
}
|
||||
|
||||
static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data *aud)
|
||||
static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data2 *aud)
|
||||
{
|
||||
if (aud->algo == OSMO_AUTH_ALG_NONE)
|
||||
return;
|
||||
@@ -183,7 +187,7 @@ static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_d
|
||||
"\naud3g.k\t%s"
|
||||
,
|
||||
osmo_auth_alg_name(aud->algo),
|
||||
hexdump_buf(aud->u.umts.k));
|
||||
osmo_hexdump_nospc(aud->u.umts.k, aud->u.umts.k_len));
|
||||
/* hexdump uses a static string buffer, hence only one hexdump per
|
||||
* printf(). */
|
||||
ctrl_cmd_reply_printf(cmd,
|
||||
@@ -192,11 +196,82 @@ static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_d
|
||||
"\naud3g.sqn\t%" PRIu64
|
||||
,
|
||||
aud->u.umts.opc_is_op? "op" : "opc",
|
||||
hexdump_buf(aud->u.umts.opc),
|
||||
osmo_hexdump_nospc(aud->u.umts.opc, aud->u.umts.opc_len),
|
||||
aud->u.umts.ind_bitlen,
|
||||
aud->u.umts.sqn);
|
||||
}
|
||||
|
||||
CTRL_CMD_DEFINE_WO_NOVRF(subscr_create, "create");
|
||||
static int set_subscr_create(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct hlr *hlr = data;
|
||||
const char *imsi = cmd->value;
|
||||
int rc;
|
||||
|
||||
if (!osmo_imsi_str_valid(imsi)) {
|
||||
cmd->reply = "Invalid IMSI value.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
/* Create the subscriber in the DB */
|
||||
rc = db_subscr_create(g_hlr->dbc, imsi, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS);
|
||||
if (rc) {
|
||||
if (rc == -EEXIST)
|
||||
cmd->reply = "Subscriber already exists.";
|
||||
else
|
||||
cmd->reply = "Cannot create subscriber.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
LOGP(DCTRL, LOGL_INFO, "Created subscriber IMSI='%s'\n",
|
||||
imsi);
|
||||
|
||||
/* Retrieve data of newly created subscriber: */
|
||||
rc = db_subscr_get_by_imsi(hlr->dbc, imsi, &subscr);
|
||||
if (rc < 0) {
|
||||
cmd->reply = "Failed retrieving ID of newly created subscriber.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
cmd->reply = talloc_asprintf(cmd, "%" PRIu64, subscr.id);
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
CTRL_CMD_DEFINE_WO_NOVRF(subscr_delete, "delete");
|
||||
static int set_subscr_delete(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct hlr *hlr = data;
|
||||
const char *imsi = cmd->value;
|
||||
int rc;
|
||||
|
||||
if (!osmo_imsi_str_valid(imsi)) {
|
||||
cmd->reply = "Invalid IMSI value.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
/* Retrieve data of newly created subscriber: */
|
||||
rc = db_subscr_get_by_imsi(hlr->dbc, imsi, &subscr);
|
||||
if (rc < 0) {
|
||||
cmd->reply = "Subscriber doesn't exist.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
/* Create the subscriber in the DB */
|
||||
rc = db_subscr_delete_by_id(g_hlr->dbc, subscr.id);
|
||||
if (rc) {
|
||||
cmd->reply = "Cannot delete subscriber.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
LOGP(DCTRL, LOGL_INFO, "Deleted subscriber IMSI='%s'\n",
|
||||
imsi);
|
||||
|
||||
cmd->reply = talloc_asprintf(cmd, "%" PRIu64, subscr.id);
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
CTRL_CMD_DEFINE_RO(subscr_info, "info");
|
||||
static int get_subscr_info(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
@@ -216,8 +291,8 @@ CTRL_CMD_DEFINE_RO(subscr_info_aud, "info-aud");
|
||||
static int get_subscr_info_aud(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
const char *imsi;
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
struct osmo_sub_auth_data aud3g;
|
||||
struct osmo_sub_auth_data2 aud2g;
|
||||
struct osmo_sub_auth_data2 aud3g;
|
||||
struct hlr *hlr = data;
|
||||
const char *by_selector = cmd->node;
|
||||
int rc;
|
||||
@@ -252,8 +327,8 @@ CTRL_CMD_DEFINE_RO(subscr_info_all, "info-all");
|
||||
static int get_subscr_info_all(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
struct osmo_sub_auth_data aud3g;
|
||||
struct osmo_sub_auth_data2 aud2g;
|
||||
struct osmo_sub_auth_data2 aud3g;
|
||||
struct hlr *hlr = data;
|
||||
const char *by_selector = cmd->node;
|
||||
int rc;
|
||||
@@ -351,17 +426,316 @@ static int set_subscr_cs_enabled(struct ctrl_cmd *cmd, void *data)
|
||||
return set_subscr_cs_ps_enabled(cmd, data, false);
|
||||
}
|
||||
|
||||
int hlr_ctrl_cmds_install()
|
||||
CTRL_CMD_DEFINE_RO(subscr_imsi, "imsi");
|
||||
static int get_subscr_imsi(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
int rc = 0;
|
||||
struct hlr_subscriber subscr;
|
||||
struct hlr *hlr = data;
|
||||
const char *by_selector = cmd->node;
|
||||
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_aud);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_all);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_ps_enabled);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_cs_enabled);
|
||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
||||
return CTRL_CMD_ERROR;
|
||||
|
||||
return rc;
|
||||
cmd->reply = talloc_strdup(cmd, subscr.imsi);
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
CTRL_CMD_DEFINE(subscr_msisdn, "msisdn");
|
||||
static int verify_subscr_msisdn(struct ctrl_cmd *cmd, const char *value, void *data)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
if (!value)
|
||||
return 1;
|
||||
if (strlen(value) > sizeof(subscr.msisdn) - 1)
|
||||
return 1;
|
||||
if (strcmp(value, "none") != 0 && !osmo_msisdn_str_valid(value))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
static int get_subscr_msisdn(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct hlr *hlr = data;
|
||||
const char *by_selector = cmd->node;
|
||||
|
||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
||||
return CTRL_CMD_ERROR;
|
||||
|
||||
if (strlen(subscr.msisdn) == 0)
|
||||
snprintf(subscr.msisdn, sizeof(subscr.msisdn), "none");
|
||||
|
||||
cmd->reply = talloc_asprintf(cmd, "%s", subscr.msisdn);
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
static int set_subscr_msisdn(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct hlr *hlr = data;
|
||||
const char *by_selector = cmd->node;
|
||||
const char *msisdn;
|
||||
|
||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
||||
return CTRL_CMD_ERROR;
|
||||
|
||||
if (strcmp(cmd->value, "none") == 0)
|
||||
msisdn = NULL;
|
||||
else
|
||||
msisdn = cmd->value;
|
||||
|
||||
if (db_subscr_update_msisdn_by_imsi(g_hlr->dbc, subscr.imsi, msisdn)) {
|
||||
cmd->reply = "Update MSISDN failed";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
cmd->reply = "OK";
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
/* value format: <algo[,KI]> */
|
||||
CTRL_CMD_DEFINE(subscr_aud2g, "aud2g");
|
||||
static int verify_subscr_aud2g(struct ctrl_cmd *cmd, const char *value, void *data)
|
||||
{
|
||||
if (!value)
|
||||
return 1;
|
||||
if (strcasecmp(value, "none") != 0 && !strchr(value, ','))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
static int get_subscr_aud2g(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct hlr *hlr = data;
|
||||
const char *by_selector = cmd->node;
|
||||
struct osmo_sub_auth_data2 aud2g;
|
||||
struct osmo_sub_auth_data2 aud3g_unused;
|
||||
int rc;
|
||||
|
||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
||||
return CTRL_CMD_ERROR;
|
||||
|
||||
rc = db_get_auth_data(hlr->dbc, subscr.imsi, &aud2g, &aud3g_unused, NULL);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
break;
|
||||
case -ENOENT:
|
||||
case -ENOKEY:
|
||||
aud2g.algo = OSMO_AUTH_ALG_NONE;
|
||||
break;
|
||||
default:
|
||||
cmd->reply = "Error retrieving data from database.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
if (aud2g.algo == OSMO_AUTH_ALG_NONE) {
|
||||
cmd->reply = "none";
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
cmd->reply = talloc_asprintf(cmd, "%s,%s", osmo_auth_alg_name(aud2g.algo),
|
||||
hexdump_buf(aud2g.u.gsm.ki));
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
static int set_subscr_aud2g(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct hlr *hlr = data;
|
||||
const char *by_selector = cmd->node;
|
||||
char *tmp = NULL, *tok, *saveptr;
|
||||
int minlen = 0;
|
||||
int maxlen = 0;
|
||||
struct sub_auth_data_str aud2g = {
|
||||
.type = OSMO_AUTH_TYPE_GSM
|
||||
};
|
||||
|
||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
||||
return CTRL_CMD_ERROR;
|
||||
|
||||
tmp = talloc_strdup(cmd, cmd->value);
|
||||
if (!tmp) {
|
||||
cmd->reply = "OOM";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
/* Parse alg_type: */
|
||||
tok = strtok_r(tmp, ",", &saveptr);
|
||||
if (!tok) {
|
||||
cmd->reply = "Invalid format";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
if (strcmp(tok, "none") == 0) {
|
||||
aud2g.algo = OSMO_AUTH_ALG_NONE;
|
||||
} else if (!auth_algo_parse(tok, &aud2g.algo, &minlen, &maxlen, NULL, NULL)) {
|
||||
cmd->reply = "Unknown auth algorithm.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
if (aud2g.algo != OSMO_AUTH_ALG_NONE) {
|
||||
tok = strtok_r(NULL, "\0", &saveptr);
|
||||
if (!tok) {
|
||||
cmd->reply = "Invalid format.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
aud2g.u.gsm.ki = tok;
|
||||
if (!osmo_is_hexstr(aud2g.u.gsm.ki, minlen * 2, maxlen * 2, true)) {
|
||||
cmd->reply = "Invalid KI.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud2g)) {
|
||||
cmd->reply = "Update aud2g failed.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
cmd->reply = "OK";
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
/* value format: <algo[,KI,(op|opc),OP_C[,ind_bitlen]]> */
|
||||
CTRL_CMD_DEFINE(subscr_aud3g, "aud3g");
|
||||
static int verify_subscr_aud3g(struct ctrl_cmd *cmd, const char *value, void *data)
|
||||
{
|
||||
if (!value)
|
||||
return 1;
|
||||
if (strcasecmp(value, "none") != 0 && !strchr(value, ','))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
static int get_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct hlr *hlr = data;
|
||||
const char *by_selector = cmd->node;
|
||||
struct osmo_sub_auth_data2 aud2g_unused;
|
||||
struct osmo_sub_auth_data2 aud3g;
|
||||
int rc;
|
||||
|
||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
||||
return CTRL_CMD_ERROR;
|
||||
|
||||
rc = db_get_auth_data(hlr->dbc, subscr.imsi, &aud2g_unused, &aud3g, NULL);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
break;
|
||||
case -ENOENT:
|
||||
case -ENOKEY:
|
||||
aud3g.algo = OSMO_AUTH_ALG_NONE;
|
||||
break;
|
||||
default:
|
||||
cmd->reply = "Error retrieving data from database.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
if (aud3g.algo == OSMO_AUTH_ALG_NONE) {
|
||||
cmd->reply = "none";
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
cmd->reply = talloc_asprintf(cmd, "%s,%s,%s,%s,%u", osmo_auth_alg_name(aud3g.algo),
|
||||
osmo_hexdump_nospc_c(cmd, aud3g.u.umts.k, aud3g.u.umts.k_len),
|
||||
aud3g.u.umts.opc_is_op ? "OP" : "OPC",
|
||||
osmo_hexdump_nospc_c(cmd, aud3g.u.umts.opc, aud3g.u.umts.opc_len),
|
||||
aud3g.u.umts.ind_bitlen);
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
static int set_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct hlr *hlr = data;
|
||||
const char *by_selector = cmd->node;
|
||||
char *tmp = NULL, *tok, *saveptr;
|
||||
int minlen = 0, minlen_opc = 0;
|
||||
int maxlen = 0, maxlen_opc = 0;
|
||||
struct sub_auth_data_str aud3g = {
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.u.umts = {
|
||||
.ind_bitlen = 5,
|
||||
},
|
||||
};
|
||||
bool ind_bitlen_present;
|
||||
|
||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
||||
return CTRL_CMD_ERROR;
|
||||
|
||||
tmp = talloc_strdup(cmd, cmd->value);
|
||||
if (!tmp) {
|
||||
cmd->reply = "OOM";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
/* Parse alg_type: */
|
||||
tok = strtok_r(tmp, ",", &saveptr);
|
||||
if (!tok) {
|
||||
cmd->reply = "Invalid format.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
if (strcmp(tok, "none") == 0) {
|
||||
aud3g.algo = OSMO_AUTH_ALG_NONE;
|
||||
} else if (!auth_algo_parse(tok, &aud3g.algo, &minlen, &maxlen, &minlen_opc, &maxlen_opc)) {
|
||||
cmd->reply = "Unknown auth algorithm.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
if (aud3g.algo != OSMO_AUTH_ALG_NONE) {
|
||||
/* Parse K */
|
||||
tok = strtok_r(NULL, ",", &saveptr);
|
||||
if (!tok) {
|
||||
cmd->reply = "Invalid format.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
aud3g.u.umts.k = tok;
|
||||
if (!osmo_is_hexstr(aud3g.u.umts.k, minlen * 2, maxlen * 2, true)) {
|
||||
cmd->reply = "Invalid KI.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
/* Parse OP/OPC choice */
|
||||
tok = strtok_r(NULL, ",", &saveptr);
|
||||
if (!tok) {
|
||||
cmd->reply = "Invalid format.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
if (strcasecmp(tok, "op") == 0) {
|
||||
aud3g.u.umts.opc_is_op = true;
|
||||
} else if (strcasecmp(tok, "opc") == 0) {
|
||||
aud3g.u.umts.opc_is_op = false;
|
||||
} else {
|
||||
cmd->reply = "Invalid format.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
/* Parse OP/OPC value */
|
||||
ind_bitlen_present = !!strchr(saveptr, ',');
|
||||
tok = strtok_r(NULL, ind_bitlen_present ? "," : "\0", &saveptr);
|
||||
if (!tok) {
|
||||
cmd->reply = "Invalid format.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
aud3g.u.umts.opc = tok;
|
||||
if (!osmo_is_hexstr(aud3g.u.umts.opc, minlen_opc * 2, maxlen_opc * 2, true)) {
|
||||
cmd->reply = talloc_asprintf(cmd, "Invalid OP/OPC.");
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
if (ind_bitlen_present) {
|
||||
/* Parse bitlen_ind */
|
||||
tok = strtok_r(NULL, "\0", &saveptr);
|
||||
if (!tok || tok[0] == '\0') {
|
||||
cmd->reply = "Invalid format.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
aud3g.u.umts.ind_bitlen = atoi(tok);
|
||||
}
|
||||
}
|
||||
|
||||
if (db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud3g)) {
|
||||
cmd->reply = "Update aud3g failed.";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
cmd->reply = "OK";
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
|
||||
static int hlr_ctrl_node_lookup(void *data, vector vline, int *node_type,
|
||||
@@ -389,14 +763,31 @@ static int hlr_ctrl_node_lookup(void *data, vector vline, int *node_type,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int hlr_ctrl_cmds_install(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR, &cmd_subscr_create);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR, &cmd_subscr_delete);
|
||||
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_aud);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_all);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_ps_enabled);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_cs_enabled);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_imsi);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_msisdn);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_aud2g);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_aud3g);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr)
|
||||
{
|
||||
int rc;
|
||||
struct ctrl_handle *hdl = ctrl_interface_setup_dynip2(hlr,
|
||||
hlr->ctrl_bind_addr,
|
||||
OSMO_CTRL_PORT_HLR,
|
||||
hlr_ctrl_node_lookup,
|
||||
_LAST_CTRL_NODE_HLR);
|
||||
struct ctrl_handle *hdl = ctrl_interface_setup2(hlr, OSMO_CTRL_PORT_HLR, hlr_ctrl_node_lookup,
|
||||
_LAST_CTRL_NODE_HLR);
|
||||
if (!hdl)
|
||||
return NULL;
|
||||
|
||||
|
||||
102
src/db.c
102
src/db.c
@@ -1,4 +1,4 @@
|
||||
/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
|
||||
/* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "db_bootstrap.h"
|
||||
|
||||
/* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */
|
||||
#define CURRENT_SCHEMA_VERSION 5
|
||||
#define CURRENT_SCHEMA_VERSION 7
|
||||
|
||||
#define SEL_COLUMNS \
|
||||
"id," \
|
||||
@@ -53,9 +53,10 @@
|
||||
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;",
|
||||
"WHERE last_lu_seen IS NOT NULL AND last_lu_seen > datetime('now','-1 month') 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 = ?",
|
||||
@@ -91,7 +92,14 @@ static const char *stmt_sql[] = {
|
||||
[DB_STMT_SET_LAST_LU_SEEN] = "UPDATE subscriber SET last_lu_seen = datetime($val, 'unixepoch') WHERE id = $subscriber_id",
|
||||
[DB_STMT_SET_LAST_LU_SEEN_PS] = "UPDATE subscriber SET last_lu_seen_ps = datetime($val, 'unixepoch') WHERE id = $subscriber_id",
|
||||
[DB_STMT_EXISTS_BY_IMSI] = "SELECT 1 FROM subscriber WHERE imsi = $imsi",
|
||||
[DB_STMT_EXISTS_AUTHORIZED_BY_IMSI] = "SELECT 1 FROM subscriber WHERE imsi = $imsi AND (nam_cs = 1 OR nam_ps = 1)",
|
||||
[DB_STMT_IS_CREATED_ON_DEMAND_BY_IMSI] =
|
||||
"SELECT 1 FROM subscriber WHERE imsi = $imsi AND length(msisdn) = $msisdn_len"
|
||||
" AND nam_cs = 0 AND nam_ps = 0 AND vlr_number IS NULL",
|
||||
[DB_STMT_EXISTS_BY_MSISDN] = "SELECT 1 FROM subscriber WHERE msisdn = $msisdn",
|
||||
[DB_STMT_IND_ADD] = "INSERT INTO ind (vlr) VALUES ($vlr)",
|
||||
[DB_STMT_IND_SELECT] = "SELECT ind FROM ind WHERE vlr = $vlr",
|
||||
[DB_STMT_IND_DEL] = "DELETE FROM ind WHERE vlr = $vlr",
|
||||
};
|
||||
|
||||
static void sql3_error_log_cb(void *arg, int err_code, const char *msg)
|
||||
@@ -231,9 +239,9 @@ void db_close(struct db_context *dbc)
|
||||
talloc_free(dbc);
|
||||
}
|
||||
|
||||
static int db_run_statements(struct db_context *dbc, const char **statements, size_t statements_count)
|
||||
static int db_run_statements(struct db_context *dbc, const char * const *statements, size_t statements_count)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
int i;
|
||||
for (i = 0; i < statements_count; i++) {
|
||||
const char *stmt_str = statements[i];
|
||||
@@ -304,7 +312,7 @@ static int
|
||||
db_upgrade_v1(struct db_context *dbc)
|
||||
{
|
||||
int rc;
|
||||
const char *statements[] = {
|
||||
const char * const statements[] = {
|
||||
"ALTER TABLE subscriber ADD COLUMN last_lu_seen TIMESTAMP default NULL",
|
||||
"PRAGMA user_version = 1",
|
||||
};
|
||||
@@ -320,7 +328,7 @@ db_upgrade_v1(struct db_context *dbc)
|
||||
static int db_upgrade_v2(struct db_context *dbc)
|
||||
{
|
||||
int rc;
|
||||
const char *statements[] = {
|
||||
const char * const statements[] = {
|
||||
"ALTER TABLE subscriber ADD COLUMN imei VARCHAR(14)",
|
||||
"PRAGMA user_version = 2",
|
||||
};
|
||||
@@ -433,7 +441,7 @@ static int db_upgrade_v3(struct db_context *dbc)
|
||||
"ms_purged_ps," \
|
||||
"last_lu_seen"
|
||||
|
||||
const char *statements[] = {
|
||||
const char * const statements[] = {
|
||||
"BEGIN TRANSACTION",
|
||||
"CREATE TEMPORARY TABLE subscriber_backup" SUBSCR_V3_CREATE,
|
||||
"INSERT INTO subscriber_backup SELECT " SUBSCR_V2_COLUMN_NAMES " FROM subscriber",
|
||||
@@ -456,7 +464,7 @@ static int db_upgrade_v3(struct db_context *dbc)
|
||||
static int db_upgrade_v4(struct db_context *dbc)
|
||||
{
|
||||
int rc;
|
||||
const char *statements[] = {
|
||||
const char * const statements[] = {
|
||||
"ALTER TABLE subscriber ADD COLUMN last_lu_seen_ps TIMESTAMP default NULL",
|
||||
"PRAGMA user_version = 4",
|
||||
};
|
||||
@@ -472,7 +480,7 @@ static int db_upgrade_v4(struct db_context *dbc)
|
||||
static int db_upgrade_v5(struct db_context *dbc)
|
||||
{
|
||||
int rc;
|
||||
const char *statements[] = {
|
||||
const char * const statements[] = {
|
||||
"ALTER TABLE subscriber ADD COLUMN vlr_via_proxy VARCHAR",
|
||||
"ALTER TABLE subscriber ADD COLUMN sgsn_via_proxy VARCHAR",
|
||||
"PRAGMA user_version = 5",
|
||||
@@ -486,6 +494,69 @@ static int db_upgrade_v5(struct db_context *dbc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int db_upgrade_v6(struct db_context *dbc)
|
||||
{
|
||||
int rc;
|
||||
const char * const statements[] = {
|
||||
"CREATE TABLE ind (\n"
|
||||
" -- 3G auth IND pool to be used for this VLR\n"
|
||||
" ind INTEGER PRIMARY KEY,\n"
|
||||
" -- VLR identification, usually the GSUP source_name\n"
|
||||
" vlr TEXT NOT NULL,\n"
|
||||
" UNIQUE (vlr)\n"
|
||||
")"
|
||||
,
|
||||
"PRAGMA user_version = 6",
|
||||
};
|
||||
|
||||
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 6\n");
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int db_upgrade_v7(struct db_context *dbc)
|
||||
{
|
||||
int rc;
|
||||
/* SQLite doesn't allow us to change the column type in-place, so we
|
||||
* first rename the old table, create a new table and then copy
|
||||
* the data over before deleting the old table */
|
||||
#define CREATE_AUC_3G_V7 \
|
||||
"CREATE TABLE auc_3g (\n" \
|
||||
" subscriber_id INTEGER PRIMARY KEY, -- subscriber.id\n" \
|
||||
" algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value\n" \
|
||||
" k VARCHAR(64) NOT NULL, -- hex string: subscriber's secret key (128/256bit)\n" \
|
||||
" op VARCHAR(64), -- hex string: operator's secret key (128/256bit)\n" \
|
||||
" opc VARCHAR(64), -- hex string: derived from OP and K (128/256bit)\n" \
|
||||
" sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage\n" \
|
||||
" -- nr of index bits at lower SQN end\n" \
|
||||
" ind_bitlen INTEGER NOT NULL DEFAULT 5\n" \
|
||||
");"
|
||||
const char * const statements[] = {
|
||||
"BEGIN TRANSACTION",
|
||||
/* rename old table */
|
||||
"ALTER TABLE auc_3g RENAME TO old_auc_3g",
|
||||
/* create new table */
|
||||
CREATE_AUC_3G_V7,
|
||||
/* copy over old data */
|
||||
"INSERT INTO auc_3g SELECT subscriber_id, algo_id_3g, k, op, opc,sqn, ind_bitlen FROM old_auc_3g",
|
||||
/* delete old table */
|
||||
"DROP TABLE old_auc_3g",
|
||||
/* update user_version */
|
||||
"PRAGMA user_version = 7",
|
||||
"COMMIT",
|
||||
};
|
||||
|
||||
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 7\n");
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
typedef int (*db_upgrade_func_t)(struct db_context *dbc);
|
||||
static db_upgrade_func_t db_upgrade_path[] = {
|
||||
db_upgrade_v1,
|
||||
@@ -493,6 +564,8 @@ static db_upgrade_func_t db_upgrade_path[] = {
|
||||
db_upgrade_v3,
|
||||
db_upgrade_v4,
|
||||
db_upgrade_v5,
|
||||
db_upgrade_v6,
|
||||
db_upgrade_v7,
|
||||
};
|
||||
|
||||
static int db_get_user_version(struct db_context *dbc)
|
||||
@@ -526,6 +599,7 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logg
|
||||
int rc;
|
||||
bool has_sqlite_config_sqllog = false;
|
||||
int version;
|
||||
bool version_changed = false;
|
||||
|
||||
LOGP(DDB, LOGL_NOTICE, "using database: %s\n", fname);
|
||||
LOGP(DDB, LOGL_INFO, "Compiled against SQLite3 lib version %s\n", SQLITE_VERSION);
|
||||
@@ -603,6 +677,7 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logg
|
||||
goto out_free;
|
||||
}
|
||||
version = CURRENT_SCHEMA_VERSION;
|
||||
version_changed = true;
|
||||
}
|
||||
|
||||
LOGP(DDB, LOGL_NOTICE, "Database '%s' has HLR DB schema version %d\n", dbc->fname, version);
|
||||
@@ -617,6 +692,7 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logg
|
||||
}
|
||||
LOGP(DDB, LOGL_NOTICE, "Database '%s' has been upgraded to HLR DB schema version %d\n",
|
||||
dbc->fname, version+1);
|
||||
version_changed = true;
|
||||
}
|
||||
|
||||
if (version != CURRENT_SCHEMA_VERSION) {
|
||||
@@ -633,6 +709,12 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logg
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Flush the cache after changing the version, to make the scenario
|
||||
* less likely that after an unclean shutdown the DB gets restored
|
||||
* with the right table layout but wrong version (SYS#7394). */
|
||||
if (version_changed)
|
||||
sqlite3_db_cacheflush(dbc->db);
|
||||
|
||||
/* prepare all SQL statements */
|
||||
for (i = 0; i < ARRAY_SIZE(dbc->stmt); i++) {
|
||||
rc = sqlite3_prepare_v2(dbc->db, stmt_sql[i], -1,
|
||||
|
||||
48
src/db_auc.c
48
src/db_auc.c
@@ -1,4 +1,4 @@
|
||||
/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
|
||||
/* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
@@ -74,9 +74,9 @@ out:
|
||||
}
|
||||
|
||||
/* hexparse a specific column of a sqlite prepared statement into dst (with length check)
|
||||
* returns 0 for success, -EIO on error */
|
||||
static int hexparse_stmt(uint8_t *dst, size_t dst_len, sqlite3_stmt *stmt, int col, const char *col_name,
|
||||
const char *imsi)
|
||||
* returns byte length in case of success, -EIO on error */
|
||||
static int hexparse_stmt(uint8_t *dst, size_t dst_len_min, size_t dst_len_max, sqlite3_stmt *stmt,
|
||||
int col, const char *col_name, const char *imsi)
|
||||
{
|
||||
const uint8_t *text;
|
||||
size_t col_len;
|
||||
@@ -84,9 +84,15 @@ static int hexparse_stmt(uint8_t *dst, size_t dst_len, sqlite3_stmt *stmt, int c
|
||||
/* Bytes are stored as hex strings in database, hence divide length by two */
|
||||
col_len = sqlite3_column_bytes(stmt, col) / 2;
|
||||
|
||||
if (col_len != dst_len) {
|
||||
LOGAUC(imsi, LOGL_ERROR, "Error reading %s, expected length %lu but has length %lu\n", col_name,
|
||||
dst_len, col_len);
|
||||
if (col_len < dst_len_min) {
|
||||
LOGAUC(imsi, LOGL_ERROR, "Error reading %s, expected min length %lu but has length %lu\n", col_name,
|
||||
dst_len_min, col_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (col_len > dst_len_max) {
|
||||
LOGAUC(imsi, LOGL_ERROR, "Error reading %s, expected max length %lu but has length %lu\n", col_name,
|
||||
dst_len_max, col_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -95,8 +101,11 @@ static int hexparse_stmt(uint8_t *dst, size_t dst_len, sqlite3_stmt *stmt, int c
|
||||
LOGAUC(imsi, LOGL_ERROR, "Error reading %s\n", col_name);
|
||||
return -EIO;
|
||||
}
|
||||
osmo_hexparse((void *)text, dst, dst_len);
|
||||
return 0;
|
||||
|
||||
if (osmo_hexparse((void *)text, dst, dst_len_max) != col_len)
|
||||
return -EINVAL;
|
||||
|
||||
return col_len;
|
||||
}
|
||||
|
||||
/* obtain the authentication data for a given imsi
|
||||
@@ -104,8 +113,8 @@ static int hexparse_stmt(uint8_t *dst, size_t dst_len, sqlite3_stmt *stmt, int c
|
||||
* -ENOENT if the IMSI is not known, -ENOKEY if the IMSI is known but has no auth data,
|
||||
* -EIO on db failure */
|
||||
int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
||||
struct osmo_sub_auth_data *aud2g,
|
||||
struct osmo_sub_auth_data *aud3g,
|
||||
struct osmo_sub_auth_data2 *aud2g,
|
||||
struct osmo_sub_auth_data2 *aud3g,
|
||||
int64_t *subscr_id)
|
||||
{
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_AUC_BY_IMSI];
|
||||
@@ -139,7 +148,8 @@ int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
||||
/* obtain result values using sqlite3_column_*() */
|
||||
if (sqlite3_column_type(stmt, 1) == SQLITE_INTEGER) {
|
||||
/* we do have some 2G authentication data */
|
||||
if (hexparse_stmt(aud2g->u.gsm.ki, sizeof(aud2g->u.gsm.ki), stmt, 2, "Ki", imsi))
|
||||
if (hexparse_stmt(aud2g->u.gsm.ki, sizeof(aud2g->u.gsm.ki), sizeof(aud2g->u.gsm.ki),
|
||||
stmt, 2, "Ki", imsi) < 0)
|
||||
goto end_2g;
|
||||
aud2g->algo = sqlite3_column_int(stmt, 1);
|
||||
aud2g->type = OSMO_AUTH_TYPE_GSM;
|
||||
@@ -148,24 +158,30 @@ int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
||||
end_2g:
|
||||
if (sqlite3_column_type(stmt, 3) == SQLITE_INTEGER) {
|
||||
/* we do have some 3G authentication data */
|
||||
if (hexparse_stmt(aud3g->u.umts.k, sizeof(aud3g->u.umts.k), stmt, 4, "K", imsi)) {
|
||||
rc = hexparse_stmt(aud3g->u.umts.k, 16, sizeof(aud3g->u.umts.k), stmt, 4, "K", imsi);
|
||||
if (rc < 0) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
aud3g->u.umts.k_len = rc;
|
||||
aud3g->algo = sqlite3_column_int(stmt, 3);
|
||||
|
||||
/* UMTS Subscribers can have either OP or OPC */
|
||||
if (sqlite3_column_text(stmt, 5)) {
|
||||
if (hexparse_stmt(aud3g->u.umts.opc, sizeof(aud3g->u.umts.opc), stmt, 5, "OP", imsi)) {
|
||||
rc = hexparse_stmt(aud3g->u.umts.opc, 16, sizeof(aud3g->u.umts.opc), stmt, 5, "OP", imsi);
|
||||
if (rc < 0) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
aud3g->u.umts.opc_len = rc;
|
||||
aud3g->u.umts.opc_is_op = 1;
|
||||
} else {
|
||||
if (hexparse_stmt(aud3g->u.umts.opc, sizeof(aud3g->u.umts.opc), stmt, 6, "OPC", imsi)) {
|
||||
rc = hexparse_stmt(aud3g->u.umts.opc, 16, sizeof(aud3g->u.umts.opc), stmt, 6, "OPC", imsi);
|
||||
if (rc < 0) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
aud3g->u.umts.opc_len = rc;
|
||||
aud3g->u.umts.opc_is_op = 0;
|
||||
}
|
||||
aud3g->u.umts.sqn = sqlite3_column_int64(stmt, 7);
|
||||
@@ -191,7 +207,7 @@ int db_get_auc(struct db_context *dbc, const char *imsi,
|
||||
unsigned int num_vec, const uint8_t *rand_auts,
|
||||
const uint8_t *auts, bool separation_bit)
|
||||
{
|
||||
struct osmo_sub_auth_data aud2g, aud3g;
|
||||
struct osmo_sub_auth_data2 aud2g, aud3g;
|
||||
int64_t subscr_id;
|
||||
int ret = 0;
|
||||
int rc;
|
||||
|
||||
180
src/db_hlr.c
180
src/db_hlr.c
@@ -1,4 +1,4 @@
|
||||
/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
|
||||
/* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
@@ -45,7 +45,8 @@
|
||||
* \param[in,out] dbc database context.
|
||||
* \param[in] imsi ASCII string of IMSI digits, is validated.
|
||||
* \param[in] flags Bitmask of DB_SUBSCR_FLAG_*.
|
||||
* \returns 0 on success, -EINVAL on invalid IMSI, -EIO on database error.
|
||||
* \returns 0 on success, -EINVAL on invalid IMSI, -EEXIST if subscriber with
|
||||
* provided imsi already exists, -EIO on other database errors.
|
||||
*/
|
||||
int db_subscr_create(struct db_context *dbc, const char *imsi, uint8_t flags)
|
||||
{
|
||||
@@ -73,6 +74,8 @@ int db_subscr_create(struct db_context *dbc, const char *imsi, uint8_t flags)
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGHLR(imsi, LOGL_ERROR, "Cannot create subscriber: SQL error: (%d) %s\n",
|
||||
rc, sqlite3_errmsg(dbc->db));
|
||||
if (rc == SQLITE_CONSTRAINT_UNIQUE)
|
||||
return -EEXIST;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -235,8 +238,9 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
|
||||
case OSMO_AUTH_ALG_COMP128v1:
|
||||
case OSMO_AUTH_ALG_COMP128v2:
|
||||
case OSMO_AUTH_ALG_COMP128v3:
|
||||
case OSMO_AUTH_ALG_XOR:
|
||||
case OSMO_AUTH_ALG_XOR_2G:
|
||||
break;
|
||||
case OSMO_AUTH_ALG_XOR_3G:
|
||||
case OSMO_AUTH_ALG_MILENAGE:
|
||||
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
||||
" auth algo not suited for 2G: %s\n",
|
||||
@@ -264,11 +268,12 @@ 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:
|
||||
case OSMO_AUTH_ALG_XOR_3G:
|
||||
break;
|
||||
case OSMO_AUTH_ALG_COMP128v1:
|
||||
case OSMO_AUTH_ALG_COMP128v2:
|
||||
case OSMO_AUTH_ALG_COMP128v3:
|
||||
case OSMO_AUTH_ALG_XOR_2G:
|
||||
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
||||
" auth algo not suited for 3G: %s\n",
|
||||
osmo_auth_alg_name(aud->algo));
|
||||
@@ -281,12 +286,12 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
|
||||
|
||||
if (aud->algo == OSMO_AUTH_ALG_NONE)
|
||||
break;
|
||||
if (!osmo_is_hexstr(aud->u.umts.k, 32, 32, true)) {
|
||||
if (!osmo_is_hexstr(aud->u.umts.k, 32, 64, true)) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
||||
" Invalid K: '%s'\n", aud->u.umts.k);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!osmo_is_hexstr(aud->u.umts.opc, 32, 32, true)) {
|
||||
if (!osmo_is_hexstr(aud->u.umts.opc, 32, 64, true)) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
||||
" Invalid OP/OPC: '%s'\n", aud->u.umts.opc);
|
||||
return -EINVAL;
|
||||
@@ -550,6 +555,59 @@ int db_subscr_exists_by_imsi(struct db_context *dbc, const char *imsi) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! Check if a subscriber exists and has CS or PS service in the HLR database.
|
||||
* \param[in, out] dbc database context.
|
||||
* \param[in] imsi ASCII string of IMSI digits.
|
||||
* \returns 0 if exists & authorized, -ENOENT if not, -EIO on database error.
|
||||
*/
|
||||
int db_subscr_authorized_by_imsi(struct db_context *dbc, const char *imsi) {
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_EXISTS_AUTHORIZED_BY_IMSI];
|
||||
const char *err;
|
||||
int rc;
|
||||
|
||||
if (!db_bind_text(stmt, NULL, imsi))
|
||||
return -EIO;
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
db_remove_reset(stmt);
|
||||
if (rc == SQLITE_ROW)
|
||||
return 0; /* exists */
|
||||
if (rc == SQLITE_DONE)
|
||||
return -ENOENT; /* does not exist */
|
||||
|
||||
err = sqlite3_errmsg(dbc->db);
|
||||
LOGP(DAUC, LOGL_ERROR, "Failed to check for authorized subscriber by IMSI='%s': %s\n", imsi, err);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! Check if a subscriber exists and has ever been attached
|
||||
* \param[in, out] dbc database context.
|
||||
* \param[in] imsi ASCII string of IMSI digits.
|
||||
* \returns 0 if has vlr_number, -ENOENT if not, -EIO on database error.
|
||||
*/
|
||||
int db_subscr_is_created_on_demand_by_imsi(struct db_context *dbc, const char *imsi, unsigned int msisdn_len) {
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_IS_CREATED_ON_DEMAND_BY_IMSI];
|
||||
const char *err;
|
||||
int rc;
|
||||
|
||||
if (!db_bind_text(stmt, "$imsi", imsi))
|
||||
return -EIO;
|
||||
|
||||
if (!db_bind_int(stmt, "$msisdn_len", msisdn_len))
|
||||
return -EIO;
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
db_remove_reset(stmt);
|
||||
if (rc == SQLITE_ROW)
|
||||
return 0; /* exists */
|
||||
if (rc == SQLITE_DONE)
|
||||
return -ENOENT; /* does not exist */
|
||||
|
||||
err = sqlite3_errmsg(dbc->db);
|
||||
LOGP(DAUC, LOGL_ERROR, "Failed to check for on demand subscriber by IMSI='%s': %s\n", imsi, err);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! Retrieve subscriber data from the HLR database.
|
||||
* \param[in,out] dbc database context.
|
||||
* \param[in] imsi ASCII string of IMSI digits.
|
||||
@@ -648,6 +706,8 @@ int db_subscrs_get(struct db_context *dbc, const char *filter_type, const char *
|
||||
|
||||
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) {
|
||||
@@ -693,9 +753,12 @@ int db_subscrs_get(struct db_context *dbc, const char *filter_type, const char *
|
||||
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)
|
||||
if (show_ls) {
|
||||
parse_last_lu_seen(&subscr.last_lu_seen, (const char *)sqlite3_column_text(stmt, 14),
|
||||
subscr.imsi, "CS");
|
||||
copy_sqlite3_text_to_buf(subscr.vlr_number, stmt, 4);
|
||||
}
|
||||
|
||||
get_cb(&subscr, data);
|
||||
rc = sqlite3_step(stmt);
|
||||
(*count)++;
|
||||
@@ -970,3 +1033,106 @@ out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _db_ind_run(struct db_context *dbc, sqlite3_stmt *stmt, const char *vlr, bool reset)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!db_bind_text(stmt, "$vlr", vlr))
|
||||
return -EIO;
|
||||
|
||||
/* execute the statement */
|
||||
rc = sqlite3_step(stmt);
|
||||
if (reset)
|
||||
db_remove_reset(stmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int _db_ind_add(struct db_context *dbc, const char *vlr)
|
||||
{
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_IND_ADD];
|
||||
if (_db_ind_run(dbc, stmt, vlr, true) != SQLITE_DONE) {
|
||||
LOGP(DDB, LOGL_ERROR, "Cannot create IND entry for %s\n", osmo_quote_str_c(OTC_SELECT, vlr, -1));
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _db_ind_del(struct db_context *dbc, const char *vlr)
|
||||
{
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_IND_DEL];
|
||||
_db_ind_run(dbc, stmt, vlr, true);
|
||||
/* We don't really care about the result. If it didn't exist, then that was the goal anyway. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _db_ind_get(struct db_context *dbc, const char *vlr, unsigned int *ind)
|
||||
{
|
||||
int ret = 0;
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_IND_SELECT];
|
||||
int rc = _db_ind_run(dbc, stmt, vlr, false);
|
||||
if (rc == SQLITE_DONE) {
|
||||
/* Does not exist yet */
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
} else if (rc != SQLITE_ROW) {
|
||||
LOGP(DDB, LOGL_ERROR, "Error executing SQL: %d\n", rc);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
OSMO_ASSERT(ind);
|
||||
*ind = sqlite3_column_int64(stmt, 0);
|
||||
out:
|
||||
db_remove_reset(stmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _db_ind(struct db_context *dbc, const struct osmo_cni_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:
|
||||
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));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
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));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (del)
|
||||
return _db_ind_del(dbc, vlr_name);
|
||||
|
||||
rc = _db_ind_get(dbc, vlr_name, ind);
|
||||
if (!rc)
|
||||
return 0;
|
||||
|
||||
/* Does not exist yet, create. */
|
||||
rc = _db_ind_add(dbc, vlr_name);
|
||||
if (rc) {
|
||||
LOGP(DDB, LOGL_ERROR, "Error creating IND entry for %s\n", osmo_quote_str_c(OTC_SELECT, vlr_name, -1));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* To be sure, query again from scratch. */
|
||||
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)
|
||||
{
|
||||
return _db_ind(dbc, vlr, ind, false);
|
||||
}
|
||||
|
||||
int db_ind_del(struct db_context *dbc, const struct osmo_cni_peer_id *vlr)
|
||||
{
|
||||
return _db_ind(dbc, vlr, NULL, true);
|
||||
}
|
||||
|
||||
@@ -18,10 +18,6 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id: dbd_helper.c,v 1.44 2011/08/09 11:14:14 mhoenicka Exp $
|
||||
*/
|
||||
|
||||
|
||||
25
src/dgsm.c
25
src/dgsm.c
@@ -58,6 +58,12 @@ static void resolve_hlr_result_cb(struct osmo_mslookup_client *client,
|
||||
if (result->rc != OSMO_MSLOOKUP_RC_RESULT) {
|
||||
LOG_DGSM(query->id.imsi, LOGL_ERROR, "Failed to resolve remote HLR: %s\n",
|
||||
osmo_mslookup_result_name_c(OTC_SELECT, query, result));
|
||||
if (g_hlr->mslookup.client.subscr_create_on_demand_fallback &&
|
||||
db_subscr_exists_by_imsi(g_hlr->dbc, query->id.imsi) != 0) {
|
||||
struct osmo_gsup_req *req = proxy_deferred_gsup_req_get_by_imsi(proxy, query->id.imsi);
|
||||
if (req && req->gsup.message_type == OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST)
|
||||
dgsm_fallback_to_hlr(req);
|
||||
}
|
||||
proxy_subscr_del(proxy, query->id.imsi);
|
||||
return;
|
||||
}
|
||||
@@ -91,8 +97,17 @@ bool dgsm_check_forward_gsup_msg(struct osmo_gsup_req *req)
|
||||
struct osmo_mslookup_query_handling handling;
|
||||
uint32_t request_handle;
|
||||
|
||||
/* If the IMSI is known in the local HLR, then we won't proxy. */
|
||||
if (db_subscr_exists_by_imsi(g_hlr->dbc, req->gsup.imsi) == 0)
|
||||
/* If the IMSI is authorized in the local HLR, then we won't proxy */
|
||||
if (db_subscr_authorized_by_imsi(g_hlr->dbc, req->gsup.imsi) == 0)
|
||||
return false;
|
||||
/* unless configuration tells us to do otherwise. */
|
||||
if (!g_hlr->mslookup.ignore_created_on_demand && !g_hlr->mslookup.auth_imsi_only &&
|
||||
db_subscr_exists_by_imsi(g_hlr->dbc, req->gsup.imsi) == 0)
|
||||
return false;
|
||||
|
||||
if (!g_hlr->mslookup.auth_imsi_only && !(g_hlr->mslookup.ignore_created_on_demand &&
|
||||
db_subscr_is_created_on_demand_by_imsi(g_hlr->dbc, req->gsup.imsi,
|
||||
g_hlr->subscr_create_on_demand.rand_msisdn_len) == 0))
|
||||
return false;
|
||||
|
||||
/* Are we already forwarding this IMSI to a remote HLR? */
|
||||
@@ -168,9 +183,9 @@ void dgsm_init(void *ctx)
|
||||
dgsm_ctx = talloc_named_const(ctx, 0, "dgsm");
|
||||
INIT_LLIST_HEAD(&g_hlr->mslookup.server.local_site_services);
|
||||
|
||||
g_hlr->mslookup.server.local_attach_max_age = 60 * 60;
|
||||
g_hlr->mslookup.server.local_attach_max_age = OSMO_DGSM_DEFAULT_LOCAL_ATTACH_MAX_AGE;
|
||||
|
||||
g_hlr->mslookup.client.result_timeout_milliseconds = 2000;
|
||||
g_hlr->mslookup.client.result_timeout_milliseconds = OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS;
|
||||
|
||||
g_hlr->gsup_unit_name.unit_name = "HLR";
|
||||
g_hlr->gsup_unit_name.serno = "unnamed-HLR";
|
||||
@@ -191,7 +206,7 @@ void dgsm_start(void *ctx)
|
||||
dgsm_mdns_client_config_apply();
|
||||
}
|
||||
|
||||
void dgsm_stop()
|
||||
void dgsm_stop(void)
|
||||
{
|
||||
g_hlr->mslookup.allow_startup = false;
|
||||
mslookup_server_mdns_config_apply();
|
||||
|
||||
191
src/dgsm_vty.c
191
src/dgsm_vty.c
@@ -22,9 +22,11 @@
|
||||
#include <osmocom/mslookup/mslookup_client_mdns.h>
|
||||
#include <osmocom/mslookup/mdns.h>
|
||||
#include <osmocom/hlr/hlr_vty.h>
|
||||
#include <osmocom/hlr/proxy.h>
|
||||
#include <osmocom/hlr/mslookup_server.h>
|
||||
#include <osmocom/hlr/mslookup_server_mdns.h>
|
||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
|
||||
struct cmd_node mslookup_node = {
|
||||
MSLOOKUP_NODE,
|
||||
@@ -188,6 +190,53 @@ DEFUN(cfg_mslookup_server_no_mdns_bind,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mslookup_server_max_age,
|
||||
cfg_mslookup_server_max_age_cmd,
|
||||
"max-age <1-21600>",
|
||||
"How old can the Last Location Update be for the mslookup server to respond\n"
|
||||
"max age in seconds\n")
|
||||
{
|
||||
uint32_t val = atol(argv[0]);
|
||||
g_hlr->mslookup.server.local_attach_max_age = val;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mslookup_auth_imsi_only,
|
||||
cfg_mslookup_auth_imsi_only_cmd,
|
||||
"authorized-imsi-only",
|
||||
"On local GSUP, use mslookup ignoring local HLR + don't answer queries for IMSIs without PS or CS network access mode")
|
||||
{
|
||||
g_hlr->mslookup.auth_imsi_only = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mslookup_no_auth_imsi_only,
|
||||
cfg_mslookup_no_auth_imsi_only_cmd,
|
||||
"no authorized-imsi-only",
|
||||
NO_STR "Answer Local GSUP/mDNS queries for any IMSI in the local HLR database")
|
||||
{
|
||||
g_hlr->mslookup.auth_imsi_only = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mslookup_cod,
|
||||
cfg_mslookup_cod_cmd,
|
||||
"ignore-created-on-demand",
|
||||
"Ignore IMSIs that were created-on-demand")
|
||||
{
|
||||
g_hlr->mslookup.ignore_created_on_demand = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mslookup_no_cod,
|
||||
cfg_mslookup_no_cod_cmd,
|
||||
"no ignore-created-on-demand",
|
||||
NO_STR "Answer mslookup and local GSUP for created on demand IMSIs")
|
||||
{
|
||||
g_hlr->mslookup.ignore_created_on_demand = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
struct cmd_node mslookup_server_msc_node = {
|
||||
MSLOOKUP_SERVER_MSC_NODE,
|
||||
"%s(config-mslookup-server-msc)# ",
|
||||
@@ -350,6 +399,24 @@ DEFUN(cfg_mslookup_no_client,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mslookup_client_subscr_cod_fallback,
|
||||
cfg_mslookup_client_subscr_cod_fallback_cmd,
|
||||
"create-on-demand-fallback",
|
||||
"If the msclient does not get a response from mDNS, proceed according to this HLR subscriber-create-on-demand config")
|
||||
{
|
||||
g_hlr->mslookup.client.subscr_create_on_demand_fallback = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mslookup_client_no_subscr_cod_fallback,
|
||||
cfg_mslookup_client_no_subscr_cod_fallback_cmd,
|
||||
"no create-on-demand-fallback",
|
||||
NO_STR "Return IMSI UNKNOWN if the mslookup client does not receive a response from mDNS")
|
||||
{
|
||||
g_hlr->mslookup.client.subscr_create_on_demand_fallback = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_mslookup_client_timeout,
|
||||
cfg_mslookup_client_timeout_cmd,
|
||||
"timeout <1-100000>",
|
||||
@@ -421,6 +488,11 @@ int config_write_mslookup(struct vty *vty)
|
||||
|
||||
vty_out(vty, "mslookup%s", VTY_NEWLINE);
|
||||
|
||||
if (g_hlr->mslookup.auth_imsi_only)
|
||||
vty_out(vty, " authorized-imsi-only%s", VTY_NEWLINE);
|
||||
if (g_hlr->mslookup.ignore_created_on_demand)
|
||||
vty_out(vty, " ignore-created-on-demand%s", VTY_NEWLINE);
|
||||
|
||||
if (g_hlr->mslookup.server.enable || !llist_empty(&g_hlr->mslookup.server.local_site_services)) {
|
||||
struct mslookup_server_msc_cfg *msc;
|
||||
|
||||
@@ -442,14 +514,17 @@ 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))
|
||||
continue;
|
||||
vty_out(vty, " msc %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE);
|
||||
config_write_msc_services(vty, " ", msc);
|
||||
vty_out(vty, " msc ipa-name %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE);
|
||||
config_write_msc_services(vty, " ", msc);
|
||||
}
|
||||
if (g_hlr->mslookup.server.local_attach_max_age != OSMO_DGSM_DEFAULT_LOCAL_ATTACH_MAX_AGE)
|
||||
vty_out(vty, " max-age %u%s",
|
||||
g_hlr->mslookup.server.local_attach_max_age, VTY_NEWLINE);
|
||||
|
||||
/* If the server is disabled, still output the above to not lose the service config. */
|
||||
if (!g_hlr->mslookup.server.enable)
|
||||
@@ -475,6 +550,12 @@ int config_write_mslookup(struct vty *vty)
|
||||
vty_out(vty, " mdns domain-suffix %s%s",
|
||||
g_hlr->mslookup.client.mdns.domain_suffix,
|
||||
VTY_NEWLINE);
|
||||
if (g_hlr->mslookup.client.result_timeout_milliseconds != OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS)
|
||||
vty_out(vty, " timeout %u%s",
|
||||
g_hlr->mslookup.client.result_timeout_milliseconds,
|
||||
VTY_NEWLINE);
|
||||
if (g_hlr->mslookup.client.subscr_create_on_demand_fallback)
|
||||
vty_out(vty, " create-on-demand-fallback%s", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
@@ -541,11 +622,110 @@ DEFUN(do_mslookup_show_services,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
struct proxy_subscr_listentry {
|
||||
struct llist_head entry;
|
||||
timestamp_t last_update;
|
||||
struct proxy_subscr data;
|
||||
};
|
||||
|
||||
struct proxy_pending_gsup_req {
|
||||
struct llist_head entry;
|
||||
struct osmo_gsup_req *req;
|
||||
timestamp_t received_at;
|
||||
};
|
||||
|
||||
static void write_one_proxy(struct vty *vty, struct proxy_subscr_listentry *e)
|
||||
{
|
||||
struct proxy_subscr p = e->data;
|
||||
uint32_t age;
|
||||
|
||||
vty_out(vty, "%-12s %-16s %-12s:%-4u ",
|
||||
strlen(p.msisdn) == 0 ? "Unknown" : p.msisdn,
|
||||
strlen(p.imsi) == 0 ? "Unknown" : p.imsi,
|
||||
p.remote_hlr_addr.ip ? p.remote_hlr_addr.ip : "Unknown",
|
||||
p.remote_hlr_addr.port);
|
||||
|
||||
if (!timestamp_age(&e->last_update, &age)) {
|
||||
vty_out(vty, "Invalid%s", VTY_NEWLINE);
|
||||
return;
|
||||
}
|
||||
|
||||
#define UNIT_AGO(UNITNAME, UNITVAL) \
|
||||
if (age >= (UNITVAL)) { \
|
||||
vty_out(vty, "%u%s", age / (UNITVAL), UNITNAME); \
|
||||
age = age % (UNITVAL); \
|
||||
}
|
||||
UNIT_AGO("d", 60*60*24);
|
||||
UNIT_AGO("h", 60*60);
|
||||
UNIT_AGO("m", 60);
|
||||
UNIT_AGO("s", 1);
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
#undef UNIT_AGO
|
||||
}
|
||||
|
||||
static void write_one_proxy_request(struct vty *vty, struct osmo_gsup_req *r)
|
||||
{
|
||||
vty_out(vty, "IMSI: %s TYPE: %s%s",
|
||||
r->gsup.imsi,
|
||||
osmo_gsup_message_type_name(r->gsup.message_type),
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(do_proxy_del_sub,
|
||||
do_proxy_del_sub_cmd,
|
||||
"proxy subscriber-delete [IMSI]",
|
||||
"Subscriber Proxy \n"
|
||||
"Delete by IMSI\n"
|
||||
"IMSI of subscriber to delete from the Proxy"
|
||||
)
|
||||
{
|
||||
const char *imsi = argv[0];
|
||||
if (!osmo_imsi_str_valid(imsi)) {
|
||||
vty_out(vty, "%% Not a valid IMSI: %s%s", imsi, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (proxy_subscr_del(g_hlr->gs->proxy, imsi) == 0)
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% Unable to delete a Proxy for: %s%s", imsi, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(do_proxy_show,
|
||||
do_proxy_show_cmd,
|
||||
"show proxy",
|
||||
SHOW_STR "Proxy Entries\n")
|
||||
{
|
||||
struct proxy_subscr_listentry *e;
|
||||
struct proxy_pending_gsup_req *p;
|
||||
unsigned int count = 0;
|
||||
|
||||
vty_out(vty, "MSISDN IMSI HLR AGE%s", VTY_NEWLINE);
|
||||
vty_out(vty, "------------ ---------------- -------------------- ------%s", VTY_NEWLINE);
|
||||
llist_for_each_entry(e, &g_hlr->gs->proxy->subscr_list, entry) {
|
||||
count++;
|
||||
write_one_proxy(vty, e);
|
||||
}
|
||||
|
||||
vty_out(vty, "%s%s",
|
||||
(count == 0) ? "% No proxy subscribers" : "", VTY_NEWLINE);
|
||||
if (!llist_count(&g_hlr->gs->proxy->pending_gsup_reqs))
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "In-flight Proxy Subscribers Requests:%s", VTY_NEWLINE);
|
||||
llist_for_each_entry(p, &g_hlr->gs->proxy->pending_gsup_reqs, entry) {
|
||||
write_one_proxy_request(vty, p->req);
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
void dgsm_vty_init(void)
|
||||
{
|
||||
install_element(CONFIG_NODE, &cfg_mslookup_cmd);
|
||||
|
||||
install_node(&mslookup_node, config_write_mslookup);
|
||||
install_element(MSLOOKUP_NODE, &cfg_mslookup_auth_imsi_only_cmd);
|
||||
install_element(MSLOOKUP_NODE, &cfg_mslookup_no_auth_imsi_only_cmd);
|
||||
install_element(MSLOOKUP_NODE, &cfg_mslookup_cod_cmd);
|
||||
install_element(MSLOOKUP_NODE, &cfg_mslookup_no_cod_cmd);
|
||||
install_element(MSLOOKUP_NODE, &cfg_mslookup_mdns_cmd);
|
||||
install_element(MSLOOKUP_NODE, &cfg_mslookup_mdns_domain_suffix_cmd);
|
||||
install_element(MSLOOKUP_NODE, &cfg_mslookup_no_mdns_cmd);
|
||||
@@ -559,6 +739,7 @@ void dgsm_vty_init(void)
|
||||
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_service_cmd);
|
||||
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_no_service_cmd);
|
||||
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_no_service_addr_cmd);
|
||||
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_max_age_cmd);
|
||||
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_cmd);
|
||||
|
||||
install_node(&mslookup_server_msc_node, NULL);
|
||||
@@ -569,6 +750,8 @@ void dgsm_vty_init(void)
|
||||
install_element(MSLOOKUP_NODE, &cfg_mslookup_client_cmd);
|
||||
install_element(MSLOOKUP_NODE, &cfg_mslookup_no_client_cmd);
|
||||
install_node(&mslookup_client_node, NULL);
|
||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_subscr_cod_fallback_cmd);
|
||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_subscr_cod_fallback_cmd);
|
||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_timeout_cmd);
|
||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_mdns_bind_cmd);
|
||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_mdns_domain_suffix_cmd);
|
||||
@@ -577,4 +760,6 @@ void dgsm_vty_init(void)
|
||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_gateway_proxy_cmd);
|
||||
|
||||
install_element_ve(&do_mslookup_show_services_cmd);
|
||||
install_element_ve(&do_proxy_show_cmd);
|
||||
install_element_ve(&do_proxy_del_sub_cmd);
|
||||
}
|
||||
|
||||
@@ -24,14 +24,16 @@
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/abis/ipa.h>
|
||||
#include <osmocom/abis/ipaccess.h>
|
||||
#include <osmocom/gsm/gsm48_ie.h>
|
||||
#include <osmocom/gsm/apn.h>
|
||||
#include <osmocom/gsm/protocol/ipaccess.h>
|
||||
#include <osmocom/gsm/ipa.h>
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
#include <osmocom/abis/ipa.h>
|
||||
|
||||
#include <osmocom/hlr/gsup_server.h>
|
||||
#include <osmocom/hlr/gsup_router.h>
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
|
||||
#define LOG_GSUP_CONN(conn, level, fmt, args...) \
|
||||
LOGP(DLGSUP, level, "GSUP peer %s: " fmt, \
|
||||
@@ -48,7 +50,7 @@ static void osmo_gsup_server_send(struct osmo_gsup_conn *conn,
|
||||
int proto_ext, struct msgb *msg_tx)
|
||||
{
|
||||
ipa_prepend_header_ext(msg_tx, proto_ext);
|
||||
ipa_msg_push_header(msg_tx, IPAC_PROTO_OSMO);
|
||||
ipa_prepend_header(msg_tx, IPAC_PROTO_OSMO);
|
||||
ipa_server_conn_send(conn->conn, msg_tx);
|
||||
}
|
||||
|
||||
@@ -179,11 +181,9 @@ static int osmo_gsup_server_read_cb(struct ipa_server_conn *conn,
|
||||
|
||||
if (hh->proto == IPAC_PROTO_IPACCESS) {
|
||||
rc = ipa_server_conn_ccm(conn, msg);
|
||||
if (rc < 0) {
|
||||
/* conn is already invalid here! */
|
||||
return -1;
|
||||
}
|
||||
msgb_free(msg);
|
||||
if (rc < 0) /* conn is already invalid here! */
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -317,43 +317,6 @@ static int osmo_gsup_server_closed_cb(struct ipa_server_conn *conn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct osmo_gsup_conn *c;
|
||||
struct osmo_gsup_conn *prev_conn;
|
||||
|
||||
c = llist_first_entry_or_null(clients, struct osmo_gsup_conn, list);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
static void update_fd_settings(int fd)
|
||||
{
|
||||
int ret;
|
||||
@@ -386,10 +349,9 @@ static int osmo_gsup_server_accept_cb(struct ipa_server_link *link, int fd)
|
||||
|
||||
/* link data structure with server structure */
|
||||
conn->server = gsups;
|
||||
osmo_gsup_server_add_conn(&gsups->clients, conn);
|
||||
llist_add_tail(&conn->list, &gsups->clients);
|
||||
|
||||
LOGP(DLGSUP, LOGL_INFO, "New GSUP client %s:%d (IND=%u)\n",
|
||||
conn->conn->addr, conn->conn->port, conn->auc_3g_ind);
|
||||
LOGP(DLGSUP, LOGL_INFO, "New GSUP client %s:%d\n", conn->conn->addr, conn->conn->port);
|
||||
|
||||
update_fd_settings(fd);
|
||||
|
||||
@@ -484,19 +446,16 @@ int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
|
||||
* \param[out] gsup The gsup message to populate.
|
||||
* \param[in] imsi The subscriber's IMSI.
|
||||
* \param[in] msisdn The subscriber's MSISDN.
|
||||
* \param[out] msisdn_enc A buffer large enough to store the MSISDN in encoded form.
|
||||
* \param[in] msisdn_enc_size Size of the buffer (must be >= OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN).
|
||||
* \param[out] apn_buf A buffer large enough to store an APN (required if cn_domain is OSMO_GSUP_CN_DOMAIN_PS).
|
||||
* \param[in] apn_buf_size Size of APN buffer (must be >= APN_MAXLEN).
|
||||
* \param[in] cn_domain The CN Domain of the subscriber connection.
|
||||
* \param[in] talloc_ctx To allocation memory for dynamic fields (msisdn, apn) in the gsup field
|
||||
* \returns 0 on success, and negative on error.
|
||||
*/
|
||||
int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
|
||||
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)
|
||||
enum osmo_gsup_cn_domain cn_domain,
|
||||
void *talloc_ctx)
|
||||
{
|
||||
int len;
|
||||
uint8_t *msisdn_buf = talloc_size(talloc_ctx, OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN);
|
||||
|
||||
OSMO_ASSERT(gsup);
|
||||
*gsup = (struct osmo_gsup_message){
|
||||
@@ -505,27 +464,29 @@ int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup,
|
||||
|
||||
osmo_strlcpy(gsup->imsi, imsi, sizeof(gsup->imsi));
|
||||
|
||||
if (msisdn_enc_size < OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN)
|
||||
return -ENOSPC;
|
||||
|
||||
OSMO_ASSERT(msisdn_enc);
|
||||
len = gsm48_encode_bcd_number(msisdn_enc, msisdn_enc_size, 0, msisdn);
|
||||
len = gsm48_encode_bcd_number(msisdn_buf, OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN, 0, msisdn);
|
||||
if (len < 1) {
|
||||
LOGP(DLGSUP, LOGL_ERROR, "%s: Error: cannot encode MSISDN '%s'\n", imsi, msisdn);
|
||||
return -ENOSPC;
|
||||
}
|
||||
gsup->msisdn_enc = msisdn_enc;
|
||||
gsup->msisdn_enc = msisdn_buf;
|
||||
gsup->msisdn_enc_len = len;
|
||||
|
||||
#pragma message "FIXME: deal with encoding the following data: gsup.hlr_enc"
|
||||
|
||||
gsup->cn_domain = cn_domain;
|
||||
if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS) {
|
||||
OSMO_ASSERT(apn_buf_size >= APN_MAXLEN);
|
||||
OSMO_ASSERT(apn_buf);
|
||||
/* FIXME: PDP infos - use more fine-grained access control
|
||||
instead of wildcard APN */
|
||||
osmo_gsup_configure_wildcard_apn(gsup, apn_buf, apn_buf_size);
|
||||
if (g_hlr->ps.pdp_profile.enabled) {
|
||||
OSMO_ASSERT(g_hlr->ps.pdp_profile.num_pdp_infos <= ARRAY_SIZE(g_hlr->ps.pdp_profile.pdp_infos));
|
||||
OSMO_ASSERT(g_hlr->ps.pdp_profile.num_pdp_infos <= ARRAY_SIZE(gsup->pdp_infos));
|
||||
memcpy(gsup->pdp_infos,
|
||||
g_hlr->ps.pdp_profile.pdp_infos,
|
||||
sizeof(struct osmo_gsup_pdp_info) * g_hlr->ps.pdp_profile.num_pdp_infos);
|
||||
gsup->num_pdp_infos = g_hlr->ps.pdp_profile.num_pdp_infos;
|
||||
} else {
|
||||
uint8_t *apn_buf = talloc_size(talloc_ctx, APN_MAXLEN);
|
||||
osmo_gsup_configure_wildcard_apn(gsup, apn_buf, APN_MAXLEN);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -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=2:0:2
|
||||
|
||||
AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include \
|
||||
$(TALLOC_CFLAGS) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOABIS_CFLAGS)
|
||||
@@ -11,6 +11,7 @@ lib_LTLIBRARIES = libosmo-gsup-client.la
|
||||
libosmo_gsup_client_la_SOURCES = \
|
||||
cni_peer_id.c \
|
||||
gsup_client.c \
|
||||
gsup_client_mux.c \
|
||||
gsup_req.c \
|
||||
$(NULL)
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* Author: Jacob Erlbeck
|
||||
* Author: Neels Hofmeyr
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
@@ -24,6 +26,7 @@
|
||||
#include <osmocom/gsupclient/gsup_client.h>
|
||||
|
||||
#include <osmocom/abis/ipa.h>
|
||||
#include <osmocom/gsm/ipa.h>
|
||||
#include <osmocom/gsm/oap_client.h>
|
||||
#include <osmocom/gsm/protocol/ipaccess.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
@@ -42,7 +45,7 @@ static void gsup_client_send_ping(struct osmo_gsup_client *gsupc)
|
||||
|
||||
msg->l2h = msgb_put(msg, 1);
|
||||
msg->l2h[0] = IPAC_MSGT_PING;
|
||||
ipa_msg_push_header(msg, IPAC_PROTO_IPACCESS);
|
||||
ipa_prepend_header(msg, IPAC_PROTO_IPACCESS);
|
||||
ipa_client_conn_send(gsupc->link, msg);
|
||||
}
|
||||
|
||||
@@ -112,7 +115,7 @@ static void client_send(struct osmo_gsup_client *gsupc, int proto_ext,
|
||||
struct msgb *msg_tx)
|
||||
{
|
||||
ipa_prepend_header_ext(msg_tx, proto_ext);
|
||||
ipa_msg_push_header(msg_tx, IPAC_PROTO_OSMO);
|
||||
ipa_prepend_header(msg_tx, IPAC_PROTO_OSMO);
|
||||
ipa_client_conn_send(gsupc->link, msg_tx);
|
||||
/* msg_tx is now queued and will be freed. */
|
||||
}
|
||||
@@ -304,7 +307,7 @@ struct osmo_gsup_client *osmo_gsup_client_create3(void *talloc_ctx, struct osmo_
|
||||
|
||||
OSMO_ASSERT(config->ipa_dev->unit_name);
|
||||
|
||||
gsupc = talloc_zero(talloc_ctx, struct osmo_gsup_client);
|
||||
gsupc = talloc(talloc_ctx, struct osmo_gsup_client);
|
||||
OSMO_ASSERT(gsupc);
|
||||
*gsupc = (struct osmo_gsup_client){
|
||||
.unit_name = (const char *)config->ipa_dev->unit_name, /* API backwards compat */
|
||||
@@ -447,3 +450,36 @@ struct msgb *osmo_gsup_client_msgb_alloc(void)
|
||||
{
|
||||
return msgb_alloc_headroom(4000, 64, __func__);
|
||||
}
|
||||
|
||||
void *osmo_gsup_client_get_data(const struct osmo_gsup_client *gsupc)
|
||||
{
|
||||
return gsupc->data;
|
||||
}
|
||||
|
||||
void osmo_gsup_client_set_data(struct osmo_gsup_client *gsupc, void *data)
|
||||
{
|
||||
gsupc->data = data;
|
||||
}
|
||||
|
||||
const char *osmo_gsup_client_get_rem_addr(const struct osmo_gsup_client *gsupc)
|
||||
{
|
||||
if (!gsupc->link)
|
||||
return NULL;
|
||||
return gsupc->link->addr;
|
||||
}
|
||||
uint16_t osmo_gsup_client_get_rem_port(const struct osmo_gsup_client *gsupc)
|
||||
{
|
||||
if (!gsupc->link)
|
||||
return 0;
|
||||
return gsupc->link->port;
|
||||
}
|
||||
|
||||
bool osmo_gsup_client_is_connected(const struct osmo_gsup_client *gsupc)
|
||||
{
|
||||
return gsupc->is_connected;
|
||||
}
|
||||
|
||||
const struct ipaccess_unit *osmo_gsup_client_get_ipaccess_unit(const struct osmo_gsup_client *gsupc)
|
||||
{
|
||||
return gsupc->ipa_dev;
|
||||
}
|
||||
|
||||
196
src/gsupclient/gsup_client_mux.c
Normal file
196
src/gsupclient/gsup_client_mux.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/* Directing individual GSUP messages to their respective handlers. */
|
||||
/*
|
||||
* (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Author: Neels Hofmeyr
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include <osmocom/gsupclient/gsup_client.h>
|
||||
#include <osmocom/gsupclient/gsup_client_mux.h>
|
||||
|
||||
static enum osmo_gsup_message_class gsup_client_mux_classify(struct gsup_client_mux *gcm,
|
||||
const struct osmo_gsup_message *gsup_msg)
|
||||
{
|
||||
if (gsup_msg->message_class)
|
||||
return gsup_msg->message_class;
|
||||
|
||||
LOGP(DLGSUP, LOGL_DEBUG, "No explicit GSUP Message Class, trying to guess from message type %s\n",
|
||||
osmo_gsup_message_type_name(gsup_msg->message_type));
|
||||
|
||||
switch (gsup_msg->message_type) {
|
||||
case OSMO_GSUP_MSGT_PROC_SS_REQUEST:
|
||||
case OSMO_GSUP_MSGT_PROC_SS_RESULT:
|
||||
case OSMO_GSUP_MSGT_PROC_SS_ERROR:
|
||||
return OSMO_GSUP_MESSAGE_CLASS_USSD;
|
||||
|
||||
/* GSM 04.11 code implementing MO SMS */
|
||||
case OSMO_GSUP_MSGT_MO_FORWARD_SM_ERROR:
|
||||
case OSMO_GSUP_MSGT_MO_FORWARD_SM_RESULT:
|
||||
case OSMO_GSUP_MSGT_READY_FOR_SM_ERROR:
|
||||
case OSMO_GSUP_MSGT_READY_FOR_SM_RESULT:
|
||||
case OSMO_GSUP_MSGT_MT_FORWARD_SM_REQUEST:
|
||||
return OSMO_GSUP_MESSAGE_CLASS_SMS;
|
||||
|
||||
default:
|
||||
return OSMO_GSUP_MESSAGE_CLASS_SUBSCRIBER_MANAGEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Non-static for unit tests */
|
||||
int gsup_client_mux_rx(struct osmo_gsup_client *gsup_client, struct msgb *msg)
|
||||
{
|
||||
struct gsup_client_mux *gcm = osmo_gsup_client_get_data(gsup_client);
|
||||
struct osmo_gsup_message gsup;
|
||||
enum osmo_gsup_message_class message_class;
|
||||
int rc;
|
||||
|
||||
rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup);
|
||||
if (rc < 0) {
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Failed to decode GSUP message: '%s' (%d) [ %s]\n",
|
||||
get_value_string(gsm48_gmm_cause_names, -rc), -rc, osmo_hexdump(msg->data, msg->len));
|
||||
goto msgb_free_and_return;
|
||||
}
|
||||
|
||||
if (!gsup.imsi[0]) {
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Failed to decode GSUP message: missing IMSI\n");
|
||||
if (OSMO_GSUP_IS_MSGT_REQUEST(gsup.message_type))
|
||||
gsup_client_mux_tx_error_reply(gcm, &gsup, GMM_CAUSE_INV_MAND_INFO);
|
||||
rc = -GMM_CAUSE_INV_MAND_INFO;
|
||||
goto msgb_free_and_return;
|
||||
}
|
||||
|
||||
message_class = gsup_client_mux_classify(gcm, &gsup);
|
||||
|
||||
if (message_class <= OSMO_GSUP_MESSAGE_CLASS_UNSET || message_class >= ARRAY_SIZE(gcm->rx_cb)) {
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Failed to classify GSUP message target\n");
|
||||
rc = -EINVAL;
|
||||
goto msgb_free_and_return;
|
||||
}
|
||||
|
||||
if (!gcm->rx_cb[message_class].func) {
|
||||
LOGP(DLGSUP, LOGL_ERROR, "No receiver set up for GSUP Message Class %s\n", osmo_gsup_message_class_name(message_class));
|
||||
rc = -ENOTSUP;
|
||||
goto msgb_free_and_return;
|
||||
}
|
||||
|
||||
rc = gcm->rx_cb[message_class].func(gcm, gcm->rx_cb[message_class].data, &gsup);
|
||||
|
||||
msgb_free_and_return:
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Make it clear that struct gsup_client_mux should be talloc allocated, so that it can be used as talloc parent. */
|
||||
struct gsup_client_mux *gsup_client_mux_alloc(void *talloc_ctx)
|
||||
{
|
||||
return talloc_zero(talloc_ctx, struct gsup_client_mux);
|
||||
}
|
||||
|
||||
/* Start a GSUP client to serve this gsup_client_mux. */
|
||||
int gsup_client_mux_start(struct gsup_client_mux *gcm, const char *gsup_server_addr_str, uint16_t gsup_server_port,
|
||||
struct ipaccess_unit *ipa_dev)
|
||||
{
|
||||
gcm->gsup_client = osmo_gsup_client_create2(gcm, ipa_dev,
|
||||
gsup_server_addr_str,
|
||||
gsup_server_port,
|
||||
&gsup_client_mux_rx, NULL);
|
||||
if (!gcm->gsup_client)
|
||||
return -ENOMEM;
|
||||
osmo_gsup_client_set_data(gcm->gsup_client, gcm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gsup_client_mux_tx(struct gsup_client_mux *gcm, const struct osmo_gsup_message *gsup_msg)
|
||||
{
|
||||
struct msgb *msg;
|
||||
int rc;
|
||||
|
||||
if (!gcm || !gcm->gsup_client) {
|
||||
LOGP(DLGSUP, LOGL_ERROR, "GSUP link is down, cannot send GSUP message\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
msg = osmo_gsup_client_msgb_alloc();
|
||||
rc = osmo_gsup_encode(msg, gsup_msg);
|
||||
if (rc < 0) {
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Failed to encode GSUP message: '%s'\n", strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
return osmo_gsup_client_send(gcm->gsup_client, msg);
|
||||
}
|
||||
|
||||
/* Set GSUP source_name to our local IPA name */
|
||||
void gsup_client_mux_tx_set_source(const struct gsup_client_mux *gcm,
|
||||
struct osmo_gsup_message *gsup_msg)
|
||||
{
|
||||
const char *local_msc_name;
|
||||
const struct ipaccess_unit *ipa_dev;
|
||||
|
||||
if (!gcm)
|
||||
return;
|
||||
if (!gcm->gsup_client)
|
||||
return;
|
||||
ipa_dev = osmo_gsup_client_get_ipaccess_unit(gcm->gsup_client);
|
||||
if (!ipa_dev)
|
||||
return;
|
||||
local_msc_name = ipa_dev->serno;
|
||||
if (!local_msc_name)
|
||||
return;
|
||||
gsup_msg->source_name = (const uint8_t *) local_msc_name;
|
||||
gsup_msg->source_name_len = strlen(local_msc_name) + 1;
|
||||
}
|
||||
|
||||
/* Transmit GSUP error in response to original message */
|
||||
void gsup_client_mux_tx_error_reply(struct gsup_client_mux *gcm, const struct osmo_gsup_message *gsup_orig,
|
||||
enum gsm48_gmm_cause cause)
|
||||
{
|
||||
struct osmo_gsup_message gsup_reply;
|
||||
|
||||
/* No need to answer if we couldn't parse an ERROR message type, only REQUESTs need an error reply. */
|
||||
if (!OSMO_GSUP_IS_MSGT_REQUEST(gsup_orig->message_type))
|
||||
return;
|
||||
|
||||
gsup_reply = (struct osmo_gsup_message){
|
||||
.cause = cause,
|
||||
.message_type = OSMO_GSUP_TO_MSGT_ERROR(gsup_orig->message_type),
|
||||
.message_class = gsup_orig->message_class,
|
||||
.destination_name = gsup_orig->source_name,
|
||||
.destination_name_len = gsup_orig->source_name_len,
|
||||
|
||||
/* RP-Message-Reference is mandatory for SM Service */
|
||||
.sm_rp_mr = gsup_orig->sm_rp_mr,
|
||||
};
|
||||
|
||||
OSMO_STRLCPY_ARRAY(gsup_reply.imsi, gsup_orig->imsi);
|
||||
gsup_client_mux_tx_set_source(gcm, &gsup_reply);
|
||||
|
||||
/* For SS/USSD, it's important to keep both session state and ID IEs */
|
||||
if (gsup_orig->session_state != OSMO_GSUP_SESSION_STATE_NONE) {
|
||||
gsup_reply.session_state = OSMO_GSUP_SESSION_STATE_END;
|
||||
gsup_reply.session_id = gsup_orig->session_id;
|
||||
}
|
||||
|
||||
if (osmo_gsup_client_enc_send(gcm->gsup_client, &gsup_reply))
|
||||
LOGP(DLGSUP, LOGL_ERROR, "Failed to send Error reply (imsi=%s)\n",
|
||||
osmo_quote_str(gsup_orig->imsi, -1));
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
|
||||
88
src/hlr.c
88
src/hlr.c
@@ -49,6 +49,7 @@
|
||||
#include <osmocom/hlr/rand.h>
|
||||
#include <osmocom/hlr/hlr_vty.h>
|
||||
#include <osmocom/hlr/hlr_ussd.h>
|
||||
#include <osmocom/hlr/hlr_sms.h>
|
||||
#include <osmocom/hlr/dgsm.h>
|
||||
#include <osmocom/hlr/proxy.h>
|
||||
#include <osmocom/hlr/lu_fsm.h>
|
||||
@@ -85,8 +86,6 @@ osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
|
||||
|
||||
llist_for_each_entry(co, &g_hlr->gs->clients, list) {
|
||||
struct osmo_gsup_message gsup = { };
|
||||
uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];
|
||||
uint8_t apn[APN_MAXLEN];
|
||||
struct msgb *msg_out;
|
||||
uint8_t *peer;
|
||||
int peer_len;
|
||||
@@ -131,8 +130,7 @@ osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
|
||||
subscr->imsi, cn_domain == OSMO_GSUP_CN_DOMAIN_PS ? "PS" : "CS",
|
||||
osmo_quote_str(peer_compare, -1));
|
||||
|
||||
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi, subscr->msisdn, msisdn_enc,
|
||||
sizeof(msisdn_enc), apn, sizeof(apn), cn_domain) != 0) {
|
||||
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi, subscr->msisdn, cn_domain, OTC_SELECT) != 0) {
|
||||
LOGP(DLGSUP, LOGL_ERROR,
|
||||
"IMSI='%s': Cannot notify GSUP client; could not create gsup message "
|
||||
"for %s:%u\n", subscr->imsi,
|
||||
@@ -206,23 +204,34 @@ static int subscr_create_on_demand(const char *imsi)
|
||||
{
|
||||
char msisdn[GSM23003_MSISDN_MAX_DIGITS + 1];
|
||||
int rc;
|
||||
unsigned int rand_msisdn_len = g_hlr->subscr_create_on_demand_rand_msisdn_len;
|
||||
|
||||
if (!g_hlr->subscr_create_on_demand)
|
||||
return -1;
|
||||
if (db_subscr_exists_by_imsi(g_hlr->dbc, imsi) == 0)
|
||||
return -1;
|
||||
if (rand_msisdn_len && generate_new_msisdn(msisdn, imsi, rand_msisdn_len) != 0)
|
||||
|
||||
switch (g_hlr->subscr_create_on_demand.mode) {
|
||||
case SUBSCR_COD_MODE_MSISDN_FROM_IMSI:
|
||||
OSMO_STRLCPY_ARRAY(msisdn, imsi);
|
||||
break;
|
||||
case SUBSCR_COD_MODE_RAND_MSISDN:
|
||||
if (generate_new_msisdn(msisdn, imsi, g_hlr->subscr_create_on_demand.rand_msisdn_len) != 0)
|
||||
return -1;
|
||||
break;
|
||||
case SUBSCR_COD_MODE_NO_MSISDN:
|
||||
msisdn[0] = '\0';
|
||||
break;
|
||||
case SUBSCR_COD_MODE_DISABLED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGP(DMAIN, LOGL_INFO, "IMSI='%s': Creating subscriber on demand\n", imsi);
|
||||
rc = db_subscr_create(g_hlr->dbc, imsi, g_hlr->subscr_create_on_demand_flags);
|
||||
rc = db_subscr_create(g_hlr->dbc, imsi, g_hlr->subscr_create_on_demand.flags);
|
||||
if (rc) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "Failed to create subscriber on demand (rc=%d): IMSI='%s'\n", rc, imsi);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!rand_msisdn_len)
|
||||
if (msisdn[0] == '\0')
|
||||
return 0;
|
||||
|
||||
/* Update MSISDN of the new (just allocated) subscriber */
|
||||
@@ -281,13 +290,14 @@ int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val,
|
||||
***********************************************************************/
|
||||
|
||||
/* process an incoming SAI request */
|
||||
static int rx_send_auth_info(unsigned int auc_3g_ind, struct osmo_gsup_req *req)
|
||||
static int rx_send_auth_info(struct osmo_gsup_req *req)
|
||||
{
|
||||
struct osmo_gsup_message gsup_out = {
|
||||
.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT,
|
||||
};
|
||||
bool separation_bit = false;
|
||||
int num_auth_vectors = OSMO_GSUP_MAX_NUM_AUTH_INFO;
|
||||
unsigned int auc_3g_ind;
|
||||
int rc;
|
||||
|
||||
subscr_create_on_demand(req->gsup.imsi);
|
||||
@@ -298,6 +308,14 @@ static int rx_send_auth_info(unsigned int auc_3g_ind, struct osmo_gsup_req *req)
|
||||
if (req->gsup.num_auth_vectors > 0 &&
|
||||
req->gsup.num_auth_vectors <= OSMO_GSUP_MAX_NUM_AUTH_INFO)
|
||||
num_auth_vectors = req->gsup.num_auth_vectors;
|
||||
rc = db_ind(g_hlr->dbc, &req->source_name, &auc_3g_ind);
|
||||
if (rc) {
|
||||
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);
|
||||
auc_3g_ind = 0;
|
||||
}
|
||||
|
||||
rc = db_get_auc(g_hlr->dbc, req->gsup.imsi, auc_3g_ind,
|
||||
gsup_out.auth_vectors,
|
||||
@@ -315,7 +333,11 @@ static int rx_send_auth_info(unsigned int auc_3g_ind, struct osmo_gsup_req *req)
|
||||
" Returning slightly inaccurate cause 'IMSI Unknown' via GSUP");
|
||||
return rc;
|
||||
case -ENOENT:
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "IMSI unknown");
|
||||
osmo_gsup_req_respond_err(req,
|
||||
(req->gsup.cn_domain == OSMO_GSUP_CN_DOMAIN_CS) ?
|
||||
g_hlr->no_proxy_reject_cause.cs :
|
||||
g_hlr->no_proxy_reject_cause.ps,
|
||||
"IMSI unknown");
|
||||
return rc;
|
||||
default:
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "failure to look up IMSI in db");
|
||||
@@ -373,7 +395,7 @@ static int rx_purge_ms_req(struct osmo_gsup_req *req)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int rx_check_imei_req(struct osmo_gsup_req *req)
|
||||
static int rx_check_imei_req(struct osmo_gsup_req *req, bool final)
|
||||
{
|
||||
struct osmo_gsup_message gsup_reply;
|
||||
char imei[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1] = {0};
|
||||
@@ -427,7 +449,7 @@ static int rx_check_imei_req(struct osmo_gsup_req *req)
|
||||
.message_type = OSMO_GSUP_MSGT_CHECK_IMEI_RESULT,
|
||||
.imei_result = OSMO_GSUP_IMEI_RESULT_ACK,
|
||||
};
|
||||
return osmo_gsup_req_respond(req, &gsup_reply, false, true);
|
||||
return osmo_gsup_req_respond(req, &gsup_reply, false, final);
|
||||
}
|
||||
|
||||
static char namebuf[255];
|
||||
@@ -517,7 +539,7 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
|
||||
switch (req->gsup.message_type) {
|
||||
/* requests sent to us */
|
||||
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:
|
||||
rx_send_auth_info(conn->auc_3g_ind, req);
|
||||
rx_send_auth_info(req);
|
||||
break;
|
||||
case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST:
|
||||
rx_upd_loc_req(conn, req);
|
||||
@@ -548,7 +570,16 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
|
||||
lu_rx_gsup(req);
|
||||
break;
|
||||
case OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST:
|
||||
rx_check_imei_req(req);
|
||||
rx_check_imei_req(req, true);
|
||||
break;
|
||||
case OSMO_GSUP_MSGT_MO_FORWARD_SM_REQUEST:
|
||||
forward_mo_sms(req);
|
||||
break;
|
||||
case OSMO_GSUP_MSGT_MT_FORWARD_SM_REQUEST:
|
||||
forward_mt_sms(req);
|
||||
break;
|
||||
case OSMO_GSUP_MSGT_READY_FOR_SM_REQUEST:
|
||||
rx_ready_for_sm_req(req);
|
||||
break;
|
||||
default:
|
||||
LOGP(DMAIN, LOGL_DEBUG, "Unhandled GSUP message type %s\n",
|
||||
@@ -559,12 +590,18 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_usage()
|
||||
void dgsm_fallback_to_hlr(struct osmo_gsup_req *req) {
|
||||
LOGP(DDGSM, LOGL_DEBUG, "Fall back to HLR from DGSM for [%s]\n",
|
||||
osmo_gsup_message_type_name(req->gsup.message_type));
|
||||
rx_check_imei_req(req, false);
|
||||
}
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
printf("Usage: osmo-hlr\n");
|
||||
}
|
||||
|
||||
static void print_help()
|
||||
static void print_help(void)
|
||||
{
|
||||
printf(" -h --help This text.\n");
|
||||
printf(" -c --config-file filename The config file to use.\n");
|
||||
@@ -718,7 +755,7 @@ static void signal_hdlr(int signal)
|
||||
}
|
||||
|
||||
static const char vlr_copyright[] =
|
||||
"Copyright (C) 2016, 2017 by Harald Welte, sysmocom s.f.m.c. GmbH\r\n"
|
||||
"Copyright (C) 2016-2023 by Harald Welte, sysmocom s.f.m.c. GmbH\r\n"
|
||||
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
|
||||
"This is free software: you are free to change and redistribute it.\r\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\r\n";
|
||||
@@ -727,7 +764,6 @@ static struct vty_app_info vty_info = {
|
||||
.name = "OsmoHLR",
|
||||
.version = PACKAGE_VERSION,
|
||||
.copyright = vlr_copyright,
|
||||
.is_config_node = hlr_vty_is_config_node,
|
||||
.go_parent_cb = hlr_vty_go_parent,
|
||||
};
|
||||
|
||||
@@ -744,12 +780,18 @@ int main(int argc, char **argv)
|
||||
|
||||
g_hlr = talloc_zero(hlr_ctx, struct hlr);
|
||||
INIT_LLIST_HEAD(&g_hlr->euse_list);
|
||||
INIT_LLIST_HEAD(&g_hlr->smsc_list);
|
||||
INIT_LLIST_HEAD(&g_hlr->ss_sessions);
|
||||
INIT_LLIST_HEAD(&g_hlr->ussd_routes);
|
||||
INIT_LLIST_HEAD(&g_hlr->smsc_routes);
|
||||
INIT_LLIST_HEAD(&g_hlr->mslookup.server.local_site_services);
|
||||
g_hlr->db_file_path = talloc_strdup(g_hlr, HLR_DEFAULT_DB_FILE_PATH);
|
||||
g_hlr->mslookup.server.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT);
|
||||
g_hlr->mslookup.client.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT);
|
||||
g_hlr->reject_cause.cs = GMM_CAUSE_PLMN_NOTALLOWED;
|
||||
g_hlr->no_proxy_reject_cause.cs = GMM_CAUSE_PLMN_NOTALLOWED;
|
||||
g_hlr->reject_cause.ps = GMM_CAUSE_NET_FAIL;
|
||||
g_hlr->no_proxy_reject_cause.ps = GMM_CAUSE_NET_FAIL;
|
||||
|
||||
/* Init default (call independent) SS session guard timeout value */
|
||||
g_hlr->ncss_guard_timeout = NCSS_GUARD_TIMEOUT_DEFAULT;
|
||||
@@ -766,7 +808,7 @@ int main(int argc, char **argv)
|
||||
osmo_stats_init(hlr_ctx);
|
||||
vty_init(&vty_info);
|
||||
ctrl_vty_init(hlr_ctx);
|
||||
hlr_vty_init();
|
||||
hlr_vty_init(hlr_ctx);
|
||||
dgsm_vty_init();
|
||||
osmo_cpu_sched_vty_init(hlr_ctx);
|
||||
handle_options(argc, argv);
|
||||
@@ -807,8 +849,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* start telnet after reading config for vty_get_bind_addr() */
|
||||
rc = telnet_init_dynif(hlr_ctx, NULL, vty_get_bind_addr(),
|
||||
OSMO_VTY_PORT_HLR);
|
||||
rc = telnet_init_default(hlr_ctx, NULL, OSMO_VTY_PORT_HLR);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@@ -821,7 +862,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
proxy_init(g_hlr->gs);
|
||||
|
||||
g_hlr->ctrl_bind_addr = ctrl_vty_get_bind_addr();
|
||||
g_hlr->ctrl = hlr_controlif_setup(g_hlr);
|
||||
|
||||
dgsm_start(hlr_ctx);
|
||||
|
||||
@@ -51,7 +51,7 @@ static struct {
|
||||
.db_upgrade = false,
|
||||
};
|
||||
|
||||
static void print_help()
|
||||
static void print_help(void)
|
||||
{
|
||||
printf("\n");
|
||||
printf("Usage: osmo-hlr-db-tool [-l <hlr.db>] [create|import-nitb-db <nitb.db>]\n");
|
||||
|
||||
276
src/hlr_sms.c
Normal file
276
src/hlr_sms.c
Normal file
@@ -0,0 +1,276 @@
|
||||
/* OsmoHLR SMS-over-GSUP routing implementation */
|
||||
|
||||
/* Author: Mychaela N. Falconia <falcon@freecalypso.org>, 2023 - however,
|
||||
* Mother Mychaela's contributions are NOT subject to copyright.
|
||||
* No rights reserved, all rights relinquished.
|
||||
*
|
||||
* Based on earlier unmerged work by Vadim Yanitskiy, 2019.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
#include <osmocom/gsm/gsm48_ie.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_11.h>
|
||||
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/hlr_sms.h>
|
||||
#include <osmocom/hlr/gsup_server.h>
|
||||
#include <osmocom/hlr/gsup_router.h>
|
||||
#include <osmocom/hlr/logging.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
|
||||
/***********************************************************************
|
||||
* core data structures expressing config from VTY
|
||||
***********************************************************************/
|
||||
|
||||
struct hlr_smsc *smsc_find(struct hlr *hlr, const char *name)
|
||||
{
|
||||
struct hlr_smsc *smsc;
|
||||
|
||||
llist_for_each_entry(smsc, &hlr->smsc_list, list) {
|
||||
if (!strcmp(smsc->name, name))
|
||||
return smsc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct hlr_smsc *smsc_alloc(struct hlr *hlr, const char *name)
|
||||
{
|
||||
struct hlr_smsc *smsc = smsc_find(hlr, name);
|
||||
if (smsc)
|
||||
return NULL;
|
||||
|
||||
smsc = talloc_zero(hlr, struct hlr_smsc);
|
||||
smsc->name = talloc_strdup(smsc, name);
|
||||
smsc->hlr = hlr;
|
||||
llist_add_tail(&smsc->list, &hlr->smsc_list);
|
||||
|
||||
return smsc;
|
||||
}
|
||||
|
||||
void smsc_free(struct hlr_smsc *smsc)
|
||||
{
|
||||
llist_del(&smsc->list);
|
||||
talloc_free(smsc);
|
||||
}
|
||||
|
||||
struct hlr_smsc_route *smsc_route_find(struct hlr *hlr, const char *num_addr)
|
||||
{
|
||||
struct hlr_smsc_route *rt;
|
||||
|
||||
llist_for_each_entry(rt, &hlr->smsc_routes, list) {
|
||||
if (!strcmp(rt->num_addr, num_addr))
|
||||
return rt;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct hlr_smsc_route *smsc_route_alloc(struct hlr *hlr, const char *num_addr,
|
||||
struct hlr_smsc *smsc)
|
||||
{
|
||||
struct hlr_smsc_route *rt;
|
||||
|
||||
if (smsc_route_find(hlr, num_addr))
|
||||
return NULL;
|
||||
|
||||
rt = talloc_zero(hlr, struct hlr_smsc_route);
|
||||
rt->num_addr = talloc_strdup(rt, num_addr);
|
||||
rt->smsc = smsc;
|
||||
llist_add_tail(&rt->list, &hlr->smsc_routes);
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
void smsc_route_free(struct hlr_smsc_route *rt)
|
||||
{
|
||||
llist_del(&rt->list);
|
||||
talloc_free(rt);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* forwarding of MO SMS to SMSCs based on SM-RP-DA
|
||||
***********************************************************************/
|
||||
|
||||
static const struct hlr_smsc *find_smsc_route(const char *smsc_addr)
|
||||
{
|
||||
const struct hlr_smsc_route *rt;
|
||||
|
||||
rt = smsc_route_find(g_hlr, smsc_addr);
|
||||
if (rt)
|
||||
return rt->smsc;
|
||||
return g_hlr->smsc_default;
|
||||
}
|
||||
|
||||
static void respond_with_sm_rp_cause(struct osmo_gsup_req *req,
|
||||
uint8_t sm_rp_cause)
|
||||
{
|
||||
struct osmo_gsup_message rsp_msg = { };
|
||||
|
||||
rsp_msg.sm_rp_cause = &sm_rp_cause;
|
||||
osmo_gsup_req_respond(req, &rsp_msg, true, true);
|
||||
}
|
||||
|
||||
/* Short Message from MSC/VLR towards SMSC */
|
||||
void forward_mo_sms(struct osmo_gsup_req *req)
|
||||
{
|
||||
uint8_t gsm48_decode_buffer[GSM411_SMSC_ADDR_MAX_OCTETS];
|
||||
char smsc_addr[GSM411_SMSC_ADDR_MAX_DIGITS+1];
|
||||
const struct hlr_smsc *smsc;
|
||||
struct osmo_cni_peer_id dest_peer;
|
||||
|
||||
/* Make sure SM-RP-DA (SMSC address) is present */
|
||||
if (req->gsup.sm_rp_da == NULL || !req->gsup.sm_rp_da_len) {
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO,
|
||||
"missing SM-RP-DA");
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->gsup.sm_rp_da_type != OSMO_GSUP_SMS_SM_RP_ODA_SMSC_ADDR) {
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO,
|
||||
"SM-RP-DA type is not SMSC");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enforce the length constrainst on SM-RP-DA, as specified in
|
||||
* GSM 04.11 section 8.2.5.2. Also enforce absence of ToN/NPI
|
||||
* extension octets at the same time. */
|
||||
if (req->gsup.sm_rp_da_len < GSM411_SMSC_ADDR_MIN_OCTETS ||
|
||||
req->gsup.sm_rp_da_len > GSM411_SMSC_ADDR_MAX_OCTETS ||
|
||||
!(req->gsup.sm_rp_da[0] & 0x80)) {
|
||||
/* This form of bogosity originates from the MS,
|
||||
* not from OsmoMSC or any other Osmocom network elements! */
|
||||
LOGP(DLSMS, LOGL_NOTICE,
|
||||
"Rx '%s' (IMSI-%s) contains invalid SM-RP-DA from MS\n",
|
||||
osmo_gsup_message_type_name(req->gsup.message_type),
|
||||
req->gsup.imsi);
|
||||
respond_with_sm_rp_cause(req, GSM411_RP_CAUSE_SEMANT_INC_MSG);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decode SMSC address from SM-RP-DA */
|
||||
gsm48_decode_buffer[0] = req->gsup.sm_rp_da_len - 1;
|
||||
memcpy(gsm48_decode_buffer + 1, req->gsup.sm_rp_da + 1,
|
||||
req->gsup.sm_rp_da_len - 1);
|
||||
gsm48_decode_bcd_number2(smsc_addr, sizeof(smsc_addr),
|
||||
gsm48_decode_buffer,
|
||||
req->gsup.sm_rp_da_len, 0);
|
||||
|
||||
/* Look for a route to this SMSC */
|
||||
smsc = find_smsc_route(smsc_addr);
|
||||
if (smsc == NULL) {
|
||||
LOGP(DLSMS, LOGL_NOTICE,
|
||||
"Failed to find a route for '%s' (IMSI-%s, SMSC-Addr-%s)\n",
|
||||
osmo_gsup_message_type_name(req->gsup.message_type),
|
||||
req->gsup.imsi, smsc_addr);
|
||||
respond_with_sm_rp_cause(req,
|
||||
GSM411_RP_CAUSE_MO_NUM_UNASSIGNED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We got the IPA name of our SMSC - forward the message */
|
||||
osmo_cni_peer_id_set(&dest_peer, OSMO_CNI_PEER_ID_IPA_NAME,
|
||||
(const uint8_t *) smsc->name,
|
||||
strlen(smsc->name) + 1);
|
||||
osmo_gsup_forward_to_local_peer(req->cb_data, &dest_peer, req, NULL);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* forwarding of MT SMS from SMSCs to MSC/VLR based on IMSI
|
||||
***********************************************************************/
|
||||
|
||||
void forward_mt_sms(struct osmo_gsup_req *req)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct osmo_cni_peer_id dest_peer;
|
||||
int rc;
|
||||
|
||||
rc = db_subscr_get_by_imsi(g_hlr->dbc, req->gsup.imsi, &subscr);
|
||||
if (rc < 0) {
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN,
|
||||
"IMSI unknown");
|
||||
return;
|
||||
}
|
||||
/* is this subscriber currently attached to a VLR? */
|
||||
if (!subscr.vlr_number[0]) {
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMPL_DETACHED,
|
||||
"subscriber not attached to a VLR");
|
||||
return;
|
||||
}
|
||||
osmo_cni_peer_id_set(&dest_peer, OSMO_CNI_PEER_ID_IPA_NAME,
|
||||
(const uint8_t *) subscr.vlr_number,
|
||||
strlen(subscr.vlr_number) + 1);
|
||||
osmo_gsup_forward_to_local_peer(req->cb_data, &dest_peer, req, NULL);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* READY-FOR-SM handling
|
||||
*
|
||||
* An MSC indicates that an MS is ready to receive messages. If one
|
||||
* or more SMSCs have previously tried to send MT SMS to this MS and
|
||||
* failed, we should pass this READY-FOR-SM message to them so they
|
||||
* can resend their queued SMS right away. But which SMSC do we
|
||||
* forward the message to? 3GPP specs call for a complicated system
|
||||
* where the HLR remembers which SMSCs have tried and failed to deliver
|
||||
* MT SMS, and those SMSCs then get notified - but that design is too
|
||||
* much complexity for the current state of Osmocom. So we keep it
|
||||
* simple: we iterate over all configured SMSCs and forward a copy
|
||||
* of the READY-FOR-SM.req message to each.
|
||||
*
|
||||
* Routing of responses is another problem: the MSC that sent
|
||||
* READY-FOR-SM.req expects only one response, and one can even argue
|
||||
* that the operation is a "success" from the perspective of the MS
|
||||
* irrespective of whether each given SMSC handled the notification
|
||||
* successfully or not. Hence our approach: we always return success
|
||||
* to the MS, and when we forward copies of READY-FOR-SM.req to SMSCs,
|
||||
* we list the HLR as the message source - this way SMSC responses
|
||||
* will terminate at this HLR and won't be forwarded to the MSC.
|
||||
***********************************************************************/
|
||||
|
||||
static void forward_req_copy_to_smsc(const struct osmo_gsup_req *req,
|
||||
const struct hlr_smsc *smsc)
|
||||
{
|
||||
const char *my_ipa_name = g_hlr->gsup_unit_name.serno;
|
||||
struct osmo_gsup_message forward = req->gsup;
|
||||
struct osmo_ipa_name smsc_ipa_name;
|
||||
|
||||
/* set the source to this HLR */
|
||||
forward.source_name = (const uint8_t *) my_ipa_name;
|
||||
forward.source_name_len = strlen(my_ipa_name) + 1;
|
||||
|
||||
/* send it off */
|
||||
LOG_GSUP_REQ(req, LOGL_INFO, "Forwarding source-reset copy to %s\n",
|
||||
smsc->name);
|
||||
osmo_ipa_name_set(&smsc_ipa_name, (const uint8_t *) smsc->name,
|
||||
strlen(smsc->name) + 1);
|
||||
osmo_gsup_enc_send_to_ipa_name(g_hlr->gs, &smsc_ipa_name, &forward);
|
||||
}
|
||||
|
||||
void rx_ready_for_sm_req(struct osmo_gsup_req *req)
|
||||
{
|
||||
struct hlr_smsc *smsc;
|
||||
|
||||
/* fan request msg out to all SMSCs */
|
||||
llist_for_each_entry(smsc, &g_hlr->smsc_list, list)
|
||||
forward_req_copy_to_smsc(req, smsc);
|
||||
|
||||
/* send OK response to the MSC and the MS */
|
||||
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_READY_FOR_SM_RESULT,
|
||||
true);
|
||||
}
|
||||
@@ -122,9 +122,40 @@ void ussd_route_del(struct hlr_ussd_route *rt)
|
||||
talloc_free(rt);
|
||||
}
|
||||
|
||||
static struct hlr_ussd_route *ussd_route_lookup_7bit(struct hlr *hlr, const char *ussd_code)
|
||||
static struct hlr_ussd_route *ussd_route_lookup_for_req(struct hlr *hlr, const struct ss_request *req)
|
||||
{
|
||||
const uint8_t cgroup = req->ussd_data_dcs >> 4;
|
||||
const uint8_t lang = req->ussd_data_dcs & 0x0f;
|
||||
char ussd_code[GSM0480_USSD_7BIT_STRING_LEN];
|
||||
struct hlr_ussd_route *rt;
|
||||
|
||||
ussd_code[0] = '\0';
|
||||
|
||||
/* We support only the Coding Group 0 (GSM 7-bit default alphabeet). In fact,
|
||||
* the USSD request is usually limited to [*#0-9], so we don't really need to
|
||||
* support other coding groups and languages. */
|
||||
switch (cgroup) {
|
||||
case 0:
|
||||
/* The Language is usually set to '1111'B (unspecified), but some UEs
|
||||
* are known to indicate '0000'B (German). */
|
||||
if (lang != 0x0f) {
|
||||
LOGP(DSS, LOGL_NOTICE, "USSD DataCodingScheme (0x%02x): "
|
||||
"the Language is usually set to 15 (unspecified), "
|
||||
"but the request indicates %u - ignoring this\n",
|
||||
req->ussd_data_dcs, lang);
|
||||
/* do not abort, attempt to decode as if it was '1111'B */
|
||||
}
|
||||
|
||||
gsm_7bit_decode_n_ussd(&ussd_code[0], sizeof(ussd_code),
|
||||
req->ussd_data, (req->ussd_data_len * 8) / 7);
|
||||
break;
|
||||
default:
|
||||
LOGP(DSS, LOGL_ERROR, "USSD DataCodingScheme (0x%02x): "
|
||||
"Coding Group %u is not supported, expecting Coding Group 0\n",
|
||||
req->ussd_data_dcs, cgroup);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
llist_for_each_entry(rt, &hlr->ussd_routes, list) {
|
||||
if (!strncmp(ussd_code, rt->prefix, strlen(rt->prefix))) {
|
||||
LOGP(DSS, LOGL_DEBUG, "Found %s '%s' (prefix '%s') for USSD "
|
||||
@@ -603,7 +634,7 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
|
||||
} else {
|
||||
/* VLR->EUSE: MO USSD. VLR is known ('conn'), EUSE is to be resolved */
|
||||
struct hlr_ussd_route *rt;
|
||||
rt = ussd_route_lookup_7bit(hlr, (const char *) req.ussd_text);
|
||||
rt = ussd_route_lookup_for_req(hlr, &req);
|
||||
if (rt) {
|
||||
if (rt->is_external) {
|
||||
ss->is_external = true;
|
||||
@@ -631,7 +662,8 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
|
||||
if (!ss) {
|
||||
LOGP(DSS, LOGL_ERROR, "%s/0x%08x: CONTINUE for unknown SS session\n",
|
||||
gsup->imsi, gsup->session_id);
|
||||
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_INV_MAND_INFO, "CONTINUE for unknown SS session");
|
||||
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_MSGT_INCOMP_P_STATE,
|
||||
"CONTINUE for unknown SS session");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -652,6 +684,8 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
|
||||
if (!ss) {
|
||||
LOGP(DSS, LOGL_ERROR, "%s/0x%08x: END for unknown SS session\n",
|
||||
gsup->imsi, gsup->session_id);
|
||||
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_MSGT_INCOMP_P_STATE,
|
||||
"END for unknown SS session");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -682,4 +716,5 @@ void rx_proc_ss_error(struct osmo_gsup_req *req)
|
||||
{
|
||||
LOGP(DSS, LOGL_NOTICE, "%s/0x%08x: Process SS ERROR (%s)\n", req->gsup.imsi, req->gsup.session_id,
|
||||
osmo_gsup_session_state_name(req->gsup.session_state));
|
||||
osmo_gsup_req_free(req);
|
||||
}
|
||||
|
||||
571
src/hlr_vty.c
571
src/hlr_vty.c
@@ -25,7 +25,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
#include <osmocom/gsm/apn.h>
|
||||
|
||||
#include <osmocom/vty/vty.h>
|
||||
#include <osmocom/vty/stats.h>
|
||||
#include <osmocom/vty/command.h>
|
||||
@@ -38,8 +44,39 @@
|
||||
#include <osmocom/hlr/hlr_vty.h>
|
||||
#include <osmocom/hlr/hlr_vty_subscr.h>
|
||||
#include <osmocom/hlr/hlr_ussd.h>
|
||||
#include <osmocom/hlr/hlr_sms.h>
|
||||
#include <osmocom/hlr/gsup_server.h>
|
||||
|
||||
static const struct value_string gsm48_gmm_cause_vty_names[] = {
|
||||
{ GMM_CAUSE_IMSI_UNKNOWN, "imsi-unknown" },
|
||||
{ GMM_CAUSE_ILLEGAL_MS, "illegal-ms" },
|
||||
{ GMM_CAUSE_PLMN_NOTALLOWED, "plmn-not-allowed" },
|
||||
{ GMM_CAUSE_LA_NOTALLOWED, "la-not-allowed" },
|
||||
{ GMM_CAUSE_ROAMING_NOTALLOWED, "roaming-not-allowed" },
|
||||
{ GMM_CAUSE_NO_SUIT_CELL_IN_LA, "no-suitable-cell-in-la" },
|
||||
{ GMM_CAUSE_NET_FAIL, "net-fail" },
|
||||
{ GMM_CAUSE_CONGESTION, "congestion" },
|
||||
{ GMM_CAUSE_GSM_AUTH_UNACCEPT, "auth-unacceptable" },
|
||||
{ GMM_CAUSE_PROTO_ERR_UNSPEC, "proto-error-unspec" },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
/* TS 24.008 4.4.4.7 */
|
||||
static const struct value_string gsm48_gmm_cause_vty_descs[] = {
|
||||
{ GMM_CAUSE_IMSI_UNKNOWN, " #02: (IMSI unknown in HLR)" },
|
||||
{ GMM_CAUSE_ILLEGAL_MS, " #03 (Illegal MS)" },
|
||||
{ GMM_CAUSE_PLMN_NOTALLOWED, " #11: (PLMN not allowed)" },
|
||||
{ GMM_CAUSE_LA_NOTALLOWED, " #12: (Location Area not allowed)" },
|
||||
{ GMM_CAUSE_ROAMING_NOTALLOWED, " #13: (Roaming not allowed in this location area)" },
|
||||
{ GMM_CAUSE_NO_SUIT_CELL_IN_LA, " #15: (No Suitable Cells In Location Area [continue search in PLMN])." },
|
||||
{ GMM_CAUSE_NET_FAIL, " #17: (Network Failure)" },
|
||||
{ GMM_CAUSE_CONGESTION, " #22: (Congestion)" },
|
||||
{ GMM_CAUSE_GSM_AUTH_UNACCEPT, " #23: (GSM authentication unacceptable [UMTS])" },
|
||||
{ GMM_CAUSE_PROTO_ERR_UNSPEC, "#111: (Protocol error, unspecified)" },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
|
||||
struct cmd_node hlr_node = {
|
||||
HLR_NODE,
|
||||
"%s(config-hlr)# ",
|
||||
@@ -70,30 +107,240 @@ DEFUN(cfg_gsup,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
struct cmd_node ps_node = {
|
||||
PS_NODE,
|
||||
"%s(config-hlr-ps)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
DEFUN(cfg_ps,
|
||||
cfg_ps_cmd,
|
||||
"ps",
|
||||
"Configure the PS options")
|
||||
{
|
||||
vty->node = PS_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
struct cmd_node ps_pdp_profiles_node = {
|
||||
PS_PDP_PROFILES_NODE,
|
||||
"%s(config-hlr-ps-pdp-profiles)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
DEFUN(cfg_ps_pdp_profiles,
|
||||
cfg_ps_pdp_profiles_cmd,
|
||||
"pdp-profiles default",
|
||||
"Define a PDP profile set.\n"
|
||||
"Define the global default profile.\n")
|
||||
{
|
||||
g_hlr->ps.pdp_profile.enabled = true;
|
||||
|
||||
vty->node = PS_PDP_PROFILES_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_ps_pdp_profiles,
|
||||
cfg_no_ps_pdp_profiles_cmd,
|
||||
"no pdp-profiles default",
|
||||
NO_STR
|
||||
"Delete PDP profile.\n"
|
||||
"Unique identifier for this PDP profile set.\n")
|
||||
{
|
||||
g_hlr->ps.pdp_profile.enabled = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct cmd_node ps_pdp_profiles_profile_node = {
|
||||
PS_PDP_PROFILES_PROFILE_NODE,
|
||||
"%s(config-hlr-ps-pdp-profile)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
|
||||
/* context_id == 0 means the slot is free */
|
||||
struct osmo_gsup_pdp_info *get_pdp_profile(uint8_t context_id)
|
||||
{
|
||||
for (int i = 0; i < OSMO_GSUP_MAX_NUM_PDP_INFO; i++) {
|
||||
struct osmo_gsup_pdp_info *info = &g_hlr->ps.pdp_profile.pdp_infos[i];
|
||||
if (info->context_id == context_id)
|
||||
return info;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct osmo_gsup_pdp_info *create_pdp_profile(uint8_t context_id)
|
||||
{
|
||||
struct osmo_gsup_pdp_info *info = get_pdp_profile(0);
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->context_id = context_id;
|
||||
info->have_info = 1;
|
||||
|
||||
g_hlr->ps.pdp_profile.num_pdp_infos++;
|
||||
return info;
|
||||
}
|
||||
|
||||
void destroy_pdp_profile(struct osmo_gsup_pdp_info *info)
|
||||
{
|
||||
info->context_id = 0;
|
||||
if (info->apn_enc)
|
||||
talloc_free((void *) info->apn_enc);
|
||||
|
||||
g_hlr->ps.pdp_profile.num_pdp_infos--;
|
||||
memset(info, 0, sizeof(*info));
|
||||
}
|
||||
|
||||
DEFUN(cfg_ps_pdp_profiles_profile,
|
||||
cfg_ps_pdp_profiles_profile_cmd,
|
||||
"profile <1-10>",
|
||||
"Configure a PDP profile\n"
|
||||
"Unique PDP context identifier. The lowest profile will be used as default context.\n")
|
||||
{
|
||||
struct osmo_gsup_pdp_info *info;
|
||||
uint8_t context_id = atoi(argv[0]);
|
||||
|
||||
info = get_pdp_profile(context_id);
|
||||
if (!info) {
|
||||
info = create_pdp_profile(context_id);
|
||||
if (!info) {
|
||||
vty_out(vty, "Failed to create profile %d!%s", context_id, VTY_NEWLINE);
|
||||
return CMD_ERR_INCOMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
vty->node = PS_PDP_PROFILES_PROFILE_NODE;
|
||||
vty->index = info;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_ps_pdp_profiles_profile,
|
||||
cfg_no_ps_pdp_profiles_profile_cmd,
|
||||
"no profile <1-10>",
|
||||
NO_STR
|
||||
"Delete a PDP profile\n"
|
||||
"Unique PDP context identifier. The lowest profile will be used as default context.\n")
|
||||
{
|
||||
struct osmo_gsup_pdp_info *info;
|
||||
uint8_t context_id = atoi(argv[0]);
|
||||
|
||||
info = get_pdp_profile(context_id);
|
||||
if (info)
|
||||
destroy_pdp_profile(info);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_ps_pdp_profile_apn, cfg_ps_pdp_profile_apn_cmd,
|
||||
"apn ID",
|
||||
"Configure the APN.\n"
|
||||
"APN name or * for wildcard apn.\n")
|
||||
{
|
||||
struct osmo_gsup_pdp_info *info = vty->index;
|
||||
const char *apn_name = argv[0];
|
||||
|
||||
/* apn encoded takes one more byte than strlen() */
|
||||
size_t apn_enc_len = strlen(apn_name) + 1;
|
||||
uint8_t *apn_enc;
|
||||
int ret;
|
||||
|
||||
if (apn_enc_len > APN_MAXLEN) {
|
||||
vty_out(vty, "APN name is too long '%s'. Max is %d!%s", apn_name, APN_MAXLEN, VTY_NEWLINE);
|
||||
return CMD_ERR_INCOMPLETE;
|
||||
}
|
||||
|
||||
info->apn_enc = apn_enc = (uint8_t *) talloc_zero_size(g_hlr, apn_enc_len);
|
||||
ret = info->apn_enc_len = osmo_apn_from_str(apn_enc, apn_enc_len, apn_name);
|
||||
if (ret < 0) {
|
||||
talloc_free(apn_enc);
|
||||
info->apn_enc = NULL;
|
||||
info->apn_enc_len = 0;
|
||||
vty_out(vty, "Invalid APN name %s!", apn_name);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_ps_pdp_profile_apn, cfg_no_ps_pdp_profile_apn_cmd,
|
||||
"no apn",
|
||||
NO_STR
|
||||
"Delete the APN.\n")
|
||||
{
|
||||
struct osmo_gsup_pdp_info *info = vty->index;
|
||||
if (info->apn_enc) {
|
||||
talloc_free((void *) info->apn_enc);
|
||||
info->apn_enc = NULL;
|
||||
info->apn_enc_len = 0;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void config_write_subscr_create_on_demand(struct vty *vty)
|
||||
{
|
||||
const uint8_t flags = g_hlr->subscr_create_on_demand.flags;
|
||||
const char *flags_str;
|
||||
|
||||
switch (g_hlr->subscr_create_on_demand.mode) {
|
||||
case SUBSCR_COD_MODE_MSISDN_FROM_IMSI:
|
||||
vty_out(vty, " subscriber-create-on-demand msisdn-from-imsi");
|
||||
break;
|
||||
case SUBSCR_COD_MODE_RAND_MSISDN:
|
||||
vty_out(vty, " subscriber-create-on-demand %u",
|
||||
g_hlr->subscr_create_on_demand.rand_msisdn_len);
|
||||
break;
|
||||
case SUBSCR_COD_MODE_NO_MSISDN:
|
||||
vty_out(vty, " subscriber-create-on-demand no-msisdn");
|
||||
break;
|
||||
case SUBSCR_COD_MODE_DISABLED:
|
||||
default:
|
||||
vty_out(vty, " no subscriber-create-on-demand%s", VTY_NEWLINE);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((flags & DB_SUBSCR_FLAG_NAM_CS) && (flags & DB_SUBSCR_FLAG_NAM_PS))
|
||||
flags_str = "cs+ps";
|
||||
else if (flags & DB_SUBSCR_FLAG_NAM_CS)
|
||||
flags_str = "cs";
|
||||
else if (flags & DB_SUBSCR_FLAG_NAM_PS)
|
||||
flags_str = "ps";
|
||||
else
|
||||
flags_str = "none";
|
||||
vty_out(vty, " %s%s", flags_str, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
|
||||
static int config_write_hlr(struct vty *vty)
|
||||
{
|
||||
vty_out(vty, "hlr%s", VTY_NEWLINE);
|
||||
|
||||
if (g_hlr->reject_cause.cs != GMM_CAUSE_PLMN_NOTALLOWED)
|
||||
vty_out(vty, " reject-cause not-found cs %s%s",
|
||||
get_value_string_or_null(gsm48_gmm_cause_vty_names,
|
||||
(uint32_t) g_hlr->reject_cause.cs), VTY_NEWLINE);
|
||||
if (g_hlr->reject_cause.ps != GMM_CAUSE_PLMN_NOTALLOWED)
|
||||
vty_out(vty, " reject-cause not-found ps %s%s",
|
||||
get_value_string_or_null(gsm48_gmm_cause_vty_names,
|
||||
(uint32_t) g_hlr->reject_cause.ps), VTY_NEWLINE);
|
||||
if (g_hlr->no_proxy_reject_cause.cs != GMM_CAUSE_NET_FAIL)
|
||||
vty_out(vty, " reject-cause no-proxy cs %s%s",
|
||||
get_value_string_or_null(gsm48_gmm_cause_vty_names,
|
||||
(uint32_t) g_hlr->no_proxy_reject_cause.cs), VTY_NEWLINE);
|
||||
if (g_hlr->no_proxy_reject_cause.ps != GMM_CAUSE_NET_FAIL)
|
||||
vty_out(vty, " reject-cause no-proxy ps %s%s",
|
||||
get_value_string_or_null(gsm48_gmm_cause_vty_names,
|
||||
(uint32_t) g_hlr->no_proxy_reject_cause.ps), VTY_NEWLINE);
|
||||
if (g_hlr->store_imei)
|
||||
vty_out(vty, " store-imei%s", VTY_NEWLINE);
|
||||
if (g_hlr->db_file_path && strcmp(g_hlr->db_file_path, HLR_DEFAULT_DB_FILE_PATH))
|
||||
vty_out(vty, " database %s%s", g_hlr->db_file_path, VTY_NEWLINE);
|
||||
if (g_hlr->subscr_create_on_demand) {
|
||||
const char *flags_str = "none";
|
||||
uint8_t flags = g_hlr->subscr_create_on_demand_flags;
|
||||
unsigned int rand_msisdn_len = g_hlr->subscr_create_on_demand_rand_msisdn_len;
|
||||
|
||||
if ((flags & DB_SUBSCR_FLAG_NAM_CS) && (flags & DB_SUBSCR_FLAG_NAM_PS))
|
||||
flags_str = "cs+ps";
|
||||
else if (flags & DB_SUBSCR_FLAG_NAM_CS)
|
||||
flags_str = "cs";
|
||||
else if (flags & DB_SUBSCR_FLAG_NAM_PS)
|
||||
flags_str = "ps";
|
||||
|
||||
if (rand_msisdn_len)
|
||||
vty_out(vty, " subscriber-create-on-demand %i %s%s", rand_msisdn_len, flags_str, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " subscriber-create-on-demand no-msisdn %s%s", flags_str, VTY_NEWLINE);
|
||||
}
|
||||
config_write_subscr_create_on_demand(vty);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -102,6 +349,39 @@ 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;
|
||||
}
|
||||
|
||||
static int config_write_hlr_ps(struct vty *vty)
|
||||
{
|
||||
vty_out(vty, " ps%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int config_write_hlr_ps_pdp_profiles(struct vty *vty)
|
||||
{
|
||||
char apn[APN_MAXLEN + 1] = {};
|
||||
|
||||
if (!g_hlr->ps.pdp_profile.enabled)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
vty_out(vty, " pdp-profiles default%s", VTY_NEWLINE);
|
||||
for (int i = 0; i < g_hlr->ps.pdp_profile.num_pdp_infos; i++) {
|
||||
struct osmo_gsup_pdp_info *pdp_info = &g_hlr->ps.pdp_profile.pdp_infos[i];
|
||||
if (!pdp_info->context_id)
|
||||
continue;
|
||||
|
||||
vty_out(vty, " profile %d%s", pdp_info->context_id, VTY_NEWLINE);
|
||||
if (!pdp_info->have_info)
|
||||
continue;
|
||||
|
||||
if (pdp_info->apn_enc && pdp_info->apn_enc_len) {
|
||||
osmo_apn_to_str(apn, pdp_info->apn_enc, pdp_info->apn_enc_len);
|
||||
vty_out(vty, " apn %s%s", apn, VTY_NEWLINE);
|
||||
}
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -114,8 +394,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, 3G_IND=%u%s",
|
||||
name, isc->addr, isc->port, conn->supports_cs, conn->supports_ps, conn->auc_3g_ind,
|
||||
vty_out(vty, " '%s' from %s:%5u, CS=%u, PS=%u%s",
|
||||
name, isc->addr, isc->port, conn->supports_cs, conn->supports_ps,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
@@ -156,7 +436,7 @@ DEFUN(cfg_hlr_gsup_ipa_name,
|
||||
{
|
||||
if (vty->type != VTY_FILE) {
|
||||
vty_out(vty, "gsup/ipa-name: The GSUP IPA name cannot be changed at run-time; "
|
||||
"It can only be set in the configuraton file.%s", VTY_NEWLINE);
|
||||
"It can only be set in the configuration file.%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
@@ -168,8 +448,6 @@ DEFUN(cfg_hlr_gsup_ipa_name,
|
||||
* USSD Entity
|
||||
***********************************************************************/
|
||||
|
||||
#include <osmocom/hlr/hlr_ussd.h>
|
||||
|
||||
#define USSD_STR "USSD Configuration\n"
|
||||
#define UROUTE_STR "Routing Configuration\n"
|
||||
#define PREFIX_STR "Prefix-Matching Route\n" "USSD Prefix\n"
|
||||
@@ -356,6 +634,185 @@ DEFUN(cfg_ncss_guard_timeout, cfg_ncss_guard_timeout_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Routing of SM-RL to GSUP-attached SMSCs
|
||||
***********************************************************************/
|
||||
|
||||
#define SMSC_STR "Configuration of GSUP routing to SMSCs\n"
|
||||
|
||||
struct cmd_node smsc_node = {
|
||||
SMSC_NODE,
|
||||
"%s(config-hlr-smsc)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
DEFUN(cfg_smsc_entity, cfg_smsc_entity_cmd,
|
||||
"smsc entity NAME",
|
||||
SMSC_STR
|
||||
"Configure a particular external SMSC\n"
|
||||
"IPA name of the external SMSC\n")
|
||||
{
|
||||
struct hlr_smsc *smsc;
|
||||
const char *id = argv[0];
|
||||
|
||||
smsc = smsc_find(g_hlr, id);
|
||||
if (!smsc) {
|
||||
smsc = smsc_alloc(g_hlr, id);
|
||||
if (!smsc)
|
||||
return CMD_WARNING;
|
||||
}
|
||||
vty->index = smsc;
|
||||
vty->index_sub = &smsc->description;
|
||||
vty->node = SMSC_NODE;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_smsc_entity, cfg_no_smsc_entity_cmd,
|
||||
"no smsc entity NAME",
|
||||
NO_STR SMSC_STR "Remove a particular external SMSC\n"
|
||||
"IPA name of the external SMSC\n")
|
||||
{
|
||||
struct hlr_smsc *smsc = smsc_find(g_hlr, argv[0]);
|
||||
if (!smsc) {
|
||||
vty_out(vty, "%% Cannot remove non-existent SMSC %s%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (g_hlr->smsc_default == smsc) {
|
||||
vty_out(vty,
|
||||
"%% Cannot remove SMSC %s, it is the default route%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
smsc_free(smsc);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_smsc_route, cfg_smsc_route_cmd,
|
||||
"smsc route NUMBER NAME",
|
||||
SMSC_STR
|
||||
"Configure GSUP route to a particular SMSC\n"
|
||||
"Numeric address of this SMSC, must match EF.SMSP programming in SIMs\n"
|
||||
"IPA name of the external SMSC\n")
|
||||
{
|
||||
struct hlr_smsc *smsc = smsc_find(g_hlr, argv[1]);
|
||||
struct hlr_smsc_route *rt = smsc_route_find(g_hlr, argv[0]);
|
||||
if (rt) {
|
||||
vty_out(vty,
|
||||
"%% Cannot add [another?] route for SMSC address %s%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (!smsc) {
|
||||
vty_out(vty, "%% Cannot find SMSC '%s'%s", argv[1],
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
smsc_route_alloc(g_hlr, argv[0], smsc);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_smsc_route, cfg_no_smsc_route_cmd,
|
||||
"no smsc route NUMBER",
|
||||
NO_STR SMSC_STR "Remove GSUP route to a particular SMSC\n"
|
||||
"Numeric address of the SMSC\n")
|
||||
{
|
||||
struct hlr_smsc_route *rt = smsc_route_find(g_hlr, argv[0]);
|
||||
if (!rt) {
|
||||
vty_out(vty, "%% Cannot find route for SMSC address %s%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
smsc_route_free(rt);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_smsc_defroute, cfg_smsc_defroute_cmd,
|
||||
"smsc default-route NAME",
|
||||
SMSC_STR
|
||||
"Configure default SMSC route for unknown SMSC numeric addresses\n"
|
||||
"IPA name of the external SMSC\n")
|
||||
{
|
||||
struct hlr_smsc *smsc;
|
||||
|
||||
smsc = smsc_find(g_hlr, argv[0]);
|
||||
if (!smsc) {
|
||||
vty_out(vty, "%% Cannot find SMSC %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (g_hlr->smsc_default != smsc) {
|
||||
vty_out(vty, "Switching default route from %s to %s%s",
|
||||
g_hlr->smsc_default ? g_hlr->smsc_default->name : "<none>",
|
||||
smsc->name, VTY_NEWLINE);
|
||||
g_hlr->smsc_default = smsc;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_smsc_defroute, cfg_no_smsc_defroute_cmd,
|
||||
"no smsc default-route",
|
||||
NO_STR SMSC_STR
|
||||
"Remove default SMSC route for unknown SMSC numeric addresses\n")
|
||||
{
|
||||
g_hlr->smsc_default = NULL;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void dump_one_smsc(struct vty *vty, struct hlr_smsc *smsc)
|
||||
{
|
||||
vty_out(vty, " smsc entity %s%s", smsc->name, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static int config_write_smsc(struct vty *vty)
|
||||
{
|
||||
struct hlr_smsc *smsc;
|
||||
struct hlr_smsc_route *rt;
|
||||
|
||||
llist_for_each_entry(smsc, &g_hlr->smsc_list, list)
|
||||
dump_one_smsc(vty, smsc);
|
||||
|
||||
llist_for_each_entry(rt, &g_hlr->smsc_routes, list) {
|
||||
vty_out(vty, " smsc route %s %s%s", rt->num_addr,
|
||||
rt->smsc->name, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
if (g_hlr->smsc_default)
|
||||
vty_out(vty, " smsc default-route %s%s",
|
||||
g_hlr->smsc_default->name, VTY_NEWLINE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFUN(cfg_reject_cause, cfg_reject_cause_cmd,
|
||||
"reject-cause TYPE CAUSE", "") /* Dynamically Generated */
|
||||
{
|
||||
int cause_code = get_string_value(gsm48_gmm_cause_vty_names, argv[2]);
|
||||
OSMO_ASSERT(cause_code >= 0);
|
||||
|
||||
if (strcmp(argv[0], "not-found") == 0) {
|
||||
if (strcmp(argv[1], "cs") == 0)
|
||||
g_hlr->reject_cause.cs = (enum gsm48_gmm_cause) cause_code;
|
||||
else
|
||||
g_hlr->reject_cause.ps = (enum gsm48_gmm_cause) cause_code;
|
||||
}
|
||||
if (strcmp(argv[0], "no-proxy") == 0) {
|
||||
if (strcmp(argv[1], "cs") == 0)
|
||||
g_hlr->no_proxy_reject_cause.cs = (enum gsm48_gmm_cause) cause_code;
|
||||
else
|
||||
g_hlr->no_proxy_reject_cause.ps = (enum gsm48_gmm_cause) cause_code;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DEFUN(cfg_store_imei, cfg_store_imei_cmd,
|
||||
"store-imei",
|
||||
"Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send"
|
||||
@@ -374,29 +831,37 @@ DEFUN(cfg_no_store_imei, cfg_no_store_imei_cmd,
|
||||
}
|
||||
|
||||
DEFUN(cfg_subscr_create_on_demand, cfg_subscr_create_on_demand_cmd,
|
||||
"subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)",
|
||||
"subscriber-create-on-demand (no-msisdn|msisdn-from-imsi|<3-15>) (none|cs|ps|cs+ps)",
|
||||
"Make a new record when a subscriber is first seen.\n"
|
||||
"Do not automatically assign MSISDN.\n"
|
||||
"Assign MSISDN identical to subscriber's IMSI.\n"
|
||||
"Length of an automatically assigned MSISDN.\n"
|
||||
"Do not allow any NAM (Network Access Mode) by default.\n"
|
||||
"Allow access to circuit switched NAM by default.\n"
|
||||
"Allow access to packet switched NAM by default.\n"
|
||||
"Allow access to circuit and packet switched NAM by default.\n")
|
||||
{
|
||||
enum subscr_create_on_demand_mode mode;
|
||||
unsigned int rand_msisdn_len = 0;
|
||||
uint8_t flags = 0x00;
|
||||
|
||||
if (strcmp(argv[0], "no-msisdn") != 0)
|
||||
if (strcmp(argv[0], "no-msisdn") == 0) {
|
||||
mode = SUBSCR_COD_MODE_NO_MSISDN;
|
||||
} else if (strcmp(argv[0], "msisdn-from-imsi") == 0) {
|
||||
mode = SUBSCR_COD_MODE_MSISDN_FROM_IMSI;
|
||||
} else { /* random MSISDN */
|
||||
mode = SUBSCR_COD_MODE_RAND_MSISDN;
|
||||
rand_msisdn_len = atoi(argv[0]);
|
||||
}
|
||||
|
||||
if (strstr(argv[1], "cs"))
|
||||
flags |= DB_SUBSCR_FLAG_NAM_CS;
|
||||
if (strstr(argv[1], "ps"))
|
||||
flags |= DB_SUBSCR_FLAG_NAM_PS;
|
||||
|
||||
g_hlr->subscr_create_on_demand = true;
|
||||
g_hlr->subscr_create_on_demand_rand_msisdn_len = rand_msisdn_len;
|
||||
g_hlr->subscr_create_on_demand_flags = flags;
|
||||
g_hlr->subscr_create_on_demand.mode = mode;
|
||||
g_hlr->subscr_create_on_demand.rand_msisdn_len = rand_msisdn_len;
|
||||
g_hlr->subscr_create_on_demand.flags = flags;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -405,7 +870,7 @@ DEFUN(cfg_no_subscr_create_on_demand, cfg_no_subscr_create_on_demand_cmd,
|
||||
"no subscriber-create-on-demand",
|
||||
"Do not make a new record when a subscriber is first seen.\n")
|
||||
{
|
||||
g_hlr->subscr_create_on_demand = false;
|
||||
g_hlr->subscr_create_on_demand.mode = SUBSCR_COD_MODE_DISABLED;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -436,20 +901,24 @@ int hlr_vty_go_parent(struct vty *vty)
|
||||
return vty->node;
|
||||
}
|
||||
|
||||
int hlr_vty_is_config_node(struct vty *vty, int node)
|
||||
void hlr_vty_init(void *hlr_ctx)
|
||||
{
|
||||
switch (node) {
|
||||
/* add items that are not config */
|
||||
case CONFIG_NODE:
|
||||
return 0;
|
||||
cfg_reject_cause_cmd.string =
|
||||
vty_cmd_string_from_valstr(hlr_ctx,
|
||||
gsm48_gmm_cause_vty_names,
|
||||
"reject-cause (not-found|no-proxy) (cs|ps) (", "|", ")",
|
||||
VTY_DO_LOWER);
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
cfg_reject_cause_cmd.doc =
|
||||
vty_cmd_string_from_valstr(hlr_ctx,
|
||||
gsm48_gmm_cause_vty_descs,
|
||||
"GSUP/GMM cause to be sent\n"
|
||||
"in the case the IMSI could not be found in the database\n"
|
||||
"in the case no remote HLR reponded to mslookup GSUP request\n"
|
||||
"for CS domain\n"
|
||||
"for PS domain\n",
|
||||
"\n", "", 0);
|
||||
|
||||
void hlr_vty_init(void)
|
||||
{
|
||||
logging_vty_add_cmds();
|
||||
osmo_talloc_vty_add_cmds();
|
||||
osmo_stats_vty_add_cmds();
|
||||
@@ -465,6 +934,20 @@ void hlr_vty_init(void)
|
||||
install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
|
||||
install_element(GSUP_NODE, &cfg_hlr_gsup_ipa_name_cmd);
|
||||
|
||||
/* PS */
|
||||
install_node(&ps_node, config_write_hlr_ps);
|
||||
install_element(HLR_NODE, &cfg_ps_cmd);
|
||||
|
||||
install_node(&ps_pdp_profiles_node, config_write_hlr_ps_pdp_profiles);
|
||||
install_element(PS_NODE, &cfg_ps_pdp_profiles_cmd);
|
||||
install_element(PS_NODE, &cfg_no_ps_pdp_profiles_cmd);
|
||||
|
||||
install_node(&ps_pdp_profiles_profile_node, NULL);
|
||||
install_element(PS_PDP_PROFILES_NODE, &cfg_ps_pdp_profiles_profile_cmd);
|
||||
install_element(PS_PDP_PROFILES_NODE, &cfg_no_ps_pdp_profiles_profile_cmd);
|
||||
install_element(PS_PDP_PROFILES_PROFILE_NODE, &cfg_ps_pdp_profile_apn_cmd);
|
||||
install_element(PS_PDP_PROFILES_PROFILE_NODE, &cfg_no_ps_pdp_profile_apn_cmd);
|
||||
|
||||
install_element(HLR_NODE, &cfg_database_cmd);
|
||||
|
||||
install_element(HLR_NODE, &cfg_euse_cmd);
|
||||
@@ -476,6 +959,16 @@ void hlr_vty_init(void)
|
||||
install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
|
||||
install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd);
|
||||
install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd);
|
||||
|
||||
install_node(&smsc_node, config_write_smsc);
|
||||
install_element(HLR_NODE, &cfg_smsc_entity_cmd);
|
||||
install_element(HLR_NODE, &cfg_no_smsc_entity_cmd);
|
||||
install_element(HLR_NODE, &cfg_smsc_route_cmd);
|
||||
install_element(HLR_NODE, &cfg_no_smsc_route_cmd);
|
||||
install_element(HLR_NODE, &cfg_smsc_defroute_cmd);
|
||||
install_element(HLR_NODE, &cfg_no_smsc_defroute_cmd);
|
||||
|
||||
install_element(HLR_NODE, &cfg_reject_cause_cmd);
|
||||
install_element(HLR_NODE, &cfg_store_imei_cmd);
|
||||
install_element(HLR_NODE, &cfg_no_store_imei_cmd);
|
||||
install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* OsmoHLR subscriber management VTY implementation */
|
||||
/* (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
/* (C) 2017-2023 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
#include <osmocom/hlr/timestamp.h>
|
||||
#include <osmocom/hlr/hlr_vty.h>
|
||||
|
||||
struct vty;
|
||||
|
||||
@@ -76,8 +77,8 @@ static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t
|
||||
static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
||||
{
|
||||
int rc;
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
struct osmo_sub_auth_data aud3g;
|
||||
struct osmo_sub_auth_data2 aud2g;
|
||||
struct osmo_sub_auth_data2 aud3g;
|
||||
|
||||
vty_out(vty, " ID: %"PRIu64"%s", subscr->id, VTY_NEWLINE);
|
||||
|
||||
@@ -136,12 +137,12 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
||||
|
||||
if (aud2g.type != OSMO_AUTH_TYPE_NONE && aud2g.type != OSMO_AUTH_TYPE_GSM) {
|
||||
vty_out(vty, "%% Error: 2G auth data is not of type 'GSM'%s", VTY_NEWLINE);
|
||||
aud2g = (struct osmo_sub_auth_data){};
|
||||
aud2g = (struct osmo_sub_auth_data2){};
|
||||
}
|
||||
|
||||
if (aud3g.type != OSMO_AUTH_TYPE_NONE && aud3g.type != OSMO_AUTH_TYPE_UMTS) {
|
||||
vty_out(vty, "%% Error: 3G auth data is not of type 'UMTS'%s", VTY_NEWLINE);
|
||||
aud3g = (struct osmo_sub_auth_data){};
|
||||
aud3g = (struct osmo_sub_auth_data2){};
|
||||
}
|
||||
|
||||
if (aud2g.algo != OSMO_AUTH_ALG_NONE && aud2g.type != OSMO_AUTH_TYPE_NONE) {
|
||||
@@ -153,9 +154,10 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
||||
|
||||
if (aud3g.algo != OSMO_AUTH_ALG_NONE && aud3g.type != OSMO_AUTH_TYPE_NONE) {
|
||||
vty_out(vty, " 3G auth: %s%s", osmo_auth_alg_name(aud3g.algo), VTY_NEWLINE);
|
||||
vty_out(vty, " K=%s%s", hexdump_buf(aud3g.u.umts.k), VTY_NEWLINE);
|
||||
vty_out(vty, " K=%s%s",
|
||||
osmo_hexdump_nospc(aud3g.u.umts.k, aud3g.u.umts.k_len), VTY_NEWLINE);
|
||||
vty_out(vty, " %s=%s%s", aud3g.u.umts.opc_is_op? "OP" : "OPC",
|
||||
hexdump_buf(aud3g.u.umts.opc), VTY_NEWLINE);
|
||||
osmo_hexdump_nospc(aud3g.u.umts.opc, aud3g.u.umts.opc_len), VTY_NEWLINE);
|
||||
vty_out(vty, " IND-bitlen=%u", aud3g.u.umts.ind_bitlen);
|
||||
if (aud3g.u.umts.sqn)
|
||||
vty_out(vty, " last-SQN=%"PRIu64, aud3g.u.umts.sqn);
|
||||
@@ -180,8 +182,11 @@ static void subscr_dump_summary_vty(struct hlr_subscriber *subscr, void *data)
|
||||
vty_out(vty," ------------- ");
|
||||
}
|
||||
vty_out(vty, " %-2s%-2s ", subscr->nam_cs ? "CS" : "", subscr->nam_ps ? "PS" : "");
|
||||
if (subscr->last_lu_seen)
|
||||
if (subscr->last_lu_seen) {
|
||||
/* VLR Number is max length 32, possibly truncate here */
|
||||
vty_out(vty, " %.22s ", subscr->vlr_number);
|
||||
dump_last_lu_seen(vty, "CS", subscr->last_lu_seen, true);
|
||||
}
|
||||
vty_out_newline(vty);
|
||||
}
|
||||
|
||||
@@ -216,8 +221,8 @@ 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 = " ------------";
|
||||
const char *ls_text = " VLR_NUMBER LAST SEEN ";
|
||||
const char *ls_line = " --------------------- ---------------------";
|
||||
if (header) {
|
||||
if (!show_ls)
|
||||
vty_out(vty, "%s%s%s%s", texts, VTY_NEWLINE, lines, VTY_NEWLINE);
|
||||
@@ -256,7 +261,7 @@ static int get_subscrs(struct vty *vty, const char *filter_type, const char *fil
|
||||
#define SUBSCRS_SHOW_HELP "Show all subscribers (with filter possibility)\n"
|
||||
|
||||
#define SUBSCR_ID "(imsi|msisdn|id|imei) IDENT"
|
||||
#define SUBSCR_FILTER "(imsi|msisdn) FILTER"
|
||||
#define SUBSCR_FILTER "(imei|imsi|msisdn) FILTER"
|
||||
|
||||
#define SUBSCR_ID_HELP \
|
||||
"Identify subscriber by IMSI\n" \
|
||||
@@ -307,7 +312,8 @@ DEFUN(show_subscriber_filtered,
|
||||
show_subscriber_filtered_cmd,
|
||||
"show subscribers " SUBSCR_FILTER,
|
||||
SHOW_STR SUBSCRS_SHOW_HELP
|
||||
"Filter Subscribers by IMSI\n" "Filter Subscribers by MSISDN\n" "String to match in msisdn or imsi\n")
|
||||
"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];
|
||||
@@ -345,7 +351,7 @@ DEFUN(subscriber_create,
|
||||
int rc;
|
||||
struct hlr_subscriber subscr;
|
||||
const char *imsi = argv[0];
|
||||
|
||||
|
||||
if (!osmo_imsi_str_valid(imsi)) {
|
||||
vty_out(vty, "%% Not a valid IMSI: %s%s", imsi, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -458,26 +464,27 @@ static bool is_hexkey_valid(struct vty *vty, const char *label,
|
||||
return false;
|
||||
}
|
||||
|
||||
#define AUTH_ALG_TYPES_2G "(comp128v1|comp128v2|comp128v3|xor)"
|
||||
#define AUTH_ALG_TYPES_2G "(comp128v1|comp128v2|comp128v3|xor-2g)"
|
||||
#define AUTH_ALG_TYPES_2G_HELP \
|
||||
"Use COMP128v1 algorithm\n" \
|
||||
"Use COMP128v2 algorithm\n" \
|
||||
"Use COMP128v3 algorithm\n" \
|
||||
"Use XOR algorithm\n"
|
||||
"Use XOR-2G algorithm\n"
|
||||
|
||||
#define AUTH_ALG_TYPES_3G "milenage"
|
||||
#define AUTH_ALG_TYPES_3G "(milenage|tuak)"
|
||||
#define AUTH_ALG_TYPES_3G_HELP \
|
||||
"Use Milenage algorithm\n"
|
||||
"Use Milenage algorithm\n" \
|
||||
"Use TUAK algorithm\n"
|
||||
|
||||
#define A38_XOR_MIN_KEY_LEN 12
|
||||
#define A38_XOR_MAX_KEY_LEN 16
|
||||
#define A38_COMP128_KEY_LEN 16
|
||||
|
||||
#define MILENAGE_KEY_LEN 16
|
||||
|
||||
static bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
|
||||
int *minlen, int *maxlen)
|
||||
bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
|
||||
int *minlen, int *maxlen, int *minlen_opc, int *maxlen_opc)
|
||||
{
|
||||
/* Default: no OP[c]. True for all 2G algorithms, and 3G-XOR. Overridden below for real 3G AKA algorithms. */
|
||||
if (minlen_opc)
|
||||
*minlen_opc = 0;
|
||||
if (maxlen_opc)
|
||||
*maxlen_opc = 0;
|
||||
|
||||
if (!strcasecmp(alg_str, "none")) {
|
||||
*algo = OSMO_AUTH_ALG_NONE;
|
||||
*minlen = *maxlen = 0;
|
||||
@@ -490,13 +497,28 @@ static bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
|
||||
} else if (!strcasecmp(alg_str, "comp128v3")) {
|
||||
*algo = OSMO_AUTH_ALG_COMP128v3;
|
||||
*minlen = *maxlen = A38_COMP128_KEY_LEN;
|
||||
} else if (!strcasecmp(alg_str, "xor")) {
|
||||
*algo = OSMO_AUTH_ALG_XOR;
|
||||
} else if (!strcasecmp(alg_str, "xor-3g")) {
|
||||
*algo = OSMO_AUTH_ALG_XOR_3G;
|
||||
*minlen = A38_XOR_MIN_KEY_LEN;
|
||||
*maxlen = A38_XOR_MAX_KEY_LEN;
|
||||
} else if (!strcasecmp(alg_str, "xor-2g")) {
|
||||
*algo = OSMO_AUTH_ALG_XOR_2G;
|
||||
*minlen = *maxlen = A38_XOR2G_KEY_LEN;
|
||||
} else if (!strcasecmp(alg_str, "milenage")) {
|
||||
*algo = OSMO_AUTH_ALG_MILENAGE;
|
||||
*minlen = *maxlen = MILENAGE_KEY_LEN;
|
||||
if (minlen_opc)
|
||||
*minlen_opc = MILENAGE_KEY_LEN;
|
||||
if (maxlen_opc)
|
||||
*maxlen_opc = MILENAGE_KEY_LEN;
|
||||
} else if (!strcasecmp(alg_str, "tuak")) {
|
||||
*algo = OSMO_AUTH_ALG_TUAK;
|
||||
*minlen = 16;
|
||||
*maxlen = 32;
|
||||
if (minlen_opc)
|
||||
*minlen_opc = 32;
|
||||
if (maxlen_opc)
|
||||
*maxlen_opc = 32;
|
||||
} else
|
||||
return false;
|
||||
return true;
|
||||
@@ -552,7 +574,7 @@ DEFUN(subscriber_aud2g,
|
||||
.u.gsm.ki = ki,
|
||||
};
|
||||
|
||||
if (!auth_algo_parse(alg_type, &aud2g.algo, &minlen, &maxlen)) {
|
||||
if (!auth_algo_parse(alg_type, &aud2g.algo, &minlen, &maxlen, NULL, NULL)) {
|
||||
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
@@ -611,21 +633,21 @@ DEFUN(subscriber_aud3g,
|
||||
SUBSCR_UPDATE_HELP
|
||||
"Set UMTS authentication data (3G, and 2G with UMTS AKA)\n"
|
||||
AUTH_ALG_TYPES_3G_HELP
|
||||
"Set Encryption Key K\n" "K as 32 hexadecimal characters\n"
|
||||
"Set OP key\n" "Set OPC key\n" "OP or OPC as 32 hexadecimal characters\n"
|
||||
"Set Encryption Key K\n" "K as 32/64 hexadecimal characters\n"
|
||||
"Set OP key\n" "Set OPC key\n" "OP or OPC as 32/64 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 minlen = 0, minlen_opc = 0;
|
||||
int maxlen = 0, maxlen_opc = 0;
|
||||
int rc;
|
||||
const char *id_type = argv[0];
|
||||
const char *id = argv[1];
|
||||
const char *alg_type = AUTH_ALG_TYPES_3G;
|
||||
const char *k = argv[2];
|
||||
bool opc_is_op = (strcasecmp("op", argv[3]) == 0);
|
||||
const char *op_opc = argv[4];
|
||||
int ind_bitlen = argc > 6? atoi(argv[6]) : 5;
|
||||
const char *alg_type = argv[2];
|
||||
const char *k = argv[3];
|
||||
bool opc_is_op = (strcasecmp("op", argv[4]) == 0);
|
||||
const char *op_opc = argv[5];
|
||||
int ind_bitlen = argc > 7 ? atoi(argv[7]) : 5;
|
||||
struct sub_auth_data_str aud3g = {
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.u.umts = {
|
||||
@@ -635,8 +657,8 @@ DEFUN(subscriber_aud3g,
|
||||
.ind_bitlen = ind_bitlen,
|
||||
},
|
||||
};
|
||||
|
||||
if (!auth_algo_parse(alg_type, &aud3g.algo, &minlen, &maxlen)) {
|
||||
|
||||
if (!auth_algo_parse(alg_type, &aud3g.algo, &minlen, &maxlen, &minlen_opc, &maxlen_opc)) {
|
||||
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
@@ -644,8 +666,7 @@ DEFUN(subscriber_aud3g,
|
||||
if (!is_hexkey_valid(vty, "K", aud3g.u.umts.k, minlen, maxlen))
|
||||
return CMD_WARNING;
|
||||
|
||||
if (!is_hexkey_valid(vty, opc_is_op ? "OP" : "OPC", aud3g.u.umts.opc,
|
||||
MILENAGE_KEY_LEN, MILENAGE_KEY_LEN))
|
||||
if (!is_hexkey_valid(vty, opc_is_op ? "OP" : "OPC", aud3g.u.umts.opc, minlen_opc, maxlen_opc))
|
||||
return CMD_WARNING;
|
||||
|
||||
if (get_subscr_by_argv(vty, id_type, id, &subscr))
|
||||
@@ -663,11 +684,11 @@ DEFUN(subscriber_aud3g,
|
||||
|
||||
DEFUN(subscriber_aud3g_xor,
|
||||
subscriber_aud3g_xor_cmd,
|
||||
SUBSCR_UPDATE "aud3g xor k K"
|
||||
SUBSCR_UPDATE "aud3g xor-3g k K"
|
||||
" [ind-bitlen] [<0-28>]",
|
||||
SUBSCR_UPDATE_HELP
|
||||
"Set UMTS authentication data (3G, and 2G with UMTS AKA)\n"
|
||||
"Use XOR algorithm\n"
|
||||
"Use XOR-3G 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")
|
||||
{
|
||||
@@ -689,8 +710,8 @@ DEFUN(subscriber_aud3g_xor,
|
||||
},
|
||||
};
|
||||
|
||||
if (!auth_algo_parse("xor", &aud3g.algo, &minlen, &maxlen)) {
|
||||
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", "xor", VTY_NEWLINE);
|
||||
if (!auth_algo_parse("xor-3g", &aud3g.algo, &minlen, &maxlen, NULL, NULL)) {
|
||||
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", "xor-3g", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,12 @@ const struct log_info_cat hlr_log_info_cat[] = {
|
||||
.color = "\033[1;35m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DCTRL] = {
|
||||
.name = "DCTRL",
|
||||
.description = "Osmocom CTRL interface",
|
||||
.color = "\033[1;30m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
},
|
||||
};
|
||||
|
||||
const struct log_info hlr_log_info = {
|
||||
|
||||
14
src/lu_fsm.c
14
src/lu_fsm.c
@@ -136,7 +136,8 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
|
||||
}
|
||||
|
||||
if (db_subscr_get_by_imsi(g_hlr->dbc, update_location_req->gsup.imsi, &lu->subscr) < 0) {
|
||||
lu_failure(lu, GMM_CAUSE_IMSI_UNKNOWN, "Subscriber does not exist");
|
||||
lu_failure(lu, (lu->is_ps) ? g_hlr->reject_cause.ps : g_hlr->reject_cause.cs,
|
||||
"Subscriber does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -241,13 +242,11 @@ static void lu_fsm_wait_insert_data_result_onenter(struct osmo_fsm_inst *fi, uin
|
||||
struct lu *lu = fi->priv;
|
||||
struct hlr_subscriber *subscr = &lu->subscr;
|
||||
struct osmo_gsup_message gsup;
|
||||
uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];
|
||||
uint8_t apn[APN_MAXLEN];
|
||||
|
||||
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi,
|
||||
subscr->msisdn, msisdn_enc, sizeof(msisdn_enc),
|
||||
apn, sizeof(apn),
|
||||
lu->is_ps? OSMO_GSUP_CN_DOMAIN_PS : OSMO_GSUP_CN_DOMAIN_CS)) {
|
||||
subscr->msisdn,
|
||||
lu->is_ps ? OSMO_GSUP_CN_DOMAIN_PS : OSMO_GSUP_CN_DOMAIN_CS,
|
||||
OTC_SELECT)) {
|
||||
lu_failure(lu, GMM_CAUSE_NET_FAIL, "cannot encode Insert Subscriber Data message");
|
||||
return;
|
||||
}
|
||||
@@ -277,6 +276,7 @@ void lu_fsm_wait_insert_data_result(struct osmo_fsm_inst *fi, uint32_t event, vo
|
||||
|
||||
case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
|
||||
lu_failure(lu, GMM_CAUSE_NET_FAIL, "Rx %s", osmo_gsup_message_type_name(req->gsup.message_type));
|
||||
osmo_gsup_req_free(req);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -314,7 +314,7 @@ static struct osmo_fsm lu_fsm = {
|
||||
.cleanup = lu_fsm_cleanup,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void lu_fsm_init()
|
||||
static __attribute__((constructor)) void lu_fsm_init(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&lu_fsm) == 0);
|
||||
}
|
||||
|
||||
@@ -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=0:0:0
|
||||
LIBVERSION=1:1:0
|
||||
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include
|
||||
AM_CFLAGS = -fPIC -Wall $(PCSC_CFLAGS) $(TALLOC_CFLAGS) $(LIBOSMOCORE_CFLAGS)
|
||||
|
||||
@@ -45,6 +45,7 @@ static char *domain_from_query(void *ctx, const struct osmo_mslookup_query *quer
|
||||
/* Get id from query */
|
||||
switch (query->id.type) {
|
||||
case OSMO_MSLOOKUP_ID_IMSI:
|
||||
case OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED:
|
||||
id = query->id.imsi;
|
||||
break;
|
||||
case OSMO_MSLOOKUP_ID_MSISDN:
|
||||
|
||||
@@ -40,7 +40,7 @@ int osmo_mdns_msg_request_encode(void *ctx, struct msgb *msg, const struct osmo_
|
||||
qst.domain = req->domain;
|
||||
qst.qtype = req->type;
|
||||
qst.qclass = OSMO_MDNS_RFC_CLASS_IN;
|
||||
if (osmo_mdns_rfc_question_encode(ctx, msg, &qst) != 0)
|
||||
if (osmo_mdns_rfc_question_encode(msg, &qst) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -106,7 +106,7 @@ int osmo_mdns_msg_answer_encode(void *ctx, struct msgb *msg, const struct osmo_m
|
||||
rec.rdlength = ans_record->length;
|
||||
rec.rdata = ans_record->data;
|
||||
|
||||
if (osmo_mdns_rfc_record_encode(ctx, msg, &rec) != 0)
|
||||
if (osmo_mdns_rfc_record_encode(msg, &rec) != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,91 +27,9 @@
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/bitvec.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/gsm/apn.h>
|
||||
#include <osmocom/mslookup/mdns_rfc.h>
|
||||
|
||||
/*
|
||||
* Encode/decode IEs
|
||||
*/
|
||||
|
||||
/*! Encode a domain string as qname (RFC 1035 4.1.2).
|
||||
* \param[in] domain multiple labels separated by dots, e.g. "sip.voice.1234.msisdn".
|
||||
* \returns allocated buffer with length-value pairs for each label (e.g. 0x03 "sip" 0x05 "voice" ...), NULL on error.
|
||||
*/
|
||||
char *osmo_mdns_rfc_qname_encode(void *ctx, const char *domain)
|
||||
{
|
||||
char *domain_dup;
|
||||
char *domain_iter;
|
||||
char buf[OSMO_MDNS_RFC_MAX_NAME_LEN + 2] = ""; /* len(qname) is len(domain) +1 */
|
||||
struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
|
||||
char *label;
|
||||
|
||||
if (strlen(domain) > OSMO_MDNS_RFC_MAX_NAME_LEN)
|
||||
return NULL;
|
||||
|
||||
domain_iter = domain_dup = talloc_strdup(ctx, domain);
|
||||
while ((label = strsep(&domain_iter, "."))) {
|
||||
size_t len = strlen(label);
|
||||
|
||||
/* Empty domain, dot at start, two dots in a row, or ending with a dot */
|
||||
if (!len)
|
||||
goto error;
|
||||
|
||||
OSMO_STRBUF_PRINTF(sb, "%c%s", (char)len, label);
|
||||
}
|
||||
|
||||
talloc_free(domain_dup);
|
||||
return talloc_strdup(ctx, buf);
|
||||
|
||||
error:
|
||||
talloc_free(domain_dup);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Decode a domain string from a qname (RFC 1035 4.1.2).
|
||||
* \param[in] qname buffer with length-value pairs for each label (e.g. 0x03 "sip" 0x05 "voice" ...)
|
||||
* \param[in] qname_max_len amount of bytes that can be read at most from the memory location that qname points to.
|
||||
* \returns allocated buffer with domain string, multiple labels separated by dots (e.g. "sip.voice.1234.msisdn"),
|
||||
* NULL on error.
|
||||
*/
|
||||
char *osmo_mdns_rfc_qname_decode(void *ctx, const char *qname, size_t qname_max_len)
|
||||
{
|
||||
const char *next_label, *qname_end = qname + qname_max_len;
|
||||
char buf[OSMO_MDNS_RFC_MAX_NAME_LEN + 1];
|
||||
int i = 0;
|
||||
|
||||
if (qname_max_len < 1)
|
||||
return NULL;
|
||||
|
||||
while (*qname) {
|
||||
size_t len;
|
||||
|
||||
if (i >= qname_max_len)
|
||||
return NULL;
|
||||
|
||||
len = *qname;
|
||||
next_label = qname + len + 1;
|
||||
|
||||
if (next_label >= qname_end || i + len > OSMO_MDNS_RFC_MAX_NAME_LEN)
|
||||
return NULL;
|
||||
|
||||
if (i) {
|
||||
/* Two dots in a row is not allowed */
|
||||
if (buf[i - 1] == '.')
|
||||
return NULL;
|
||||
|
||||
buf[i] = '.';
|
||||
i++;
|
||||
}
|
||||
|
||||
memcpy(buf + i, qname + 1, len);
|
||||
i += len;
|
||||
qname = next_label;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
|
||||
return talloc_strdup(ctx, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode/decode message sections
|
||||
*/
|
||||
@@ -151,20 +69,17 @@ int osmo_mdns_rfc_header_decode(const uint8_t *data, size_t data_len, struct osm
|
||||
/*! Encode question section (RFC 1035 4.1.2).
|
||||
* \param[in] msgb mesage buffer to which the encoded data will be appended.
|
||||
*/
|
||||
int osmo_mdns_rfc_question_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_question *qst)
|
||||
int osmo_mdns_rfc_question_encode(struct msgb *msg, const struct osmo_mdns_rfc_question *qst)
|
||||
{
|
||||
char *qname;
|
||||
size_t qname_len;
|
||||
uint8_t *qname_buf;
|
||||
uint8_t *buf;
|
||||
size_t buf_len;
|
||||
|
||||
/* qname */
|
||||
qname = osmo_mdns_rfc_qname_encode(ctx, qst->domain);
|
||||
if (!qname)
|
||||
buf_len = strlen(qst->domain) + 1;
|
||||
buf = msgb_put(msg, buf_len);
|
||||
if (osmo_apn_from_str(buf, buf_len, qst->domain) < 0)
|
||||
return -EINVAL;
|
||||
qname_len = strlen(qname) + 1;
|
||||
qname_buf = msgb_put(msg, qname_len);
|
||||
memcpy(qname_buf, qname, qname_len);
|
||||
talloc_free(qname);
|
||||
msgb_put_u8(msg, 0x00);
|
||||
|
||||
/* qtype and qclass */
|
||||
msgb_put_u16(msg, qst->qtype);
|
||||
@@ -182,21 +97,25 @@ struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const ui
|
||||
if (data_len < 6)
|
||||
return NULL;
|
||||
|
||||
/* qname */
|
||||
ret = talloc_zero(ctx, struct osmo_mdns_rfc_question);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
ret->domain = osmo_mdns_rfc_qname_decode(ret, (const char *)data, qname_len);
|
||||
if (!ret->domain) {
|
||||
talloc_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* qname */
|
||||
ret->domain = talloc_size(ret, qname_len - 1);
|
||||
if (!ret->domain)
|
||||
goto error;
|
||||
if (!osmo_apn_to_str(ret->domain, data, qname_len - 1))
|
||||
goto error;
|
||||
|
||||
/* qtype and qclass */
|
||||
ret->qtype = osmo_load16be(data + qname_len);
|
||||
ret->qclass = osmo_load16be(data + qname_len + 2);
|
||||
|
||||
return ret;
|
||||
error:
|
||||
talloc_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -206,20 +125,17 @@ struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const ui
|
||||
/*! Encode one resource record (RFC 1035 4.1.3).
|
||||
* \param[in] msgb mesage buffer to which the encoded data will be appended.
|
||||
*/
|
||||
int osmo_mdns_rfc_record_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_record *rec)
|
||||
int osmo_mdns_rfc_record_encode(struct msgb *msg, const struct osmo_mdns_rfc_record *rec)
|
||||
{
|
||||
char *name;
|
||||
size_t name_len;
|
||||
uint8_t *buf;
|
||||
size_t buf_len;
|
||||
|
||||
/* name */
|
||||
name = osmo_mdns_rfc_qname_encode(ctx, rec->domain);
|
||||
if (!name)
|
||||
buf_len = strlen(rec->domain) + 1;
|
||||
buf = msgb_put(msg, buf_len);
|
||||
if (osmo_apn_from_str(buf, buf_len, rec->domain) < 0)
|
||||
return -EINVAL;
|
||||
name_len = strlen(name) + 1;
|
||||
buf = msgb_put(msg, name_len);
|
||||
memcpy(buf, name, name_len);
|
||||
talloc_free(name);
|
||||
msgb_put_u8(msg, 0x00);
|
||||
|
||||
/* type, class, ttl, rdlength */
|
||||
msgb_put_u16(msg, rec->type);
|
||||
@@ -237,15 +153,26 @@ int osmo_mdns_rfc_record_encode(void *ctx, struct msgb *msg, const struct osmo_m
|
||||
struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len,
|
||||
size_t *record_len)
|
||||
{
|
||||
struct osmo_mdns_rfc_record *ret = talloc_zero(ctx, struct osmo_mdns_rfc_record);
|
||||
struct osmo_mdns_rfc_record *ret;
|
||||
size_t name_len;
|
||||
|
||||
/* name */
|
||||
ret->domain = osmo_mdns_rfc_qname_decode(ret, (const char *)data, data_len - 10);
|
||||
/* name length: represented as a series of labels, and terminated by a
|
||||
* label with zero length (RFC 1035 3.3). A label with zero length is a
|
||||
* NUL byte. */
|
||||
name_len = strnlen((const char *)data, data_len - 10) + 1;
|
||||
if (data[name_len])
|
||||
return NULL;
|
||||
|
||||
/* allocate ret + ret->domain */
|
||||
ret = talloc_zero(ctx, struct osmo_mdns_rfc_record);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
ret->domain = talloc_size(ctx, name_len - 1);
|
||||
if (!ret->domain)
|
||||
goto error;
|
||||
name_len = strlen(ret->domain) + 2;
|
||||
if (name_len + 10 > data_len)
|
||||
|
||||
/* name */
|
||||
if (!osmo_apn_to_str(ret->domain, data, name_len - 1))
|
||||
goto error;
|
||||
|
||||
/* type, class, ttl, rdlength */
|
||||
@@ -259,7 +186,7 @@ struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_
|
||||
/* rdata */
|
||||
ret->rdata = talloc_memdup(ret, data + name_len + 10, ret->rdlength);
|
||||
if (!ret->rdata)
|
||||
return NULL;
|
||||
goto error;
|
||||
|
||||
*record_len = name_len + 10 + ret->rdlength;
|
||||
return ret;
|
||||
|
||||
@@ -91,6 +91,7 @@ const struct value_string osmo_mslookup_id_type_names[] = {
|
||||
{ OSMO_MSLOOKUP_ID_NONE, "none" },
|
||||
{ OSMO_MSLOOKUP_ID_IMSI, "imsi" },
|
||||
{ OSMO_MSLOOKUP_ID_MSISDN, "msisdn" },
|
||||
{ OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED, "imsiauth" },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -134,6 +135,7 @@ bool osmo_mslookup_id_valid(const struct osmo_mslookup_id *id)
|
||||
{
|
||||
switch (id->type) {
|
||||
case OSMO_MSLOOKUP_ID_IMSI:
|
||||
case OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED:
|
||||
return osmo_imsi_str_valid(id->imsi);
|
||||
case OSMO_MSLOOKUP_ID_MSISDN:
|
||||
return osmo_msisdn_str_valid(id->msisdn);
|
||||
@@ -157,6 +159,7 @@ size_t osmo_mslookup_id_name_buf(char *buf, size_t buflen, const struct osmo_msl
|
||||
struct osmo_strbuf sb = { .buf = buf, .len = buflen };
|
||||
switch (id->type) {
|
||||
case OSMO_MSLOOKUP_ID_IMSI:
|
||||
case OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED:
|
||||
OSMO_STRBUF_PRINTF(sb, "%s", id->imsi);
|
||||
break;
|
||||
case OSMO_MSLOOKUP_ID_MSISDN:
|
||||
@@ -298,6 +301,7 @@ int osmo_mslookup_query_init_from_domain_str(struct osmo_mslookup_query *q, cons
|
||||
id = second_last_dot + 1;
|
||||
switch (q->id.type) {
|
||||
case OSMO_MSLOOKUP_ID_IMSI:
|
||||
case OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED:
|
||||
rc = token(q->id.imsi, sizeof(q->id.imsi), id, last_dot);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@@ -154,16 +154,20 @@ void osmo_mslookup_client_rx_result(struct osmo_mslookup_client *client, uint32_
|
||||
if (result->rc != OSMO_MSLOOKUP_RC_RESULT)
|
||||
return;
|
||||
|
||||
/* If the client wants to see all results, send this result now */
|
||||
if (req->handling.search_all && result->age > 0)
|
||||
req->handling.result_cb(client, request_handle, &req->query, result);
|
||||
|
||||
/* If we already stored an earlier successful result, keep that if its age is younger. */
|
||||
if (req->result.rc == OSMO_MSLOOKUP_RC_RESULT
|
||||
&& result->age >= req->result.age)
|
||||
&& result->age > req->result.age)
|
||||
return;
|
||||
|
||||
req->result = *result;
|
||||
|
||||
/* If age == 0, it doesn't get any better, so return the result immediately. */
|
||||
if (req->result.age == 0) {
|
||||
osmo_mslookup_request_send_result(req, true);
|
||||
osmo_mslookup_request_send_result(req, !req->handling.search_all);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ static void print_version(void)
|
||||
"\n");
|
||||
}
|
||||
|
||||
static void print_help()
|
||||
static void print_help(void)
|
||||
{
|
||||
print_version();
|
||||
printf(
|
||||
@@ -133,6 +133,10 @@ CSV_HEADERS "\n"
|
||||
" 1000-5000@sip.voice.123.msisdn Same, but silent for first second\n"
|
||||
" 10000-@smpp.sms.567.msisdn Return 1 result after 10 seconds\n"
|
||||
"\n"
|
||||
"--search-all -A\n"
|
||||
" Do not stop when a response with age of zero comes in.\n"
|
||||
" This can be used to \"search\" the entire dGSM network if for\n"
|
||||
" example there is a need to track down so-called \"evil twin\" hlr entries.\n"
|
||||
"--format -f csv (default)\n"
|
||||
" Format result lines in CSV format.\n"
|
||||
"--no-csv-headers -H\n"
|
||||
@@ -196,6 +200,7 @@ enum result_format {
|
||||
};
|
||||
|
||||
static struct {
|
||||
bool search_all;
|
||||
bool daemon;
|
||||
struct osmo_sockaddr_str mdns_addr;
|
||||
uint32_t min_delay;
|
||||
@@ -419,9 +424,9 @@ static void socket_client_close(struct socket_client *c)
|
||||
{
|
||||
struct osmo_fd *ofd = &c->ofd;
|
||||
|
||||
osmo_fd_unregister(ofd);
|
||||
close(ofd->fd);
|
||||
ofd->fd = -1;
|
||||
osmo_fd_unregister(ofd);
|
||||
|
||||
llist_del(&c->entry);
|
||||
talloc_free(c);
|
||||
@@ -429,7 +434,11 @@ static void socket_client_close(struct socket_client *c)
|
||||
|
||||
void socket_client_respond_result(struct socket_client *c, const char *response)
|
||||
{
|
||||
write(c->ofd.fd, response, strlen(response));
|
||||
size_t len = strlen(response);
|
||||
int rc = write(c->ofd.fd, response, len);
|
||||
|
||||
if (rc != len)
|
||||
print_error("%s: write() returned %d instead of %zu\n", __func__, rc, len);
|
||||
}
|
||||
|
||||
static int socket_read_cb(struct osmo_fd *ofd)
|
||||
@@ -526,8 +535,13 @@ int socket_accept(struct osmo_fd *ofd, unsigned int flags)
|
||||
|
||||
llist_add(&c->entry, &globals.socket_clients);
|
||||
|
||||
if (globals.format == FORMAT_CSV && cmdline_opts.csv_headers)
|
||||
write(c->ofd.fd, CSV_HEADERS, strlen(CSV_HEADERS));
|
||||
if (globals.format == FORMAT_CSV && cmdline_opts.csv_headers) {
|
||||
size_t len = strlen(CSV_HEADERS);
|
||||
int rc = write(c->ofd.fd, CSV_HEADERS, strlen(CSV_HEADERS));
|
||||
|
||||
if (rc != len)
|
||||
print_error("%s: write() returned %d instead of %zu\n", __func__, rc, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -555,15 +569,15 @@ int socket_init(const char *sock_path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void socket_close()
|
||||
void socket_close(void)
|
||||
{
|
||||
struct socket_client *c, *n;
|
||||
llist_for_each_entry_safe(c, n, &globals.socket_clients, entry)
|
||||
socket_client_close(c);
|
||||
if (osmo_fd_is_registered(&globals.socket_ofd)) {
|
||||
osmo_fd_unregister(&globals.socket_ofd);
|
||||
close(globals.socket_ofd.fd);
|
||||
globals.socket_ofd.fd = -1;
|
||||
osmo_fd_unregister(&globals.socket_ofd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,6 +642,7 @@ void start_query_str(const char *query_str)
|
||||
const char *domain_str = query_str;
|
||||
char *at;
|
||||
struct osmo_mslookup_query_handling h = {
|
||||
.search_all = cmdline_opts.search_all,
|
||||
.min_wait_milliseconds = cmdline_opts.min_delay,
|
||||
.result_timeout_milliseconds = cmdline_opts.timeout,
|
||||
.result_cb = mslookup_result_cb,
|
||||
@@ -730,6 +745,7 @@ int main(int argc, char **argv)
|
||||
int option_index = 0;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{ "search-all", 0, 0, 'A' },
|
||||
{ "format", 1, 0, 'f' },
|
||||
{ "no-csv-headers", 0, 0, 'H' },
|
||||
{ "daemon", 0, 0, 'd' },
|
||||
@@ -755,12 +771,15 @@ int main(int argc, char **argv)
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
c = getopt_long(argc, argv, "f:Hdm:M:D:t:T:s:SqhV", long_options, &option_index);
|
||||
c = getopt_long(argc, argv, "Af:Hdm:M:D:t:T:s:SqhV", long_options, &option_index);
|
||||
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'A':
|
||||
cmdline_opts.search_all = true;
|
||||
break;
|
||||
case 'f':
|
||||
cmdline_opts.format_str = optarg;
|
||||
break;
|
||||
|
||||
@@ -49,7 +49,7 @@ static void set_result(struct osmo_mslookup_result *result,
|
||||
result->age = age;
|
||||
}
|
||||
|
||||
const struct mslookup_service_host *mslookup_server_get_local_gsup_addr()
|
||||
const struct mslookup_service_host *mslookup_server_get_local_gsup_addr(void)
|
||||
{
|
||||
static struct mslookup_service_host gsup_bind = {};
|
||||
struct mslookup_service_host *host;
|
||||
@@ -192,12 +192,37 @@ static void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,
|
||||
{
|
||||
const struct mslookup_service_host *host;
|
||||
int rc;
|
||||
bool exists = false;
|
||||
bool auth_imsi_only = false;
|
||||
bool created_on_demand = false;
|
||||
|
||||
switch (query->id.type) {
|
||||
case OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED:
|
||||
auth_imsi_only = true;
|
||||
case OSMO_MSLOOKUP_ID_IMSI:
|
||||
/* Entries that have been created by subscriber create on demand
|
||||
will have default msisdn length. and will not have any vlr_number entry.
|
||||
We should not answer for these, unless they have CS/PS service. */
|
||||
if (g_hlr->mslookup.ignore_created_on_demand) {
|
||||
rc = db_subscr_is_created_on_demand_by_imsi(g_hlr->dbc, query->id.imsi,
|
||||
g_hlr->subscr_create_on_demand.rand_msisdn_len);
|
||||
if (!rc) {
|
||||
exists = true;
|
||||
created_on_demand = true;
|
||||
rc = -ENOENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rc = db_subscr_exists_by_imsi(g_hlr->dbc, query->id.imsi);
|
||||
if (g_hlr->mslookup.auth_imsi_only || auth_imsi_only) {
|
||||
if (!rc)
|
||||
exists = true;
|
||||
rc = db_subscr_authorized_by_imsi(g_hlr->dbc, query->id.imsi);
|
||||
}
|
||||
break;
|
||||
case OSMO_MSLOOKUP_ID_MSISDN:
|
||||
rc = db_subscr_exists_by_msisdn(g_hlr->dbc, query->id.msisdn);
|
||||
/* FIXME: The log message below might not match */
|
||||
break;
|
||||
default:
|
||||
LOGP(DMSLOOKUP, LOGL_ERROR, "Unknown mslookup ID type: %d\n", query->id.type);
|
||||
@@ -206,8 +231,11 @@ static void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: does not exist in local HLR\n",
|
||||
osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));
|
||||
LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: %s%s%s in local HLR\n",
|
||||
osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
|
||||
(exists) ? "exists but" : "does not exist",
|
||||
(created_on_demand) ? " is created on demand and since untouched" : "",
|
||||
(exists && !created_on_demand) ? " is not authorized" : "");
|
||||
*result = not_found;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ void osmo_mslookup_server_mdns_stop(struct osmo_mslookup_server_mdns *server)
|
||||
talloc_free(server);
|
||||
}
|
||||
|
||||
void mslookup_server_mdns_config_apply()
|
||||
void mslookup_server_mdns_config_apply(void)
|
||||
{
|
||||
/* Check whether to start/stop/restart mDNS server */
|
||||
bool should_run;
|
||||
|
||||
33
src/proxy.c
33
src/proxy.c
@@ -29,6 +29,7 @@
|
||||
#include <osmocom/gsupclient/gsup_client.h>
|
||||
#include <osmocom/gsupclient/gsup_req.h>
|
||||
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/logging.h>
|
||||
#include <osmocom/hlr/proxy.h>
|
||||
#include <osmocom/hlr/remote_hlr.h>
|
||||
@@ -80,7 +81,23 @@ static void proxy_deferred_gsup_req_add(struct proxy *proxy, struct osmo_gsup_re
|
||||
static void proxy_pending_req_remote_hlr_connect_result(struct osmo_gsup_req *req, struct remote_hlr *remote_hlr)
|
||||
{
|
||||
if (!remote_hlr || !remote_hlr_is_up(remote_hlr)) {
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "Proxy: Failed to connect to home HLR");
|
||||
/* Do not respond with an error to a CHECK_IMEI_REQUEST as osmo-msc will send a LU Reject Cause #6
|
||||
* Just respond ACK and deal with the IMSI check that comes next. */
|
||||
if (req->gsup.message_type == OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST) {
|
||||
/* Accept all IMEIs */
|
||||
struct osmo_gsup_message gsup_reply = (struct osmo_gsup_message){
|
||||
.message_type = OSMO_GSUP_MSGT_CHECK_IMEI_RESULT,
|
||||
.imei_result = OSMO_GSUP_IMEI_RESULT_ACK,
|
||||
};
|
||||
osmo_gsup_req_respond(req, &gsup_reply, false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
osmo_gsup_req_respond_err(req,
|
||||
(req->gsup.cn_domain == OSMO_GSUP_CN_DOMAIN_CS) ?
|
||||
g_hlr->no_proxy_reject_cause.cs :
|
||||
g_hlr->no_proxy_reject_cause.ps,
|
||||
"Proxy: Failed to connect to home HLR");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,6 +117,19 @@ static bool proxy_deferred_gsup_req_waiting(struct proxy *proxy, const char *ims
|
||||
return false;
|
||||
}
|
||||
|
||||
struct osmo_gsup_req *proxy_deferred_gsup_req_get_by_imsi(struct proxy *proxy, const char *imsi)
|
||||
{
|
||||
struct proxy_pending_gsup_req *p;
|
||||
OSMO_ASSERT(imsi);
|
||||
|
||||
llist_for_each_entry(p, &proxy->pending_gsup_reqs, entry) {
|
||||
if (strcmp(p->req->gsup.imsi, imsi))
|
||||
continue;
|
||||
return p->req;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Result of looking for remote HLR. If it failed, pass remote_hlr as NULL. On failure, the remote_hlr may be passed
|
||||
* NULL. */
|
||||
static void proxy_deferred_gsup_req_pop(struct proxy *proxy, const char *imsi, struct remote_hlr *remote_hlr)
|
||||
@@ -190,6 +220,7 @@ int proxy_subscr_create_or_update(struct proxy *proxy, const struct proxy_subscr
|
||||
int _proxy_subscr_del(struct proxy_subscr_listentry *e)
|
||||
{
|
||||
llist_del(&e->entry);
|
||||
talloc_free(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
#include <osmocom/gsm/gsm23003.h>
|
||||
#include <osmocom/abis/ipa.h>
|
||||
#include <osmocom/gsm/ipa.h>
|
||||
#include <osmocom/gsupclient/gsup_client.h>
|
||||
#include <osmocom/hlr/logging.h>
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
@@ -66,7 +66,7 @@ static void remote_hlr_err_reply(struct remote_hlr *rh, const struct osmo_gsup_m
|
||||
* The local MSC shall be indicated by gsup.destination_name. */
|
||||
static int remote_hlr_rx(struct osmo_gsup_client *gsupc, struct msgb *msg)
|
||||
{
|
||||
struct remote_hlr *rh = gsupc->data;
|
||||
struct remote_hlr *rh = osmo_gsup_client_get_data(gsupc);
|
||||
struct proxy_subscr proxy_subscr;
|
||||
struct osmo_gsup_message gsup;
|
||||
int rc;
|
||||
@@ -108,7 +108,7 @@ struct remote_hlr_pending_up {
|
||||
|
||||
static bool remote_hlr_up_down(struct osmo_gsup_client *gsupc, bool up)
|
||||
{
|
||||
struct remote_hlr *remote_hlr = gsupc->data;
|
||||
struct remote_hlr *remote_hlr = osmo_gsup_client_get_data(gsupc);
|
||||
struct remote_hlr_pending_up *p, *n;
|
||||
if (!up) {
|
||||
LOG_REMOTE_HLR(remote_hlr, LOGL_NOTICE, "link to remote HLR is down, removing GSUP client\n");
|
||||
@@ -127,7 +127,7 @@ static bool remote_hlr_up_down(struct osmo_gsup_client *gsupc, bool up)
|
||||
|
||||
bool remote_hlr_is_up(struct remote_hlr *remote_hlr)
|
||||
{
|
||||
return remote_hlr && remote_hlr->gsupc && remote_hlr->gsupc->is_connected;
|
||||
return remote_hlr && remote_hlr->gsupc && osmo_gsup_client_is_connected(remote_hlr->gsupc);
|
||||
}
|
||||
|
||||
struct remote_hlr *remote_hlr_get_or_connect(const struct osmo_sockaddr_str *addr, bool connect,
|
||||
@@ -180,7 +180,7 @@ struct remote_hlr *remote_hlr_get_or_connect(const struct osmo_sockaddr_str *add
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rh->gsupc->data = rh;
|
||||
osmo_gsup_client_set_data(rh->gsupc, rh);
|
||||
llist_add(&rh->entry, &remote_hlrs);
|
||||
|
||||
add_result_cb:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
SUBDIRS = \
|
||||
auc \
|
||||
gsup_server \
|
||||
db \
|
||||
gsup \
|
||||
db_upgrade \
|
||||
@@ -70,6 +69,9 @@ vty-test:
|
||||
|
||||
CTRL_TEST_DB = hlr_ctrl_test.db
|
||||
|
||||
# Run a specific test with: 'make ctrl-test CTRL_TEST=test_subscriber.ctrl'
|
||||
CTRL_TEST ?= *.ctrl
|
||||
|
||||
# To update the CTRL script from current application behavior,
|
||||
# pass -u to ctrl_script_runner.py by doing:
|
||||
# make ctrl-test U=-u
|
||||
@@ -80,7 +82,7 @@ ctrl-test:
|
||||
osmo_verify_transcript_ctrl.py -v \
|
||||
-p 4259 \
|
||||
-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l $(CTRL_TEST_DB)" \
|
||||
$(U) $(srcdir)/*.ctrl
|
||||
$(U) $(srcdir)/$(CTRL_TEST)
|
||||
-rm -f $(CTRL_TEST_DB)
|
||||
-rm $(CTRL_TEST_DB)-*
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@ SUBDIRS = gen_ts_55_205_test_sets
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-ggdb3 \
|
||||
-I$(top_srcdir)/include \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(NULL)
|
||||
@@ -23,17 +23,15 @@ EXTRA_DIST = \
|
||||
auc_ts_55_205_test_sets.err \
|
||||
$(NULL)
|
||||
|
||||
check_PROGRAMS = auc_ts_55_205_test_sets
|
||||
|
||||
noinst_PROGRAMS = auc_test
|
||||
check_PROGRAMS = auc_test auc_ts_55_205_test_sets
|
||||
|
||||
auc_test_SOURCES = \
|
||||
auc_test.c \
|
||||
$(NULL)
|
||||
|
||||
auc_test_LDADD = \
|
||||
$(top_srcdir)/src/auc.c \
|
||||
$(top_srcdir)/src/logging.c \
|
||||
$(top_builddir)/src/auc.o \
|
||||
$(top_builddir)/src/logging.o \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(NULL)
|
||||
@@ -43,8 +41,8 @@ auc_ts_55_205_test_sets_SOURCES = \
|
||||
$(NULL)
|
||||
|
||||
auc_ts_55_205_test_sets_LDADD = \
|
||||
$(top_srcdir)/src/auc.c \
|
||||
$(top_srcdir)/src/logging.c \
|
||||
$(top_builddir)/src/auc.o \
|
||||
$(top_builddir)/src/logging.o \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
@@ -116,14 +116,14 @@ int rand_get(uint8_t *rand, unsigned int len)
|
||||
/* Subscriber with 2G-only (COMP128v1) authentication data */
|
||||
static void test_gen_vectors_2g_only(void)
|
||||
{
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
struct osmo_sub_auth_data aud3g;
|
||||
struct osmo_sub_auth_data2 aud2g;
|
||||
struct osmo_sub_auth_data2 aud3g;
|
||||
struct osmo_auth_vector vec;
|
||||
int rc;
|
||||
|
||||
comment_start();
|
||||
|
||||
aud2g = (struct osmo_sub_auth_data){
|
||||
aud2g = (struct osmo_sub_auth_data2){
|
||||
.type = OSMO_AUTH_TYPE_GSM,
|
||||
.algo = OSMO_AUTH_ALG_COMP128v1,
|
||||
};
|
||||
@@ -131,7 +131,7 @@ static void test_gen_vectors_2g_only(void)
|
||||
osmo_hexparse("EB215756028D60E3275E613320AEC880",
|
||||
aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
|
||||
|
||||
aud3g = (struct osmo_sub_auth_data){ 0 };
|
||||
aud3g = (struct osmo_sub_auth_data2){ 0 };
|
||||
|
||||
next_rand("39fa2f4e3d523d8619a73b4f65c3e14d", true);
|
||||
|
||||
@@ -179,14 +179,14 @@ static void test_gen_vectors_2g_only(void)
|
||||
* reflects the default configuration of sysmoUSIM-SJS1 */
|
||||
static void test_gen_vectors_2g_plus_3g(void)
|
||||
{
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
struct osmo_sub_auth_data aud3g;
|
||||
struct osmo_sub_auth_data2 aud2g;
|
||||
struct osmo_sub_auth_data2 aud3g;
|
||||
struct osmo_auth_vector vec;
|
||||
int rc;
|
||||
|
||||
comment_start();
|
||||
|
||||
aud2g = (struct osmo_sub_auth_data){
|
||||
aud2g = (struct osmo_sub_auth_data2){
|
||||
.type = OSMO_AUTH_TYPE_GSM,
|
||||
.algo = OSMO_AUTH_ALG_COMP128v1,
|
||||
};
|
||||
@@ -194,9 +194,11 @@ static void test_gen_vectors_2g_plus_3g(void)
|
||||
osmo_hexparse("EB215756028D60E3275E613320AEC880",
|
||||
aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
|
||||
|
||||
aud3g = (struct osmo_sub_auth_data){
|
||||
aud3g = (struct osmo_sub_auth_data2){
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||
.u.umts.k_len = 16,
|
||||
.u.umts.opc_len = 16,
|
||||
.u.umts.sqn = 31,
|
||||
};
|
||||
|
||||
@@ -292,8 +294,8 @@ void _test_gen_vectors_3g_only__expect_vecs(struct osmo_auth_vector vecs[3])
|
||||
* tuples are suitable for both 2G and 3G authentication */
|
||||
static void test_gen_vectors_3g_only(void)
|
||||
{
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
struct osmo_sub_auth_data aud3g;
|
||||
struct osmo_sub_auth_data2 aud2g;
|
||||
struct osmo_sub_auth_data2 aud3g;
|
||||
struct osmo_auth_vector vec;
|
||||
struct osmo_auth_vector vecs[3];
|
||||
uint8_t auts[14];
|
||||
@@ -302,11 +304,13 @@ static void test_gen_vectors_3g_only(void)
|
||||
|
||||
comment_start();
|
||||
|
||||
aud2g = (struct osmo_sub_auth_data){ 0 };
|
||||
aud2g = (struct osmo_sub_auth_data2){ 0 };
|
||||
|
||||
aud3g = (struct osmo_sub_auth_data){
|
||||
aud3g = (struct osmo_sub_auth_data2){
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||
.u.umts.k_len = 16,
|
||||
.u.umts.opc_len = 16,
|
||||
.u.umts.sqn = 31,
|
||||
};
|
||||
|
||||
@@ -466,18 +470,20 @@ static void test_gen_vectors_3g_only(void)
|
||||
* 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_sub_auth_data2 aud2g;
|
||||
struct osmo_sub_auth_data2 aud3g;
|
||||
struct osmo_auth_vector vec;
|
||||
int rc;
|
||||
|
||||
comment_start();
|
||||
|
||||
aud2g = (struct osmo_sub_auth_data){ 0 };
|
||||
aud2g = (struct osmo_sub_auth_data2){ 0 };
|
||||
|
||||
aud3g = (struct osmo_sub_auth_data){
|
||||
aud3g = (struct osmo_sub_auth_data2){
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.algo = OSMO_AUTH_ALG_XOR,
|
||||
.algo = OSMO_AUTH_ALG_XOR_3G,
|
||||
.u.umts.k_len = 16,
|
||||
.u.umts.opc_len = 16,
|
||||
.u.umts.sqn = 0,
|
||||
};
|
||||
|
||||
@@ -509,7 +515,7 @@ static void test_gen_vectors_3g_xor(void)
|
||||
}
|
||||
|
||||
/* Test a variety of invalid authentication data combinations */
|
||||
void test_gen_vectors_bad_args()
|
||||
void test_gen_vectors_bad_args(void)
|
||||
{
|
||||
struct osmo_auth_vector vec;
|
||||
uint8_t auts[14];
|
||||
@@ -517,39 +523,43 @@ void test_gen_vectors_bad_args()
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
struct osmo_sub_auth_data aud2g = {
|
||||
struct osmo_sub_auth_data2 aud2g = {
|
||||
.type = OSMO_AUTH_TYPE_GSM,
|
||||
.algo = OSMO_AUTH_ALG_COMP128v1,
|
||||
};
|
||||
|
||||
struct osmo_sub_auth_data aud3g = {
|
||||
struct osmo_sub_auth_data2 aud3g = {
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||
.u.umts.k_len = 16,
|
||||
.u.umts.opc_len = 16,
|
||||
};
|
||||
|
||||
struct osmo_sub_auth_data aud2g_noalg = {
|
||||
struct osmo_sub_auth_data2 aud2g_noalg = {
|
||||
.type = OSMO_AUTH_TYPE_GSM,
|
||||
.algo = OSMO_AUTH_ALG_NONE,
|
||||
};
|
||||
|
||||
struct osmo_sub_auth_data aud3g_noalg = {
|
||||
struct osmo_sub_auth_data2 aud3g_noalg = {
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.algo = OSMO_AUTH_ALG_NONE,
|
||||
.u.umts.k_len = 16,
|
||||
.u.umts.opc_len = 16,
|
||||
};
|
||||
|
||||
struct osmo_sub_auth_data aud_notype = {
|
||||
struct osmo_sub_auth_data2 aud_notype = {
|
||||
.type = OSMO_AUTH_TYPE_NONE,
|
||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||
};
|
||||
|
||||
struct osmo_sub_auth_data no_aud = {
|
||||
struct osmo_sub_auth_data2 no_aud = {
|
||||
.type = OSMO_AUTH_TYPE_NONE,
|
||||
.algo = OSMO_AUTH_ALG_NONE,
|
||||
};
|
||||
|
||||
struct {
|
||||
struct osmo_sub_auth_data *aud2g;
|
||||
struct osmo_sub_auth_data *aud3g;
|
||||
struct osmo_sub_auth_data2 *aud2g;
|
||||
struct osmo_sub_auth_data2 *aud3g;
|
||||
uint8_t *rand_auts;
|
||||
uint8_t *auts;
|
||||
const char *label;
|
||||
|
||||
@@ -24,43 +24,46 @@
|
||||
|
||||
static void {func_name}(void)
|
||||
{{
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
struct osmo_sub_auth_data aud3g;
|
||||
struct osmo_auth_vector vec;
|
||||
int rc;
|
||||
struct osmo_sub_auth_data2 aud2g;
|
||||
struct osmo_sub_auth_data2 aud3g;
|
||||
struct osmo_auth_vector vec;
|
||||
int rc;
|
||||
|
||||
comment_start();
|
||||
comment_start();
|
||||
|
||||
aud2g = (struct osmo_sub_auth_data){{ 0 }};
|
||||
aud2g = (struct osmo_sub_auth_data2){{ 0 }};
|
||||
|
||||
aud3g = (struct osmo_sub_auth_data){{
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||
aud3g = (struct osmo_sub_auth_data2){{
|
||||
.type = OSMO_AUTH_TYPE_UMTS,
|
||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||
.u.umts.k_len = 16,
|
||||
.u.umts.opc_len = 16,
|
||||
.u.umts.sqn = 31,
|
||||
}};
|
||||
}};
|
||||
|
||||
osmo_hexparse("{Ki}",
|
||||
aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
|
||||
osmo_hexparse("{OPc}",
|
||||
aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
|
||||
osmo_hexparse("{Ki}",
|
||||
aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
|
||||
osmo_hexparse("{OPc}",
|
||||
aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
|
||||
|
||||
osmo_hexparse("{RAND}",
|
||||
fake_rand, sizeof(fake_rand));
|
||||
osmo_hexparse("{RAND}",
|
||||
fake_rand, sizeof(fake_rand));
|
||||
|
||||
vec = (struct osmo_auth_vector){{ {{0}} }};
|
||||
vec = (struct osmo_auth_vector){{ {{0}} }};
|
||||
vec.res_len = 8;
|
||||
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64);
|
||||
rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
|
||||
VERBOSE_ASSERT(rc, == 1, "%d");
|
||||
rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
|
||||
VERBOSE_ASSERT(rc, == 1, "%d");
|
||||
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 32, "%"PRIu64);
|
||||
|
||||
VEC_IS(&vec,
|
||||
" rand: {RAND}\n"
|
||||
" ck: {MIL3G-CK}\n"
|
||||
" ik: {MIL3G-IK}\n"
|
||||
" res: {MIL3G-RES}0000000000000000\n"
|
||||
" kc: {Kc}\n"
|
||||
" sres: {SRES#1}\n"
|
||||
);
|
||||
VEC_IS(&vec,
|
||||
" rand: {RAND}\n"
|
||||
" ck: {MIL3G-CK}\n"
|
||||
" ik: {MIL3G-IK}\n"
|
||||
" res: {MIL3G-RES}0000000000000000\n"
|
||||
" kc: {Kc}\n"
|
||||
" sres: {SRES#1}\n"
|
||||
);
|
||||
|
||||
comment_end();
|
||||
}}
|
||||
|
||||
@@ -55,7 +55,7 @@ char *vec_str(const struct osmo_auth_vector *vec)
|
||||
if (pos >= end) \
|
||||
return buf; \
|
||||
pos += snprintf(pos, sizeof(buf) - (pos - buf), \
|
||||
" " #what ": %s\n", \
|
||||
" " #what ": %s\n", \
|
||||
osmo_hexdump_nospc((void*)&vec->what, sizeof(vec->what)))
|
||||
|
||||
append(rand);
|
||||
@@ -71,7 +71,7 @@ char *vec_str(const struct osmo_auth_vector *vec)
|
||||
|
||||
#define VEC_IS(vec, expect) do { \
|
||||
char *_is = vec_str(vec); \
|
||||
if (strcmp(_is, expect)) { \
|
||||
if (strcmp(_is, expect)) { \
|
||||
fprintf(stderr, "MISMATCH! expected ==\n%s\n", \
|
||||
expect); \
|
||||
char *a = _is; \
|
||||
@@ -100,7 +100,7 @@ int rand_get(uint8_t *rand, unsigned int len)
|
||||
|
||||
FUNCTIONS
|
||||
|
||||
int main()
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("3GPP TS 55.205 Test Sets\n");
|
||||
void *tall_ctx = talloc_named_const(NULL, 1, "test");
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
AM_CFLAGS = \
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_builddir)/include \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-ggdb3 \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
|
||||
@@ -122,16 +122,16 @@ static void _fill_invalid(void *dest, size_t size)
|
||||
/* Not linking the real auc_compute_vectors(), just returning num_vec.
|
||||
* This gets called by db_get_auc(), but we're only interested in its rc. */
|
||||
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||
struct osmo_sub_auth_data *aud2g,
|
||||
struct osmo_sub_auth_data *aud3g,
|
||||
struct osmo_sub_auth_data2 *aud2g,
|
||||
struct osmo_sub_auth_data2 *aud3g,
|
||||
const uint8_t *rand_auts, const uint8_t *auts)
|
||||
{ return num_vec; }
|
||||
|
||||
static struct db_context *dbc = NULL;
|
||||
static void *ctx = NULL;
|
||||
static struct hlr_subscriber g_subscr;
|
||||
static struct osmo_sub_auth_data g_aud2g;
|
||||
static struct osmo_sub_auth_data g_aud3g;
|
||||
static struct osmo_sub_auth_data2 g_aud2g;
|
||||
static struct osmo_sub_auth_data2 g_aud3g;
|
||||
static int g_rc;
|
||||
static int64_t g_id;
|
||||
|
||||
@@ -180,18 +180,21 @@ void dump_subscr(struct hlr_subscriber *subscr)
|
||||
#undef Pb
|
||||
}
|
||||
|
||||
void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
|
||||
void dump_aud(const char *label, struct osmo_sub_auth_data2 *aud)
|
||||
{
|
||||
if (aud->type == OSMO_AUTH_TYPE_NONE) {
|
||||
fprintf(stderr, "%s: none\n", label);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: struct osmo_sub_auth_data {\n", label);
|
||||
fprintf(stderr, "%s: struct osmo_sub_auth_data2 {\n", label);
|
||||
#define Pf(name, fmt) \
|
||||
Pfo(name, fmt, aud)
|
||||
#define Phex(name) \
|
||||
Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, sizeof(aud->name)))
|
||||
#define Phexl(name, len) \
|
||||
Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, aud->len))
|
||||
|
||||
|
||||
Pfv(type, "%s", osmo_sub_auth_type_name(aud->type));
|
||||
Pfv(algo, "%s", osmo_auth_alg_name(aud->algo));
|
||||
@@ -200,9 +203,9 @@ void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
|
||||
Phex(u.gsm.ki);
|
||||
break;
|
||||
case OSMO_AUTH_TYPE_UMTS:
|
||||
Phex(u.umts.opc);
|
||||
Phexl(u.umts.opc, u.umts.opc_len);
|
||||
Pf(u.umts.opc_is_op, "%u");
|
||||
Phex(u.umts.k);
|
||||
Phexl(u.umts.k, u.umts.k_len);
|
||||
Phex(u.umts.amf);
|
||||
if (aud->u.umts.sqn) {
|
||||
Pf(u.umts.sqn, "%"PRIu64);
|
||||
@@ -219,6 +222,7 @@ void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
|
||||
|
||||
#undef Pf
|
||||
#undef Phex
|
||||
#undef Phexl
|
||||
}
|
||||
|
||||
void db_raw_sql(struct db_context *dbc, const char *sql)
|
||||
@@ -246,7 +250,7 @@ static int db_subscr_lu_str(struct db_context *dbc, int64_t subscr_id,
|
||||
return db_subscr_lu(dbc, subscr_id, &vlr_nr, is_ps, NULL);
|
||||
}
|
||||
|
||||
static void test_subscr_create_update_sel_delete()
|
||||
static void test_subscr_create_update_sel_delete(void)
|
||||
{
|
||||
int64_t id0, id1, id2, id_short;
|
||||
comment_start();
|
||||
@@ -262,13 +266,13 @@ static void test_subscr_create_update_sel_delete()
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||
ASSERT_SEL(imsi, imsi2, 0);
|
||||
id2 = g_subscr.id;
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
|
||||
ASSERT_SEL(imsi, imsi0, 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
|
||||
ASSERT_SEL(imsi, imsi1, 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
|
||||
ASSERT_SEL(imsi, imsi2, 0);
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, "123456789 000003", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EINVAL);
|
||||
@@ -541,7 +545,7 @@ static const struct sub_auth_data_str *mk_aud_3g(enum osmo_auth_algo algo,
|
||||
return &aud;
|
||||
}
|
||||
|
||||
static void test_subscr_aud()
|
||||
static void test_subscr_aud(void)
|
||||
{
|
||||
int64_t id;
|
||||
|
||||
@@ -586,7 +590,7 @@ static void test_subscr_aud()
|
||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||
|
||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||
mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")),
|
||||
mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")),
|
||||
0);
|
||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||
|
||||
@@ -604,7 +608,7 @@ static void test_subscr_aud()
|
||||
-ENOENT);
|
||||
|
||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||
mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")),
|
||||
mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")),
|
||||
0);
|
||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||
|
||||
@@ -707,12 +711,12 @@ static void test_subscr_aud()
|
||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||
|
||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||
mk_aud_2g(OSMO_AUTH_ALG_XOR, "f000000000000f00000000000f000000f00000000")),
|
||||
mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f000000000000f00000000000f000000f00000000")),
|
||||
-EINVAL);
|
||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||
|
||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||
mk_aud_2g(OSMO_AUTH_ALG_XOR, "f00")),
|
||||
mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f00")),
|
||||
-EINVAL);
|
||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||
|
||||
@@ -783,7 +787,7 @@ static void test_subscr_aud()
|
||||
|
||||
/* Make each key too short in this test. Note that we can't set them longer than the allowed size without changing the
|
||||
* table structure. */
|
||||
static void test_subscr_aud_invalid_len()
|
||||
static void test_subscr_aud_invalid_len(void)
|
||||
{
|
||||
int64_t id;
|
||||
|
||||
@@ -845,7 +849,7 @@ static void test_subscr_aud_invalid_len()
|
||||
comment_end();
|
||||
}
|
||||
|
||||
static void test_subscr_sqn()
|
||||
static void test_subscr_sqn(void)
|
||||
{
|
||||
int64_t id;
|
||||
|
||||
@@ -918,6 +922,50 @@ static void test_subscr_sqn()
|
||||
comment_end();
|
||||
}
|
||||
|
||||
static void test_ind(void)
|
||||
{
|
||||
comment_start();
|
||||
|
||||
#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)); \
|
||||
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)); \
|
||||
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)
|
||||
|
||||
ASSERT_IND("msc-23", 1);
|
||||
ASSERT_IND("sgsn-11", 2);
|
||||
ASSERT_IND("msc-42", 3);
|
||||
ASSERT_IND("sgsn-22", 4);
|
||||
ASSERT_IND("msc-0x17", 5);
|
||||
ASSERT_IND("sgsn-0xaa", 6);
|
||||
ASSERT_IND("msc-42", 3);
|
||||
ASSERT_IND("sgsn-22", 4);
|
||||
ASSERT_IND("msc-0x17", 5);
|
||||
ASSERT_IND("sgsn-0xaa", 6);
|
||||
ASSERT_IND("sgsn-0xbb", 7);
|
||||
ASSERT_IND("msc-0x2a", 8);
|
||||
ASSERT_IND("msc-42", 3);
|
||||
ASSERT_IND("sgsn-22", 4);
|
||||
ASSERT_IND("msc-23", 1);
|
||||
ASSERT_IND("sgsn-11", 2);
|
||||
|
||||
IND_DEL("msc-0x17"); /* dropped IND == 5 */
|
||||
ASSERT_IND("msc-0x2a", 8); /* known CS remains where it is */
|
||||
ASSERT_IND("any-unknown", 9); /* new VLR takes a new IND from the end */
|
||||
|
||||
comment_end();
|
||||
}
|
||||
|
||||
static struct {
|
||||
bool verbose;
|
||||
} cmdline_opts = {
|
||||
@@ -1002,6 +1050,7 @@ int main(int argc, char **argv)
|
||||
test_subscr_aud();
|
||||
test_subscr_aud_invalid_len();
|
||||
test_subscr_sqn();
|
||||
test_ind();
|
||||
|
||||
printf("Done\n");
|
||||
db_close(dbc);
|
||||
|
||||
@@ -27,7 +27,7 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000002',
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
|
||||
db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
|
||||
DAUC IMSI='123456789000000': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
||||
@@ -36,10 +36,10 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000000',
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
|
||||
db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
|
||||
DAUC IMSI='123456789000001': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
||||
|
||||
db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
|
||||
db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
|
||||
DAUC IMSI='123456789000001': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi1, &g_subscr) --> 0
|
||||
@@ -48,10 +48,10 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000001',
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
|
||||
db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
|
||||
DAUC IMSI='123456789000002': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
||||
|
||||
db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
|
||||
db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
|
||||
DAUC IMSI='123456789000002': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi2, &g_subscr) --> 0
|
||||
@@ -824,7 +824,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "01234567
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v1,
|
||||
.u.gsm.ki = '0123456789abcdef0123456789abcdef',
|
||||
@@ -841,7 +841,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "01234567
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v1,
|
||||
.u.gsm.ki = '0123456789abcdef0123456789abcdef',
|
||||
@@ -853,7 +853,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v2, "BeadedBe
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v2,
|
||||
.u.gsm.ki = 'beadedbeeaced1ebbeddefacedfacade',
|
||||
@@ -865,21 +865,21 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v3, "DeafBedd
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'deafbeddedbabeacceededfadeddecaf',
|
||||
}
|
||||
3G: none
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")) --> 0
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = XOR,
|
||||
.algo = XOR-2G,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: none
|
||||
@@ -900,14 +900,14 @@ DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> -ENOENT
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")) --> 0
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = XOR,
|
||||
.algo = XOR-2G,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: none
|
||||
@@ -932,7 +932,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -954,7 +954,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -970,7 +970,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'deaf0ff1ced0d0dabbedd1ced1cef00d',
|
||||
@@ -985,7 +985,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1001,7 +1001,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
|
||||
@@ -1033,7 +1033,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
|
||||
@@ -1069,12 +1069,12 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCaf
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1097,12 +1097,12 @@ DAUC Cannot update auth tokens: Unknown auth algo: 99999
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1112,17 +1112,17 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
.u.umts.ind_bitlen = 5,
|
||||
}
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "f000000000000f00000000000f000000f00000000")) --> -EINVAL
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f000000000000f00000000000f000000f00000000")) --> -EINVAL
|
||||
DAUC Cannot update auth tokens: Invalid KI: 'f000000000000f00000000000f000000f00000000'
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1132,17 +1132,17 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
.u.umts.ind_bitlen = 5,
|
||||
}
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "f00")) --> -EINVAL
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f00")) --> -EINVAL
|
||||
DAUC Cannot update auth tokens: Invalid KI: 'f00'
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1157,12 +1157,12 @@ DAUC Cannot update auth tokens: auth algo not suited for 2G: MILENAGE
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1177,12 +1177,12 @@ DAUC Cannot update auth tokens: Invalid OP/OPC: '0f000000000000f00000000000f0000
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1197,12 +1197,12 @@ DAUC Cannot update auth tokens: Invalid K: '000000000000f00000000000f000000'
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1217,12 +1217,12 @@ DAUC Cannot update auth tokens: Invalid ind_bitlen: 29
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1237,12 +1237,12 @@ DAUC Cannot update auth tokens: Invalid OP/OPC: 'X000000000000f00000000000f00000
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1257,12 +1257,12 @@ DAUC Cannot update auth tokens: Invalid K: 'f000000000000 f00000000000 f000000'
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
|
||||
2G: struct osmo_sub_auth_data {
|
||||
2G: struct osmo_sub_auth_data2 {
|
||||
.type = GSM,
|
||||
.algo = COMP128v3,
|
||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||
}
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1338,7 +1338,7 @@ sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
|
||||
sqlite3_step(stmt) --> SQLITE_DONE
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': Error reading Ki, expected length 16 but has length 15
|
||||
DAUC IMSI='123456789000000': Error reading Ki, expected min length 16 but has length 15
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
|
||||
@@ -1359,7 +1359,7 @@ sqlite3_step(stmt) --> SQLITE_DONE
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': Error reading K, expected length 16 but has length 15
|
||||
DAUC IMSI='123456789000000': Error reading K, expected min length 16 but has length 15
|
||||
|
||||
|
||||
|
||||
@@ -1374,7 +1374,7 @@ sqlite3_step(stmt) --> SQLITE_DONE
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': Error reading OP, expected length 16 but has length 15
|
||||
DAUC IMSI='123456789000000': Error reading OP, expected min length 16 but has length 15
|
||||
|
||||
|
||||
|
||||
@@ -1389,7 +1389,7 @@ sqlite3_step(stmt) --> SQLITE_DONE
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': Error reading OPC, expected length 16 but has length 15
|
||||
DAUC IMSI='123456789000000': Error reading OPC, expected min length 16 but has length 15
|
||||
|
||||
|
||||
|
||||
@@ -1458,7 +1458,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1477,7 +1477,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1495,7 +1495,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1513,7 +1513,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1534,7 +1534,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1550,7 +1550,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1568,7 +1568,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1586,7 +1586,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
2G: none
|
||||
3G: struct osmo_sub_auth_data {
|
||||
3G: struct osmo_sub_auth_data2 {
|
||||
.type = UMTS,
|
||||
.algo = MILENAGE,
|
||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||
@@ -1613,3 +1613,83 @@ db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> -ENOENT
|
||||
|
||||
===== test_subscr_sqn: SUCCESS
|
||||
|
||||
|
||||
===== test_ind
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"msc-23\0" ind = 1
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"sgsn-11\0" ind = 2
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"msc-42\0" ind = 3
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"sgsn-22\0" ind = 4
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"msc-0x17\0" ind = 5
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"sgsn-0xaa\0" ind = 6
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"msc-42\0" ind = 3
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"sgsn-22\0" ind = 4
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"msc-0x17\0" ind = 5
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"sgsn-0xaa\0" ind = 6
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"sgsn-0xbb\0" ind = 7
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"msc-0x2a\0" ind = 8
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"msc-42\0" ind = 3
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"sgsn-22\0" ind = 4
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"msc-23\0" ind = 1
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"sgsn-11\0" ind = 2
|
||||
|
||||
db_ind_del(dbc, &vlr) --> 0
|
||||
|
||||
"msc-0x17\0" ind deleted
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"msc-0x2a\0" ind = 8
|
||||
|
||||
db_ind(dbc, &vlr, &ind) --> 0
|
||||
|
||||
"any-unknown\0" ind = 9
|
||||
|
||||
===== test_ind: SUCCESS
|
||||
|
||||
|
||||
@@ -43,5 +43,5 @@ OsmoHLR# subscriber imsi 5555555 create
|
||||
MSISDN: none
|
||||
OsmoHLR# subscriber imsi 5555555 update msisdn 55555555555555
|
||||
% Updated subscriber IMSI='5555555' to MSISDN='55555555555555'
|
||||
OsmoHLR# subscriber imsi 5555555 update aud2g xor ki 55555555555555555555555555555555
|
||||
OsmoHLR# subscriber imsi 5555555 update aud2g xor-2g ki 55555555555555555555555555555555
|
||||
OsmoHLR# subscriber imsi 5555555 update aud3g milenage k 55555555555555555555555555555555 opc 55555555555555555555555555555555
|
||||
|
||||
@@ -12,7 +12,7 @@ Table auc_2g contents:
|
||||
algo_id_2g|ki|subscriber_id
|
||||
1|BeefedCafeFaceAcedAddedDecadeFee|1
|
||||
2|33333333333333333333333333333333|4
|
||||
4|55555555555555555555555555555555|6
|
||||
6|55555555555555555555555555555555|6
|
||||
|
||||
Table: auc_3g
|
||||
name|type|notnull|dflt_value|pk
|
||||
@@ -85,6 +85,8 @@ DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 2
|
||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 3
|
||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 4
|
||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 5
|
||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 6
|
||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 7
|
||||
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
|
||||
|
||||
Resulting db:
|
||||
@@ -99,15 +101,15 @@ Table auc_2g contents:
|
||||
algo_id_2g|ki|subscriber_id
|
||||
1|BeefedCafeFaceAcedAddedDecadeFee|1
|
||||
2|33333333333333333333333333333333|4
|
||||
4|55555555555555555555555555555555|6
|
||||
6|55555555555555555555555555555555|6
|
||||
|
||||
Table: auc_3g
|
||||
name|type|notnull|dflt_value|pk
|
||||
algo_id_3g|INTEGER|1||0
|
||||
ind_bitlen|INTEGER|1|5|0
|
||||
k|VARCHAR(32)|1||0
|
||||
op|VARCHAR(32)|0||0
|
||||
opc|VARCHAR(32)|0||0
|
||||
k|VARCHAR(64)|1||0
|
||||
op|VARCHAR(64)|0||0
|
||||
opc|VARCHAR(64)|0||0
|
||||
sqn|INTEGER|1|0|0
|
||||
subscriber_id|INTEGER|0||1
|
||||
|
||||
@@ -117,6 +119,13 @@ algo_id_3g|ind_bitlen|k|op|opc|sqn|subscriber_id
|
||||
5|5|44444444444444444444444444444444|44444444444444444444444444444444||0|5
|
||||
5|5|55555555555555555555555555555555||55555555555555555555555555555555|0|6
|
||||
|
||||
Table: ind
|
||||
name|type|notnull|dflt_value|pk
|
||||
ind|INTEGER|0||1
|
||||
vlr|TEXT|1||0
|
||||
|
||||
Table ind contents:
|
||||
|
||||
Table: subscriber
|
||||
name|type|notnull|dflt_value|pk
|
||||
ggsn_number|VARCHAR(15)|0||0
|
||||
@@ -171,5 +180,5 @@ osmo-hlr --database $db --db-check --config-file $srcdir/osmo-hlr.cfg
|
||||
rc = 0
|
||||
DMAIN hlr starting
|
||||
DDB using database: <PATH>test.db
|
||||
DDB Database <PATH>test.db' has HLR DB schema version 5
|
||||
DDB Database <PATH>test.db' has HLR DB schema version 7
|
||||
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
|
||||
|
||||
@@ -61,7 +61,7 @@ CREATE TABLE auc_2g (
|
||||
);
|
||||
INSERT INTO auc_2g VALUES(1,1,'BeefedCafeFaceAcedAddedDecadeFee');
|
||||
INSERT INTO auc_2g VALUES(4,2,'33333333333333333333333333333333');
|
||||
INSERT INTO auc_2g VALUES(6,4,'55555555555555555555555555555555');
|
||||
INSERT INTO auc_2g VALUES(6,6,'55555555555555555555555555555555');
|
||||
CREATE TABLE auc_3g (
|
||||
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
|
||||
algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(NULL)
|
||||
@@ -17,7 +17,7 @@ EXTRA_DIST = \
|
||||
gsup_test.err \
|
||||
$(NULL)
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
check_PROGRAMS = \
|
||||
gsup_test \
|
||||
$(NULL)
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
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/cni_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"
|
||||
@@ -1,145 +0,0 @@
|
||||
/* (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;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
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
|
||||
@@ -1,11 +1,11 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
-ggdb3 \
|
||||
-I$(top_srcdir)/include \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMOABIS_CFLAGS) \
|
||||
|
||||
@@ -32,148 +32,6 @@ struct qname_enc_dec_test {
|
||||
size_t qname_max_len; /* default: strlen(qname) + 1 */
|
||||
};
|
||||
|
||||
static const struct qname_enc_dec_test qname_enc_dec_test_data[] = {
|
||||
{
|
||||
/* OK: typical mslookup domain */
|
||||
.domain = "hlr.1234567.imsi",
|
||||
.qname = "\x03" "hlr" "\x07" "1234567" "\x04" "imsi",
|
||||
},
|
||||
{
|
||||
/* Wrong format: double dot */
|
||||
.domain = "hlr..imsi",
|
||||
.qname = NULL,
|
||||
},
|
||||
{
|
||||
/* Wrong format: double dot */
|
||||
.domain = "hlr",
|
||||
.qname = "\x03hlr\0\x03imsi",
|
||||
},
|
||||
{
|
||||
/* Wrong format: dot at end */
|
||||
.domain = "hlr.",
|
||||
.qname = NULL,
|
||||
},
|
||||
{
|
||||
/* Wrong format: dot at start */
|
||||
.domain = ".hlr",
|
||||
.qname = NULL,
|
||||
},
|
||||
{
|
||||
/* Wrong format: empty */
|
||||
.domain = "",
|
||||
.qname = NULL,
|
||||
},
|
||||
{
|
||||
/* OK: maximum length */
|
||||
.domain =
|
||||
"123456789." "123456789." "123456789." "123456789." "123456789."
|
||||
"123456789." "123456789." "123456789." "123456789." "123456789."
|
||||
"123456789." "123456789." "123456789." "123456789." "123456789."
|
||||
"123456789." "123456789." "123456789." "123456789." "123456789."
|
||||
"123456789." "123456789." "123456789." "123456789." "123456789."
|
||||
"12345"
|
||||
,
|
||||
.qname =
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
"\x05" "12345"
|
||||
},
|
||||
{
|
||||
/* Error: too long domain */
|
||||
.domain =
|
||||
"123456789." "123456789." "123456789." "123456789." "123456789."
|
||||
"123456789." "123456789." "123456789." "123456789." "123456789."
|
||||
"123456789." "123456789." "123456789." "123456789." "123456789."
|
||||
"123456789." "123456789." "123456789." "123456789." "123456789."
|
||||
"123456789." "123456789." "123456789." "123456789." "123456789."
|
||||
"12345toolong"
|
||||
,
|
||||
.qname = NULL,
|
||||
},
|
||||
{
|
||||
/* Error: too long qname */
|
||||
.domain = NULL,
|
||||
.qname =
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
"\t123456789\t123456789\t123456789\t123456789\t123456789"
|
||||
},
|
||||
{
|
||||
/* Error: wrong token length in qname */
|
||||
.domain = NULL,
|
||||
.qname = "\x03" "hlr" "\x07" "1234567" "\x05" "imsi",
|
||||
},
|
||||
{
|
||||
/* Error: wrong token length in qname */
|
||||
.domain = NULL,
|
||||
.qname = "\x02" "hlr" "\x07" "1234567" "\x04" "imsi",
|
||||
},
|
||||
{
|
||||
/* Wrong format: token length at end of qname */
|
||||
.domain = NULL,
|
||||
.qname = "\x03hlr\x03",
|
||||
},
|
||||
{
|
||||
/* Error: overflow in label length */
|
||||
.domain = NULL,
|
||||
.qname = "\x03" "hlr" "\x07" "1234567" "\x04" "imsi",
|
||||
.qname_max_len = 17,
|
||||
},
|
||||
};
|
||||
|
||||
void test_enc_dec_rfc_qname(void *ctx)
|
||||
{
|
||||
char quote_buf[300];
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "-- %s --\n", __func__);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(qname_enc_dec_test_data); i++) {
|
||||
const struct qname_enc_dec_test *t = &qname_enc_dec_test_data[i];
|
||||
char *res;
|
||||
|
||||
if (t->domain) {
|
||||
fprintf(stderr, "domain: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), t->domain, -1));
|
||||
fprintf(stderr, "exp: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), t->qname, -1));
|
||||
res = osmo_mdns_rfc_qname_encode(ctx, t->domain);
|
||||
fprintf(stderr, "res: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), res, -1));
|
||||
if (t->qname == res || (t->qname && res && strcmp(t->qname, res) == 0))
|
||||
fprintf(stderr, "=> OK\n");
|
||||
else
|
||||
fprintf(stderr, "=> ERROR\n");
|
||||
if (res)
|
||||
talloc_free(res);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
if (t->qname) {
|
||||
size_t qname_max_len = t->qname_max_len;
|
||||
if (qname_max_len)
|
||||
fprintf(stderr, "qname_max_len: %lu\n", qname_max_len);
|
||||
else
|
||||
qname_max_len = strlen(t->qname) + 1;
|
||||
|
||||
fprintf(stderr, "qname: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), t->qname, -1));
|
||||
fprintf(stderr, "exp: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), t->domain, -1));
|
||||
res = osmo_mdns_rfc_qname_decode(ctx, t->qname, qname_max_len);
|
||||
fprintf(stderr, "res: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), res, -1));
|
||||
if (t->domain == res || (t->domain && res && strcmp(t->domain, res) == 0))
|
||||
fprintf(stderr, "=> OK\n");
|
||||
else
|
||||
fprintf(stderr, "=> ERROR\n");
|
||||
if (res)
|
||||
talloc_free(res);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define PRINT_HDR(hdr, name) \
|
||||
fprintf(stderr, "header %s:\n" \
|
||||
".id = %i\n" \
|
||||
@@ -216,7 +74,7 @@ static const struct osmo_mdns_rfc_header header_enc_dec_test_data[] = {
|
||||
},
|
||||
};
|
||||
|
||||
void test_enc_dec_rfc_header()
|
||||
void test_enc_dec_rfc_header(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -241,7 +99,7 @@ void test_enc_dec_rfc_header()
|
||||
}
|
||||
}
|
||||
|
||||
void test_enc_dec_rfc_header_einval()
|
||||
void test_enc_dec_rfc_header_einval(void)
|
||||
{
|
||||
struct osmo_mdns_rfc_header out = {0};
|
||||
struct msgb *msg = msgb_alloc(4096, "dns_test");
|
||||
@@ -289,7 +147,7 @@ void test_enc_dec_rfc_question(void *ctx)
|
||||
struct msgb *msg = msgb_alloc(4096, "dns_test");
|
||||
|
||||
PRINT_QST(&in, "in");
|
||||
assert(osmo_mdns_rfc_question_encode(ctx, msg, &in) == 0);
|
||||
assert(osmo_mdns_rfc_question_encode(msg, &in) == 0);
|
||||
fprintf(stderr, "encoded: %s\n", osmo_hexdump(msgb_data(msg), msgb_length(msg)));
|
||||
out = osmo_mdns_rfc_question_decode(ctx, msgb_data(msg), msgb_length(msg));
|
||||
assert(out);
|
||||
@@ -353,7 +211,7 @@ void test_enc_dec_rfc_record(void *ctx)
|
||||
size_t record_len;
|
||||
|
||||
PRINT_REC(&in, "in");
|
||||
assert(osmo_mdns_rfc_record_encode(ctx, msg, &in) == 0);
|
||||
assert(osmo_mdns_rfc_record_encode(msg, &in) == 0);
|
||||
fprintf(stderr, "encoded: %s\n", osmo_hexdump(msgb_data(msg), msgb_length(msg)));
|
||||
out = osmo_mdns_rfc_record_decode(ctx, msgb_data(msg), msgb_length(msg), &record_len);
|
||||
fprintf(stderr, "record_len: %lu\n", record_len);
|
||||
@@ -578,7 +436,7 @@ static void test_result_from_answer(void *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
void *ctx = talloc_named_const(NULL, 0, "main");
|
||||
osmo_init_logging2(ctx, NULL);
|
||||
@@ -589,7 +447,6 @@ int main()
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
log_set_use_color(osmo_stderr_target, 0);
|
||||
|
||||
test_enc_dec_rfc_qname(ctx);
|
||||
test_enc_dec_rfc_header();
|
||||
test_enc_dec_rfc_header_einval();
|
||||
test_enc_dec_rfc_question(ctx);
|
||||
|
||||
@@ -1,85 +1,3 @@
|
||||
-- test_enc_dec_rfc_qname --
|
||||
domain: "hlr.1234567.imsi"
|
||||
exp: "\3hlr\a1234567\4imsi"
|
||||
res: "\3hlr\a1234567\4imsi"
|
||||
=> OK
|
||||
|
||||
qname: "\3hlr\a1234567\4imsi"
|
||||
exp: "hlr.1234567.imsi"
|
||||
res: "hlr.1234567.imsi"
|
||||
=> OK
|
||||
|
||||
domain: "hlr..imsi"
|
||||
exp: NULL
|
||||
res: NULL
|
||||
=> OK
|
||||
|
||||
domain: "hlr"
|
||||
exp: "\3hlr"
|
||||
res: "\3hlr"
|
||||
=> OK
|
||||
|
||||
qname: "\3hlr"
|
||||
exp: "hlr"
|
||||
res: "hlr"
|
||||
=> OK
|
||||
|
||||
domain: "hlr."
|
||||
exp: NULL
|
||||
res: NULL
|
||||
=> OK
|
||||
|
||||
domain: ".hlr"
|
||||
exp: NULL
|
||||
res: NULL
|
||||
=> OK
|
||||
|
||||
domain: ""
|
||||
exp: NULL
|
||||
res: NULL
|
||||
=> OK
|
||||
|
||||
domain: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.12345"
|
||||
exp: "\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\512345"
|
||||
res: "\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\512345"
|
||||
=> OK
|
||||
|
||||
qname: "\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\512345"
|
||||
exp: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.12345"
|
||||
res: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.12345"
|
||||
=> OK
|
||||
|
||||
domain: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.12345toolong"
|
||||
exp: NULL
|
||||
res: NULL
|
||||
=> OK
|
||||
|
||||
qname: "\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\
|
||||
exp: NULL
|
||||
res: NULL
|
||||
=> OK
|
||||
|
||||
qname: "\3hlr\a1234567\5imsi"
|
||||
exp: NULL
|
||||
res: NULL
|
||||
=> OK
|
||||
|
||||
qname: "\2hlr\a1234567\4imsi"
|
||||
exp: NULL
|
||||
res: NULL
|
||||
=> OK
|
||||
|
||||
qname: "\3hlr\3"
|
||||
exp: NULL
|
||||
res: NULL
|
||||
=> OK
|
||||
|
||||
qname_max_len: 17
|
||||
qname: "\3hlr\a1234567\4imsi"
|
||||
exp: NULL
|
||||
res: NULL
|
||||
=> OK
|
||||
|
||||
-- test_enc_dec_rfc_header --
|
||||
header in:
|
||||
.id = 1337
|
||||
|
||||
@@ -80,14 +80,14 @@ static int server_recv(struct osmo_fd *osmo_fd, unsigned int what)
|
||||
return n;
|
||||
}
|
||||
|
||||
static void server_init()
|
||||
static void server_init(void)
|
||||
{
|
||||
fprintf(stderr, "%s\n", __func__);
|
||||
server_mc = osmo_mdns_sock_init(ctx, TEST_IP, TEST_PORT, server_recv, NULL, 0);
|
||||
OSMO_ASSERT(server_mc);
|
||||
}
|
||||
|
||||
static void server_stop()
|
||||
static void server_stop(void)
|
||||
{
|
||||
fprintf(stderr, "%s\n", __func__);
|
||||
OSMO_ASSERT(server_mc);
|
||||
@@ -98,7 +98,7 @@ static void server_stop()
|
||||
struct osmo_mslookup_client* client;
|
||||
struct osmo_mslookup_client_method* client_method;
|
||||
|
||||
static void client_init()
|
||||
static void client_init(void)
|
||||
{
|
||||
fprintf(stderr, "%s\n", __func__);
|
||||
client = osmo_mslookup_client_new(ctx);
|
||||
@@ -117,7 +117,7 @@ static void client_recv(struct osmo_mslookup_client *client, uint32_t request_ha
|
||||
osmo_mslookup_client_request_cancel(client, request_handle);
|
||||
}
|
||||
|
||||
static void client_query()
|
||||
static void client_query(void)
|
||||
{
|
||||
struct osmo_mslookup_id id = {.type = OSMO_MSLOOKUP_ID_IMSI,
|
||||
.imsi = "123456789012345"};
|
||||
@@ -134,7 +134,7 @@ static void client_query()
|
||||
osmo_mslookup_client_request(client, &query, &handling);
|
||||
}
|
||||
|
||||
static void client_stop()
|
||||
static void client_stop(void)
|
||||
{
|
||||
fprintf(stderr, "%s\n", __func__);
|
||||
osmo_mslookup_client_free(client);
|
||||
@@ -154,7 +154,7 @@ const struct timeval fake_time_start_time = { 0, 0 };
|
||||
osmo_timers_update(); \
|
||||
} while (0)
|
||||
|
||||
static void fake_time_start()
|
||||
static void fake_time_start(void)
|
||||
{
|
||||
struct timespec *clock_override;
|
||||
|
||||
@@ -167,7 +167,7 @@ static void fake_time_start()
|
||||
osmo_clock_override_enable(CLOCK_MONOTONIC, true);
|
||||
fake_time_passes(0, 0);
|
||||
}
|
||||
static void test_server_client()
|
||||
static void test_server_client(void)
|
||||
{
|
||||
fprintf(stderr, "-- %s --\n", __func__);
|
||||
server_init();
|
||||
@@ -190,7 +190,7 @@ static void test_server_client()
|
||||
client_stop();
|
||||
}
|
||||
|
||||
bool is_multicast_enabled()
|
||||
bool is_multicast_enabled(void)
|
||||
{
|
||||
bool ret = true;
|
||||
struct addrinfo *ai;
|
||||
@@ -222,7 +222,7 @@ bool is_multicast_enabled()
|
||||
/*
|
||||
* Run all tests
|
||||
*/
|
||||
int main()
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (!is_multicast_enabled()) {
|
||||
fprintf(stderr, "ERROR: multicast is disabled! (OS#4361)");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user