mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
synced 2025-10-23 00:12:14 +00:00
Compare commits
48 Commits
6784ed14b7
...
945cc067b3
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 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
open_collective: osmocom
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -86,3 +86,5 @@ contrib/osmo-hlr.spec
|
||||
/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 = \
|
||||
|
39
README.md
39
README.md
@@ -1,8 +1,8 @@
|
||||
osmo-hlr - Osmocom HLR Implementation
|
||||
=====================================
|
||||
|
||||
This repository contains a C-language implementation of a GSM Home
|
||||
Location Register (HLR). It is part of the
|
||||
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.
|
||||
|
||||
@@ -10,13 +10,14 @@ Warning: While the HLR logical functionality is implemented, OsmoHLR
|
||||
does not use the ETSI/3GPP TCAP/MAP protocol stack. Instead, a much
|
||||
simpler custom protocol (GSUP) is used. This means, OsmoHLR is of
|
||||
no use outside the context of an Osmocom core network. You can use
|
||||
it with OsmoMSC, OsmoSGSN etc. - but not with third party components.
|
||||
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
|
||||
The official homepage of the project is <https://osmocom.org/projects/osmo-hlr/wiki>.
|
||||
|
||||
GIT Repository
|
||||
--------------
|
||||
@@ -33,11 +34,18 @@ Documentation
|
||||
User Manuals and VTY reference manuals are [optionally] built in PDF form
|
||||
as part of the build process.
|
||||
|
||||
Pre-rendered PDF version of the current "master" can be found at
|
||||
[User Manual](https://ftp.osmocom.org/docs/latest/osmohlr-usermanual.pdf)
|
||||
as well as the VTY reference manuals
|
||||
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
|
||||
------------
|
||||
|
||||
@@ -50,16 +58,23 @@ 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
|
||||
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
|
||||
|
||||
We us a gerrit based patch submission/review process for managing
|
||||
We use a Gerrit based patch submission/review process for managing
|
||||
contributions. Please see
|
||||
https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit for
|
||||
<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
|
||||
<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
|
||||
|
11
configure.ac
11
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.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.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)
|
||||
|
||||
@@ -203,7 +203,6 @@ 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
|
||||
|
@@ -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
|
||||
|
@@ -1,195 +0,0 @@
|
||||
#
|
||||
# spec file for package osmo-hlr
|
||||
#
|
||||
# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
|
||||
# Copyright (c) 2016, Martin Hauke <mardnh@gmx.de>
|
||||
#
|
||||
# All modifications and additions to the file contributed by third parties
|
||||
# remain the property of their copyright owners, unless otherwise agreed
|
||||
# upon. The license for this file, and modifications and additions to the
|
||||
# file, is the same license as for the pristine package itself (unless the
|
||||
# license for the pristine package is not an Open Source License, in which
|
||||
# case the license is the MIT License). An "Open Source License" is a
|
||||
# license that conforms to the Open Source Definition (Version 1.9)
|
||||
# published by the Open Source Initiative.
|
||||
|
||||
Name: osmo-hlr
|
||||
Version: @VERSION@
|
||||
Release: 0
|
||||
Summary: Osmocom Home Location Register for GSUP protocol towards OsmoSGSN and OsmoCSCN
|
||||
License: AGPL-3.0-or-later AND GPL-2.0-or-later
|
||||
Group: Productivity/Telephony/Servers
|
||||
URL: https://osmocom.org/projects/osmo-hlr
|
||||
Source: %{name}-%{version}.tar.xz
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: automake
|
||||
BuildRequires: libtool
|
||||
BuildRequires: pkgconfig >= 0.20
|
||||
BuildRequires: python3
|
||||
%if 0%{?suse_version}
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%endif
|
||||
BuildRequires: pkgconfig(libosmoabis) >= 1.5.0
|
||||
BuildRequires: pkgconfig(libosmocore) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmoctrl) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmogsm) >= 1.9.0
|
||||
BuildRequires: pkgconfig(libosmovty) >= 1.9.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-mslookup1
|
||||
Summary: Osmocom MS lookup library
|
||||
License: GPL-2.0-or-later
|
||||
Group: System/Libraries
|
||||
|
||||
%description -n libosmo-mslookup1
|
||||
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-mslookup1 = %{version}
|
||||
|
||||
%description -n libosmo-mslookup-devel
|
||||
This shared library contains routines for looking up mobile subscribers.
|
||||
|
||||
This subpackage contains libraries and header files for developing
|
||||
applications that want to make use of libosmo-mslookup.
|
||||
|
||||
|
||||
%package -n osmo-mslookup-client
|
||||
Summary: Standalone program using libosmo-mslookup
|
||||
License: GPL-2.0-or-later
|
||||
Group: Development/Libraries/C and C++
|
||||
|
||||
%description -n osmo-mslookup-client
|
||||
Standalone program using libosmo-mslookup to easily integrate with programs
|
||||
that want to connect services (SIP, SMS,...) to the current location of a
|
||||
subscriber.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
echo "%{version}" >.tarball-version
|
||||
autoreconf -fi
|
||||
%configure \
|
||||
--docdir="%{_docdir}/%{name}" \
|
||||
--with-systemdsystemunitdir=%{_unitdir} \
|
||||
--enable-shared \
|
||||
--disable-static
|
||||
make V=1 %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
%make_install
|
||||
install -d "%{buildroot}/%{_localstatedir}/lib/osmocom"
|
||||
find %{buildroot} -type f -name "*.la" -delete -print
|
||||
|
||||
%check
|
||||
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
|
||||
|
||||
%if 0%{?suse_version}
|
||||
%preun
|
||||
%service_del_preun %{name}.service
|
||||
|
||||
%postun
|
||||
%service_del_postun %{name}.service
|
||||
|
||||
%pre
|
||||
%service_add_pre %{name}.service
|
||||
%endif
|
||||
|
||||
%post
|
||||
%if 0%{?suse_version}
|
||||
%service_add_post %{name}.service
|
||||
%endif
|
||||
/usr/share/osmocom/osmo-hlr-post-upgrade.sh
|
||||
|
||||
%post -n libosmo-gsup-client0 -p /sbin/ldconfig
|
||||
%postun -n libosmo-gsup-client0 -p /sbin/ldconfig
|
||||
%post -n libosmo-mslookup1 -p /sbin/ldconfig
|
||||
%postun -n libosmo-mslookup1 -p /sbin/ldconfig
|
||||
|
||||
%files
|
||||
%license COPYING
|
||||
%dir %{_docdir}/%{name}
|
||||
%dir %{_docdir}/%{name}/examples
|
||||
%{_docdir}/%{name}/examples/osmo-hlr.cfg
|
||||
%{_docdir}/%{name}/examples/osmo-hlr-dgsm.cfg
|
||||
%dir %{_docdir}/%{name}/sql
|
||||
%{_docdir}/%{name}/sql/hlr.sql
|
||||
%{_docdir}/%{name}/sql//hlr_data.sql
|
||||
%dir %{_sysconfdir}/osmocom
|
||||
%dir %{_localstatedir}/lib/osmocom
|
||||
%{_bindir}/osmo-hlr
|
||||
%{_bindir}/osmo-hlr-db-tool
|
||||
%dir %{_sysconfdir}/osmocom
|
||||
%config %{_sysconfdir}/osmocom/osmo-hlr.cfg
|
||||
%{_unitdir}/osmo-hlr.service
|
||||
%dir %{_datadir}/osmocom
|
||||
%{_datadir}/osmocom/osmo-hlr-post-upgrade.sh
|
||||
|
||||
%files -n libosmo-gsup-client0
|
||||
%{_libdir}/libosmo-gsup-client.so.0*
|
||||
|
||||
%files -n libosmo-gsup-client-devel
|
||||
%{_bindir}/osmo-euse-demo
|
||||
%dir %{_includedir}/osmocom
|
||||
%dir %{_includedir}/osmocom/gsupclient
|
||||
%{_includedir}/osmocom/gsupclient/*.h
|
||||
%{_libdir}/libosmo-gsup-client.so
|
||||
%{_libdir}/pkgconfig/libosmo-gsup-client.pc
|
||||
|
||||
%files -n libosmo-mslookup1
|
||||
%{_libdir}/libosmo-mslookup.so.1*
|
||||
|
||||
%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
|
@@ -9,6 +9,8 @@ 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
|
||||
|
70
debian/changelog
vendored
70
debian/changelog
vendored
@@ -1,3 +1,73 @@
|
||||
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 ]
|
||||
|
8
debian/control
vendored
8
debian/control
vendored
@@ -7,12 +7,12 @@ Build-Depends: debhelper (>= 10),
|
||||
dh-autoreconf,
|
||||
autotools-dev,
|
||||
python3-minimal,
|
||||
libosmocore-dev (>= 1.9.0),
|
||||
libosmo-abis-dev (>= 1.5.0),
|
||||
libosmo-netif-dev (>= 1.4.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.5.0)
|
||||
osmo-gsm-manuals-dev (>= 1.6.0)
|
||||
Standards-Version: 3.9.6
|
||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr
|
||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr
|
||||
|
18
debian/copyright
vendored
18
debian/copyright
vendored
@@ -6,6 +6,10 @@ Files: *
|
||||
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/>.
|
||||
|
38
debian/postinst
vendored
38
debian/postinst
vendored
@@ -3,3 +3,41 @@
|
||||
# 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
|
||||
|
@@ -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 \
|
||||
|
@@ -40,6 +40,8 @@ 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,
|
||||
@@ -157,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,
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#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>
|
||||
|
||||
|
@@ -39,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;
|
||||
@@ -56,8 +63,16 @@ struct hlr {
|
||||
|
||||
struct llist_head euse_list;
|
||||
struct hlr_euse *euse_default;
|
||||
enum gsm48_gmm_cause reject_cause;
|
||||
enum gsm48_gmm_cause no_proxy_reject_cause;
|
||||
|
||||
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 {
|
||||
@@ -74,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;
|
||||
@@ -119,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;
|
||||
};
|
||||
|
||||
@@ -129,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,6 +31,7 @@ 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,
|
||||
@@ -47,7 +48,6 @@ enum hlr_vty_node {
|
||||
#define A38_COMP128_KEY_LEN 16
|
||||
#define MILENAGE_KEY_LEN 16
|
||||
|
||||
int hlr_vty_is_config_node(struct vty *vty, int node);
|
||||
int hlr_vty_go_parent(struct vty *vty);
|
||||
void hlr_vty_init(void *hlr_ctx);
|
||||
void dgsm_vty_init(void);
|
||||
|
@@ -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);
|
||||
|
@@ -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)))
|
@@ -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 \
|
||||
|
15
src/ctrl.c
15
src/ctrl.c
@@ -426,6 +426,20 @@ static int set_subscr_cs_enabled(struct ctrl_cmd *cmd, void *data)
|
||||
return set_subscr_cs_ps_enabled(cmd, data, false);
|
||||
}
|
||||
|
||||
CTRL_CMD_DEFINE_RO(subscr_imsi, "imsi");
|
||||
static int get_subscr_imsi(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;
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -761,6 +775,7 @@ static int hlr_ctrl_cmds_install(void)
|
||||
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);
|
||||
|
15
src/db.c
15
src/db.c
@@ -53,7 +53,7 @@
|
||||
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",
|
||||
@@ -92,6 +92,10 @@ 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",
|
||||
@@ -595,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);
|
||||
@@ -672,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);
|
||||
@@ -686,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) {
|
||||
@@ -702,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,
|
||||
|
58
src/db_hlr.c
58
src/db_hlr.c
@@ -555,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.
|
||||
@@ -700,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)++;
|
||||
|
21
src/dgsm.c
21
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,7 +183,7 @@ 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 = OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS;
|
||||
|
||||
|
181
src/dgsm_vty.c
181
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;
|
||||
|
||||
@@ -450,6 +522,9 @@ int config_write_mslookup(struct vty *vty)
|
||||
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)
|
||||
@@ -479,6 +554,8 @@ int config_write_mslookup(struct vty *vty)
|
||||
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;
|
||||
@@ -545,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);
|
||||
@@ -563,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);
|
||||
@@ -573,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);
|
||||
@@ -581,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,11 +24,12 @@
|
||||
#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>
|
||||
@@ -49,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);
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
60
src/hlr.c
60
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>
|
||||
@@ -203,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 */
|
||||
@@ -321,7 +333,11 @@ static int rx_send_auth_info(struct osmo_gsup_req *req)
|
||||
" Returning slightly inaccurate cause 'IMSI Unknown' via GSUP");
|
||||
return rc;
|
||||
case -ENOENT:
|
||||
osmo_gsup_req_respond_err(req, g_hlr->reject_cause, "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");
|
||||
@@ -379,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};
|
||||
@@ -433,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];
|
||||
@@ -554,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",
|
||||
@@ -565,6 +590,12 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -733,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,
|
||||
};
|
||||
|
||||
@@ -750,14 +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 = GMM_CAUSE_IMSI_UNKNOWN;
|
||||
g_hlr->no_proxy_reject_cause = GMM_CAUSE_IMSI_UNKNOWN;
|
||||
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;
|
||||
|
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);
|
||||
}
|
295
src/hlr_vty.c
295
src/hlr_vty.c
@@ -44,6 +44,7 @@
|
||||
#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[] = {
|
||||
@@ -281,40 +282,65 @@ DEFUN(cfg_no_ps_pdp_profile_apn, cfg_no_ps_pdp_profile_apn_cmd,
|
||||
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 != GMM_CAUSE_IMSI_UNKNOWN)
|
||||
vty_out(vty, " reject-cause not-found %s%s",
|
||||
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), VTY_NEWLINE);
|
||||
if (g_hlr->no_proxy_reject_cause != GMM_CAUSE_IMSI_UNKNOWN)
|
||||
vty_out(vty, " reject-cause no-proxy %s%s",
|
||||
(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->no_proxy_reject_cause), VTY_NEWLINE);
|
||||
(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;
|
||||
}
|
||||
|
||||
@@ -422,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"
|
||||
@@ -610,21 +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[1]);
|
||||
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)
|
||||
g_hlr->reject_cause = (enum gsm48_gmm_cause) cause_code;
|
||||
if (strcmp(argv[0], "no-proxy") == 0)
|
||||
g_hlr->no_proxy_reject_cause = (enum gsm48_gmm_cause) cause_code;
|
||||
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"
|
||||
@@ -643,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;
|
||||
}
|
||||
@@ -674,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;
|
||||
}
|
||||
|
||||
@@ -705,24 +901,12 @@ int hlr_vty_go_parent(struct vty *vty)
|
||||
return vty->node;
|
||||
}
|
||||
|
||||
int hlr_vty_is_config_node(struct vty *vty, int node)
|
||||
{
|
||||
switch (node) {
|
||||
/* add items that are not config */
|
||||
case CONFIG_NODE:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void hlr_vty_init(void *hlr_ctx)
|
||||
{
|
||||
cfg_reject_cause_cmd.string =
|
||||
vty_cmd_string_from_valstr(hlr_ctx,
|
||||
gsm48_gmm_cause_vty_names,
|
||||
"reject-cause (not-found|no-proxy) (", "|", ")",
|
||||
"reject-cause (not-found|no-proxy) (cs|ps) (", "|", ")",
|
||||
VTY_DO_LOWER);
|
||||
|
||||
cfg_reject_cause_cmd.doc =
|
||||
@@ -730,7 +914,9 @@ void hlr_vty_init(void *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",
|
||||
"in the case no remote HLR reponded to mslookup GSUP request\n"
|
||||
"for CS domain\n"
|
||||
"for PS domain\n",
|
||||
"\n", "", 0);
|
||||
|
||||
logging_vty_add_cmds();
|
||||
@@ -773,6 +959,15 @@ void hlr_vty_init(void *hlr_ctx)
|
||||
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);
|
||||
|
@@ -182,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);
|
||||
}
|
||||
|
||||
@@ -218,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);
|
||||
|
@@ -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, g_hlr->reject_cause, "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;
|
||||
}
|
||||
|
||||
|
@@ -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:
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
19
src/proxy.c
19
src/proxy.c
@@ -92,7 +92,11 @@ static void proxy_pending_req_remote_hlr_connect_result(struct osmo_gsup_req *re
|
||||
osmo_gsup_req_respond(req, &gsup_reply, false, true);
|
||||
return;
|
||||
}
|
||||
osmo_gsup_req_respond_err(req, g_hlr->no_proxy_reject_cause,
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -113,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)
|
||||
|
@@ -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:
|
||||
|
@@ -47,6 +47,7 @@ OsmoHLR(config-hlr)# ?
|
||||
no Negate a command or set its defaults
|
||||
ussd USSD Configuration
|
||||
ncss-guard-timeout Set guard timer for NCSS (call independent SS) session activity
|
||||
smsc Configuration of GSUP routing to SMSCs
|
||||
reject-cause GSUP/GMM cause to be sent
|
||||
store-imei Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').
|
||||
subscriber-create-on-demand Make a new record when a subscriber is first seen.
|
||||
@@ -63,10 +64,16 @@ OsmoHLR(config-hlr)# list
|
||||
ussd default-route external EUSE
|
||||
no ussd default-route
|
||||
ncss-guard-timeout <0-255>
|
||||
smsc entity NAME
|
||||
no smsc entity NAME
|
||||
smsc route NUMBER NAME
|
||||
no smsc route NUMBER
|
||||
smsc default-route NAME
|
||||
no smsc default-route
|
||||
reject-cause (not-found|no-proxy) (imsi-unknown|illegal-ms|plmn-not-allowed|la-not-allowed|roaming-not-allowed|no-suitable-cell-in-la|net-fail|congestion|auth-unacceptable|proto-error-unspec)
|
||||
store-imei
|
||||
no store-imei
|
||||
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)
|
||||
no subscriber-create-on-demand
|
||||
|
||||
OsmoHLR(config-hlr)# gsup
|
||||
@@ -106,8 +113,11 @@ log stderr
|
||||
logging level dgsm notice
|
||||
...
|
||||
hlr
|
||||
reject-cause not-found plmn-not-allowed
|
||||
reject-cause no-proxy net-fail
|
||||
store-imei
|
||||
database hlr_vty_test.db
|
||||
no subscriber-create-on-demand
|
||||
gsup
|
||||
bind ip 127.0.0.1
|
||||
ipa-name unnamed-HLR
|
||||
|
@@ -10,6 +10,14 @@ hlr
|
||||
subscriber-create-on-demand no-msisdn none
|
||||
...
|
||||
|
||||
OsmoHLR(config-hlr)# subscriber-create-on-demand msisdn-from-imsi cs+ps
|
||||
OsmoHLR(config-hlr)# show running-config
|
||||
...
|
||||
hlr
|
||||
...
|
||||
subscriber-create-on-demand msisdn-from-imsi cs+ps
|
||||
...
|
||||
|
||||
OsmoHLR(config-hlr)# subscriber-create-on-demand 3 none
|
||||
OsmoHLR(config-hlr)# show running-config
|
||||
...
|
||||
|
Reference in New Issue
Block a user