mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
synced 2025-11-03 21:53:30 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f8f1b9777 | ||
|
|
a5ed663dea | ||
|
|
15031855bf | ||
|
|
83b909e4f3 | ||
|
|
fde8f64d1d | ||
|
|
d8e8a8425a | ||
|
|
c1d56fd2e9 | ||
|
|
6ac66ac3ad | ||
|
|
769a7f46f4 | ||
|
|
5bc457e19a | ||
|
|
e3c788d9a8 | ||
|
|
e6751dd207 | ||
|
|
e8b7b8634b | ||
|
|
ce172efc0b | ||
|
|
2f1049827b | ||
|
|
92d1c4a0de | ||
|
|
fc4af602ba | ||
|
|
011e781da7 | ||
|
|
cb88c34aca | ||
|
|
e18e3a42f1 | ||
|
|
710e0c9486 | ||
|
|
f6d457e7ef | ||
|
|
fa287c579c | ||
|
|
e78241ae07 | ||
|
|
62d916f3cd | ||
|
|
3ad481afbf | ||
|
|
6aa871db71 | ||
|
|
16a16e6aa4 | ||
|
|
fac52fbd6b | ||
|
|
f0c02ad9c7 | ||
|
|
43c36f99dd | ||
|
|
008ce4bd43 | ||
|
|
f13a8bc4f9 | ||
|
|
50bf7b775b | ||
|
|
cb508554df | ||
|
|
06455eac9c | ||
|
|
2bdcc8eec9 |
19
.gitignore
vendored
19
.gitignore
vendored
@@ -26,7 +26,6 @@ m4
|
|||||||
*.m4
|
*.m4
|
||||||
missing
|
missing
|
||||||
.deps
|
.deps
|
||||||
*~
|
|
||||||
|
|
||||||
*.pc
|
*.pc
|
||||||
.libs
|
.libs
|
||||||
@@ -68,21 +67,3 @@ doc/manuals/generated/
|
|||||||
doc/manuals/osmomsc-usermanual.xml
|
doc/manuals/osmomsc-usermanual.xml
|
||||||
doc/manuals/common
|
doc/manuals/common
|
||||||
doc/manuals/build
|
doc/manuals/build
|
||||||
|
|
||||||
contrib/osmo-hlr.spec
|
|
||||||
/debian/.debhelper/
|
|
||||||
/debian/libosmo-gsup-client-dev/
|
|
||||||
/debian/files
|
|
||||||
/debian/autoreconf.after
|
|
||||||
/debian/autoreconf.before
|
|
||||||
/debian/libosmo-gsup-client0/
|
|
||||||
/debian/libosmo-mslookup0/
|
|
||||||
/debian/osmo-hlr-dbg/
|
|
||||||
/debian/tmp/
|
|
||||||
/doc/manuals/vty/hlr_vty_reference.xml
|
|
||||||
/debian/libosmo-mslookup-dev/
|
|
||||||
/debian/osmo-hlr-doc/
|
|
||||||
/debian/osmo-hlr/
|
|
||||||
/debian/osmo-mslookup-utils/
|
|
||||||
/debian/*.log
|
|
||||||
/debian/*.substvars
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
AUTOMAKE_OPTIONS = foreign dist-bzip2
|
AUTOMAKE_OPTIONS = foreign dist-bzip2
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
|
doc \
|
||||||
src \
|
src \
|
||||||
include \
|
include \
|
||||||
doc \
|
|
||||||
sql \
|
sql \
|
||||||
contrib \
|
contrib \
|
||||||
tests \
|
tests \
|
||||||
@@ -11,16 +11,13 @@ SUBDIRS = \
|
|||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
.version \
|
.version \
|
||||||
contrib/osmo-hlr.spec.in \
|
|
||||||
debian \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||||
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
|
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
|
||||||
|
|
||||||
pkgconfigdir = $(libdir)/pkgconfig
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = libosmo-gsup-client.pc \
|
pkgconfig_DATA = libosmo-gsup-client.pc
|
||||||
libosmo-mslookup.pc
|
|
||||||
|
|
||||||
@RELMAKE@
|
@RELMAKE@
|
||||||
|
|
||||||
|
|||||||
65
README.md
65
README.md
@@ -1,65 +0,0 @@
|
|||||||
osmo-hlr - Osmocom HLR Implementation
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
This repository contains a C-language implementation of a GSM Home
|
|
||||||
Location Register (HLR). It is part of the
|
|
||||||
[Osmocom](https://osmocom.org/) Open Source Mobile Communications
|
|
||||||
project.
|
|
||||||
|
|
||||||
Warning: While the HLR logical functionality is implemented, OsmoHLR
|
|
||||||
does not use the ETSI/3GPP TCAP/MAP protocol stack. Instead, a much
|
|
||||||
simpler custom protocol (GSUP) is used. This means, OsmoHLR is of
|
|
||||||
no use outside the context of an Osmocom core network. You can use
|
|
||||||
it with OsmoMSC, OsmoSGSN etc. - but not with third party components.
|
|
||||||
|
|
||||||
Homepage
|
|
||||||
--------
|
|
||||||
|
|
||||||
The official homepage of the project is
|
|
||||||
https://osmocom.org/projects/osmo-hlr/wiki
|
|
||||||
|
|
||||||
GIT Repository
|
|
||||||
--------------
|
|
||||||
|
|
||||||
You can clone from the official osmo-hlr.git repository using
|
|
||||||
|
|
||||||
git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr
|
|
||||||
|
|
||||||
There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr>
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
-------------
|
|
||||||
|
|
||||||
User Manuals and VTY reference manuals are [optionally] built in PDF form
|
|
||||||
as part of the build process.
|
|
||||||
|
|
||||||
Pre-rendered PDF version of the current "master" can be found at
|
|
||||||
[User Manual](https://ftp.osmocom.org/docs/latest/osmohlr-usermanual.pdf)
|
|
||||||
as well as the VTY reference manuals
|
|
||||||
* [VTY Reference Manual for osmo-hlr](https://ftp.osmocom.org/docs/latest/osmohlr-vty-reference.pdf)
|
|
||||||
|
|
||||||
Mailing List
|
|
||||||
------------
|
|
||||||
|
|
||||||
Discussions related to osmo-hlr are happening on the
|
|
||||||
openbsc@lists.osmocom.org mailing list, please see
|
|
||||||
https://lists.osmocom.org/mailman/listinfo/openbsc for subscription
|
|
||||||
options and the list archive.
|
|
||||||
|
|
||||||
Please observe the [Osmocom Mailing List
|
|
||||||
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
|
|
||||||
when posting.
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
------------
|
|
||||||
|
|
||||||
Our coding standards are described at
|
|
||||||
https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards
|
|
||||||
|
|
||||||
We us a gerrit based patch submission/review process for managing
|
|
||||||
contributions. Please see
|
|
||||||
https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit for
|
|
||||||
more details
|
|
||||||
|
|
||||||
The current patch queue for osmo-hlr can be seen at
|
|
||||||
https://gerrit.osmocom.org/#/q/project:osmo-hlr+status:open
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
|
|
||||||
# according to https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
|
|
||||||
# In short:
|
|
||||||
# LIBVERSION=c:r:a
|
|
||||||
# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
|
|
||||||
# If any interfaces have been added, removed, or changed since the last update: c + 1:0:0.
|
|
||||||
# If any interfaces have been added since the last public release: c:r:a + 1.
|
|
||||||
# If any interfaces have been removed or changed since the last public release: c:r:0.
|
|
||||||
#library what description / commit summary line
|
|
||||||
31
configure.ac
31
configure.ac
@@ -12,8 +12,6 @@ AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip 1.9])
|
|||||||
|
|
||||||
AC_CONFIG_TESTDIR(tests)
|
AC_CONFIG_TESTDIR(tests)
|
||||||
|
|
||||||
CFLAGS="$CFLAGS -std=gnu11"
|
|
||||||
|
|
||||||
dnl kernel style compile messages
|
dnl kernel style compile messages
|
||||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||||
|
|
||||||
@@ -27,11 +25,6 @@ AC_PROG_MKDIR_P
|
|||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
|
|
||||||
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
|
|
||||||
AS_CASE(["$LD"],[*clang*],
|
|
||||||
[AS_CASE(["${host_os}"],
|
|
||||||
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
|
|
||||||
|
|
||||||
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
|
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
|
||||||
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
|
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
|
||||||
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
|
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
|
||||||
@@ -41,11 +34,11 @@ PKG_PROG_PKG_CONFIG([0.20])
|
|||||||
|
|
||||||
PKG_CHECK_MODULES(TALLOC, [talloc >= 2.0.1])
|
PKG_CHECK_MODULES(TALLOC, [talloc >= 2.0.1])
|
||||||
|
|
||||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
|
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.2.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
|
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.2.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
|
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.2.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
|
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.2.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0)
|
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0)
|
||||||
|
|
||||||
PKG_CHECK_MODULES(SQLITE3, sqlite3)
|
PKG_CHECK_MODULES(SQLITE3, sqlite3)
|
||||||
|
|
||||||
@@ -93,7 +86,6 @@ AC_ARG_ENABLE(werror,
|
|||||||
if test x"$werror" = x"yes"
|
if test x"$werror" = x"yes"
|
||||||
then
|
then
|
||||||
WERROR_FLAGS="-Werror"
|
WERROR_FLAGS="-Werror"
|
||||||
WERROR_FLAGS+=" -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition"
|
|
||||||
WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
|
WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
|
||||||
WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
|
WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
|
||||||
CFLAGS="$CFLAGS $WERROR_FLAGS"
|
CFLAGS="$CFLAGS $WERROR_FLAGS"
|
||||||
@@ -108,22 +100,13 @@ if test "x$enable_ext_tests" = "xyes" ; then
|
|||||||
AM_PATH_PYTHON
|
AM_PATH_PYTHON
|
||||||
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
|
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
|
||||||
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
|
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
|
||||||
AC_MSG_ERROR([Please install https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests to run the VTY/CTRL tests.])
|
AC_MSG_ERROR([Please install git://osmocom.org/python/osmo-python-tests to run the VTY/CTRL tests.])
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
|
AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
|
||||||
AC_MSG_RESULT([$enable_ext_tests])
|
AC_MSG_RESULT([$enable_ext_tests])
|
||||||
AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes")
|
AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes")
|
||||||
|
|
||||||
# mslookup_client_mdns_test (OS#4385: does not work everywhere)
|
|
||||||
AC_ARG_ENABLE([mslookup_client_mdns_test],
|
|
||||||
AC_HELP_STRING([--enable-mslookup-client-mdns-test],
|
|
||||||
[Include the mslookup_client_mdns_test in make check [default=no]]),
|
|
||||||
[enable_mslookup_client_mdns_test="$enableval"],[enable_mslookup_client_mdns_test="no"])
|
|
||||||
AC_MSG_CHECKING([whether to enable mslookup_client_mdns_test])
|
|
||||||
AC_MSG_RESULT([$enable_mslookup_client_mdns_test])
|
|
||||||
AM_CONDITIONAL(ENABLE_MSLOOKUP_CLIENT_MDNS_TEST, test "x$enable_mslookup_client_mdns_test" = "xyes")
|
|
||||||
|
|
||||||
# Generate manuals
|
# Generate manuals
|
||||||
AC_ARG_ENABLE(manuals,
|
AC_ARG_ENABLE(manuals,
|
||||||
[AS_HELP_STRING(
|
[AS_HELP_STRING(
|
||||||
@@ -203,10 +186,10 @@ AC_OUTPUT(
|
|||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
contrib/systemd/Makefile
|
contrib/systemd/Makefile
|
||||||
contrib/dgsm/Makefile
|
contrib/dgsm/Makefile
|
||||||
contrib/osmo-hlr.spec
|
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
tests/auc/Makefile
|
tests/auc/Makefile
|
||||||
tests/auc/gen_ts_55_205_test_sets/Makefile
|
tests/auc/gen_ts_55_205_test_sets/Makefile
|
||||||
|
tests/gsup_server/Makefile
|
||||||
tests/gsup/Makefile
|
tests/gsup/Makefile
|
||||||
tests/db/Makefile
|
tests/db/Makefile
|
||||||
tests/db_upgrade/Makefile
|
tests/db_upgrade/Makefile
|
||||||
|
|||||||
@@ -2,13 +2,3 @@ SUBDIRS = \
|
|||||||
systemd \
|
systemd \
|
||||||
dgsm \
|
dgsm \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
EXTRA_DIST = osmo-hlr-post-upgrade.sh
|
|
||||||
|
|
||||||
install-data-hook:
|
|
||||||
install -Dm755 $(srcdir)/osmo-hlr-post-upgrade.sh \
|
|
||||||
-t $(DESTDIR)$(datadir)/osmocom/
|
|
||||||
|
|
||||||
uninstall-hook:
|
|
||||||
@$(PRE_UNINSTALL)
|
|
||||||
$(RM) $(DESTDIR)$(datadir)/osmocom/osmo-hlr-post-upgrade.sh
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
SPDX-License-Identifier: MIT
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
Copyright 2019 sysmocom s.f.m.c GmbH <info@sysmocom.de>
|
Copyright 2019 sysmocom s.f.m.c GmbH <info@sysmocom.de>
|
||||||
|
|
||||||
WARNING: this is just a proof-of-concept implementation, it blocks for every
|
WARNING: this is just a proof-of-concept implementation, it blocks for every
|
||||||
received SMPP request and is not suitable for servicing more than one request
|
received SMPP request and is not suitable for servicing more than one request
|
||||||
at a time.
|
at a time.
|
||||||
|
|
||||||
Based on esme.py from RCCN (license changed with permission from author):
|
Based on esme.py from RCCN:
|
||||||
https://github.com/Rhizomatica/rccn/blob/master/rccn/esme.py
|
https://github.com/Rhizomatica/rccn/blob/master/rccn/esme.py
|
||||||
Copyright 2017 keith <keith@rhizomatica.org>
|
Copyright 2017 keith <keith@rhizomatica.org>
|
||||||
|
|
||||||
@@ -39,7 +39,13 @@ import time
|
|||||||
|
|
||||||
def can_handle_pdu(pdu):
|
def can_handle_pdu(pdu):
|
||||||
if not isinstance(pdu, smpplib.command.DeliverSM):
|
if not isinstance(pdu, smpplib.command.DeliverSM):
|
||||||
logging.info('PDU is not a DeliverSM, ignoring')
|
logging.info('PDU is not a DeliverSM. Is OsmoMSC configured properly?')
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Multipart SMS etc. not handled here (see RCCN's esme.py)
|
||||||
|
if pdu.esm_class & smpplib.consts.SMPP_GSMFEAT_UDHI:
|
||||||
|
logging.info("UDH (User Data Header) handling not implemented in this"
|
||||||
|
" example, dropping message.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if int(pdu.dest_addr_ton) == smpplib.consts.SMPP_TON_INTL:
|
if int(pdu.dest_addr_ton) == smpplib.consts.SMPP_TON_INTL:
|
||||||
@@ -63,8 +69,7 @@ def query_mslookup(service_type, id, id_type='msisdn'):
|
|||||||
return json.loads(result_line)
|
return json.loads(result_line)
|
||||||
|
|
||||||
|
|
||||||
def tx_sms(dst_host, dst_port, source, destination, registered_delivery,
|
def tx_sms(dst_host, dst_port, source, destination, unicode_text):
|
||||||
unicode_text):
|
|
||||||
smpp_client = smpplib.client.Client(dst_host, dst_port, 90)
|
smpp_client = smpplib.client.Client(dst_host, dst_port, 90)
|
||||||
smpp_client.connect()
|
smpp_client.connect()
|
||||||
smpp_client.bind_transceiver(system_id=args.dst_id, password=args.dst_pass)
|
smpp_client.bind_transceiver(system_id=args.dst_id, password=args.dst_pass)
|
||||||
@@ -79,7 +84,7 @@ def tx_sms(dst_host, dst_port, source, destination, registered_delivery,
|
|||||||
dest_addr_npi=smpplib.consts.SMPP_NPI_ISDN,
|
dest_addr_npi=smpplib.consts.SMPP_NPI_ISDN,
|
||||||
destination_addr=destination.decode(),
|
destination_addr=destination.decode(),
|
||||||
short_message=unicode_text,
|
short_message=unicode_text,
|
||||||
registered_delivery=registered_delivery,
|
registered_delivery=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
smpp_client.unbind()
|
smpp_client.unbind()
|
||||||
@@ -100,9 +105,6 @@ def rx_deliver_sm(pdu):
|
|||||||
time.sleep(args.sleep)
|
time.sleep(args.sleep)
|
||||||
logging.info("Sleep done")
|
logging.info("Sleep done")
|
||||||
|
|
||||||
if args.always_fail is not None:
|
|
||||||
return args.always_fail
|
|
||||||
|
|
||||||
result = query_mslookup("smpp.sms", msisdn)
|
result = query_mslookup("smpp.sms", msisdn)
|
||||||
if 'v4' not in result or not result['v4']:
|
if 'v4' not in result or not result['v4']:
|
||||||
logging.info('No IPv4 result from mslookup! This example only'
|
logging.info('No IPv4 result from mslookup! This example only'
|
||||||
@@ -111,8 +113,7 @@ def rx_deliver_sm(pdu):
|
|||||||
|
|
||||||
dst_host, dst_port = result['v4']
|
dst_host, dst_port = result['v4']
|
||||||
tx_sms(dst_host, dst_port, pdu.source_addr,
|
tx_sms(dst_host, dst_port, pdu.source_addr,
|
||||||
pdu.destination_addr, int(pdu.registered_delivery),
|
pdu.destination_addr, pdu.short_message)
|
||||||
pdu.short_message)
|
|
||||||
|
|
||||||
return smpplib.consts.SMPP_ESME_ROK
|
return smpplib.consts.SMPP_ESME_ROK
|
||||||
|
|
||||||
@@ -150,35 +151,12 @@ def main():
|
|||||||
parser.add_argument('--sleep', default=0, type=float,
|
parser.add_argument('--sleep', default=0, type=float,
|
||||||
help='sleep time in seconds before forwarding an SMS,'
|
help='sleep time in seconds before forwarding an SMS,'
|
||||||
' to test multithreading (default: 0)')
|
' to test multithreading (default: 0)')
|
||||||
parser.add_argument('--always-fail', default=None, metavar='SMPP_ESME_ERRCODE',
|
|
||||||
help='test delivery failure: always return an error code on Deliver-SM,'
|
|
||||||
' pass an smpplib error code name like RDELIVERYFAILURE (see smpplib/consts.py),'
|
|
||||||
' or an SMPP error code in hex digits')
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO, format='[%(asctime)s]'
|
logging.basicConfig(level=logging.INFO, format='[%(asctime)s]'
|
||||||
' (%(threadName)s) %(message)s', datefmt="%H:%M:%S")
|
' (%(threadName)s) %(message)s', datefmt="%H:%M:%S")
|
||||||
|
|
||||||
if args.always_fail:
|
|
||||||
resolved = None
|
|
||||||
name = 'SMPP_ESME_' + args.always_fail
|
|
||||||
if hasattr(smpplib.consts, name):
|
|
||||||
resolved = getattr(smpplib.consts, name)
|
|
||||||
if resolved is None:
|
|
||||||
try:
|
|
||||||
resolved = int(args.always_fail, 16)
|
|
||||||
except ValueError:
|
|
||||||
resolved = None
|
|
||||||
if resolved is None:
|
|
||||||
print('Invalid argument for --always-fail: %r' % args.always_fail)
|
|
||||||
exit(1)
|
|
||||||
args.always_fail = resolved
|
|
||||||
logging.info('--always-fail: returning error code %s to all Deliver-SM' % hex(args.always_fail))
|
|
||||||
|
|
||||||
smpp_bind()
|
smpp_bind()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
||||||
# vim: expandtab tabstop=4 shiftwidth=4
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
SPDX-License-Identifier: MIT
|
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
Copyright 2019 sysmocom s.f.m.c GmbH <info@sysmocom.de>
|
Copyright 2019 sysmocom s.f.m.c GmbH <info@sysmocom.de>
|
||||||
|
|
||||||
This is a freeswitch dialplan implementation, see:
|
This is a freeswitch dialplan implementation, see:
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ osmo-build-dep.sh libosmo-abis
|
|||||||
# Additional configure options and depends
|
# Additional configure options and depends
|
||||||
CONFIG=""
|
CONFIG=""
|
||||||
if [ "$WITH_MANUALS" = "1" ]; then
|
if [ "$WITH_MANUALS" = "1" ]; then
|
||||||
|
osmo-build-dep.sh osmo-gsm-manuals
|
||||||
CONFIG="--enable-manuals"
|
CONFIG="--enable-manuals"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -48,19 +49,14 @@ set -x
|
|||||||
|
|
||||||
cd "$base"
|
cd "$base"
|
||||||
autoreconf --install --force
|
autoreconf --install --force
|
||||||
./configure \
|
./configure --enable-sanitize --enable-external-tests --enable-werror $CONFIG
|
||||||
--enable-sanitize \
|
|
||||||
--enable-external-tests \
|
|
||||||
--enable-mslookup-client-mdns-test \
|
|
||||||
--enable-werror \
|
|
||||||
$CONFIG
|
|
||||||
$MAKE $PARALLEL_MAKE
|
$MAKE $PARALLEL_MAKE
|
||||||
$MAKE check || cat-testlogs.sh
|
$MAKE check || cat-testlogs.sh
|
||||||
DISTCHECK_CONFIGURE_FLAGS="$CONFIG" $MAKE $PARALLEL_MAKE distcheck || cat-testlogs.sh
|
DISTCHECK_CONFIGURE_FLAGS="$CONFIG" $MAKE distcheck || cat-testlogs.sh
|
||||||
|
|
||||||
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
|
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
|
||||||
make -C "$base/doc/manuals" publish
|
make -C "$base/doc/manuals" publish
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$MAKE $PARALLEL_MAKE maintainer-clean
|
$MAKE maintainer-clean
|
||||||
osmo-clean-workspace.sh
|
osmo-clean-workspace.sh
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
# Copyright 2021 sysmocom s.f.m.c GmbH <info@sysmocom.de>
|
|
||||||
#
|
|
||||||
# Packagers are supposed to call this script in post-upgrade, so it can safely
|
|
||||||
# upgrade the database scheme if required.
|
|
||||||
|
|
||||||
DB="/var/lib/osmocom/hlr.db"
|
|
||||||
IS_ACTIVE=0
|
|
||||||
|
|
||||||
msg() {
|
|
||||||
echo "osmo-hlr-post-upgrade: $@"
|
|
||||||
}
|
|
||||||
|
|
||||||
err() {
|
|
||||||
msg "ERROR: $@"
|
|
||||||
}
|
|
||||||
|
|
||||||
open_db() {
|
|
||||||
# Attempt to open the database with osmo-hlr-db-tool, it will fail if
|
|
||||||
# upgrading the schema is required
|
|
||||||
osmo-hlr-db-tool -s -l "$DB" create
|
|
||||||
}
|
|
||||||
|
|
||||||
check_upgrade_required() {
|
|
||||||
if ! [ -e "$DB" ]; then
|
|
||||||
msg "nothing to do (no existing database)"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if open_db 2>/dev/null; then
|
|
||||||
msg "nothing to do (database version is up to date)"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg "database upgrade is required"
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_service() {
|
|
||||||
if systemctl is-active -q osmo-hlr; then
|
|
||||||
IS_ACTIVE=1
|
|
||||||
msg "stopping osmo-hlr service"
|
|
||||||
systemctl stop osmo-hlr
|
|
||||||
|
|
||||||
# Verify that it stopped
|
|
||||||
for i in $(seq 1 100); do
|
|
||||||
if ! systemctl is-active -q osmo-hlr; then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
sleep 0.1
|
|
||||||
done
|
|
||||||
|
|
||||||
err "failed to stop osmo-hlr service"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
msg "osmo-hlr service is not running"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
create_backup() {
|
|
||||||
backup="$DB.$(date +%Y%m%d%H%M%S).bak"
|
|
||||||
msg "creating backup: $backup"
|
|
||||||
if [ -e "$backup" ]; then
|
|
||||||
err "backup already exists: $backup"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
cp "$DB" "$backup"
|
|
||||||
}
|
|
||||||
|
|
||||||
upgrade() {
|
|
||||||
msg "performing database upgrade"
|
|
||||||
osmo-hlr-db-tool -s -U -l "$DB" create
|
|
||||||
|
|
||||||
if ! open_db 2>/dev/null; then
|
|
||||||
err "failed to open the database after upgrade"
|
|
||||||
err "osmo-hlr-db-tool output:"
|
|
||||||
open_db
|
|
||||||
# exit because of "set -e"
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg "database upgrade successful"
|
|
||||||
}
|
|
||||||
|
|
||||||
start_service() {
|
|
||||||
if [ "$IS_ACTIVE" = "1" ]; then
|
|
||||||
msg "starting osmo-hlr service"
|
|
||||||
systemctl start osmo-hlr
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
check_upgrade_required
|
|
||||||
stop_service
|
|
||||||
create_backup
|
|
||||||
upgrade
|
|
||||||
start_service
|
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
#
|
|
||||||
# spec file for package osmo-hlr
|
|
||||||
#
|
|
||||||
# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
|
|
||||||
# Copyright (c) 2016, Martin Hauke <mardnh@gmx.de>
|
|
||||||
#
|
|
||||||
# All modifications and additions to the file contributed by third parties
|
|
||||||
# remain the property of their copyright owners, unless otherwise agreed
|
|
||||||
# upon. The license for this file, and modifications and additions to the
|
|
||||||
# file, is the same license as for the pristine package itself (unless the
|
|
||||||
# license for the pristine package is not an Open Source License, in which
|
|
||||||
# case the license is the MIT License). An "Open Source License" is a
|
|
||||||
# license that conforms to the Open Source Definition (Version 1.9)
|
|
||||||
# published by the Open Source Initiative.
|
|
||||||
|
|
||||||
Name: osmo-hlr
|
|
||||||
Version: @VERSION@
|
|
||||||
Release: 0
|
|
||||||
Summary: Osmocom Home Location Register for GSUP protocol towards OsmoSGSN and OsmoCSCN
|
|
||||||
License: AGPL-3.0-or-later AND GPL-2.0-or-later
|
|
||||||
Group: Productivity/Telephony/Servers
|
|
||||||
URL: https://osmocom.org/projects/osmo-hlr
|
|
||||||
Source: %{name}-%{version}.tar.xz
|
|
||||||
BuildRequires: autoconf
|
|
||||||
BuildRequires: automake
|
|
||||||
BuildRequires: libtool
|
|
||||||
BuildRequires: pkgconfig >= 0.20
|
|
||||||
BuildRequires: python3
|
|
||||||
%if 0%{?suse_version}
|
|
||||||
BuildRequires: systemd-rpm-macros
|
|
||||||
%endif
|
|
||||||
BuildRequires: pkgconfig(libosmoabis) >= 1.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
|
|
||||||
@@ -1,17 +1,12 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Osmocom Home Location Register (OsmoHLR)
|
Description=Osmocom Home Location Register (OsmoHLR)
|
||||||
Documentation=https://osmocom.org/projects/osmo-hlr/wiki/OsmoHLR
|
Documentation=https://osmocom.org/projects/osmo-hlr/wiki/OsmoHLR
|
||||||
After=network-online.target
|
|
||||||
Wants=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
Restart=always
|
Restart=always
|
||||||
StateDirectory=osmocom
|
ExecStart=/usr/bin/osmo-hlr -U -c /etc/osmocom/osmo-hlr.cfg -l /var/lib/osmocom/hlr.db
|
||||||
WorkingDirectory=%S/osmocom
|
|
||||||
ExecStart=/usr/bin/osmo-hlr -c /etc/osmocom/osmo-hlr.cfg -l /var/lib/osmocom/hlr.db
|
|
||||||
RestartSec=2
|
RestartSec=2
|
||||||
ProtectHome=true
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
264
debian/changelog
vendored
264
debian/changelog
vendored
@@ -1,267 +1,3 @@
|
|||||||
osmo-hlr (1.7.0) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Oliver Smith ]
|
|
||||||
* Run struct_endianness.py
|
|
||||||
* tests/db/db_test.err: adjust to XOR-3G rename
|
|
||||||
* debian: set compat level to 10
|
|
||||||
* systemd: depend on networking-online.target
|
|
||||||
|
|
||||||
[ Pau Espin Pedrol ]
|
|
||||||
* mslookup: Call osmo_fd_unregister() before closing and changing bfd->fd
|
|
||||||
|
|
||||||
[ Vadim Yanitskiy ]
|
|
||||||
* tests/auc/Makefile.am: put object files to LDADD
|
|
||||||
* tests/*/Makefile.am: move -I to AM_CPPFLAGS
|
|
||||||
* lu_fsm: fix memleak in lu_fsm_wait_insert_data_result()
|
|
||||||
* ussd: fix GSUP memleaks in rx_proc_ss_{req,error}()
|
|
||||||
* gsup_server: fix msgb memleak in osmo_gsup_server_read_cb()
|
|
||||||
* USSD: fix handling of ussd-DataCodingScheme != 0x0f
|
|
||||||
|
|
||||||
[ Alexander Couzens ]
|
|
||||||
* hlr: use talloc for memory allocation in osmo_gsup_create_insert_subscriber_data_msg
|
|
||||||
* Add support for multiple APN profiles for subscriber data
|
|
||||||
|
|
||||||
[ Harald Welte ]
|
|
||||||
* Introduce support for XOR-2G algorithm
|
|
||||||
* cosmetic: gen_ts_55_205_test_sets/func_template.c: Use tab-indent
|
|
||||||
* cosmetic: gen_ts_55_205_test_sets/main_template tabs istead of spaces
|
|
||||||
* Port to new libosmogsm 'struct osmo_sub_auth_data2'
|
|
||||||
* src/db.c: Switch from "const char *statements" to "const char * const"
|
|
||||||
* db: extend database schema to support 256bit K and/or OP[c] values
|
|
||||||
* Add VTY support for TUAK algorithm
|
|
||||||
|
|
||||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 14:41:33 +0200
|
|
||||||
|
|
||||||
osmo-hlr (1.6.0) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Vadim Yanitskiy ]
|
|
||||||
* db_auc: hexparse_stmt(): check value returned by osmo_hexparse()
|
|
||||||
|
|
||||||
[ Max ]
|
|
||||||
* Set working directory in systemd service file
|
|
||||||
* Ignore .deb build byproducts
|
|
||||||
* Debian: bump copyright year to match current
|
|
||||||
* Debian: reformat package description
|
|
||||||
* systemd: enable basic hardening
|
|
||||||
* Debian: install osmo-hlr-dgsm.cfg as example config
|
|
||||||
* hlr_vty.c: fix typo
|
|
||||||
* ctrl: take both address and port from vty config
|
|
||||||
|
|
||||||
[ Harald Welte ]
|
|
||||||
* Support building with -Werror=strict-prototypes / -Werror=old-style-definition
|
|
||||||
* Add -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition
|
|
||||||
|
|
||||||
[ arehbein ]
|
|
||||||
* osmo-hlr: Transition to use of 'telnet_init_default'
|
|
||||||
|
|
||||||
[ Oliver Smith ]
|
|
||||||
* osmo_mdns_rfc_record_decode: check ret of talloc
|
|
||||||
* osmo_mdns_rfc_record_decode: proper free on err
|
|
||||||
* mslookup: use apn functions from libosmocore
|
|
||||||
* osmo_mdns_rfc_record/question_encode: remove ctx
|
|
||||||
|
|
||||||
[ Keith ]
|
|
||||||
* Vty: Fixup config shown/written from vty
|
|
||||||
|
|
||||||
[ Neels Hofmeyr ]
|
|
||||||
* fix memleak of proxy_subscr_listentry
|
|
||||||
|
|
||||||
[ Alexander Couzens ]
|
|
||||||
* Add vty `reject-cause` to set the reject cause
|
|
||||||
|
|
||||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 16:49:14 +0100
|
|
||||||
|
|
||||||
osmo-hlr (1.5.0) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Oliver Smith ]
|
|
||||||
* treewide: remove FSF address
|
|
||||||
|
|
||||||
[ Vadim Yanitskiy ]
|
|
||||||
* fixup: debian: remove unneeded dependency libdbd-sqlite3
|
|
||||||
* debian: add new 'osmo-mslookup-utils' package
|
|
||||||
* tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS'
|
|
||||||
|
|
||||||
[ Pau Espin Pedrol ]
|
|
||||||
* ctrl: Mark function as static
|
|
||||||
* tests: Allow specyfing specific ctrl test to run
|
|
||||||
* tests/ctrl: Move ERROR test scenario to proper file
|
|
||||||
* Fix db_subscr_create() not returning -EEXIST expected by VTY subscriber create cmd
|
|
||||||
* ctrl: Introduce cmd SET subscriber.create <imsi>
|
|
||||||
* ctrl: Introduce CTRL command subscriber.by-*.msisdn
|
|
||||||
* cosmetic: hlr_vty_subscr.c: Fix trailing whitespace
|
|
||||||
* ctrl: Introduce cmd SET subscriber.delete <imsi>
|
|
||||||
* ctrl: Introduce CTRL command subscriber.by-*.aud2g <algo[,ki]>
|
|
||||||
* ctrl: Introduce CTRL command subscriber.by-*.aud3g <algo[,KI,(op|opc),OP_C[,ind_bitlen]]>
|
|
||||||
* doc: Document new subscriber CTRL commands
|
|
||||||
|
|
||||||
[ Harald Welte ]
|
|
||||||
* update git URLs (git -> https; gitea)
|
|
||||||
|
|
||||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 28 Jun 2022 18:38:31 +0200
|
|
||||||
|
|
||||||
osmo-hlr (1.4.0) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Keith ]
|
|
||||||
* Correct configuration written from vty
|
|
||||||
* vty: enable show subscribers filtered by IMEI
|
|
||||||
|
|
||||||
[ Harald Welte ]
|
|
||||||
* add README.md file as customary for cgit, github, gitlab, etc.
|
|
||||||
|
|
||||||
[ Oliver Smith ]
|
|
||||||
* Add post-upgrade script for automatic db upgrade
|
|
||||||
* debian/control: remove dh-systemd build-depend
|
|
||||||
|
|
||||||
[ Pau Espin Pedrol ]
|
|
||||||
* db: Avoid use uninitialized rc if running 0 statements
|
|
||||||
|
|
||||||
[ Neels Hofmeyr ]
|
|
||||||
* db v6: determine 3G AUC IND from VLR name
|
|
||||||
|
|
||||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 16 Nov 2021 14:56:41 +0100
|
|
||||||
|
|
||||||
osmo-hlr (1.3.0) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Alexander Couzens ]
|
|
||||||
* hlr: respect the num_auth_vectors requested
|
|
||||||
* hlr: remove unused internal USSD list
|
|
||||||
|
|
||||||
[ Oliver Smith ]
|
|
||||||
* add libosmo-mslookup abstract client
|
|
||||||
* add mDNS lookup method to libosmo-mslookup
|
|
||||||
* Makefile.am: fix pkgconfig_DATA
|
|
||||||
* add mDNS lookup method to libosmo-mslookup (#2)
|
|
||||||
* contrib/dgsm/ add example esme and dialplan
|
|
||||||
* mslookup_client.c: fix dereferencing null pointer
|
|
||||||
* mdns_msg.c: always call va_end
|
|
||||||
* mslookup_client_mdns.c: fix dereferencing null
|
|
||||||
* osmo-mslookup-client.c: fix dereferencing null
|
|
||||||
* osmo-mslookup-client: fix dereferencing null
|
|
||||||
* mdns_sock.c: fix resource leak of sock
|
|
||||||
* mdns_rfc.c: fix possible access of uninit. mem
|
|
||||||
* mslookup_client_mdns_test: disable by default
|
|
||||||
* mslookup_client_mdns_test: no automatic skip
|
|
||||||
* Cosmetic: mention OS#4491 in location cancel code
|
|
||||||
* hlr_vty_subscr: prettier output for last LU seen
|
|
||||||
* contrib: import RPM spec
|
|
||||||
* contrib: integrate RPM spec
|
|
||||||
* Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
|
|
||||||
* contrib/jenkins: don't build osmo-gsm-manuals
|
|
||||||
* configure.ac: set -std=gnu11
|
|
||||||
|
|
||||||
[ Neels Hofmeyr ]
|
|
||||||
* add osmo-mslookup-client program
|
|
||||||
* add osmo-mslookup-client program (#2)
|
|
||||||
* fix missing braces in LOGP_GSUP_FWD
|
|
||||||
* gsup_client.c: fix deprecation for client create func
|
|
||||||
* 1/2: refactor: add and use lu_fsm, osmo_gsup_req, osmo_ipa_name
|
|
||||||
* 2/2: wrap ipa_name in osmo_cni_peer_id with type enum and union
|
|
||||||
* gsup client: add up_down_cb(), add osmo_gsup_client_create3()
|
|
||||||
* db v5: prep for D-GSM: add vlr_via_proxy and sgsn_via_proxy
|
|
||||||
* enlarge the GSUP message headroom
|
|
||||||
* test_nodes.vty: remove cruft
|
|
||||||
* D-GSM 1/n: add mslookup server in osmo-hlr
|
|
||||||
* D-GSM 2/n: implement mDNS method of mslookup server
|
|
||||||
* D-GSM 3/n: implement roaming by mslookup in osmo-hlr
|
|
||||||
* gsup_server: send routing error back to the correct peer
|
|
||||||
* adoc: add D-GSM chapter to osmohlr-usermanual
|
|
||||||
* drop error log for when a subscriber does not exist
|
|
||||||
* vty: show subscriber: change format of 'last LU seen'
|
|
||||||
* vty: show subscriber: show lu d,h,m,s ago, not just seconds
|
|
||||||
* auc3g: officially wrap IND around IND_bitlen space
|
|
||||||
* make osmo_cni_peer_id_cmp() NULL safe
|
|
||||||
* osmo_gsup_req_new(): require from_peer != NULL
|
|
||||||
* gsup_server.c: properly handle negative rc from osmo_gsup_conn_ccm_get()
|
|
||||||
* osmo_mslookup_server_mdns_rx(): handle read() rc == 0
|
|
||||||
* hlr_subscr_nam(): fix condition to fix nam=false notifications
|
|
||||||
* esme_dgsm.py: add --always-fail option for debugging SMPP
|
|
||||||
* osmo-mslookup-client: fix segfault for respond_error() caller
|
|
||||||
* manual: describe subscriber import by SQL
|
|
||||||
|
|
||||||
[ Harald Welte ]
|
|
||||||
* Revert "add osmo-mslookup-client program"
|
|
||||||
* Revert "add mDNS lookup method to libosmo-mslookup"
|
|
||||||
* Use OSMO_FD_* instead of deprecated BSC_FD_*
|
|
||||||
* support the XOR algorithm for UMTS AKA
|
|
||||||
* auc_test.c: Add some comments on what the test cases actually do
|
|
||||||
* main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
|
|
||||||
* manuals: generate vty reference xml at build time
|
|
||||||
|
|
||||||
[ Vadim Yanitskiy ]
|
|
||||||
* db: fix possible SQLite3 allocated memory leak in db_open()
|
|
||||||
* gsup_server: fix typo: s/omso_gsup_message/osmo_gsup_message/
|
|
||||||
* debian/control: change maintainer to the Osmocom team / mailing list
|
|
||||||
* cosmetic: fix spelling in logging message: existAnt -> existEnt
|
|
||||||
* doc/manuals: fix s/There/The/ in 'USSD Configuration'
|
|
||||||
* doc/manuals: re-organize description of internal USSD handlers
|
|
||||||
* USSD: fix handle_ussd(): do not free() unconditionally
|
|
||||||
* USSD: add special 'idle' handler to IUSE for testing
|
|
||||||
|
|
||||||
[ Eric ]
|
|
||||||
* configure.ac: fix libtool issue with clang and sanitizer
|
|
||||||
|
|
||||||
[ Philipp Maier ]
|
|
||||||
* doc: do not use loglevel info for log category ss
|
|
||||||
|
|
||||||
[ Pau Espin Pedrol ]
|
|
||||||
* configure.ac: Fix trailing whitespace
|
|
||||||
* doc: Update VTY reference xml file
|
|
||||||
* Support setting rt-prio and cpu-affinity mask through VTY
|
|
||||||
* Set TCP NODELAY sockopt to GSUP cli and srv connections
|
|
||||||
* contrib/jenkins: Enable parallel make in make distcheck
|
|
||||||
* .gitignore: Ignore new autofoo tmp files
|
|
||||||
* tests: Replace deprecated API log_set_print_filename
|
|
||||||
|
|
||||||
[ Keith ]
|
|
||||||
* osmo-hlr-db-tool: Make import from osmo-nitb less "lossy"
|
|
||||||
* Correct vty inline help for show subscriber
|
|
||||||
* Add vty command to show summary of all or filtered subscribers
|
|
||||||
* Fix Coverity Warnings
|
|
||||||
|
|
||||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 23 Feb 2021 18:13:53 +0100
|
|
||||||
|
|
||||||
osmo-hlr (1.2.0) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Ruben Undheim ]
|
|
||||||
* Fix test for return codes on mipsel and alpha archs
|
|
||||||
|
|
||||||
[ Thorsten Alteholz ]
|
|
||||||
* fix spelling errors detected by lintian
|
|
||||||
|
|
||||||
[ Pau Espin Pedrol ]
|
|
||||||
* tests: Fix db_test err file to expect error code name instead of value
|
|
||||||
|
|
||||||
[ Oliver Smith ]
|
|
||||||
* tests/test_nodes.vty: check less libosmocore cmds
|
|
||||||
* tests/db_upgrade: disable for old sqlite versions
|
|
||||||
* gitignore: add tests/db_upgrade/*.dump
|
|
||||||
* gsup_client.h: fix license header: GPLv2+
|
|
||||||
* tests/auc: change back to python3
|
|
||||||
|
|
||||||
[ Neels Hofmeyr ]
|
|
||||||
* fix double free in osmo_gsup_client_enc_send()
|
|
||||||
* db upgrade to v2: log version 2, not 1
|
|
||||||
* fix upgrade to version 2: imei column default value
|
|
||||||
* add --db-check option
|
|
||||||
* hlr.sql: move comment
|
|
||||||
* add db_upgrade test
|
|
||||||
* hlr db schema 3: hlr_number -> msc_number
|
|
||||||
* db.c: code dup: add db_run_statements() for arrays of statements
|
|
||||||
* move headers to include/osmocom/hlr
|
|
||||||
* fix upgrade test in presence of ~/.sqliterc
|
|
||||||
* db upgrade: remove some code dup
|
|
||||||
* add osmo_gsup_msgb_alloc()
|
|
||||||
* Makefile convenience: add VTY_TEST var to run only one test
|
|
||||||
* remove gsup_test
|
|
||||||
* test_nodes.vty: tweak: add some '?' checks
|
|
||||||
* db v4: add column last_lu_seen_ps
|
|
||||||
|
|
||||||
[ Harald Welte ]
|
|
||||||
* AUC: Add support for setting the AMF separation bit to '1' for EUTRAN
|
|
||||||
* hlr: exit(2) on unsupported positional arguments on command line
|
|
||||||
|
|
||||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 03 Jan 2020 12:37:35 +0100
|
|
||||||
|
|
||||||
osmo-hlr (1.1.0) unstable; urgency=medium
|
osmo-hlr (1.1.0) unstable; urgency=medium
|
||||||
|
|
||||||
[ Oliver Smith ]
|
[ Oliver Smith ]
|
||||||
|
|||||||
2
debian/compat
vendored
2
debian/compat
vendored
@@ -1 +1 @@
|
|||||||
10
|
9
|
||||||
|
|||||||
38
debian/control
vendored
38
debian/control
vendored
@@ -1,30 +1,30 @@
|
|||||||
Source: osmo-hlr
|
Source: osmo-hlr
|
||||||
Section: net
|
Section: net
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
Maintainer: Max Suraev <msuraev@sysmocom.de>
|
||||||
Build-Depends: debhelper (>= 10),
|
Build-Depends: debhelper (>= 9),
|
||||||
pkg-config,
|
pkg-config,
|
||||||
dh-autoreconf,
|
dh-autoreconf,
|
||||||
|
dh-systemd (>= 1.5),
|
||||||
autotools-dev,
|
autotools-dev,
|
||||||
python3-minimal,
|
python3-minimal,
|
||||||
libosmocore-dev (>= 1.9.0),
|
libosmocore-dev,
|
||||||
libosmo-abis-dev (>= 1.5.0),
|
libosmo-abis-dev,
|
||||||
libosmo-netif-dev (>= 1.4.0),
|
libosmo-netif-dev,
|
||||||
libsqlite3-dev,
|
libsqlite3-dev,
|
||||||
sqlite3,
|
sqlite3,
|
||||||
osmo-gsm-manuals-dev (>= 1.5.0)
|
osmo-gsm-manuals-dev
|
||||||
Standards-Version: 3.9.6
|
Standards-Version: 3.9.6
|
||||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr
|
Vcs-Browser: http://cgit.osmocom.org/osmo-hlr
|
||||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr
|
Vcs-Git: git://git.osmocom.org/osmo-hlr
|
||||||
Homepage: https://projects.osmocom.org/projects/osmo-hlr
|
Homepage: https://projects.osmocom.org/projects/osmo-hlr
|
||||||
|
|
||||||
Package: osmo-hlr
|
Package: osmo-hlr
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
Depends: ${shlibs:Depends}, ${misc:Depends}, libdbd-sqlite3
|
||||||
Description: Osmocom Home Location Register
|
Description: Osmocom Home Location Register
|
||||||
OsmoHLR is a Osmocom implementation of HLR (Home Location Registrar) which
|
OsmoHLR is a Osmocom implementation of HLR (Home Location Registrar) which works over GSUP
|
||||||
works over GSUP protocol. The subscribers are store in sqlite DB.
|
protocol. The subscribers are store in sqlite DB. It supports both 2G and 3G authentication.
|
||||||
It supports both 2G and 3G authentication.
|
|
||||||
|
|
||||||
Package: osmo-hlr-dbg
|
Package: osmo-hlr-dbg
|
||||||
Architecture: any
|
Architecture: any
|
||||||
@@ -59,7 +59,7 @@ Description: Development headers of Osmocom GSUP client library
|
|||||||
.
|
.
|
||||||
This package contains the development headers.
|
This package contains the development headers.
|
||||||
|
|
||||||
Package: libosmo-mslookup1
|
Package: libosmo-mslookup0
|
||||||
Section: libs
|
Section: libs
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Multi-Arch: same
|
Multi-Arch: same
|
||||||
@@ -73,7 +73,7 @@ Package: libosmo-mslookup-dev
|
|||||||
Architecture: any
|
Architecture: any
|
||||||
Multi-Arch: same
|
Multi-Arch: same
|
||||||
Depends: ${misc:Depends},
|
Depends: ${misc:Depends},
|
||||||
libosmo-mslookup1 (= ${binary:Version}),
|
libosmo-mslookup0 (= ${binary:Version}),
|
||||||
libosmocore-dev
|
libosmocore-dev
|
||||||
Pre-Depends: ${misc:Pre-Depends}
|
Pre-Depends: ${misc:Pre-Depends}
|
||||||
Description: Development headers of Osmocom MS lookup library
|
Description: Development headers of Osmocom MS lookup library
|
||||||
@@ -81,16 +81,6 @@ Description: Development headers of Osmocom MS lookup library
|
|||||||
.
|
.
|
||||||
This package contains the development headers.
|
This package contains the development headers.
|
||||||
|
|
||||||
Package: osmo-mslookup-utils
|
|
||||||
Architecture: any
|
|
||||||
Section: utils
|
|
||||||
Depends: ${shlibs:Depends},
|
|
||||||
libosmo-mslookup1 (= ${binary:Version}),
|
|
||||||
${misc:Depends}
|
|
||||||
Multi-Arch: same
|
|
||||||
Description: Utilities for Osmocom MS lookup
|
|
||||||
This package contains a simple MS lookup client utility.
|
|
||||||
|
|
||||||
Package: osmo-hlr-doc
|
Package: osmo-hlr-doc
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Section: doc
|
Section: doc
|
||||||
|
|||||||
2
debian/copyright
vendored
2
debian/copyright
vendored
@@ -3,7 +3,7 @@ Upstream-Name: OsmoHLR
|
|||||||
Source: http://cgit.osmocom.org/osmo-hlr/
|
Source: http://cgit.osmocom.org/osmo-hlr/
|
||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2016-2022 Sysmocom s. f. m. c. GmbH <info@sysmocom.de>
|
Copyright: 2016-2017 Sysmocom s. f. m. c. GmbH <info@sysmocom.de>
|
||||||
License: AGPL-3+
|
License: AGPL-3+
|
||||||
|
|
||||||
License: AGPL-3+
|
License: AGPL-3+
|
||||||
|
|||||||
3
debian/osmo-hlr.install
vendored
3
debian/osmo-hlr.install
vendored
@@ -5,5 +5,4 @@
|
|||||||
/usr/share/doc/osmo-hlr/sql/hlr.sql
|
/usr/share/doc/osmo-hlr/sql/hlr.sql
|
||||||
/usr/share/doc/osmo-hlr/sql/hlr_data.sql
|
/usr/share/doc/osmo-hlr/sql/hlr_data.sql
|
||||||
/usr/share/doc/osmo-hlr/examples/osmo-hlr.cfg
|
/usr/share/doc/osmo-hlr/examples/osmo-hlr.cfg
|
||||||
/usr/share/doc/osmo-hlr/examples/osmo-hlr-dgsm.cfg
|
/var/lib/osmocom
|
||||||
/usr/share/osmocom/osmo-hlr-post-upgrade.sh
|
|
||||||
|
|||||||
1
debian/osmo-mslookup-utils.install
vendored
1
debian/osmo-mslookup-utils.install
vendored
@@ -1 +0,0 @@
|
|||||||
usr/bin/osmo-mslookup-client
|
|
||||||
5
debian/postinst
vendored
5
debian/postinst
vendored
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
# Debian's postinst script is called on both installation and upgrade. Call the
|
|
||||||
# post-upgrade script in both cases, it won't do anything if there is nothing
|
|
||||||
# to do.
|
|
||||||
/usr/share/osmocom/osmo-hlr-post-upgrade.sh
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# OsmoHLR example configuration for Distributed GSM (mslookup)
|
|
||||||
hlr
|
|
||||||
gsup
|
|
||||||
# For D-GSM roaming, osmo-hlr's GSUP must listen on a public IP:
|
|
||||||
bind ip 10.9.8.7
|
|
||||||
# Each HLR should identify with a distinct name
|
|
||||||
ipa-name hlr-23
|
|
||||||
mslookup
|
|
||||||
# Bind mslookup mDNS server and client on default multicast address and port:
|
|
||||||
# 239.192.23.42 port 4266
|
|
||||||
mdns bind
|
|
||||||
# Tell the mslookup server in osmo-hlr which IP+ports to return when a
|
|
||||||
# remote voice call or SMS wants to deliver to a local subscriber:
|
|
||||||
server
|
|
||||||
# local osmo-sip-connector SIP port
|
|
||||||
service sip.voice at 10.9.8.7 5060
|
|
||||||
# local osmo-msc SMPP port
|
|
||||||
service smpp.sms at 10.9.8.7 2775
|
|
||||||
# experimental: SMS-over-GSUP: this HLR's GSUP port
|
|
||||||
service gsup.sms at 10.9.8.7 4222
|
|
||||||
# only required if different from above 'gsup'/'bind ip':
|
|
||||||
#service gsup.hlr at 10.9.8.7 4222
|
|
||||||
@@ -12,7 +12,7 @@ log stderr
|
|||||||
logging level main notice
|
logging level main notice
|
||||||
logging level db notice
|
logging level db notice
|
||||||
logging level auc notice
|
logging level auc notice
|
||||||
logging level ss notice
|
logging level ss info
|
||||||
logging level linp error
|
logging level linp error
|
||||||
!
|
!
|
||||||
line vty
|
line vty
|
||||||
@@ -24,9 +24,10 @@ hlr
|
|||||||
bind ip 127.0.0.1
|
bind ip 127.0.0.1
|
||||||
ussd route prefix *#100# internal own-msisdn
|
ussd route prefix *#100# internal own-msisdn
|
||||||
ussd route prefix *#101# internal own-imsi
|
ussd route prefix *#101# internal own-imsi
|
||||||
ps
|
ussd route prefix *#102# internal get-ran
|
||||||
pdp-profiles default
|
ussd route prefix *#200# internal gsm-off
|
||||||
profile 1
|
ussd route prefix *#201# internal gsm-on
|
||||||
apn internet
|
ussd route prefix *#300# internal umts-off
|
||||||
profile 2
|
ussd route prefix *#301# internal umts-on
|
||||||
apn *
|
ussd route prefix *#400# internal lte-off
|
||||||
|
ussd route prefix *#401# internal lte-on
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
EXTRA_DIST = \
|
EXTRA_DIST = example_subscriber_add_update_delete.vty \
|
||||||
example_subscriber_add_update_delete.vty \
|
|
||||||
example_subscriber_aud2g.ctrl \
|
|
||||||
example_subscriber_aud3g.ctrl \
|
|
||||||
example_subscriber_cs_ps_enabled.ctrl \
|
example_subscriber_cs_ps_enabled.ctrl \
|
||||||
example_subscriber_info.ctrl \
|
example_subscriber_info.ctrl \
|
||||||
example_subscriber_msisdn.ctrl \
|
|
||||||
osmohlr-usermanual.adoc \
|
osmohlr-usermanual.adoc \
|
||||||
osmohlr-usermanual-docinfo.xml \
|
osmohlr-usermanual-docinfo.xml \
|
||||||
osmohlr-vty-reference.xml \
|
osmohlr-vty-reference.xml \
|
||||||
@@ -18,12 +14,6 @@ if BUILD_MANUALS
|
|||||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
|
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
|
||||||
|
|
||||||
VTY_REFERENCE = osmohlr-vty-reference.xml
|
VTY_REFERENCE = osmohlr-vty-reference.xml
|
||||||
|
|
||||||
BUILT_REFERENCE_XML = $(builddir)/vty/hlr_vty_reference.xml
|
|
||||||
$(builddir)/vty/hlr_vty_reference.xml: $(top_builddir)/src/osmo-hlr
|
|
||||||
mkdir -p $(builddir)/vty
|
|
||||||
$(top_builddir)/src/osmo-hlr --vty-ref-xml > $@
|
|
||||||
|
|
||||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
||||||
|
|
||||||
OSMO_REPOSITORY = osmo-hlr
|
OSMO_REPOSITORY = osmo-hlr
|
||||||
|
|||||||
@@ -5,16 +5,6 @@ The actual protocol is described in <<common-control-if>>, the variables common
|
|||||||
to all programs using it are described in <<ctrl_common_vars>>. This section
|
to all programs using it are described in <<ctrl_common_vars>>. This section
|
||||||
describes the CTRL interface variables specific to OsmoHLR.
|
describes the CTRL interface variables specific to OsmoHLR.
|
||||||
|
|
||||||
Subscribers can be created and deleted using the following SET commands:
|
|
||||||
|
|
||||||
.Subscriber management commands available on OsmoHLR's Control interface
|
|
||||||
[options="header",width="100%",cols="35%,65%"]
|
|
||||||
|===
|
|
||||||
|Command|Comment
|
|
||||||
|subscriber.create '123456'|Create a new subscriber with IMSI "123456" to the database. Returns database ID of the subscriber being created.
|
|
||||||
|subscriber.delete '123456'|Delete subscriber with IMSI "123456" from database. Returns database ID of the subscriber being deleted.
|
|
||||||
|===
|
|
||||||
|
|
||||||
All subscriber variables are available by different selectors, which are freely
|
All subscriber variables are available by different selectors, which are freely
|
||||||
interchangeable:
|
interchangeable:
|
||||||
|
|
||||||
@@ -38,9 +28,6 @@ Each of the above selectors feature all of these control variables:
|
|||||||
|subscriber.by-\*.*info-all*|R|No||List both 'info' and 'info-aud' in one
|
|subscriber.by-\*.*info-all*|R|No||List both 'info' and 'info-aud' in one
|
||||||
|subscriber.by-\*.*cs-enabled*|RW|No|'1' or '0'|Enable/disable circuit-switched access
|
|subscriber.by-\*.*cs-enabled*|RW|No|'1' or '0'|Enable/disable circuit-switched access
|
||||||
|subscriber.by-\*.*ps-enabled*|RW|No|'1' or '0'|Enable/disable packet-switched access
|
|subscriber.by-\*.*ps-enabled*|RW|No|'1' or '0'|Enable/disable packet-switched access
|
||||||
|subscriber.by-\*.*msisdn*|RW|No|valid MSISDN string|Get/Set assigned MSISDN
|
|
||||||
|subscriber.by-\*.*aud2g*|RW|No|'algo[,KI]'|Get/Set 2g Authentication Data
|
|
||||||
|subscriber.by-\*.*aud2g*|RW|No|'algo[,KI,("op"|"opc"),OP_C[,ind_bitlen]]'|Get/Set 3g Authentication Data
|
|
||||||
|===
|
|===
|
||||||
|
|
||||||
=== subscriber.by-*.info, info-aud, info-all
|
=== subscriber.by-*.info, info-aud, info-all
|
||||||
@@ -117,63 +104,3 @@ commands:
|
|||||||
----
|
----
|
||||||
include::../example_subscriber_cs_ps_enabled.ctrl[]
|
include::../example_subscriber_cs_ps_enabled.ctrl[]
|
||||||
----
|
----
|
||||||
|
|
||||||
=== subscriber.by-*.msisdn
|
|
||||||
|
|
||||||
Get or set the MSISDN currently assigned to a subscriber.
|
|
||||||
|
|
||||||
|
|
||||||
This is an example transcript that illustrates use of this command:
|
|
||||||
|
|
||||||
----
|
|
||||||
include::../example_subscriber_msisdn.ctrl[]
|
|
||||||
----
|
|
||||||
|
|
||||||
=== subscriber.by-*.aud2g
|
|
||||||
|
|
||||||
Get or set the 2G Authentication data of a subscriber.
|
|
||||||
|
|
||||||
The information is stored/retrieved as a comma separated list of fields:
|
|
||||||
|
|
||||||
----
|
|
||||||
algo[,KI]
|
|
||||||
----
|
|
||||||
|
|
||||||
Where::
|
|
||||||
* *KI* is the KI as a hexadecimal string.
|
|
||||||
* *algo* is one of the following algorithms: _none, xor, comp128v1, comp128v2,
|
|
||||||
comp128v3_.
|
|
||||||
|
|
||||||
All values are case insensitive.
|
|
||||||
|
|
||||||
This is an example transcript that illustrates use of this command:
|
|
||||||
|
|
||||||
----
|
|
||||||
include::../example_subscriber_aud2g.ctrl[]
|
|
||||||
----
|
|
||||||
|
|
||||||
=== subscriber.by-*.aud3g
|
|
||||||
|
|
||||||
Get or set the 3G Authentication data of a subscriber.
|
|
||||||
|
|
||||||
The information is stored/retrieved as a comma separated list of fields:
|
|
||||||
|
|
||||||
----
|
|
||||||
algo[,KI,("op"|"opc"),OP_C[,ind_bitlen]]
|
|
||||||
----
|
|
||||||
|
|
||||||
Where:
|
|
||||||
* *KI* is the KI as a hexadecimal string.
|
|
||||||
* *algo* is one of the following algorithms: _none, xor, milenage_.
|
|
||||||
* "op" or "opc" indicates whether next field is an OP or OPC value.
|
|
||||||
* *OP_C* contains an OP or OPC values as hexadecimal string, based on what the
|
|
||||||
previous field specifies.
|
|
||||||
* *ind_bitlen* is set to 5 by default if not provided.
|
|
||||||
|
|
||||||
All values are case insensitive.
|
|
||||||
|
|
||||||
This is an example transcript that illustrates use of this command:
|
|
||||||
|
|
||||||
----
|
|
||||||
include::../example_subscriber_aud3g.ctrl[]
|
|
||||||
----
|
|
||||||
|
|||||||
@@ -214,12 +214,6 @@ port, but beware that the IP address must be from a multicast range, see <<ietf-
|
|||||||
mslookup
|
mslookup
|
||||||
mdns bind 239.192.23.42 4266
|
mdns bind 239.192.23.42 4266
|
||||||
|
|
||||||
Domain names generated from mslookup queries (e.g. "sip.voice.123.msisdn") should not collide with IANA permitted
|
|
||||||
domains. Therefore we add the "mdns.osmocom.org" suffix. It can be overridden as follows:
|
|
||||||
|
|
||||||
mslookup
|
|
||||||
mdns domain-suffix mdns.osmocom.org
|
|
||||||
|
|
||||||
==== Server: Site Services
|
==== Server: Site Services
|
||||||
|
|
||||||
The mslookup server requires a list of service addresses provided at the local site, in order to respond to service
|
The mslookup server requires a list of service addresses provided at the local site, in order to respond to service
|
||||||
@@ -230,25 +224,23 @@ requests matching locally attached subscribers.
|
|||||||
service sip.voice at 10.9.8.7 5060
|
service sip.voice at 10.9.8.7 5060
|
||||||
service smpp.sms at 10.9.8.7 2775
|
service smpp.sms at 10.9.8.7 2775
|
||||||
|
|
||||||
In this example:
|
In this example, "10.9.8.7 5060" would be the IP address and port on which the local site's PBX is bound to receive SIP
|
||||||
|
Invite requests; "10.9.8.7 2775" would be the local site's OsmoMSC SMPP bind address and port.
|
||||||
|
|
||||||
- "10.9.8.7 5060" are the IP address and port on which the local site's osmo-sip-connector is bound to receive SIP
|
Obviously, these IP addresses must be routable back to this site from all other sites. If, for example, the PBX is
|
||||||
Invite requests.
|
configured to bind on "0.0.0.0", it won't work to enter the same as service address -- remote sites cannot route to
|
||||||
- "10.9.8.7 2775" are the local site's OsmoMSC SMPP bind address and port.
|
0.0.0.0. Instead, the mslookup service requires a public IP address of a local interface. For the same reasons, never
|
||||||
|
add link-local addresses like 127.0.0.1 as mslookup services.
|
||||||
Obviously, these IP addresses must be routable back to this site from all other sites. Using link-local or "ANY"
|
|
||||||
addresses, like 127.0.0.1 or 0.0.0.0, will not work here. Instead, each service config requires a public IP address that
|
|
||||||
all remote requestors are able to reach (not necessarily on the host that osmo-hlr is running on).
|
|
||||||
|
|
||||||
If a site has more than one MSC, services can also be configured for each MSC individually, keyed by the IPA unit name
|
If a site has more than one MSC, services can also be configured for each MSC individually, keyed by the IPA unit name
|
||||||
that each MSC sends on the GSUP link:
|
that each MSC sends on the GSUP link:
|
||||||
|
|
||||||
mslookup
|
mslookup
|
||||||
server
|
server
|
||||||
msc ipa-name msc-262-42-0
|
msc msc-262-42-0
|
||||||
service sip.voice at 10.11.12.13 5060
|
service sip.voice at 10.11.12.13 5060
|
||||||
service smpp.sms at 10.11.12.13 2775
|
service smpp.sms at 10.11.12.13 2775
|
||||||
msc ipa-name msc-901-70-0
|
msc msc-901-70-0
|
||||||
service sip.voice at 10.9.8.7 5060
|
service sip.voice at 10.9.8.7 5060
|
||||||
service smpp.sms at 10.9.8.7 2775
|
service smpp.sms at 10.9.8.7 2775
|
||||||
|
|
||||||
@@ -332,7 +324,7 @@ The mslookup ID types are fixed, while service names can be chosen arbitrarily.
|
|||||||
|===
|
|===
|
||||||
|Service Name|Protocol|Description
|
|Service Name|Protocol|Description
|
||||||
|gsup.hlr | GSUP | Home HLR's GSUP server, to handle Location Updating related procedures
|
|gsup.hlr | GSUP | Home HLR's GSUP server, to handle Location Updating related procedures
|
||||||
|sip.voice | SIP | OsmoSIPConnector, to receive a SIP Invite (MT side of a call)
|
|sip.voice | SIP | SIP PBX or OsmoSIPConnector, to receive a SIP Invite (MT side of a call)
|
||||||
|smpp.sms | SMPP | Destination OsmoMSC (or other SMPP server) to deliver an SMS to the recipient
|
|smpp.sms | SMPP | Destination OsmoMSC (or other SMPP server) to deliver an SMS to the recipient
|
||||||
|gsup.sms | GSUP | GSUP peer to deliver an SMS to the recipient using SMS-over-GSUP
|
|gsup.sms | GSUP | GSUP peer to deliver an SMS to the recipient using SMS-over-GSUP
|
||||||
|===
|
|===
|
||||||
@@ -420,7 +412,6 @@ dialplan implementation. An example dialplan implementation for FreeSWITCH that
|
|||||||
osmo-hlr source tree under `contrib`, called `freeswitch_dialplan_dgsm.py`.
|
osmo-hlr source tree under `contrib`, called `freeswitch_dialplan_dgsm.py`.
|
||||||
|
|
||||||
To integrate it with your FREESWITCH setup, add a new `extension` block to your `dialplan/public.xml`:
|
To integrate it with your FREESWITCH setup, add a new `extension` block to your `dialplan/public.xml`:
|
||||||
|
|
||||||
----
|
----
|
||||||
<extension name="outbound">
|
<extension name="outbound">
|
||||||
<condition field="destination_number" expression=".*">
|
<condition field="destination_number" expression=".*">
|
||||||
@@ -434,7 +425,6 @@ To integrate it with your FREESWITCH setup, add a new `extension` block to your
|
|||||||
|
|
||||||
Make sure that the dir containing `freeswitch_dialplan_dgsm.py` is in your `PYTHONPATH` environment variable, and start
|
Make sure that the dir containing `freeswitch_dialplan_dgsm.py` is in your `PYTHONPATH` environment variable, and start
|
||||||
the server:
|
the server:
|
||||||
|
|
||||||
----
|
----
|
||||||
$ export PYTHONPATH="$PYTHONPATH:/home/user/code/osmo-hlr/contrib/dgsm"
|
$ export PYTHONPATH="$PYTHONPATH:/home/user/code/osmo-hlr/contrib/dgsm"
|
||||||
$ freeswitch -nf -nonat -nonatmap -nocal -nort -c
|
$ freeswitch -nf -nonat -nonatmap -nocal -nort -c
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ this database file will be created in the current working directory.
|
|||||||
|
|
||||||
Alternatively, you may use the `osmo-hlr-db-tool`, which is installed along
|
Alternatively, you may use the `osmo-hlr-db-tool`, which is installed along
|
||||||
with `osmo-hlr`, to bootstrap an empty database, or to migrate subscriber data
|
with `osmo-hlr`, to bootstrap an empty database, or to migrate subscriber data
|
||||||
from an old 'OsmoNITB' database. See <<db_import_nitb>>.
|
from an old 'OsmoNITB' database. See `osmo-hlr-db-tool --help`.
|
||||||
|
|
||||||
=== Multiple instances
|
=== Multiple instances
|
||||||
|
|
||||||
|
|||||||
@@ -127,83 +127,3 @@ OsmoHLR# subscriber imei 35761300444848 show
|
|||||||
----
|
----
|
||||||
<1> Randomly generated 5 digit MSISDN
|
<1> Randomly generated 5 digit MSISDN
|
||||||
<2> Disabled CS and PS NAM prevent the subscriber from accessing the network
|
<2> Disabled CS and PS NAM prevent the subscriber from accessing the network
|
||||||
|
|
||||||
|
|
||||||
=== Import Subscriber Data
|
|
||||||
|
|
||||||
==== Scripted Import
|
|
||||||
|
|
||||||
WARNING: It is not generally a good idea to depend on the HLR database's internal table structure, but in the lack of an
|
|
||||||
automated import procedure, this example is provided as an ad-hoc method to aid automated subscriber import. This is not
|
|
||||||
guaranteed to remain valid.
|
|
||||||
|
|
||||||
NOTE: We may add CSV and other import methods to the `osmo-hlr-db-tool`, but so far that is not implemented. Contact the
|
|
||||||
community if you are interested in such a feature being implemented.
|
|
||||||
|
|
||||||
NOTE: `sqlite3` is available from your distribution packages or `sqlite.org`.
|
|
||||||
|
|
||||||
Currently, probably the easiest way to automatically import subscribers to OsmoHLR is to write out a text file with SQL
|
|
||||||
commands per subscriber, and feed that to `sqlite3`, as described below.
|
|
||||||
|
|
||||||
A difficulty is to always choose subscriber IDs that are not yet in use. For an initial import, the subscriber ID may be
|
|
||||||
incremented per subscriber record. If adding more subscribers to an existing database, it is necessary to choose
|
|
||||||
subscriber IDs that are not yet in use. Get the highest ID in use with:
|
|
||||||
|
|
||||||
----
|
|
||||||
sqlite3 hlr.db 'select max(id) from subscriber'
|
|
||||||
----
|
|
||||||
|
|
||||||
A full SQL example of adding a single subscriber with id 23, IMSI 001010123456789, MSISDN 1234, Ki for COMP128v1, and K
|
|
||||||
and OPC for Milenage:
|
|
||||||
|
|
||||||
----
|
|
||||||
INSERT subscriber (id, imsi, msisdn) VALUES (23, '001010123456789', '1234');
|
|
||||||
|
|
||||||
INSERT INTO auc_2g (subscriber_id, algo_id_2g, ki)
|
|
||||||
VALUES(23, 1, '0123456789abcdef0123456789abcdef');
|
|
||||||
|
|
||||||
INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, op, opc)
|
|
||||||
VALUES(23, 5, '0123456789abcdef0123456789abcdef',NULL,'0123456789abcdef0123456789abcdef');
|
|
||||||
----
|
|
||||||
|
|
||||||
Table entries to `auc_2g` and/or `auc_3g` may be omitted if no such key material is required.
|
|
||||||
|
|
||||||
UMTS Milenage auth (on both 2G and 3G RAN) is configured by the `auc_3g` table. `algo_id_3g` must currently always be 5
|
|
||||||
(MILENAGE).
|
|
||||||
|
|
||||||
The algorithm IDs for `algo_id_2g` and `algo_id_3g` are:
|
|
||||||
|
|
||||||
.Algorithm IDs in OsmoHLR's database
|
|
||||||
[options="header",width="50%",cols="40%,60%"]
|
|
||||||
|===
|
|
||||||
|`algo_id_2g` / `algo_id_3g` | Authentication Algorithm
|
|
||||||
| 1 | COMP128v1
|
|
||||||
| 2 | COMP128v2
|
|
||||||
| 3 | COMP128v3
|
|
||||||
| 4 | XOR
|
|
||||||
| 5 | MILENAGE
|
|
||||||
|===
|
|
||||||
|
|
||||||
Create an empty HLR database with
|
|
||||||
|
|
||||||
----
|
|
||||||
osmo-hlr-db-tool -l hlr.db create
|
|
||||||
----
|
|
||||||
|
|
||||||
Repeat above SQL commands per subscriber, incrementing the subscriber ID for each block, then feed the SQL commands for
|
|
||||||
the subscribers to be imported to the `sqlite3` command line tool:
|
|
||||||
|
|
||||||
----
|
|
||||||
sqlite3 hlr.db < subscribers.sql
|
|
||||||
----
|
|
||||||
|
|
||||||
[[db_import_nitb]]
|
|
||||||
==== Import OsmoNITB database
|
|
||||||
|
|
||||||
To upgrade from old OsmoNITB to OsmoHLR, use `osmo-hlr-db-tool`:
|
|
||||||
|
|
||||||
----
|
|
||||||
osmo-hlr-db-tool -l hlr.db import-nitb-db nitb.db
|
|
||||||
----
|
|
||||||
|
|
||||||
Be aware that the import is lossy, only the IMSI, MSISDN, nam_cs/ps and 2G auth data are set.
|
|
||||||
|
|||||||
@@ -50,29 +50,15 @@ prefix route to the named EUSE. All USSD short codes starting with *123 will be
|
|||||||
routed to the named EUSE.
|
routed to the named EUSE.
|
||||||
|
|
||||||
`ussd route prefix *#100# internal own-msisdn` installs a prefix route
|
`ussd route prefix *#100# internal own-msisdn` installs a prefix route
|
||||||
to the named internal USSD handler. The above command will restore
|
to the named internal USSD handler. There above command will restore
|
||||||
the old behavior, in which *#100# will return a text message containing
|
the old behavior, in which *#100# will return a text message containing
|
||||||
the subscribers own phone number. More information on internal USSD
|
the subscribers own phone number. There is one other handler called
|
||||||
handlers can be found in <<iuse_handlers>>.
|
`own-imsi` which will return the IMSI instead of the MSISDN.
|
||||||
|
|
||||||
`ussd default-route external foobar-00-00-00-00-00-00` installs a
|
`ussd default-route external foobar-00-00-00-00-00-00` installs a
|
||||||
default route to the named EUSE. This means that all USSD codes for
|
default route to the named EUSE. This means that all USSD codes for
|
||||||
which no more specific route exists will be routed to the named EUSE.
|
which no more specific route exists will be routed to the named EUSE.
|
||||||
|
|
||||||
[[iuse_handlers]]
|
|
||||||
=== Built-in USSD handlers
|
|
||||||
|
|
||||||
OsmoHLR has an Internal USSD Entity (IUSE) that allows to handle some
|
|
||||||
USSD requests internally. It features a set of simple handlers, which
|
|
||||||
can be assigned to one or more USSD request prefixes:
|
|
||||||
|
|
||||||
* `own-msisdn` returns subscriber's MSISDN (if assigned);
|
|
||||||
* `own-imsi` returns subscriber's IMSI;
|
|
||||||
* `test-idle` keeps the session idle until the MS terminates it, or
|
|
||||||
the guard timer expires (may be useful for testing).
|
|
||||||
|
|
||||||
Additional handlers can be added on request.
|
|
||||||
|
|
||||||
=== Example EUSE program
|
=== Example EUSE program
|
||||||
|
|
||||||
We have provided an example EUSE developed in C language using existing
|
We have provided an example EUSE developed in C language using existing
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
GET 1 subscriber.by-imsi-901991234567891.aud2g
|
|
||||||
GET_REPLY 1 subscriber.by-imsi-901991234567891.aud2g none
|
|
||||||
|
|
||||||
SET 2 subscriber.by-imsi-901991234567891.aud2g xor,c01ffedc1cadaeac1d1f1edacac1ab0a
|
|
||||||
SET_REPLY 2 subscriber.by-imsi-901991234567891.aud2g OK
|
|
||||||
|
|
||||||
GET 3 subscriber.by-imsi-901991234567891.aud2g
|
|
||||||
GET_REPLY 3 subscriber.by-imsi-901991234567891.aud2g XOR,c01ffedc1cadaeac1d1f1edacac1ab0a
|
|
||||||
|
|
||||||
SET 4 subscriber.by-imsi-901991234567891.aud2g none
|
|
||||||
SET_REPLY 4 subscriber.by-imsi-901991234567891.aud2g OK
|
|
||||||
|
|
||||||
GET 5 subscriber.by-imsi-901991234567891.aud2g
|
|
||||||
GET_REPLY 5 subscriber.by-imsi-901991234567891.aud2g none
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
GET 117 subscriber.by-imsi-901991234567891.aud3g
|
|
||||||
GET_REPLY 117 subscriber.by-imsi-901991234567891.aud3g none
|
|
||||||
|
|
||||||
SET 118 subscriber.by-imsi-901991234567891.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OP,FB2A3D1B360F599ABAB99DB8669F8308
|
|
||||||
SET_REPLY 118 subscriber.by-imsi-901991234567891.aud3g OK
|
|
||||||
|
|
||||||
GET 119 subscriber.by-imsi-901991234567891.aud3g
|
|
||||||
GET_REPLY 119 subscriber.by-imsi-901991234567891.aud3g MILENAGE,c01ffedc1cadaeac1d1f1edacac1ab0a,OP,fb2a3d1b360f599abab99db8669f8308,5
|
|
||||||
|
|
||||||
SET 120 subscriber.by-imsi-901991234567891.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,FB2A3D1B360F599ABAB99DB8669F8308,7
|
|
||||||
SET_REPLY 120 subscriber.by-imsi-901991234567891.aud3g OK
|
|
||||||
|
|
||||||
GET 121 subscriber.by-imsi-901991234567891.aud3g
|
|
||||||
GET_REPLY 121 subscriber.by-imsi-901991234567891.aud3g MILENAGE,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,fb2a3d1b360f599abab99db8669f8308,7
|
|
||||||
|
|
||||||
SET 122 subscriber.by-imsi-901991234567891.aud3g none
|
|
||||||
SET_REPLY 122 subscriber.by-imsi-901991234567891.aud3g OK
|
|
||||||
|
|
||||||
GET 123 subscriber.by-imsi-901991234567891.aud3g
|
|
||||||
GET_REPLY 123 subscriber.by-imsi-901991234567891.aud3g none
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
GET 1 subscriber.by-imsi-901991234567891.msisdn
|
|
||||||
GET_REPLY 1 subscriber.by-imsi-901991234567891.msisdn none
|
|
||||||
|
|
||||||
SET 2 subscriber.by-imsi-901991234567891.msisdn 555666
|
|
||||||
SET_REPLY 2 subscriber.by-imsi-901991234567891.msisdn OK
|
|
||||||
|
|
||||||
GET 3 subscriber.by-imsi-901991234567891.msisdn
|
|
||||||
GET_REPLY 3 subscriber.by-imsi-901991234567891.msisdn 555666
|
|
||||||
@@ -28,8 +28,6 @@ include::{srcdir}/chapters/dgsm.adoc[]
|
|||||||
|
|
||||||
include::./common/chapters/gsup.adoc[]
|
include::./common/chapters/gsup.adoc[]
|
||||||
|
|
||||||
include::./common/chapters/vty_cpu_sched.adoc[]
|
|
||||||
|
|
||||||
include::./common/chapters/port_numbers.adoc[]
|
include::./common/chapters/port_numbers.adoc[]
|
||||||
|
|
||||||
include::./common/chapters/bibliography.adoc[]
|
include::./common/chapters/bibliography.adoc[]
|
||||||
@@ -37,3 +35,4 @@ include::./common/chapters/bibliography.adoc[]
|
|||||||
include::./common/chapters/glossary.adoc[]
|
include::./common/chapters/glossary.adoc[]
|
||||||
|
|
||||||
include::./common/chapters/gfdl.adoc[]
|
include::./common/chapters/gfdl.adoc[]
|
||||||
|
|
||||||
|
|||||||
1431
doc/manuals/vty/hlr_vty_reference.xml
Normal file
1431
doc/manuals/vty/hlr_vty_reference.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
SUBDIRS = osmocom
|
SUBDIRS = osmocom
|
||||||
|
|
||||||
nobase_include_HEADERS = \
|
nobase_include_HEADERS = \
|
||||||
osmocom/gsupclient/cni_peer_id.h \
|
osmocom/gsupclient/gsup_peer_id.h \
|
||||||
osmocom/gsupclient/gsup_client.h \
|
osmocom/gsupclient/gsup_client.h \
|
||||||
osmocom/gsupclient/gsup_req.h \
|
osmocom/gsupclient/gsup_req.h \
|
||||||
osmocom/mslookup/mdns.h \
|
osmocom/mslookup/mdns.h \
|
||||||
|
|||||||
@@ -32,35 +32,33 @@ struct osmo_ipa_name {
|
|||||||
uint8_t val[128];
|
uint8_t val[128];
|
||||||
};
|
};
|
||||||
|
|
||||||
bool osmo_ipa_name_is_empty(const struct osmo_ipa_name *ipa_name);
|
bool osmo_ipa_name_is_empty(struct osmo_ipa_name *ipa_name);
|
||||||
int osmo_ipa_name_set(struct osmo_ipa_name *ipa_name, const uint8_t *val, size_t len);
|
int osmo_ipa_name_set(struct osmo_ipa_name *ipa_name, const uint8_t *val, size_t len);
|
||||||
int osmo_ipa_name_set_str(struct osmo_ipa_name *ipa_name, const char *str_fmt, ...);
|
int osmo_ipa_name_set_str(struct osmo_ipa_name *ipa_name, const char *str_fmt, ...);
|
||||||
int osmo_ipa_name_cmp(const struct osmo_ipa_name *a, const struct osmo_ipa_name *b);
|
int osmo_ipa_name_cmp(const struct osmo_ipa_name *a, const struct osmo_ipa_name *b);
|
||||||
const char *osmo_ipa_name_to_str_c(void *ctx, const struct osmo_ipa_name *ipa_name);
|
|
||||||
const char *osmo_ipa_name_to_str(const struct osmo_ipa_name *ipa_name);
|
const char *osmo_ipa_name_to_str(const struct osmo_ipa_name *ipa_name);
|
||||||
|
|
||||||
enum osmo_cni_peer_id_type {
|
enum osmo_gsup_peer_id_type {
|
||||||
OSMO_CNI_PEER_ID_EMPTY=0,
|
OSMO_GSUP_PEER_ID_EMPTY=0,
|
||||||
OSMO_CNI_PEER_ID_IPA_NAME,
|
OSMO_GSUP_PEER_ID_IPA_NAME,
|
||||||
/* OSMO_CNI_PEER_ID_GLOBAL_TITLE, <-- currently not implemented, but likely future possibility */
|
/* OSMO_GSUP_PEER_ID_GLOBAL_TITLE, <-- currently not implemented, but likely future possibility */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct value_string osmo_cni_peer_id_type_names[];
|
extern const struct value_string osmo_gsup_peer_id_type_names[];
|
||||||
static inline const char *osmo_cni_peer_id_type_name(enum osmo_cni_peer_id_type val)
|
static inline const char *osmo_gsup_peer_id_type_name(enum osmo_gsup_peer_id_type val)
|
||||||
{ return get_value_string(osmo_cni_peer_id_type_names, val); }
|
{ return get_value_string(osmo_gsup_peer_id_type_names, val); }
|
||||||
|
|
||||||
struct osmo_cni_peer_id {
|
struct osmo_gsup_peer_id {
|
||||||
enum osmo_cni_peer_id_type type;
|
enum osmo_gsup_peer_id_type type;
|
||||||
union {
|
union {
|
||||||
struct osmo_ipa_name ipa_name;
|
struct osmo_ipa_name ipa_name;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
bool osmo_cni_peer_id_is_empty(const struct osmo_cni_peer_id *cni_peer_id);
|
bool osmo_gsup_peer_id_is_empty(struct osmo_gsup_peer_id *gsup_peer_id);
|
||||||
int osmo_cni_peer_id_set(struct osmo_cni_peer_id *cni_peer_id, enum osmo_cni_peer_id_type type,
|
int osmo_gsup_peer_id_set(struct osmo_gsup_peer_id *gsup_peer_id, enum osmo_gsup_peer_id_type type,
|
||||||
const uint8_t *val, size_t len);
|
const uint8_t *val, size_t len);
|
||||||
int osmo_cni_peer_id_set_str(struct osmo_cni_peer_id *cni_peer_id, enum osmo_cni_peer_id_type type,
|
int osmo_gsup_peer_id_set_str(struct osmo_gsup_peer_id *gsup_peer_id, enum osmo_gsup_peer_id_type type,
|
||||||
const char *str_fmt, ...);
|
const char *str_fmt, ...);
|
||||||
int osmo_cni_peer_id_cmp(const struct osmo_cni_peer_id *a, const struct osmo_cni_peer_id *b);
|
int osmo_gsup_peer_id_cmp(const struct osmo_gsup_peer_id *a, const struct osmo_gsup_peer_id *b);
|
||||||
const char *osmo_cni_peer_id_to_str(const struct osmo_cni_peer_id *cni_peer_id);
|
const char *osmo_gsup_peer_id_to_str(const struct osmo_gsup_peer_id *gsup_peer_id);
|
||||||
const char *osmo_cni_peer_id_to_str_c(void *ctx, const struct osmo_cni_peer_id *cni_peer_id);
|
|
||||||
@@ -19,14 +19,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <osmocom/gsm/gsup.h>
|
#include <osmocom/gsm/gsup.h>
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
|
|
||||||
struct osmo_gsup_req;
|
struct osmo_gsup_req;
|
||||||
|
|
||||||
#define LOG_GSUP_REQ_CAT_SRC(req, subsys, level, file, line, fmt, args...) \
|
#define LOG_GSUP_REQ_CAT_SRC(req, subsys, level, file, line, fmt, args...) \
|
||||||
LOGPSRC(subsys, level, file, line, "GSUP %u: %s: IMSI-%s %s: " fmt, \
|
LOGPSRC(subsys, level, file, line, "GSUP %u: %s: IMSI-%s %s: " fmt, \
|
||||||
(req) ? (req)->nr : 0, \
|
(req) ? (req)->nr : 0, \
|
||||||
(req) ? osmo_cni_peer_id_to_str(&(req)->source_name) : "NULL", \
|
(req) ? osmo_gsup_peer_id_to_str(&(req)->source_name) : "NULL", \
|
||||||
(req) ? (req)->gsup.imsi : "NULL", \
|
(req) ? (req)->gsup.imsi : "NULL", \
|
||||||
(req) ? osmo_gsup_message_type_name((req)->gsup.message_type) : "NULL", \
|
(req) ? osmo_gsup_message_type_name((req)->gsup.message_type) : "NULL", \
|
||||||
##args)
|
##args)
|
||||||
@@ -56,11 +56,11 @@ struct osmo_gsup_req {
|
|||||||
/* The ultimate source of this message: the source_name form the GSUP message, or, if not present, then the
|
/* The ultimate source of this message: the source_name form the GSUP message, or, if not present, then the
|
||||||
* immediate GSUP peer. GSUP messages going via a proxy reflect the initial source in the source_name.
|
* immediate GSUP peer. GSUP messages going via a proxy reflect the initial source in the source_name.
|
||||||
* This source_name is implicitly added to the routes for the conn the message was received on. */
|
* This source_name is implicitly added to the routes for the conn the message was received on. */
|
||||||
struct osmo_cni_peer_id source_name;
|
struct osmo_gsup_peer_id source_name;
|
||||||
|
|
||||||
/* If the source_name is not an immediate GSUP peer, this is set to the closest intermediate peer between here
|
/* If the source_name is not an immediate GSUP peer, this is set to the closest intermediate peer between here
|
||||||
* and source_name. */
|
* and source_name. */
|
||||||
struct osmo_cni_peer_id via_proxy;
|
struct osmo_gsup_peer_id via_proxy;
|
||||||
|
|
||||||
/* Identify this request by number, for logging. */
|
/* Identify this request by number, for logging. */
|
||||||
unsigned int nr;
|
unsigned int nr;
|
||||||
@@ -82,28 +82,24 @@ struct osmo_gsup_req {
|
|||||||
struct msgb *msg;
|
struct msgb *msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id *from_peer, struct msgb *msg,
|
struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_gsup_peer_id *from_peer, struct msgb *msg,
|
||||||
osmo_gsup_req_send_response_t send_response_cb, void *cb_data,
|
osmo_gsup_req_send_response_t send_response_cb, void *cb_data,
|
||||||
struct llist_head *add_to_list);
|
struct llist_head *add_to_list);
|
||||||
void osmo_gsup_req_free(struct osmo_gsup_req *req);
|
void osmo_gsup_req_free(struct osmo_gsup_req *req);
|
||||||
|
|
||||||
/*! See _osmo_gsup_req_respond() for details.
|
/*! Call _osmo_gsup_req_respond() to convey the sender's source file and line in the logs. */
|
||||||
* Call _osmo_gsup_req_respond(), passing the caller's source file and line for logging. */
|
|
||||||
#define osmo_gsup_req_respond(REQ, RESPONSE, ERROR, FINAL_RESPONSE) \
|
#define osmo_gsup_req_respond(REQ, RESPONSE, ERROR, FINAL_RESPONSE) \
|
||||||
_osmo_gsup_req_respond(REQ, RESPONSE, ERROR, FINAL_RESPONSE, __FILE__, __LINE__)
|
_osmo_gsup_req_respond(REQ, RESPONSE, ERROR, FINAL_RESPONSE, __FILE__, __LINE__)
|
||||||
int _osmo_gsup_req_respond(struct osmo_gsup_req *req, struct osmo_gsup_message *response,
|
int _osmo_gsup_req_respond(struct osmo_gsup_req *req, struct osmo_gsup_message *response,
|
||||||
bool error, bool final_response, const char *file, int line);
|
bool error, bool final_response, const char *file, int line);
|
||||||
|
|
||||||
/*! See _osmo_gsup_req_respond_msgt() for details.
|
/*! Call _osmo_gsup_req_respond_msgt() to convey the sender's source file and line in the logs. */
|
||||||
* Call _osmo_gsup_req_respond_msgt(), passing the caller's source file and line for logging. */
|
|
||||||
#define osmo_gsup_req_respond_msgt(REQ, MESSAGE_TYPE, FINAL_RESPONSE) \
|
#define osmo_gsup_req_respond_msgt(REQ, MESSAGE_TYPE, FINAL_RESPONSE) \
|
||||||
_osmo_gsup_req_respond_msgt(REQ, MESSAGE_TYPE, FINAL_RESPONSE, __FILE__, __LINE__)
|
_osmo_gsup_req_respond_msgt(REQ, MESSAGE_TYPE, FINAL_RESPONSE, __FILE__, __LINE__)
|
||||||
int _osmo_gsup_req_respond_msgt(struct osmo_gsup_req *req, enum osmo_gsup_message_type message_type,
|
int _osmo_gsup_req_respond_msgt(struct osmo_gsup_req *req, enum osmo_gsup_message_type message_type,
|
||||||
bool final_response, const char *file, int line);
|
bool final_response, const char *file, int line);
|
||||||
|
|
||||||
/*! See _osmo_gsup_req_respond_err() for details.
|
/*! Log an error message, and call _osmo_gsup_req_respond() to convey the sender's source file and line in the logs. */
|
||||||
* Log an error message, and call _osmo_gsup_req_respond_err(), passing the caller's source file and line for logging.
|
|
||||||
*/
|
|
||||||
#define osmo_gsup_req_respond_err(REQ, CAUSE, FMT, args...) do { \
|
#define osmo_gsup_req_respond_err(REQ, CAUSE, FMT, args...) do { \
|
||||||
LOG_GSUP_REQ(REQ, LOGL_ERROR, "%s: " FMT "\n", \
|
LOG_GSUP_REQ(REQ, LOGL_ERROR, "%s: " FMT "\n", \
|
||||||
get_value_string(gsm48_gmm_cause_names, CAUSE), ##args); \
|
get_value_string(gsm48_gmm_cause_names, CAUSE), ##args); \
|
||||||
|
|||||||
@@ -16,5 +16,6 @@ noinst_HEADERS = \
|
|||||||
proxy.h \
|
proxy.h \
|
||||||
rand.h \
|
rand.h \
|
||||||
remote_hlr.h \
|
remote_hlr.h \
|
||||||
|
sms_over_gsup.h \
|
||||||
timestamp.h \
|
timestamp.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
#include <osmocom/crypt/auth.h>
|
#include <osmocom/crypt/auth.h>
|
||||||
|
|
||||||
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||||
struct osmo_sub_auth_data2 *aud2g,
|
struct osmo_sub_auth_data *aud2g,
|
||||||
struct osmo_sub_auth_data2 *aud3g,
|
struct osmo_sub_auth_data *aud3g,
|
||||||
const uint8_t *rand_auts, const uint8_t *auts);
|
const uint8_t *rand_auts, const uint8_t *auts);
|
||||||
|
|||||||
@@ -30,4 +30,5 @@ enum hlr_ctrl_node {
|
|||||||
_LAST_CTRL_NODE_HLR
|
_LAST_CTRL_NODE_HLR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int hlr_ctrl_cmds_install();
|
||||||
struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr);
|
struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr);
|
||||||
|
|||||||
@@ -3,19 +3,13 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
#include <osmocom/gsm/gsup.h>
|
#include <osmocom/gsm/gsup.h>
|
||||||
|
#include <osmocom/gsm/gsm_utils.h>
|
||||||
|
|
||||||
struct hlr;
|
struct hlr;
|
||||||
|
|
||||||
enum stmt_idx {
|
enum stmt_idx {
|
||||||
DB_STMT_SEL_ALL,
|
|
||||||
DB_STMT_SEL_ALL_ORDER_LAST_SEEN,
|
|
||||||
DB_STMT_SEL_FILTER_MSISDN,
|
|
||||||
DB_STMT_SEL_FILTER_IMSI,
|
|
||||||
DB_STMT_SEL_FILTER_IMEI,
|
|
||||||
DB_STMT_SEL_FILTER_CS,
|
|
||||||
DB_STMT_SEL_FILTER_PS,
|
|
||||||
DB_STMT_SEL_BY_IMSI,
|
DB_STMT_SEL_BY_IMSI,
|
||||||
DB_STMT_SEL_BY_MSISDN,
|
DB_STMT_SEL_BY_MSISDN,
|
||||||
DB_STMT_SEL_BY_ID,
|
DB_STMT_SEL_BY_ID,
|
||||||
@@ -44,6 +38,8 @@ enum stmt_idx {
|
|||||||
DB_STMT_IND_ADD,
|
DB_STMT_IND_ADD,
|
||||||
DB_STMT_IND_SELECT,
|
DB_STMT_IND_SELECT,
|
||||||
DB_STMT_IND_DEL,
|
DB_STMT_IND_DEL,
|
||||||
|
DB_STMT_UPD_RAT_FLAG,
|
||||||
|
DB_STMT_RAT_BY_ID,
|
||||||
_NUM_DB_STMT
|
_NUM_DB_STMT
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,8 +66,8 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite3_log
|
|||||||
|
|
||||||
/* obtain the authentication data for a given imsi */
|
/* obtain the authentication data for a given imsi */
|
||||||
int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
||||||
struct osmo_sub_auth_data2 *aud2g,
|
struct osmo_sub_auth_data *aud2g,
|
||||||
struct osmo_sub_auth_data2 *aud3g,
|
struct osmo_sub_auth_data *aud3g,
|
||||||
int64_t *subscr_id);
|
int64_t *subscr_id);
|
||||||
|
|
||||||
int db_update_sqn(struct db_context *dbc, int64_t id,
|
int db_update_sqn(struct db_context *dbc, int64_t id,
|
||||||
@@ -111,9 +107,16 @@ struct hlr_subscriber {
|
|||||||
bool ms_purged_ps;
|
bool ms_purged_ps;
|
||||||
time_t last_lu_seen;
|
time_t last_lu_seen;
|
||||||
time_t last_lu_seen_ps;
|
time_t last_lu_seen_ps;
|
||||||
|
char last_lu_rat_cs[128];
|
||||||
|
char last_lu_rat_ps[128];
|
||||||
/* talloc'd IPA unit name */
|
/* talloc'd IPA unit name */
|
||||||
struct osmo_ipa_name vlr_via_proxy;
|
struct osmo_ipa_name vlr_via_proxy;
|
||||||
struct osmo_ipa_name sgsn_via_proxy;
|
struct osmo_ipa_name sgsn_via_proxy;
|
||||||
|
bool rat_types[OSMO_RAT_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hlr_subscriber hlr_subscriber_empty = {
|
||||||
|
.rat_types = { true, true, true },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A format string for use with strptime(3). This format string is
|
/* A format string for use with strptime(3). This format string is
|
||||||
@@ -121,7 +124,7 @@ struct hlr_subscriber {
|
|||||||
* See https://sqlite.org/lang_datefunc.html, function datetime(). */
|
* See https://sqlite.org/lang_datefunc.html, function datetime(). */
|
||||||
#define DB_LAST_LU_SEEN_FMT "%Y-%m-%d %H:%M:%S"
|
#define DB_LAST_LU_SEEN_FMT "%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
/* Like struct osmo_sub_auth_data2, but the keys are in hexdump representation.
|
/* Like struct osmo_sub_auth_data, but the keys are in hexdump representation.
|
||||||
* This is useful because SQLite requires them in hexdump format, and callers
|
* This is useful because SQLite requires them in hexdump format, and callers
|
||||||
* like the VTY and CTRL interface also have them available as hexdump to begin
|
* like the VTY and CTRL interface also have them available as hexdump to begin
|
||||||
* with. In the binary format, a VTY command would first need to hexparse,
|
* with. In the binary format, a VTY command would first need to hexparse,
|
||||||
@@ -159,9 +162,6 @@ int db_subscr_update_imei_by_imsi(struct db_context *dbc, const char* imsi, cons
|
|||||||
int db_subscr_exists_by_imsi(struct db_context *dbc, const char *imsi);
|
int db_subscr_exists_by_imsi(struct db_context *dbc, const char *imsi);
|
||||||
int db_subscr_exists_by_msisdn(struct db_context *dbc, const char *msisdn);
|
int db_subscr_exists_by_msisdn(struct db_context *dbc, const char *msisdn);
|
||||||
|
|
||||||
int db_subscrs_get(struct db_context *dbc, const char *filter_type, const char *filter,
|
|
||||||
void (*get_cb)(struct hlr_subscriber *subscr, void *data), void *data,
|
|
||||||
int *count, const char **err);
|
|
||||||
int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
|
int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
|
||||||
struct hlr_subscriber *subscr);
|
struct hlr_subscriber *subscr);
|
||||||
int db_subscr_get_by_msisdn(struct db_context *dbc, const char *msisdn,
|
int db_subscr_get_by_msisdn(struct db_context *dbc, const char *msisdn,
|
||||||
@@ -172,13 +172,18 @@ int db_subscr_get_by_imei(struct db_context *dbc, const char *imei, struct hlr_s
|
|||||||
int db_subscr_nam(struct db_context *dbc, const char *imsi, bool nam_val, bool is_ps);
|
int db_subscr_nam(struct db_context *dbc, const char *imsi, bool nam_val, bool is_ps);
|
||||||
int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
|
int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
|
||||||
const struct osmo_ipa_name *vlr_name, bool is_ps,
|
const struct osmo_ipa_name *vlr_name, bool is_ps,
|
||||||
const struct osmo_ipa_name *via_proxy);
|
const struct osmo_ipa_name *via_proxy,
|
||||||
|
const enum osmo_rat_type rat_types[], size_t rat_types_len);
|
||||||
|
|
||||||
int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
|
int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
|
||||||
bool purge_val, bool is_ps);
|
bool purge_val, bool is_ps);
|
||||||
|
|
||||||
int db_ind(struct db_context *dbc, const struct osmo_cni_peer_id *vlr, unsigned int *ind);
|
int db_ind(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr, unsigned int *ind);
|
||||||
int db_ind_del(struct db_context *dbc, const struct osmo_cni_peer_id *vlr);
|
int db_ind_del(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr);
|
||||||
|
|
||||||
|
int db_subscr_set_rat_type_flag(struct db_context *dbc, int64_t subscr_id, enum osmo_rat_type rat, bool allowed);
|
||||||
|
int db_subscr_get_rat_types(struct db_context *dbc, struct hlr_subscriber *subscr);
|
||||||
|
int hlr_subscr_rat_flag(struct hlr *hlr, struct hlr_subscriber *subscr, enum osmo_rat_type rat, bool allowed);
|
||||||
|
|
||||||
/*! Call sqlite3_column_text() and copy result to a char[].
|
/*! Call sqlite3_column_text() and copy result to a char[].
|
||||||
* \param[out] buf A char[] used as sizeof() arg(!) and osmo_strlcpy() target.
|
* \param[out] buf A char[] used as sizeof() arg(!) and osmo_strlcpy() target.
|
||||||
|
|||||||
@@ -22,10 +22,9 @@
|
|||||||
#include <osmocom/mslookup/mslookup.h>
|
#include <osmocom/mslookup/mslookup.h>
|
||||||
#include <osmocom/hlr/gsup_server.h>
|
#include <osmocom/hlr/gsup_server.h>
|
||||||
#include <osmocom/hlr/logging.h>
|
#include <osmocom/hlr/logging.h>
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
#include <osmocom/gsupclient/gsup_req.h>
|
#include <osmocom/gsupclient/gsup_req.h>
|
||||||
|
|
||||||
#define OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS 2000
|
|
||||||
#define LOG_DGSM(imsi, level, fmt, args...) \
|
#define LOG_DGSM(imsi, level, fmt, args...) \
|
||||||
LOGP(DDGSM, level, "(IMSI-%s) " fmt, imsi, ##args)
|
LOGP(DDGSM, level, "(IMSI-%s) " fmt, imsi, ##args)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <osmocom/abis/ipa.h>
|
#include <osmocom/abis/ipa.h>
|
||||||
#include <osmocom/abis/ipaccess.h>
|
#include <osmocom/abis/ipaccess.h>
|
||||||
#include <osmocom/gsm/gsup.h>
|
#include <osmocom/gsm/gsup.h>
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
#include <osmocom/gsupclient/gsup_req.h>
|
#include <osmocom/gsupclient/gsup_req.h>
|
||||||
|
|
||||||
#ifndef OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN
|
#ifndef OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN
|
||||||
@@ -42,6 +42,8 @@ struct osmo_gsup_conn {
|
|||||||
//struct oap_state oap_state;
|
//struct oap_state oap_state;
|
||||||
struct tlv_parsed ccm;
|
struct tlv_parsed ccm;
|
||||||
|
|
||||||
|
unsigned int auc_3g_ind; /*!< IND index used for UMTS AKA SQN */
|
||||||
|
|
||||||
/* Set when Location Update is received: */
|
/* Set when Location Update is received: */
|
||||||
bool supports_cs; /* client supports OSMO_GSUP_CN_DOMAIN_CS */
|
bool supports_cs; /* client supports OSMO_GSUP_CN_DOMAIN_CS */
|
||||||
bool supports_ps; /* client supports OSMO_GSUP_CN_DOMAIN_PS */
|
bool supports_ps; /* client supports OSMO_GSUP_CN_DOMAIN_PS */
|
||||||
@@ -69,6 +71,8 @@ void osmo_gsup_server_destroy(struct osmo_gsup_server *gsups);
|
|||||||
int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
|
int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
|
||||||
uint8_t *apn_buf, size_t apn_buf_size);
|
uint8_t *apn_buf, size_t apn_buf_size);
|
||||||
int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
|
int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
|
||||||
enum osmo_gsup_cn_domain cn_domain, void *talloc_ctx);
|
uint8_t *msisdn_enc, size_t msisdn_enc_size,
|
||||||
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_cni_peer_id *to_peer,
|
uint8_t *apn_buf, size_t apn_buf_size,
|
||||||
|
enum osmo_gsup_cn_domain cn_domain);
|
||||||
|
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_gsup_peer_id *to_peer,
|
||||||
struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup);
|
struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup);
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
|
||||||
#include <osmocom/core/linuxlist.h>
|
#include <osmocom/core/linuxlist.h>
|
||||||
#include <osmocom/gsm/ipa.h>
|
#include <osmocom/gsm/ipa.h>
|
||||||
#include <osmocom/core/tdef.h>
|
#include <osmocom/core/tdef.h>
|
||||||
@@ -49,6 +48,7 @@ struct hlr {
|
|||||||
|
|
||||||
/* Control Interface */
|
/* Control Interface */
|
||||||
struct ctrl_handle *ctrl;
|
struct ctrl_handle *ctrl;
|
||||||
|
const char *ctrl_bind_addr;
|
||||||
|
|
||||||
/* Local bind addr */
|
/* Local bind addr */
|
||||||
char *gsup_bind_addr;
|
char *gsup_bind_addr;
|
||||||
@@ -56,16 +56,7 @@ struct hlr {
|
|||||||
|
|
||||||
struct llist_head euse_list;
|
struct llist_head euse_list;
|
||||||
struct hlr_euse *euse_default;
|
struct hlr_euse *euse_default;
|
||||||
enum gsm48_gmm_cause reject_cause;
|
struct llist_head iuse_list;
|
||||||
enum gsm48_gmm_cause no_proxy_reject_cause;
|
|
||||||
/* PS: APN default configuration used by Subscription Data on ISR */
|
|
||||||
struct {
|
|
||||||
struct {
|
|
||||||
bool enabled;
|
|
||||||
struct osmo_gsup_pdp_info pdp_infos[OSMO_GSUP_MAX_NUM_PDP_INFO];
|
|
||||||
size_t num_pdp_infos;
|
|
||||||
} pdp_profile;
|
|
||||||
} ps;
|
|
||||||
|
|
||||||
/* NCSS (call independent) session guard timeout value */
|
/* NCSS (call independent) session guard timeout value */
|
||||||
int ncss_guard_timeout;
|
int ncss_guard_timeout;
|
||||||
@@ -121,6 +112,14 @@ struct hlr {
|
|||||||
} mdns;
|
} mdns;
|
||||||
} client;
|
} client;
|
||||||
} mslookup;
|
} mslookup;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
/* FIXME actually use branch fixeria/sms for SMSC routing. completely unimplemented */
|
||||||
|
struct osmo_gsup_peer_id smsc;
|
||||||
|
|
||||||
|
/* If no SMSC is present / responsible, try punching the SMS through directly when this is true. */
|
||||||
|
bool try_direct_delivery;
|
||||||
|
} sms_over_gsup;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct hlr *g_hlr;
|
extern struct hlr *g_hlr;
|
||||||
|
|||||||
@@ -35,19 +35,9 @@ enum hlr_vty_node {
|
|||||||
MSLOOKUP_SERVER_NODE,
|
MSLOOKUP_SERVER_NODE,
|
||||||
MSLOOKUP_SERVER_MSC_NODE,
|
MSLOOKUP_SERVER_MSC_NODE,
|
||||||
MSLOOKUP_CLIENT_NODE,
|
MSLOOKUP_CLIENT_NODE,
|
||||||
PS_NODE,
|
|
||||||
PS_PDP_PROFILES_NODE,
|
|
||||||
PS_PDP_PROFILES_PROFILE_NODE,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define A38_XOR_MIN_KEY_LEN 12
|
|
||||||
#define A38_XOR_MAX_KEY_LEN 16
|
|
||||||
#define A38_XOR2G_KEY_LEN 16
|
|
||||||
#define A38_COMP128_KEY_LEN 16
|
|
||||||
#define MILENAGE_KEY_LEN 16
|
|
||||||
|
|
||||||
int hlr_vty_is_config_node(struct vty *vty, int node);
|
int hlr_vty_is_config_node(struct vty *vty, int node);
|
||||||
int hlr_vty_go_parent(struct vty *vty);
|
int hlr_vty_go_parent(struct vty *vty);
|
||||||
void hlr_vty_init(void *hlr_ctx);
|
void hlr_vty_init(void);
|
||||||
void dgsm_vty_init(void);
|
void dgsm_vty_init(void);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ enum {
|
|||||||
DMSLOOKUP,
|
DMSLOOKUP,
|
||||||
DLU,
|
DLU,
|
||||||
DDGSM,
|
DDGSM,
|
||||||
DCTRL,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct log_info hlr_log_info;
|
extern const struct log_info hlr_log_info;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
#include <osmocom/mslookup/mslookup.h>
|
#include <osmocom/mslookup/mslookup.h>
|
||||||
|
|
||||||
struct osmo_mslookup_query;
|
struct osmo_mslookup_query;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
||||||
#include <osmocom/core/sockaddr_str.h>
|
#include <osmocom/core/sockaddr_str.h>
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
#include <osmocom/hlr/timestamp.h>
|
#include <osmocom/hlr/timestamp.h>
|
||||||
|
|
||||||
struct osmo_gsup_req;
|
struct osmo_gsup_req;
|
||||||
|
|||||||
8
include/osmocom/hlr/sms_over_gsup.h
Normal file
8
include/osmocom/hlr/sms_over_gsup.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <osmocom/gsupclient/gsup_req.h>
|
||||||
|
|
||||||
|
#define OSMO_MSLOOKUP_SERVICE_SMS_GSUP "gsup.sms"
|
||||||
|
|
||||||
|
bool sms_over_gsup_check_handle_msg(struct osmo_gsup_req *req);
|
||||||
@@ -71,7 +71,7 @@ struct osmo_mdns_rfc_header {
|
|||||||
uint16_t nscount; /* Number of authority records */
|
uint16_t nscount; /* Number of authority records */
|
||||||
uint16_t arcount; /* Number of additional records */
|
uint16_t arcount; /* Number of additional records */
|
||||||
#elif OSMO_IS_BIG_ENDIAN
|
#elif OSMO_IS_BIG_ENDIAN
|
||||||
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
|
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
uint8_t qr:1, opcode:4, aa:1, tc:1, rd:1;
|
uint8_t qr:1, opcode:4, aa:1, tc:1, rd:1;
|
||||||
uint8_t ra:1, z:3, rcode:4;
|
uint8_t ra:1, z:3, rcode:4;
|
||||||
@@ -99,12 +99,15 @@ struct osmo_mdns_rfc_record {
|
|||||||
uint8_t *rdata;
|
uint8_t *rdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
char *osmo_mdns_rfc_qname_encode(void *ctx, const char *domain);
|
||||||
|
char *osmo_mdns_rfc_qname_decode(void *ctx, const char *qname, size_t qname_len);
|
||||||
|
|
||||||
void osmo_mdns_rfc_header_encode(struct msgb *msg, const struct osmo_mdns_rfc_header *hdr);
|
void osmo_mdns_rfc_header_encode(struct msgb *msg, const struct osmo_mdns_rfc_header *hdr);
|
||||||
int osmo_mdns_rfc_header_decode(const uint8_t *data, size_t data_len, struct osmo_mdns_rfc_header *hdr);
|
int osmo_mdns_rfc_header_decode(const uint8_t *data, size_t data_len, struct osmo_mdns_rfc_header *hdr);
|
||||||
|
|
||||||
int osmo_mdns_rfc_question_encode(struct msgb *msg, const struct osmo_mdns_rfc_question *qst);
|
int osmo_mdns_rfc_question_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_question *qst);
|
||||||
struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const uint8_t *data, size_t data_len);
|
struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const uint8_t *data, size_t data_len);
|
||||||
|
|
||||||
int osmo_mdns_rfc_record_encode(struct msgb *msg, const struct osmo_mdns_rfc_record *rec);
|
int osmo_mdns_rfc_record_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_record *rec);
|
||||||
struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len,
|
struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len,
|
||||||
size_t *record_len);
|
size_t *record_len);
|
||||||
|
|||||||
24
sql/hlr.sql
24
sql/hlr.sql
@@ -45,6 +45,12 @@ CREATE TABLE subscriber (
|
|||||||
last_lu_seen TIMESTAMP default NULL,
|
last_lu_seen TIMESTAMP default NULL,
|
||||||
last_lu_seen_ps TIMESTAMP default NULL,
|
last_lu_seen_ps TIMESTAMP default NULL,
|
||||||
|
|
||||||
|
-- Last Radio Access Type list as sent during Location Updating Request.
|
||||||
|
-- This is usually just one RAT name, but can be a comma separated list of strings
|
||||||
|
-- of all the RAT types sent during Location Updating Request.
|
||||||
|
last_lu_rat_cs TEXT default NULL,
|
||||||
|
last_lu_rat_ps TEXT default NULL,
|
||||||
|
|
||||||
-- When a LU was received via a proxy, that proxy's hlr_number is stored here,
|
-- When a LU was received via a proxy, that proxy's hlr_number is stored here,
|
||||||
-- while vlr_number reflects the MSC on the far side of that proxy.
|
-- while vlr_number reflects the MSC on the far side of that proxy.
|
||||||
vlr_via_proxy VARCHAR,
|
vlr_via_proxy VARCHAR,
|
||||||
@@ -71,9 +77,9 @@ CREATE TABLE auc_2g (
|
|||||||
CREATE TABLE auc_3g (
|
CREATE TABLE auc_3g (
|
||||||
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
|
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
|
||||||
algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value
|
algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value
|
||||||
k VARCHAR(64) NOT NULL, -- hex string: subscriber's secret key (128/256bit)
|
k VARCHAR(32) NOT NULL, -- hex string: subscriber's secret key (128bit)
|
||||||
op VARCHAR(64), -- hex string: operator's secret key (128/256bit)
|
op VARCHAR(32), -- hex string: operator's secret key (128bit)
|
||||||
opc VARCHAR(64), -- hex string: derived from OP and K (128/256bit)
|
opc VARCHAR(32), -- hex string: derived from OP and K (128bit)
|
||||||
sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage
|
sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage
|
||||||
-- nr of index bits at lower SQN end
|
-- nr of index bits at lower SQN end
|
||||||
ind_bitlen INTEGER NOT NULL DEFAULT 5
|
ind_bitlen INTEGER NOT NULL DEFAULT 5
|
||||||
@@ -87,8 +93,18 @@ CREATE TABLE ind (
|
|||||||
UNIQUE (vlr)
|
UNIQUE (vlr)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Optional: add subscriber entries to allow or disallow specific RATs (2G or 3G or ...).
|
||||||
|
-- If a subscriber has no entry, that means that all RATs are allowed (backwards compat).
|
||||||
|
CREATE TABLE subscriber_rat (
|
||||||
|
subscriber_id INTEGER, -- subscriber.id
|
||||||
|
rat TEXT CHECK(rat in ('GERAN-A', 'UTRAN-Iu','EUTRAN-SGs')) NOT NULL, -- Radio Access Technology, see enum ran_type
|
||||||
|
allowed BOOLEAN CHECK(allowed in (0, 1)) NOT NULL DEFAULT 0,
|
||||||
|
UNIQUE (subscriber_id, rat)
|
||||||
|
);
|
||||||
|
|
||||||
CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi);
|
CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi);
|
||||||
|
CREATE UNIQUE INDEX idx_subscr_rat_flag ON subscriber_rat (subscriber_id, rat);
|
||||||
|
|
||||||
-- Set HLR database schema version number
|
-- Set HLR database schema version number
|
||||||
-- Note: This constant is currently duplicated in src/db.c and must be kept in sync!
|
-- Note: This constant is currently duplicated in src/db.c and must be kept in sync!
|
||||||
PRAGMA user_version = 7;
|
PRAGMA user_version = 8;
|
||||||
|
|||||||
8
sql/upgrade_v2_to_v3.sql
Normal file
8
sql/upgrade_v2_to_v3.sql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
CREATE TABLE subscriber_rat (
|
||||||
|
subscriber_id INTEGER, -- subscriber.id
|
||||||
|
rat TEXT CHECK(rat in ('GERAN-A', 'UTRAN-Iu')) NOT NULL, -- Radio Access Technology, see enum ran_type
|
||||||
|
allowed BOOLEAN NOT NULL DEFAULT 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
PRAGMA user_version = 3;
|
||||||
@@ -61,6 +61,7 @@ osmo_hlr_SOURCES = \
|
|||||||
mslookup_server.c \
|
mslookup_server.c \
|
||||||
mslookup_server_mdns.c \
|
mslookup_server_mdns.c \
|
||||||
dgsm_vty.c \
|
dgsm_vty.c \
|
||||||
|
sms_over_gsup.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
osmo_hlr_LDADD = \
|
osmo_hlr_LDADD = \
|
||||||
@@ -82,7 +83,7 @@ osmo_hlr_db_tool_SOURCES = \
|
|||||||
logging.c \
|
logging.c \
|
||||||
rand_urandom.c \
|
rand_urandom.c \
|
||||||
dbd_decode_binary.c \
|
dbd_decode_binary.c \
|
||||||
$(srcdir)/gsupclient/cni_peer_id.c \
|
$(srcdir)/gsupclient/gsup_peer_id.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
osmo_hlr_db_tool_LDADD = \
|
osmo_hlr_db_tool_LDADD = \
|
||||||
@@ -111,7 +112,7 @@ BOOTSTRAP_SQL = $(top_srcdir)/sql/hlr.sql
|
|||||||
db_bootstrap.h: $(BOOTSTRAP_SQL) $(srcdir)/db_sql2c.sed
|
db_bootstrap.h: $(BOOTSTRAP_SQL) $(srcdir)/db_sql2c.sed
|
||||||
echo "/* DO NOT EDIT THIS FILE. It is generated from files in osmo-hlr.git/sql/ */" > "$@"
|
echo "/* DO NOT EDIT THIS FILE. It is generated from files in osmo-hlr.git/sql/ */" > "$@"
|
||||||
echo "#pragma once" >> "$@"
|
echo "#pragma once" >> "$@"
|
||||||
echo "static const char * const stmt_bootstrap_sql[] = {" >> "$@"
|
echo "static const char *stmt_bootstrap_sql[] = {" >> "$@"
|
||||||
cat "$(BOOTSTRAP_SQL)" \
|
cat "$(BOOTSTRAP_SQL)" \
|
||||||
| sed -f "$(srcdir)/db_sql2c.sed" \
|
| sed -f "$(srcdir)/db_sql2c.sed" \
|
||||||
>> "$@"
|
>> "$@"
|
||||||
|
|||||||
21
src/auc.c
21
src/auc.c
@@ -1,4 +1,4 @@
|
|||||||
/* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
|
/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
@@ -32,8 +32,8 @@
|
|||||||
/* compute given number of vectors using either aud2g or aud2g or a combination
|
/* compute given number of vectors using either aud2g or aud2g or a combination
|
||||||
* of both. Handles re-synchronization if rand_auts and auts are set */
|
* of both. Handles re-synchronization if rand_auts and auts are set */
|
||||||
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||||
struct osmo_sub_auth_data2 *aud2g,
|
struct osmo_sub_auth_data *aud2g,
|
||||||
struct osmo_sub_auth_data2 *aud3g,
|
struct osmo_sub_auth_data *aud3g,
|
||||||
const uint8_t *rand_auts, const uint8_t *auts)
|
const uint8_t *rand_auts, const uint8_t *auts)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@@ -93,10 +93,10 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
|||||||
: "2G only",
|
: "2G only",
|
||||||
auts? ", with AUTS resync" : "");
|
auts? ", with AUTS resync" : "");
|
||||||
if (aud3g) {
|
if (aud3g) {
|
||||||
DBGP("3G: k = %s\n", hex(aud3g->u.umts.k, aud3g->u.umts.k_len));
|
DBGP("3G: k = %s\n", hexb(aud3g->u.umts.k));
|
||||||
DBGP("3G: %s = %s\n",
|
DBGP("3G: %s = %s\n",
|
||||||
aud3g->u.umts.opc_is_op? "OP" : "opc",
|
aud3g->u.umts.opc_is_op? "OP" : "opc",
|
||||||
hex(aud3g->u.umts.opc, aud3g->u.umts.opc_len));
|
hexb(aud3g->u.umts.opc));
|
||||||
DBGP("3G: for sqn ind %u, previous sqn was %" PRIu64 "\n",
|
DBGP("3G: for sqn ind %u, previous sqn was %" PRIu64 "\n",
|
||||||
aud3g->u.umts.ind, aud3g->u.umts.sqn);
|
aud3g->u.umts.ind, aud3g->u.umts.sqn);
|
||||||
}
|
}
|
||||||
@@ -115,9 +115,6 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
|||||||
if (aud3g) {
|
if (aud3g) {
|
||||||
/* 3G or 3G + 2G case */
|
/* 3G or 3G + 2G case */
|
||||||
|
|
||||||
/* backwards-compatibiliy: We assume all RES are 8 bytes long */
|
|
||||||
vec[i].res_len = 8;
|
|
||||||
|
|
||||||
/* Do AUTS only for the first vector or we would use
|
/* Do AUTS only for the first vector or we would use
|
||||||
* the same SQN for each following key. */
|
* the same SQN for each following key. */
|
||||||
if ((i == 0) && auts) {
|
if ((i == 0) && auts) {
|
||||||
@@ -126,10 +123,10 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
|||||||
DBGP("vector [%u]: resync: rand_auts = %s\n",
|
DBGP("vector [%u]: resync: rand_auts = %s\n",
|
||||||
i, hex(rand_auts, 16));
|
i, hex(rand_auts, 16));
|
||||||
|
|
||||||
rc = osmo_auth_gen_vec_auts2(vec+i, aud3g, auts,
|
rc = osmo_auth_gen_vec_auts(vec+i, aud3g, auts,
|
||||||
rand_auts, rand);
|
rand_auts, rand);
|
||||||
} else {
|
} else {
|
||||||
rc = osmo_auth_gen_vec2(vec+i, aud3g, rand);
|
rc = osmo_auth_gen_vec(vec+i, aud3g, rand);
|
||||||
}
|
}
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGP(DAUC, LOGL_ERROR, "Error in 3G vector "
|
LOGP(DAUC, LOGL_ERROR, "Error in 3G vector "
|
||||||
@@ -157,7 +154,7 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
|||||||
|
|
||||||
DBGP("vector [%u]: calculating 2G separately\n", i);
|
DBGP("vector [%u]: calculating 2G separately\n", i);
|
||||||
|
|
||||||
rc = osmo_auth_gen_vec2(&vtmp, aud2g, rand);
|
rc = osmo_auth_gen_vec(&vtmp, aud2g, rand);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGP(DAUC, LOGL_ERROR, "Error in 2G vector"
|
LOGP(DAUC, LOGL_ERROR, "Error in 2G vector"
|
||||||
"generation: [%u]: rc = %d\n", i, rc);
|
"generation: [%u]: rc = %d\n", i, rc);
|
||||||
@@ -168,7 +165,7 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
|||||||
vec[i].auth_types |= OSMO_AUTH_TYPE_GSM;
|
vec[i].auth_types |= OSMO_AUTH_TYPE_GSM;
|
||||||
} else {
|
} else {
|
||||||
/* 2G only case */
|
/* 2G only case */
|
||||||
rc = osmo_auth_gen_vec2(vec+i, aud2g, rand);
|
rc = osmo_auth_gen_vec(vec+i, aud2g, rand);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGP(DAUC, LOGL_ERROR, "Error in 2G vector "
|
LOGP(DAUC, LOGL_ERROR, "Error in 2G vector "
|
||||||
"generation: [%u]: rc = %d\n", i, rc);
|
"generation: [%u]: rc = %d\n", i, rc);
|
||||||
|
|||||||
418
src/ctrl.c
418
src/ctrl.c
@@ -1,6 +1,6 @@
|
|||||||
/* OsmoHLR Control Interface implementation */
|
/* OsmoHLR Control Interface implementation */
|
||||||
|
|
||||||
/* (C) 2017-2023 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
/* (C) 2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
* Author: Max Suraev <msuraev@sysmocom.de>
|
* Author: Max Suraev <msuraev@sysmocom.de>
|
||||||
@@ -31,16 +31,12 @@
|
|||||||
#include <osmocom/hlr/hlr.h>
|
#include <osmocom/hlr/hlr.h>
|
||||||
#include <osmocom/hlr/ctrl.h>
|
#include <osmocom/hlr/ctrl.h>
|
||||||
#include <osmocom/hlr/db.h>
|
#include <osmocom/hlr/db.h>
|
||||||
#include <osmocom/hlr/hlr_vty.h>
|
|
||||||
|
|
||||||
#define SEL_BY "by-"
|
#define SEL_BY "by-"
|
||||||
#define SEL_BY_IMSI SEL_BY "imsi-"
|
#define SEL_BY_IMSI SEL_BY "imsi-"
|
||||||
#define SEL_BY_MSISDN SEL_BY "msisdn-"
|
#define SEL_BY_MSISDN SEL_BY "msisdn-"
|
||||||
#define SEL_BY_ID SEL_BY "id-"
|
#define SEL_BY_ID SEL_BY "id-"
|
||||||
|
|
||||||
extern bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
|
|
||||||
int *minlen, int *maxlen, int *minlen_opc, int *maxlen_opc);
|
|
||||||
|
|
||||||
#define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
|
#define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
|
||||||
|
|
||||||
static bool startswith(const char *str, const char *start)
|
static bool startswith(const char *str, const char *start)
|
||||||
@@ -166,7 +162,7 @@ static void print_subscr_info(struct ctrl_cmd *cmd,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data2 *aud)
|
static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data *aud)
|
||||||
{
|
{
|
||||||
if (aud->algo == OSMO_AUTH_ALG_NONE)
|
if (aud->algo == OSMO_AUTH_ALG_NONE)
|
||||||
return;
|
return;
|
||||||
@@ -178,7 +174,7 @@ static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_d
|
|||||||
hexdump_buf(aud->u.gsm.ki));
|
hexdump_buf(aud->u.gsm.ki));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data2 *aud)
|
static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data *aud)
|
||||||
{
|
{
|
||||||
if (aud->algo == OSMO_AUTH_ALG_NONE)
|
if (aud->algo == OSMO_AUTH_ALG_NONE)
|
||||||
return;
|
return;
|
||||||
@@ -187,7 +183,7 @@ static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_d
|
|||||||
"\naud3g.k\t%s"
|
"\naud3g.k\t%s"
|
||||||
,
|
,
|
||||||
osmo_auth_alg_name(aud->algo),
|
osmo_auth_alg_name(aud->algo),
|
||||||
osmo_hexdump_nospc(aud->u.umts.k, aud->u.umts.k_len));
|
hexdump_buf(aud->u.umts.k));
|
||||||
/* hexdump uses a static string buffer, hence only one hexdump per
|
/* hexdump uses a static string buffer, hence only one hexdump per
|
||||||
* printf(). */
|
* printf(). */
|
||||||
ctrl_cmd_reply_printf(cmd,
|
ctrl_cmd_reply_printf(cmd,
|
||||||
@@ -196,82 +192,11 @@ static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_d
|
|||||||
"\naud3g.sqn\t%" PRIu64
|
"\naud3g.sqn\t%" PRIu64
|
||||||
,
|
,
|
||||||
aud->u.umts.opc_is_op? "op" : "opc",
|
aud->u.umts.opc_is_op? "op" : "opc",
|
||||||
osmo_hexdump_nospc(aud->u.umts.opc, aud->u.umts.opc_len),
|
hexdump_buf(aud->u.umts.opc),
|
||||||
aud->u.umts.ind_bitlen,
|
aud->u.umts.ind_bitlen,
|
||||||
aud->u.umts.sqn);
|
aud->u.umts.sqn);
|
||||||
}
|
}
|
||||||
|
|
||||||
CTRL_CMD_DEFINE_WO_NOVRF(subscr_create, "create");
|
|
||||||
static int set_subscr_create(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct hlr_subscriber subscr;
|
|
||||||
struct hlr *hlr = data;
|
|
||||||
const char *imsi = cmd->value;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!osmo_imsi_str_valid(imsi)) {
|
|
||||||
cmd->reply = "Invalid IMSI value.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the subscriber in the DB */
|
|
||||||
rc = db_subscr_create(g_hlr->dbc, imsi, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS);
|
|
||||||
if (rc) {
|
|
||||||
if (rc == -EEXIST)
|
|
||||||
cmd->reply = "Subscriber already exists.";
|
|
||||||
else
|
|
||||||
cmd->reply = "Cannot create subscriber.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGP(DCTRL, LOGL_INFO, "Created subscriber IMSI='%s'\n",
|
|
||||||
imsi);
|
|
||||||
|
|
||||||
/* Retrieve data of newly created subscriber: */
|
|
||||||
rc = db_subscr_get_by_imsi(hlr->dbc, imsi, &subscr);
|
|
||||||
if (rc < 0) {
|
|
||||||
cmd->reply = "Failed retrieving ID of newly created subscriber.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->reply = talloc_asprintf(cmd, "%" PRIu64, subscr.id);
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
CTRL_CMD_DEFINE_WO_NOVRF(subscr_delete, "delete");
|
|
||||||
static int set_subscr_delete(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct hlr_subscriber subscr;
|
|
||||||
struct hlr *hlr = data;
|
|
||||||
const char *imsi = cmd->value;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!osmo_imsi_str_valid(imsi)) {
|
|
||||||
cmd->reply = "Invalid IMSI value.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve data of newly created subscriber: */
|
|
||||||
rc = db_subscr_get_by_imsi(hlr->dbc, imsi, &subscr);
|
|
||||||
if (rc < 0) {
|
|
||||||
cmd->reply = "Subscriber doesn't exist.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create the subscriber in the DB */
|
|
||||||
rc = db_subscr_delete_by_id(g_hlr->dbc, subscr.id);
|
|
||||||
if (rc) {
|
|
||||||
cmd->reply = "Cannot delete subscriber.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGP(DCTRL, LOGL_INFO, "Deleted subscriber IMSI='%s'\n",
|
|
||||||
imsi);
|
|
||||||
|
|
||||||
cmd->reply = talloc_asprintf(cmd, "%" PRIu64, subscr.id);
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
CTRL_CMD_DEFINE_RO(subscr_info, "info");
|
CTRL_CMD_DEFINE_RO(subscr_info, "info");
|
||||||
static int get_subscr_info(struct ctrl_cmd *cmd, void *data)
|
static int get_subscr_info(struct ctrl_cmd *cmd, void *data)
|
||||||
{
|
{
|
||||||
@@ -291,8 +216,8 @@ CTRL_CMD_DEFINE_RO(subscr_info_aud, "info-aud");
|
|||||||
static int get_subscr_info_aud(struct ctrl_cmd *cmd, void *data)
|
static int get_subscr_info_aud(struct ctrl_cmd *cmd, void *data)
|
||||||
{
|
{
|
||||||
const char *imsi;
|
const char *imsi;
|
||||||
struct osmo_sub_auth_data2 aud2g;
|
struct osmo_sub_auth_data aud2g;
|
||||||
struct osmo_sub_auth_data2 aud3g;
|
struct osmo_sub_auth_data aud3g;
|
||||||
struct hlr *hlr = data;
|
struct hlr *hlr = data;
|
||||||
const char *by_selector = cmd->node;
|
const char *by_selector = cmd->node;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -327,8 +252,8 @@ CTRL_CMD_DEFINE_RO(subscr_info_all, "info-all");
|
|||||||
static int get_subscr_info_all(struct ctrl_cmd *cmd, void *data)
|
static int get_subscr_info_all(struct ctrl_cmd *cmd, void *data)
|
||||||
{
|
{
|
||||||
struct hlr_subscriber subscr;
|
struct hlr_subscriber subscr;
|
||||||
struct osmo_sub_auth_data2 aud2g;
|
struct osmo_sub_auth_data aud2g;
|
||||||
struct osmo_sub_auth_data2 aud3g;
|
struct osmo_sub_auth_data aud3g;
|
||||||
struct hlr *hlr = data;
|
struct hlr *hlr = data;
|
||||||
const char *by_selector = cmd->node;
|
const char *by_selector = cmd->node;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -426,302 +351,17 @@ static int set_subscr_cs_enabled(struct ctrl_cmd *cmd, void *data)
|
|||||||
return set_subscr_cs_ps_enabled(cmd, data, false);
|
return set_subscr_cs_ps_enabled(cmd, data, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CTRL_CMD_DEFINE(subscr_msisdn, "msisdn");
|
int hlr_ctrl_cmds_install()
|
||||||
static int verify_subscr_msisdn(struct ctrl_cmd *cmd, const char *value, void *data)
|
|
||||||
{
|
{
|
||||||
struct hlr_subscriber subscr;
|
int rc = 0;
|
||||||
if (!value)
|
|
||||||
return 1;
|
|
||||||
if (strlen(value) > sizeof(subscr.msisdn) - 1)
|
|
||||||
return 1;
|
|
||||||
if (strcmp(value, "none") != 0 && !osmo_msisdn_str_valid(value))
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int get_subscr_msisdn(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct hlr_subscriber subscr;
|
|
||||||
struct hlr *hlr = data;
|
|
||||||
const char *by_selector = cmd->node;
|
|
||||||
|
|
||||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info);
|
||||||
return CTRL_CMD_ERROR;
|
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_aud);
|
||||||
|
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_all);
|
||||||
|
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_ps_enabled);
|
||||||
|
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_cs_enabled);
|
||||||
|
|
||||||
if (strlen(subscr.msisdn) == 0)
|
return rc;
|
||||||
snprintf(subscr.msisdn, sizeof(subscr.msisdn), "none");
|
|
||||||
|
|
||||||
cmd->reply = talloc_asprintf(cmd, "%s", subscr.msisdn);
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
static int set_subscr_msisdn(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct hlr_subscriber subscr;
|
|
||||||
struct hlr *hlr = data;
|
|
||||||
const char *by_selector = cmd->node;
|
|
||||||
const char *msisdn;
|
|
||||||
|
|
||||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
|
|
||||||
if (strcmp(cmd->value, "none") == 0)
|
|
||||||
msisdn = NULL;
|
|
||||||
else
|
|
||||||
msisdn = cmd->value;
|
|
||||||
|
|
||||||
if (db_subscr_update_msisdn_by_imsi(g_hlr->dbc, subscr.imsi, msisdn)) {
|
|
||||||
cmd->reply = "Update MSISDN failed";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->reply = "OK";
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* value format: <algo[,KI]> */
|
|
||||||
CTRL_CMD_DEFINE(subscr_aud2g, "aud2g");
|
|
||||||
static int verify_subscr_aud2g(struct ctrl_cmd *cmd, const char *value, void *data)
|
|
||||||
{
|
|
||||||
if (!value)
|
|
||||||
return 1;
|
|
||||||
if (strcasecmp(value, "none") != 0 && !strchr(value, ','))
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int get_subscr_aud2g(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct hlr_subscriber subscr;
|
|
||||||
struct hlr *hlr = data;
|
|
||||||
const char *by_selector = cmd->node;
|
|
||||||
struct osmo_sub_auth_data2 aud2g;
|
|
||||||
struct osmo_sub_auth_data2 aud3g_unused;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
|
|
||||||
rc = db_get_auth_data(hlr->dbc, subscr.imsi, &aud2g, &aud3g_unused, NULL);
|
|
||||||
switch (rc) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case -ENOENT:
|
|
||||||
case -ENOKEY:
|
|
||||||
aud2g.algo = OSMO_AUTH_ALG_NONE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cmd->reply = "Error retrieving data from database.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aud2g.algo == OSMO_AUTH_ALG_NONE) {
|
|
||||||
cmd->reply = "none";
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->reply = talloc_asprintf(cmd, "%s,%s", osmo_auth_alg_name(aud2g.algo),
|
|
||||||
hexdump_buf(aud2g.u.gsm.ki));
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
static int set_subscr_aud2g(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct hlr_subscriber subscr;
|
|
||||||
struct hlr *hlr = data;
|
|
||||||
const char *by_selector = cmd->node;
|
|
||||||
char *tmp = NULL, *tok, *saveptr;
|
|
||||||
int minlen = 0;
|
|
||||||
int maxlen = 0;
|
|
||||||
struct sub_auth_data_str aud2g = {
|
|
||||||
.type = OSMO_AUTH_TYPE_GSM
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
|
|
||||||
tmp = talloc_strdup(cmd, cmd->value);
|
|
||||||
if (!tmp) {
|
|
||||||
cmd->reply = "OOM";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse alg_type: */
|
|
||||||
tok = strtok_r(tmp, ",", &saveptr);
|
|
||||||
if (!tok) {
|
|
||||||
cmd->reply = "Invalid format";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
if (strcmp(tok, "none") == 0) {
|
|
||||||
aud2g.algo = OSMO_AUTH_ALG_NONE;
|
|
||||||
} else if (!auth_algo_parse(tok, &aud2g.algo, &minlen, &maxlen, NULL, NULL)) {
|
|
||||||
cmd->reply = "Unknown auth algorithm.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aud2g.algo != OSMO_AUTH_ALG_NONE) {
|
|
||||||
tok = strtok_r(NULL, "\0", &saveptr);
|
|
||||||
if (!tok) {
|
|
||||||
cmd->reply = "Invalid format.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
aud2g.u.gsm.ki = tok;
|
|
||||||
if (!osmo_is_hexstr(aud2g.u.gsm.ki, minlen * 2, maxlen * 2, true)) {
|
|
||||||
cmd->reply = "Invalid KI.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud2g)) {
|
|
||||||
cmd->reply = "Update aud2g failed.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->reply = "OK";
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* value format: <algo[,KI,(op|opc),OP_C[,ind_bitlen]]> */
|
|
||||||
CTRL_CMD_DEFINE(subscr_aud3g, "aud3g");
|
|
||||||
static int verify_subscr_aud3g(struct ctrl_cmd *cmd, const char *value, void *data)
|
|
||||||
{
|
|
||||||
if (!value)
|
|
||||||
return 1;
|
|
||||||
if (strcasecmp(value, "none") != 0 && !strchr(value, ','))
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int get_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct hlr_subscriber subscr;
|
|
||||||
struct hlr *hlr = data;
|
|
||||||
const char *by_selector = cmd->node;
|
|
||||||
struct osmo_sub_auth_data2 aud2g_unused;
|
|
||||||
struct osmo_sub_auth_data2 aud3g;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
|
|
||||||
rc = db_get_auth_data(hlr->dbc, subscr.imsi, &aud2g_unused, &aud3g, NULL);
|
|
||||||
switch (rc) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case -ENOENT:
|
|
||||||
case -ENOKEY:
|
|
||||||
aud3g.algo = OSMO_AUTH_ALG_NONE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cmd->reply = "Error retrieving data from database.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aud3g.algo == OSMO_AUTH_ALG_NONE) {
|
|
||||||
cmd->reply = "none";
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->reply = talloc_asprintf(cmd, "%s,%s,%s,%s,%u", osmo_auth_alg_name(aud3g.algo),
|
|
||||||
osmo_hexdump_nospc_c(cmd, aud3g.u.umts.k, aud3g.u.umts.k_len),
|
|
||||||
aud3g.u.umts.opc_is_op ? "OP" : "OPC",
|
|
||||||
osmo_hexdump_nospc_c(cmd, aud3g.u.umts.opc, aud3g.u.umts.opc_len),
|
|
||||||
aud3g.u.umts.ind_bitlen);
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
static int set_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct hlr_subscriber subscr;
|
|
||||||
struct hlr *hlr = data;
|
|
||||||
const char *by_selector = cmd->node;
|
|
||||||
char *tmp = NULL, *tok, *saveptr;
|
|
||||||
int minlen = 0, minlen_opc = 0;
|
|
||||||
int maxlen = 0, maxlen_opc = 0;
|
|
||||||
struct sub_auth_data_str aud3g = {
|
|
||||||
.type = OSMO_AUTH_TYPE_UMTS,
|
|
||||||
.u.umts = {
|
|
||||||
.ind_bitlen = 5,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
bool ind_bitlen_present;
|
|
||||||
|
|
||||||
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
|
|
||||||
tmp = talloc_strdup(cmd, cmd->value);
|
|
||||||
if (!tmp) {
|
|
||||||
cmd->reply = "OOM";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse alg_type: */
|
|
||||||
tok = strtok_r(tmp, ",", &saveptr);
|
|
||||||
if (!tok) {
|
|
||||||
cmd->reply = "Invalid format.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
if (strcmp(tok, "none") == 0) {
|
|
||||||
aud3g.algo = OSMO_AUTH_ALG_NONE;
|
|
||||||
} else if (!auth_algo_parse(tok, &aud3g.algo, &minlen, &maxlen, &minlen_opc, &maxlen_opc)) {
|
|
||||||
cmd->reply = "Unknown auth algorithm.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aud3g.algo != OSMO_AUTH_ALG_NONE) {
|
|
||||||
/* Parse K */
|
|
||||||
tok = strtok_r(NULL, ",", &saveptr);
|
|
||||||
if (!tok) {
|
|
||||||
cmd->reply = "Invalid format.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
aud3g.u.umts.k = tok;
|
|
||||||
if (!osmo_is_hexstr(aud3g.u.umts.k, minlen * 2, maxlen * 2, true)) {
|
|
||||||
cmd->reply = "Invalid KI.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse OP/OPC choice */
|
|
||||||
tok = strtok_r(NULL, ",", &saveptr);
|
|
||||||
if (!tok) {
|
|
||||||
cmd->reply = "Invalid format.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
if (strcasecmp(tok, "op") == 0) {
|
|
||||||
aud3g.u.umts.opc_is_op = true;
|
|
||||||
} else if (strcasecmp(tok, "opc") == 0) {
|
|
||||||
aud3g.u.umts.opc_is_op = false;
|
|
||||||
} else {
|
|
||||||
cmd->reply = "Invalid format.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse OP/OPC value */
|
|
||||||
ind_bitlen_present = !!strchr(saveptr, ',');
|
|
||||||
tok = strtok_r(NULL, ind_bitlen_present ? "," : "\0", &saveptr);
|
|
||||||
if (!tok) {
|
|
||||||
cmd->reply = "Invalid format.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
aud3g.u.umts.opc = tok;
|
|
||||||
if (!osmo_is_hexstr(aud3g.u.umts.opc, minlen_opc * 2, maxlen_opc * 2, true)) {
|
|
||||||
cmd->reply = talloc_asprintf(cmd, "Invalid OP/OPC.");
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ind_bitlen_present) {
|
|
||||||
/* Parse bitlen_ind */
|
|
||||||
tok = strtok_r(NULL, "\0", &saveptr);
|
|
||||||
if (!tok || tok[0] == '\0') {
|
|
||||||
cmd->reply = "Invalid format.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
aud3g.u.umts.ind_bitlen = atoi(tok);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud3g)) {
|
|
||||||
cmd->reply = "Update aud3g failed.";
|
|
||||||
return CTRL_CMD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->reply = "OK";
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hlr_ctrl_node_lookup(void *data, vector vline, int *node_type,
|
static int hlr_ctrl_node_lookup(void *data, vector vline, int *node_type,
|
||||||
@@ -749,29 +389,13 @@ static int hlr_ctrl_node_lookup(void *data, vector vline, int *node_type,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hlr_ctrl_cmds_install(void)
|
|
||||||
{
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR, &cmd_subscr_create);
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR, &cmd_subscr_delete);
|
|
||||||
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info);
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_aud);
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_all);
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_ps_enabled);
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_cs_enabled);
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_msisdn);
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_aud2g);
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_aud3g);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr)
|
struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct ctrl_handle *hdl = ctrl_interface_setup2(hlr, OSMO_CTRL_PORT_HLR, hlr_ctrl_node_lookup,
|
struct ctrl_handle *hdl = ctrl_interface_setup_dynip2(hlr,
|
||||||
|
hlr->ctrl_bind_addr,
|
||||||
|
OSMO_CTRL_PORT_HLR,
|
||||||
|
hlr_ctrl_node_lookup,
|
||||||
_LAST_CTRL_NODE_HLR);
|
_LAST_CTRL_NODE_HLR);
|
||||||
if (!hdl)
|
if (!hdl)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
110
src/db.c
110
src/db.c
@@ -1,4 +1,4 @@
|
|||||||
/* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
|
/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
@@ -22,13 +22,15 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include <osmocom/hlr/logging.h>
|
#include <osmocom/hlr/logging.h>
|
||||||
#include <osmocom/hlr/db.h>
|
#include <osmocom/hlr/db.h>
|
||||||
|
|
||||||
#include "db_bootstrap.h"
|
#include "db_bootstrap.h"
|
||||||
|
|
||||||
/* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */
|
/* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */
|
||||||
#define CURRENT_SCHEMA_VERSION 7
|
#define CURRENT_SCHEMA_VERSION 8
|
||||||
|
|
||||||
#define SEL_COLUMNS \
|
#define SEL_COLUMNS \
|
||||||
"id," \
|
"id," \
|
||||||
@@ -47,18 +49,12 @@
|
|||||||
"ms_purged_ps," \
|
"ms_purged_ps," \
|
||||||
"last_lu_seen," \
|
"last_lu_seen," \
|
||||||
"last_lu_seen_ps," \
|
"last_lu_seen_ps," \
|
||||||
|
"last_lu_rat_cs," \
|
||||||
|
"last_lu_rat_ps," \
|
||||||
"vlr_via_proxy," \
|
"vlr_via_proxy," \
|
||||||
"sgsn_via_proxy"
|
"sgsn_via_proxy"
|
||||||
|
|
||||||
static const char *stmt_sql[] = {
|
static const char *stmt_sql[] = {
|
||||||
[DB_STMT_SEL_ALL] = "SELECT " SEL_COLUMNS " FROM subscriber;",
|
|
||||||
[DB_STMT_SEL_ALL_ORDER_LAST_SEEN] = "SELECT " SEL_COLUMNS " FROM subscriber "
|
|
||||||
"WHERE last_lu_seen IS NOT NULL ORDER BY last_lu_seen;",
|
|
||||||
[DB_STMT_SEL_FILTER_MSISDN] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE msisdn LIKE $search ORDER BY msisdn",
|
|
||||||
[DB_STMT_SEL_FILTER_IMSI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imsi LIKE $search ORDER BY imsi",
|
|
||||||
[DB_STMT_SEL_FILTER_IMEI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imei LIKE $search ORDER BY imei",
|
|
||||||
[DB_STMT_SEL_FILTER_CS] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE nam_cs = $search ORDER BY last_lu_seen",
|
|
||||||
[DB_STMT_SEL_FILTER_PS] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE nam_ps = $search ORDER BY last_lu_seen",
|
|
||||||
[DB_STMT_SEL_BY_IMSI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imsi = ?",
|
[DB_STMT_SEL_BY_IMSI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imsi = ?",
|
||||||
[DB_STMT_SEL_BY_MSISDN] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE msisdn = ?",
|
[DB_STMT_SEL_BY_MSISDN] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE msisdn = ?",
|
||||||
[DB_STMT_SEL_BY_ID] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE id = ?",
|
[DB_STMT_SEL_BY_ID] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE id = ?",
|
||||||
@@ -89,13 +85,23 @@ static const char *stmt_sql[] = {
|
|||||||
"INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, op, opc, ind_bitlen)"
|
"INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, op, opc, ind_bitlen)"
|
||||||
" VALUES($subscriber_id, $algo_id_3g, $k, $op, $opc, $ind_bitlen)",
|
" VALUES($subscriber_id, $algo_id_3g, $k, $op, $opc, $ind_bitlen)",
|
||||||
[DB_STMT_AUC_3G_DELETE] = "DELETE FROM auc_3g WHERE subscriber_id = $subscriber_id",
|
[DB_STMT_AUC_3G_DELETE] = "DELETE FROM auc_3g WHERE subscriber_id = $subscriber_id",
|
||||||
[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] = "UPDATE subscriber SET last_lu_seen = datetime($val, 'unixepoch'),"
|
||||||
[DB_STMT_SET_LAST_LU_SEEN_PS] = "UPDATE subscriber SET last_lu_seen_ps = datetime($val, 'unixepoch') WHERE id = $subscriber_id",
|
" last_lu_rat_cs = $rat"
|
||||||
|
" WHERE id = $subscriber_id",
|
||||||
|
[DB_STMT_SET_LAST_LU_SEEN_PS] = "UPDATE subscriber SET last_lu_seen_ps = datetime($val, 'unixepoch'),"
|
||||||
|
" last_lu_rat_ps = $rat"
|
||||||
|
" WHERE id = $subscriber_id",
|
||||||
[DB_STMT_EXISTS_BY_IMSI] = "SELECT 1 FROM subscriber WHERE imsi = $imsi",
|
[DB_STMT_EXISTS_BY_IMSI] = "SELECT 1 FROM subscriber WHERE imsi = $imsi",
|
||||||
[DB_STMT_EXISTS_BY_MSISDN] = "SELECT 1 FROM subscriber WHERE msisdn = $msisdn",
|
[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_ADD] = "INSERT INTO ind (vlr) VALUES ($vlr)",
|
||||||
[DB_STMT_IND_SELECT] = "SELECT ind FROM ind WHERE vlr = $vlr",
|
[DB_STMT_IND_SELECT] = "SELECT ind FROM ind WHERE vlr = $vlr",
|
||||||
[DB_STMT_IND_DEL] = "DELETE FROM ind WHERE vlr = $vlr",
|
[DB_STMT_IND_DEL] = "DELETE FROM ind WHERE vlr = $vlr",
|
||||||
|
[DB_STMT_UPD_RAT_FLAG] = "INSERT OR REPLACE INTO subscriber_rat (subscriber_id, rat, allowed)"
|
||||||
|
" VALUES ($subscriber_id, $rat, $allowed)",
|
||||||
|
[DB_STMT_RAT_BY_ID] =
|
||||||
|
"SELECT rat, allowed"
|
||||||
|
" FROM subscriber_rat"
|
||||||
|
" WHERE subscriber_id = $subscriber_id",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sql3_error_log_cb(void *arg, int err_code, const char *msg)
|
static void sql3_error_log_cb(void *arg, int err_code, const char *msg)
|
||||||
@@ -235,9 +241,9 @@ void db_close(struct db_context *dbc)
|
|||||||
talloc_free(dbc);
|
talloc_free(dbc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int db_run_statements(struct db_context *dbc, const char * const *statements, size_t statements_count)
|
static int db_run_statements(struct db_context *dbc, const char **statements, size_t statements_count)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < statements_count; i++) {
|
for (i = 0; i < statements_count; i++) {
|
||||||
const char *stmt_str = statements[i];
|
const char *stmt_str = statements[i];
|
||||||
@@ -308,7 +314,7 @@ static int
|
|||||||
db_upgrade_v1(struct db_context *dbc)
|
db_upgrade_v1(struct db_context *dbc)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
const char * const statements[] = {
|
const char *statements[] = {
|
||||||
"ALTER TABLE subscriber ADD COLUMN last_lu_seen TIMESTAMP default NULL",
|
"ALTER TABLE subscriber ADD COLUMN last_lu_seen TIMESTAMP default NULL",
|
||||||
"PRAGMA user_version = 1",
|
"PRAGMA user_version = 1",
|
||||||
};
|
};
|
||||||
@@ -324,7 +330,7 @@ db_upgrade_v1(struct db_context *dbc)
|
|||||||
static int db_upgrade_v2(struct db_context *dbc)
|
static int db_upgrade_v2(struct db_context *dbc)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
const char * const statements[] = {
|
const char *statements[] = {
|
||||||
"ALTER TABLE subscriber ADD COLUMN imei VARCHAR(14)",
|
"ALTER TABLE subscriber ADD COLUMN imei VARCHAR(14)",
|
||||||
"PRAGMA user_version = 2",
|
"PRAGMA user_version = 2",
|
||||||
};
|
};
|
||||||
@@ -341,7 +347,7 @@ static int db_upgrade_v3(struct db_context *dbc)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* A newer SQLite version would allow simply 'ATLER TABLE subscriber RENAME COLUMN hlr_number TO msc_number'.
|
/* A newer SQLite version would allow simply 'ALTER TABLE subscriber RENAME COLUMN hlr_number TO msc_number'.
|
||||||
* This is a really expensive workaround for that in order to cover earlier SQLite versions as well:
|
* This is a really expensive workaround for that in order to cover earlier SQLite versions as well:
|
||||||
* Create a new table with the new column name and copy the data over (https://www.sqlite.org/faq.html#q11).
|
* Create a new table with the new column name and copy the data over (https://www.sqlite.org/faq.html#q11).
|
||||||
*/
|
*/
|
||||||
@@ -437,7 +443,7 @@ static int db_upgrade_v3(struct db_context *dbc)
|
|||||||
"ms_purged_ps," \
|
"ms_purged_ps," \
|
||||||
"last_lu_seen"
|
"last_lu_seen"
|
||||||
|
|
||||||
const char * const statements[] = {
|
const char *statements[] = {
|
||||||
"BEGIN TRANSACTION",
|
"BEGIN TRANSACTION",
|
||||||
"CREATE TEMPORARY TABLE subscriber_backup" SUBSCR_V3_CREATE,
|
"CREATE TEMPORARY TABLE subscriber_backup" SUBSCR_V3_CREATE,
|
||||||
"INSERT INTO subscriber_backup SELECT " SUBSCR_V2_COLUMN_NAMES " FROM subscriber",
|
"INSERT INTO subscriber_backup SELECT " SUBSCR_V2_COLUMN_NAMES " FROM subscriber",
|
||||||
@@ -460,7 +466,7 @@ static int db_upgrade_v3(struct db_context *dbc)
|
|||||||
static int db_upgrade_v4(struct db_context *dbc)
|
static int db_upgrade_v4(struct db_context *dbc)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
const char * const statements[] = {
|
const char *statements[] = {
|
||||||
"ALTER TABLE subscriber ADD COLUMN last_lu_seen_ps TIMESTAMP default NULL",
|
"ALTER TABLE subscriber ADD COLUMN last_lu_seen_ps TIMESTAMP default NULL",
|
||||||
"PRAGMA user_version = 4",
|
"PRAGMA user_version = 4",
|
||||||
};
|
};
|
||||||
@@ -476,7 +482,7 @@ static int db_upgrade_v4(struct db_context *dbc)
|
|||||||
static int db_upgrade_v5(struct db_context *dbc)
|
static int db_upgrade_v5(struct db_context *dbc)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
const char * const statements[] = {
|
const char *statements[] = {
|
||||||
"ALTER TABLE subscriber ADD COLUMN vlr_via_proxy VARCHAR",
|
"ALTER TABLE subscriber ADD COLUMN vlr_via_proxy VARCHAR",
|
||||||
"ALTER TABLE subscriber ADD COLUMN sgsn_via_proxy VARCHAR",
|
"ALTER TABLE subscriber ADD COLUMN sgsn_via_proxy VARCHAR",
|
||||||
"PRAGMA user_version = 5",
|
"PRAGMA user_version = 5",
|
||||||
@@ -493,7 +499,7 @@ static int db_upgrade_v5(struct db_context *dbc)
|
|||||||
static int db_upgrade_v6(struct db_context *dbc)
|
static int db_upgrade_v6(struct db_context *dbc)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
const char * const statements[] = {
|
const char *statements[] = {
|
||||||
"CREATE TABLE ind (\n"
|
"CREATE TABLE ind (\n"
|
||||||
" -- 3G auth IND pool to be used for this VLR\n"
|
" -- 3G auth IND pool to be used for this VLR\n"
|
||||||
" ind INTEGER PRIMARY KEY,\n"
|
" ind INTEGER PRIMARY KEY,\n"
|
||||||
@@ -516,33 +522,34 @@ static int db_upgrade_v6(struct db_context *dbc)
|
|||||||
static int db_upgrade_v7(struct db_context *dbc)
|
static int db_upgrade_v7(struct db_context *dbc)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
/* SQLite doesn't allow us to change the column type in-place, so we
|
const char *statements[] = {
|
||||||
* first rename the old table, create a new table and then copy
|
"-- Optional: add subscriber entries to allow or disallow specific RATs (2G or 3G or ...).\n"
|
||||||
* the data over before deleting the old table */
|
"-- If a subscriber has no entry, that means that all RATs are allowed (backwards compat).\n"
|
||||||
#define CREATE_AUC_3G_V7 \
|
"CREATE TABLE subscriber_rat (\n"
|
||||||
"CREATE TABLE auc_3g (\n" \
|
" subscriber_id INTEGER, -- subscriber.id\n"
|
||||||
" subscriber_id INTEGER PRIMARY KEY, -- subscriber.id\n" \
|
" rat TEXT CHECK(rat in ('GERAN-A', 'UTRAN-Iu')) NOT NULL, -- Radio Access Technology, see enum ran_type\n"
|
||||||
" algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value\n" \
|
" allowed BOOLEAN CHECK(allowed in (0, 1)) NOT NULL DEFAULT 0,\n"
|
||||||
" k VARCHAR(64) NOT NULL, -- hex string: subscriber's secret key (128/256bit)\n" \
|
" UNIQUE (subscriber_id, rat)\n"
|
||||||
" op VARCHAR(64), -- hex string: operator's secret key (128/256bit)\n" \
|
")",
|
||||||
" opc VARCHAR(64), -- hex string: derived from OP and K (128/256bit)\n" \
|
"CREATE UNIQUE INDEX idx_subscr_rat_flag ON subscriber_rat (subscriber_id, rat)",
|
||||||
" sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage\n" \
|
|
||||||
" -- nr of index bits at lower SQN end\n" \
|
|
||||||
" ind_bitlen INTEGER NOT NULL DEFAULT 5\n" \
|
|
||||||
");"
|
|
||||||
const char * const statements[] = {
|
|
||||||
"BEGIN TRANSACTION",
|
|
||||||
/* rename old table */
|
|
||||||
"ALTER TABLE auc_3g RENAME TO old_auc_3g",
|
|
||||||
/* create new table */
|
|
||||||
CREATE_AUC_3G_V7,
|
|
||||||
/* copy over old data */
|
|
||||||
"INSERT INTO auc_3g SELECT subscriber_id, algo_id_3g, k, op, opc,sqn, ind_bitlen FROM old_auc_3g",
|
|
||||||
/* delete old table */
|
|
||||||
"DROP TABLE old_auc_3g",
|
|
||||||
/* update user_version */
|
|
||||||
"PRAGMA user_version = 7",
|
"PRAGMA user_version = 7",
|
||||||
"COMMIT",
|
};
|
||||||
|
|
||||||
|
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
|
||||||
|
if (rc != SQLITE_DONE) {
|
||||||
|
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 7\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int db_upgrade_v8(struct db_context *dbc)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
const char *statements[] = {
|
||||||
|
"ALTER TABLE subscriber ADD COLUMN last_lu_rat_cs TEXT default NULL",
|
||||||
|
"ALTER TABLE subscriber ADD COLUMN last_lu_rat_ps TEXT default NULL",
|
||||||
|
"PRAGMA user_version = 8",
|
||||||
};
|
};
|
||||||
|
|
||||||
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
|
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
|
||||||
@@ -562,6 +569,7 @@ static db_upgrade_func_t db_upgrade_path[] = {
|
|||||||
db_upgrade_v5,
|
db_upgrade_v5,
|
||||||
db_upgrade_v6,
|
db_upgrade_v6,
|
||||||
db_upgrade_v7,
|
db_upgrade_v7,
|
||||||
|
db_upgrade_v8,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int db_get_user_version(struct db_context *dbc)
|
static int db_get_user_version(struct db_context *dbc)
|
||||||
@@ -650,11 +658,9 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logg
|
|||||||
|
|
||||||
char *err_msg;
|
char *err_msg;
|
||||||
rc = sqlite3_exec(dbc->db, "PRAGMA journal_mode=WAL; PRAGMA synchonous = NORMAL;", 0, 0, &err_msg);
|
rc = sqlite3_exec(dbc->db, "PRAGMA journal_mode=WAL; PRAGMA synchonous = NORMAL;", 0, 0, &err_msg);
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK)
|
||||||
LOGP(DDB, LOGL_ERROR, "Unable to set Write-Ahead Logging: %s\n",
|
LOGP(DDB, LOGL_ERROR, "Unable to set Write-Ahead Logging: %s\n",
|
||||||
err_msg);
|
err_msg);
|
||||||
sqlite3_free(err_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
version = db_get_user_version(dbc);
|
version = db_get_user_version(dbc);
|
||||||
if (version < 0) {
|
if (version < 0) {
|
||||||
@@ -692,9 +698,9 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logg
|
|||||||
if (version < CURRENT_SCHEMA_VERSION) {
|
if (version < CURRENT_SCHEMA_VERSION) {
|
||||||
LOGP(DDB, LOGL_NOTICE, "HLR DB schema version %d is outdated\n", version);
|
LOGP(DDB, LOGL_NOTICE, "HLR DB schema version %d is outdated\n", version);
|
||||||
if (!allow_upgrade) {
|
if (!allow_upgrade) {
|
||||||
LOGP(DDB, LOGL_ERROR, "Not upgrading HLR database to schema version %d; "
|
LOGP(DDB, LOGL_ERROR, "Not upgrading HLR database from schema version %d to %d; "
|
||||||
"use the --db-upgrade option to allow HLR database upgrades\n",
|
"use the --db-upgrade option to allow HLR database upgrades\n",
|
||||||
CURRENT_SCHEMA_VERSION);
|
version, CURRENT_SCHEMA_VERSION);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
LOGP(DDB, LOGL_ERROR, "HLR DB schema version %d is unknown\n", version);
|
LOGP(DDB, LOGL_ERROR, "HLR DB schema version %d is unknown\n", version);
|
||||||
|
|||||||
48
src/db_auc.c
48
src/db_auc.c
@@ -1,4 +1,4 @@
|
|||||||
/* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
|
/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
@@ -74,9 +74,9 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* hexparse a specific column of a sqlite prepared statement into dst (with length check)
|
/* hexparse a specific column of a sqlite prepared statement into dst (with length check)
|
||||||
* returns byte length in case of success, -EIO on error */
|
* returns 0 for success, -EIO on error */
|
||||||
static int hexparse_stmt(uint8_t *dst, size_t dst_len_min, size_t dst_len_max, sqlite3_stmt *stmt,
|
static int hexparse_stmt(uint8_t *dst, size_t dst_len, sqlite3_stmt *stmt, int col, const char *col_name,
|
||||||
int col, const char *col_name, const char *imsi)
|
const char *imsi)
|
||||||
{
|
{
|
||||||
const uint8_t *text;
|
const uint8_t *text;
|
||||||
size_t col_len;
|
size_t col_len;
|
||||||
@@ -84,15 +84,9 @@ static int hexparse_stmt(uint8_t *dst, size_t dst_len_min, size_t dst_len_max, s
|
|||||||
/* Bytes are stored as hex strings in database, hence divide length by two */
|
/* Bytes are stored as hex strings in database, hence divide length by two */
|
||||||
col_len = sqlite3_column_bytes(stmt, col) / 2;
|
col_len = sqlite3_column_bytes(stmt, col) / 2;
|
||||||
|
|
||||||
if (col_len < dst_len_min) {
|
if (col_len != dst_len) {
|
||||||
LOGAUC(imsi, LOGL_ERROR, "Error reading %s, expected min length %lu but has length %lu\n", col_name,
|
LOGAUC(imsi, LOGL_ERROR, "Error reading %s, expected length %lu but has length %lu\n", col_name,
|
||||||
dst_len_min, col_len);
|
dst_len, col_len);
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (col_len > dst_len_max) {
|
|
||||||
LOGAUC(imsi, LOGL_ERROR, "Error reading %s, expected max length %lu but has length %lu\n", col_name,
|
|
||||||
dst_len_max, col_len);
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,11 +95,8 @@ static int hexparse_stmt(uint8_t *dst, size_t dst_len_min, size_t dst_len_max, s
|
|||||||
LOGAUC(imsi, LOGL_ERROR, "Error reading %s\n", col_name);
|
LOGAUC(imsi, LOGL_ERROR, "Error reading %s\n", col_name);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
osmo_hexparse((void *)text, dst, dst_len);
|
||||||
if (osmo_hexparse((void *)text, dst, dst_len_max) != col_len)
|
return 0;
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return col_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* obtain the authentication data for a given imsi
|
/* obtain the authentication data for a given imsi
|
||||||
@@ -113,8 +104,8 @@ static int hexparse_stmt(uint8_t *dst, size_t dst_len_min, size_t dst_len_max, s
|
|||||||
* -ENOENT if the IMSI is not known, -ENOKEY if the IMSI is known but has no auth data,
|
* -ENOENT if the IMSI is not known, -ENOKEY if the IMSI is known but has no auth data,
|
||||||
* -EIO on db failure */
|
* -EIO on db failure */
|
||||||
int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
||||||
struct osmo_sub_auth_data2 *aud2g,
|
struct osmo_sub_auth_data *aud2g,
|
||||||
struct osmo_sub_auth_data2 *aud3g,
|
struct osmo_sub_auth_data *aud3g,
|
||||||
int64_t *subscr_id)
|
int64_t *subscr_id)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_AUC_BY_IMSI];
|
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_AUC_BY_IMSI];
|
||||||
@@ -148,8 +139,7 @@ int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
|||||||
/* obtain result values using sqlite3_column_*() */
|
/* obtain result values using sqlite3_column_*() */
|
||||||
if (sqlite3_column_type(stmt, 1) == SQLITE_INTEGER) {
|
if (sqlite3_column_type(stmt, 1) == SQLITE_INTEGER) {
|
||||||
/* we do have some 2G authentication data */
|
/* we do have some 2G authentication data */
|
||||||
if (hexparse_stmt(aud2g->u.gsm.ki, sizeof(aud2g->u.gsm.ki), sizeof(aud2g->u.gsm.ki),
|
if (hexparse_stmt(aud2g->u.gsm.ki, sizeof(aud2g->u.gsm.ki), stmt, 2, "Ki", imsi))
|
||||||
stmt, 2, "Ki", imsi) < 0)
|
|
||||||
goto end_2g;
|
goto end_2g;
|
||||||
aud2g->algo = sqlite3_column_int(stmt, 1);
|
aud2g->algo = sqlite3_column_int(stmt, 1);
|
||||||
aud2g->type = OSMO_AUTH_TYPE_GSM;
|
aud2g->type = OSMO_AUTH_TYPE_GSM;
|
||||||
@@ -158,30 +148,24 @@ int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
|||||||
end_2g:
|
end_2g:
|
||||||
if (sqlite3_column_type(stmt, 3) == SQLITE_INTEGER) {
|
if (sqlite3_column_type(stmt, 3) == SQLITE_INTEGER) {
|
||||||
/* we do have some 3G authentication data */
|
/* we do have some 3G authentication data */
|
||||||
rc = hexparse_stmt(aud3g->u.umts.k, 16, sizeof(aud3g->u.umts.k), stmt, 4, "K", imsi);
|
if (hexparse_stmt(aud3g->u.umts.k, sizeof(aud3g->u.umts.k), stmt, 4, "K", imsi)) {
|
||||||
if (rc < 0) {
|
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
aud3g->u.umts.k_len = rc;
|
|
||||||
aud3g->algo = sqlite3_column_int(stmt, 3);
|
aud3g->algo = sqlite3_column_int(stmt, 3);
|
||||||
|
|
||||||
/* UMTS Subscribers can have either OP or OPC */
|
/* UMTS Subscribers can have either OP or OPC */
|
||||||
if (sqlite3_column_text(stmt, 5)) {
|
if (sqlite3_column_text(stmt, 5)) {
|
||||||
rc = hexparse_stmt(aud3g->u.umts.opc, 16, sizeof(aud3g->u.umts.opc), stmt, 5, "OP", imsi);
|
if (hexparse_stmt(aud3g->u.umts.opc, sizeof(aud3g->u.umts.opc), stmt, 5, "OP", imsi)) {
|
||||||
if (rc < 0) {
|
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
aud3g->u.umts.opc_len = rc;
|
|
||||||
aud3g->u.umts.opc_is_op = 1;
|
aud3g->u.umts.opc_is_op = 1;
|
||||||
} else {
|
} else {
|
||||||
rc = hexparse_stmt(aud3g->u.umts.opc, 16, sizeof(aud3g->u.umts.opc), stmt, 6, "OPC", imsi);
|
if (hexparse_stmt(aud3g->u.umts.opc, sizeof(aud3g->u.umts.opc), stmt, 6, "OPC", imsi)) {
|
||||||
if (rc < 0) {
|
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
aud3g->u.umts.opc_len = rc;
|
|
||||||
aud3g->u.umts.opc_is_op = 0;
|
aud3g->u.umts.opc_is_op = 0;
|
||||||
}
|
}
|
||||||
aud3g->u.umts.sqn = sqlite3_column_int64(stmt, 7);
|
aud3g->u.umts.sqn = sqlite3_column_int64(stmt, 7);
|
||||||
@@ -207,7 +191,7 @@ int db_get_auc(struct db_context *dbc, const char *imsi,
|
|||||||
unsigned int num_vec, const uint8_t *rand_auts,
|
unsigned int num_vec, const uint8_t *rand_auts,
|
||||||
const uint8_t *auts, bool separation_bit)
|
const uint8_t *auts, bool separation_bit)
|
||||||
{
|
{
|
||||||
struct osmo_sub_auth_data2 aud2g, aud3g;
|
struct osmo_sub_auth_data aud2g, aud3g;
|
||||||
int64_t subscr_id;
|
int64_t subscr_id;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|||||||
266
src/db_hlr.c
266
src/db_hlr.c
@@ -1,4 +1,4 @@
|
|||||||
/* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
|
/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
#include <osmocom/hlr/logging.h>
|
#include <osmocom/hlr/logging.h>
|
||||||
#include <osmocom/hlr/hlr.h>
|
#include <osmocom/hlr/hlr.h>
|
||||||
#include <osmocom/hlr/db.h>
|
#include <osmocom/hlr/db.h>
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
|
|
||||||
#define LOGHLR(imsi, level, fmt, args ...) LOGP(DAUC, level, "IMSI='%s': " fmt, imsi, ## args)
|
#define LOGHLR(imsi, level, fmt, args ...) LOGP(DAUC, level, "IMSI='%s': " fmt, imsi, ## args)
|
||||||
|
|
||||||
@@ -45,8 +45,7 @@
|
|||||||
* \param[in,out] dbc database context.
|
* \param[in,out] dbc database context.
|
||||||
* \param[in] imsi ASCII string of IMSI digits, is validated.
|
* \param[in] imsi ASCII string of IMSI digits, is validated.
|
||||||
* \param[in] flags Bitmask of DB_SUBSCR_FLAG_*.
|
* \param[in] flags Bitmask of DB_SUBSCR_FLAG_*.
|
||||||
* \returns 0 on success, -EINVAL on invalid IMSI, -EEXIST if subscriber with
|
* \returns 0 on success, -EINVAL on invalid IMSI, -EIO on database error.
|
||||||
* provided imsi already exists, -EIO on other database errors.
|
|
||||||
*/
|
*/
|
||||||
int db_subscr_create(struct db_context *dbc, const char *imsi, uint8_t flags)
|
int db_subscr_create(struct db_context *dbc, const char *imsi, uint8_t flags)
|
||||||
{
|
{
|
||||||
@@ -74,8 +73,6 @@ int db_subscr_create(struct db_context *dbc, const char *imsi, uint8_t flags)
|
|||||||
if (rc != SQLITE_DONE) {
|
if (rc != SQLITE_DONE) {
|
||||||
LOGHLR(imsi, LOGL_ERROR, "Cannot create subscriber: SQL error: (%d) %s\n",
|
LOGHLR(imsi, LOGL_ERROR, "Cannot create subscriber: SQL error: (%d) %s\n",
|
||||||
rc, sqlite3_errmsg(dbc->db));
|
rc, sqlite3_errmsg(dbc->db));
|
||||||
if (rc == SQLITE_CONSTRAINT_UNIQUE)
|
|
||||||
return -EEXIST;
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,9 +235,8 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
|
|||||||
case OSMO_AUTH_ALG_COMP128v1:
|
case OSMO_AUTH_ALG_COMP128v1:
|
||||||
case OSMO_AUTH_ALG_COMP128v2:
|
case OSMO_AUTH_ALG_COMP128v2:
|
||||||
case OSMO_AUTH_ALG_COMP128v3:
|
case OSMO_AUTH_ALG_COMP128v3:
|
||||||
case OSMO_AUTH_ALG_XOR_2G:
|
case OSMO_AUTH_ALG_XOR:
|
||||||
break;
|
break;
|
||||||
case OSMO_AUTH_ALG_XOR_3G:
|
|
||||||
case OSMO_AUTH_ALG_MILENAGE:
|
case OSMO_AUTH_ALG_MILENAGE:
|
||||||
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
||||||
" auth algo not suited for 2G: %s\n",
|
" auth algo not suited for 2G: %s\n",
|
||||||
@@ -268,12 +264,11 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
|
|||||||
switch (aud->algo) {
|
switch (aud->algo) {
|
||||||
case OSMO_AUTH_ALG_NONE:
|
case OSMO_AUTH_ALG_NONE:
|
||||||
case OSMO_AUTH_ALG_MILENAGE:
|
case OSMO_AUTH_ALG_MILENAGE:
|
||||||
case OSMO_AUTH_ALG_XOR_3G:
|
|
||||||
break;
|
break;
|
||||||
case OSMO_AUTH_ALG_COMP128v1:
|
case OSMO_AUTH_ALG_COMP128v1:
|
||||||
case OSMO_AUTH_ALG_COMP128v2:
|
case OSMO_AUTH_ALG_COMP128v2:
|
||||||
case OSMO_AUTH_ALG_COMP128v3:
|
case OSMO_AUTH_ALG_COMP128v3:
|
||||||
case OSMO_AUTH_ALG_XOR_2G:
|
case OSMO_AUTH_ALG_XOR:
|
||||||
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
||||||
" auth algo not suited for 3G: %s\n",
|
" auth algo not suited for 3G: %s\n",
|
||||||
osmo_auth_alg_name(aud->algo));
|
osmo_auth_alg_name(aud->algo));
|
||||||
@@ -286,12 +281,12 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
|
|||||||
|
|
||||||
if (aud->algo == OSMO_AUTH_ALG_NONE)
|
if (aud->algo == OSMO_AUTH_ALG_NONE)
|
||||||
break;
|
break;
|
||||||
if (!osmo_is_hexstr(aud->u.umts.k, 32, 64, true)) {
|
if (!osmo_is_hexstr(aud->u.umts.k, 32, 32, true)) {
|
||||||
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
||||||
" Invalid K: '%s'\n", aud->u.umts.k);
|
" Invalid K: '%s'\n", aud->u.umts.k);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (!osmo_is_hexstr(aud->u.umts.opc, 32, 64, true)) {
|
if (!osmo_is_hexstr(aud->u.umts.opc, 32, 32, true)) {
|
||||||
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
|
||||||
" Invalid OP/OPC: '%s'\n", aud->u.umts.opc);
|
" Invalid OP/OPC: '%s'\n", aud->u.umts.opc);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -488,7 +483,7 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
|
|||||||
if (!subscr)
|
if (!subscr)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
*subscr = (struct hlr_subscriber){};
|
*subscr = hlr_subscriber_empty;
|
||||||
|
|
||||||
/* obtain the various columns */
|
/* obtain the various columns */
|
||||||
subscr->id = sqlite3_column_int64(stmt, 0);
|
subscr->id = sqlite3_column_int64(stmt, 0);
|
||||||
@@ -510,12 +505,17 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
|
|||||||
subscr->imsi, "CS");
|
subscr->imsi, "CS");
|
||||||
parse_last_lu_seen(&subscr->last_lu_seen_ps, (const char *)sqlite3_column_text(stmt, 15),
|
parse_last_lu_seen(&subscr->last_lu_seen_ps, (const char *)sqlite3_column_text(stmt, 15),
|
||||||
subscr->imsi, "PS");
|
subscr->imsi, "PS");
|
||||||
copy_sqlite3_text_to_ipa_name(&subscr->vlr_via_proxy, stmt, 16);
|
copy_sqlite3_text_to_buf(subscr->last_lu_rat_cs, stmt, 16);
|
||||||
copy_sqlite3_text_to_ipa_name(&subscr->sgsn_via_proxy, stmt, 17);
|
copy_sqlite3_text_to_buf(subscr->last_lu_rat_ps, stmt, 17);
|
||||||
|
copy_sqlite3_text_to_ipa_name(&subscr->vlr_via_proxy, stmt, 18);
|
||||||
|
copy_sqlite3_text_to_ipa_name(&subscr->sgsn_via_proxy, stmt, 19);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
db_remove_reset(stmt);
|
db_remove_reset(stmt);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
db_subscr_get_rat_types(dbc, subscr);
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case 0:
|
case 0:
|
||||||
*err = NULL;
|
*err = NULL;
|
||||||
@@ -630,94 +630,6 @@ int db_subscr_get_by_msisdn(struct db_context *dbc, const char *msisdn,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Retrieve subscriber data from the HLR database.
|
|
||||||
* \param[in,out] dbc database context.
|
|
||||||
* \param[in] filter_type ASCII string of identifier type to search.
|
|
||||||
* \param[in] filter ASCII string to search.
|
|
||||||
* \param[in] get_cb pointer to call back function for data.
|
|
||||||
* \param[in,out] data pointer to pass to callback function.
|
|
||||||
* \param[in,out] count counter for number of matched subscribers.
|
|
||||||
* \param[in,our] err
|
|
||||||
* \returns 0 on success, -ENOENT if no subscriber was found, -EIO on
|
|
||||||
* database error.
|
|
||||||
*/
|
|
||||||
int db_subscrs_get(struct db_context *dbc, const char *filter_type, const char *filter,
|
|
||||||
void (*get_cb)(struct hlr_subscriber *subscr, void *data), void *data,
|
|
||||||
int *count, const char **err)
|
|
||||||
{
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
char search[256];
|
|
||||||
int rc;
|
|
||||||
struct hlr_subscriber subscr;
|
|
||||||
bool show_ls = false;
|
|
||||||
|
|
||||||
if (!filter_type) {
|
|
||||||
stmt = dbc->stmt[DB_STMT_SEL_ALL];
|
|
||||||
} else if (strcmp(filter_type, "imei") == 0) {
|
|
||||||
stmt = dbc->stmt[DB_STMT_SEL_FILTER_IMEI];
|
|
||||||
} else if (strcmp(filter_type, "imsi") == 0) {
|
|
||||||
stmt = dbc->stmt[DB_STMT_SEL_FILTER_IMSI];
|
|
||||||
} else if (strcmp(filter_type, "msisdn") == 0) {
|
|
||||||
stmt = dbc->stmt[DB_STMT_SEL_FILTER_MSISDN];
|
|
||||||
} else if (strcmp(filter_type, "cs") == 0) {
|
|
||||||
stmt = dbc->stmt[DB_STMT_SEL_FILTER_CS];
|
|
||||||
} else if (strcmp(filter_type, "ps") == 0) {
|
|
||||||
stmt = dbc->stmt[DB_STMT_SEL_FILTER_PS];
|
|
||||||
} else if (strcmp(filter_type, "last_lu_seen") == 0) {
|
|
||||||
show_ls = true;
|
|
||||||
stmt = dbc->stmt[DB_STMT_SEL_ALL_ORDER_LAST_SEEN];
|
|
||||||
} else {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filter_type && filter && strcmp(filter_type, "last_lu_seen") != 0) {
|
|
||||||
if (strcmp(filter, "on") == 0) {
|
|
||||||
sprintf(search, "%s", "1");
|
|
||||||
} else if (strcmp(filter, "off") == 0) {
|
|
||||||
sprintf(search, "%s", "0");
|
|
||||||
} else {
|
|
||||||
sprintf(search, "%%%s%%", filter);
|
|
||||||
}
|
|
||||||
if (!db_bind_text(stmt, "$search", search)) {
|
|
||||||
*err = sqlite3_errmsg(dbc->db);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
|
||||||
|
|
||||||
if (rc == SQLITE_DONE) {
|
|
||||||
db_remove_reset(stmt);
|
|
||||||
*err = "No matching subscriber(s)";
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (rc == SQLITE_ROW) {
|
|
||||||
subscr = (struct hlr_subscriber){
|
|
||||||
.id = sqlite3_column_int64(stmt, 0),};
|
|
||||||
copy_sqlite3_text_to_buf(subscr.imsi, stmt, 1);
|
|
||||||
copy_sqlite3_text_to_buf(subscr.msisdn, stmt, 2);
|
|
||||||
copy_sqlite3_text_to_buf(subscr.imei, stmt, 3);
|
|
||||||
subscr.nam_cs = sqlite3_column_int(stmt, 9);
|
|
||||||
subscr.nam_ps = sqlite3_column_int(stmt, 10);
|
|
||||||
if (show_ls)
|
|
||||||
parse_last_lu_seen(&subscr.last_lu_seen, (const char *)sqlite3_column_text(stmt, 14),
|
|
||||||
subscr.imsi, "CS");
|
|
||||||
get_cb(&subscr, data);
|
|
||||||
rc = sqlite3_step(stmt);
|
|
||||||
(*count)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
db_remove_reset(stmt);
|
|
||||||
if (rc != SQLITE_DONE) {
|
|
||||||
*err = sqlite3_errmsg(dbc->db);
|
|
||||||
LOGP(DAUC, LOGL_ERROR, "Cannot read subscribers from db:: %s\n", *err);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
*err = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Retrieve subscriber data from the HLR database.
|
/*! Retrieve subscriber data from the HLR database.
|
||||||
* \param[in,out] dbc database context.
|
* \param[in,out] dbc database context.
|
||||||
* \param[in] id ID of the subscriber in the HLR db.
|
* \param[in] id ID of the subscriber in the HLR db.
|
||||||
@@ -830,11 +742,14 @@ out:
|
|||||||
*/
|
*/
|
||||||
int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
|
int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
|
||||||
const struct osmo_ipa_name *vlr_name, bool is_ps,
|
const struct osmo_ipa_name *vlr_name, bool is_ps,
|
||||||
const struct osmo_ipa_name *via_proxy)
|
const struct osmo_ipa_name *via_proxy,
|
||||||
|
const enum osmo_rat_type rat_types[], size_t rat_types_len)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
int rc, ret = 0;
|
int rc, ret = 0;
|
||||||
struct timespec localtime;
|
struct timespec localtime;
|
||||||
|
char rat_types_str[128] = "";
|
||||||
|
int i;
|
||||||
|
|
||||||
stmt = dbc->stmt[is_ps ? DB_STMT_UPD_SGSN_BY_ID
|
stmt = dbc->stmt[is_ps ? DB_STMT_UPD_SGSN_BY_ID
|
||||||
: DB_STMT_UPD_VLR_BY_ID];
|
: DB_STMT_UPD_VLR_BY_ID];
|
||||||
@@ -896,6 +811,21 @@ int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < rat_types_len; i++) {
|
||||||
|
char *pos = rat_types_str + strnlen(rat_types_str, sizeof(rat_types_str));
|
||||||
|
int len = sizeof(rat_types_str) - (pos - rat_types_str);
|
||||||
|
rc = snprintf(pos, len, "%s%s", pos == rat_types_str ? "" : ",", osmo_rat_type_name(rat_types[i]));
|
||||||
|
if (rc > len) {
|
||||||
|
osmo_strlcpy(rat_types_str + sizeof(rat_types_str) - 4, "...", 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!db_bind_text(stmt, "$rat", rat_types_str)) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
if (rc != SQLITE_DONE) {
|
if (rc != SQLITE_DONE) {
|
||||||
LOGP(DAUC, LOGL_ERROR,
|
LOGP(DAUC, LOGL_ERROR,
|
||||||
@@ -1032,14 +962,14 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _db_ind(struct db_context *dbc, const struct osmo_cni_peer_id *vlr,
|
int _db_ind(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr,
|
||||||
unsigned int *ind, bool del)
|
unsigned int *ind, bool del)
|
||||||
{
|
{
|
||||||
const char *vlr_name = NULL;
|
const char *vlr_name = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
switch (vlr->type) {
|
switch (vlr->type) {
|
||||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||||
if (vlr->ipa_name.len < 2 || vlr->ipa_name.val[vlr->ipa_name.len - 1] != '\0') {
|
if (vlr->ipa_name.len < 2 || vlr->ipa_name.val[vlr->ipa_name.len - 1] != '\0') {
|
||||||
LOGP(DDB, LOGL_ERROR, "Expecting VLR ipa_name to be zero terminated; found %s\n",
|
LOGP(DDB, LOGL_ERROR, "Expecting VLR ipa_name to be zero terminated; found %s\n",
|
||||||
osmo_ipa_name_to_str(&vlr->ipa_name));
|
osmo_ipa_name_to_str(&vlr->ipa_name));
|
||||||
@@ -1048,8 +978,8 @@ int _db_ind(struct db_context *dbc, const struct osmo_cni_peer_id *vlr,
|
|||||||
vlr_name = (const char*)vlr->ipa_name.val;
|
vlr_name = (const char*)vlr->ipa_name.val;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGP(DDB, LOGL_ERROR, "Unsupported osmo_cni_peer_id type: %s\n",
|
LOGP(DDB, LOGL_ERROR, "Unsupported osmo_gsup_peer_id type: %s\n",
|
||||||
osmo_cni_peer_id_type_name(vlr->type));
|
osmo_gsup_peer_id_type_name(vlr->type));
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1071,12 +1001,128 @@ int _db_ind(struct db_context *dbc, const struct osmo_cni_peer_id *vlr,
|
|||||||
return _db_ind_get(dbc, vlr_name, ind);
|
return _db_ind_get(dbc, vlr_name, ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
int db_ind(struct db_context *dbc, const struct osmo_cni_peer_id *vlr, unsigned int *ind)
|
int db_ind(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr, unsigned int *ind)
|
||||||
{
|
{
|
||||||
return _db_ind(dbc, vlr, ind, false);
|
return _db_ind(dbc, vlr, ind, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int db_ind_del(struct db_context *dbc, const struct osmo_cni_peer_id *vlr)
|
int db_ind_del(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr)
|
||||||
{
|
{
|
||||||
return _db_ind(dbc, vlr, NULL, true);
|
return _db_ind(dbc, vlr, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int db_subscr_set_rat_type_flag(struct db_context *dbc, int64_t subscr_id, enum osmo_rat_type rat, bool allowed)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int ret = 0;
|
||||||
|
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_UPD_RAT_FLAG];
|
||||||
|
|
||||||
|
if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
OSMO_ASSERT(rat >= 0 && rat < OSMO_RAT_COUNT);
|
||||||
|
if (!db_bind_text(stmt, "$rat", osmo_rat_type_name(rat)))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (!db_bind_int(stmt, "$allowed", allowed ? 1 : 0))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
/* execute the statement */
|
||||||
|
rc = sqlite3_step(stmt);
|
||||||
|
if (rc != SQLITE_DONE) {
|
||||||
|
LOGP(DDB, LOGL_ERROR, "%s %s: SQL error: %s\n",
|
||||||
|
allowed ? "enable" : "disable", osmo_rat_type_name(rat),
|
||||||
|
sqlite3_errmsg(dbc->db));
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify execution result */
|
||||||
|
rc = sqlite3_changes(dbc->db);
|
||||||
|
if (!rc) {
|
||||||
|
LOGP(DDB, LOGL_ERROR, "Cannot %s %s: no such subscriber: ID=%" PRIu64 "\n",
|
||||||
|
allowed ? "enable" : "disable", osmo_rat_type_name(rat),
|
||||||
|
subscr_id);
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto out;
|
||||||
|
} else if (rc != 1) {
|
||||||
|
LOGP(DDB, LOGL_ERROR, "%s %s: SQL modified %d rows (expected 1)\n",
|
||||||
|
allowed ? "enable" : "disable", osmo_rat_type_name(rat),
|
||||||
|
rc);
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
db_remove_reset(stmt);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int db_subscr_get_rat_types(struct db_context *dbc, struct hlr_subscriber *subscr)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int ret = 0;
|
||||||
|
int i;
|
||||||
|
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_RAT_BY_ID];
|
||||||
|
|
||||||
|
if (!db_bind_int64(stmt, "$subscriber_id", subscr->id))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
for (i = 0; i < OSMO_RAT_COUNT; i++)
|
||||||
|
subscr->rat_types[i] = true;
|
||||||
|
|
||||||
|
/* execute the statement */
|
||||||
|
while (1) {
|
||||||
|
enum osmo_rat_type rat;
|
||||||
|
bool allowed;
|
||||||
|
|
||||||
|
rc = sqlite3_step(stmt);
|
||||||
|
|
||||||
|
if (rc == SQLITE_DONE)
|
||||||
|
break;
|
||||||
|
if (rc != SQLITE_ROW)
|
||||||
|
return -rc;
|
||||||
|
|
||||||
|
rc = get_string_value(osmo_rat_type_names, (const char*)sqlite3_column_text(stmt, 0));
|
||||||
|
if (rc == -EINVAL) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (rc <= 0 || rc >= OSMO_RAT_COUNT) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rat = rc;
|
||||||
|
|
||||||
|
allowed = sqlite3_column_int(stmt, 1);
|
||||||
|
|
||||||
|
subscr->rat_types[rat] = allowed;
|
||||||
|
LOGP(DAUC, LOGL_DEBUG, "db: imsi='%s' %s %s\n",
|
||||||
|
subscr->imsi, osmo_rat_type_name(rat), allowed ? "allowed" : "forbidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
db_remove_reset(stmt);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hlr_subscr_rat_flag(struct hlr *hlr, struct hlr_subscriber *subscr, enum osmo_rat_type rat, bool allowed)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
OSMO_ASSERT(rat >= 0 && rat < OSMO_RAT_COUNT);
|
||||||
|
|
||||||
|
db_subscr_get_rat_types(hlr->dbc, subscr);
|
||||||
|
|
||||||
|
if (subscr->rat_types[rat] == allowed) {
|
||||||
|
LOGHLR(subscr->imsi, LOGL_DEBUG, "Already has the requested value when asked to %s %s\n",
|
||||||
|
allowed ? "enable" : "disable", osmo_rat_type_name(rat));
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = db_subscr_set_rat_type_flag(hlr->dbc, subscr->id, rat, allowed);
|
||||||
|
if (rc)
|
||||||
|
return rc > 0? -rc : rc;
|
||||||
|
|
||||||
|
/* FIXME: If we're disabling, send message to VLR to detach subscriber */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,10 @@
|
|||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
* $Id: dbd_helper.c,v 1.44 2011/08/09 11:14:14 mhoenicka Exp $
|
* $Id: dbd_helper.c,v 1.44 2011/08/09 11:14:14 mhoenicka Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
#include <osmocom/mslookup/mslookup_client.h>
|
#include <osmocom/mslookup/mslookup_client.h>
|
||||||
#include <osmocom/mslookup/mslookup_client_mdns.h>
|
#include <osmocom/mslookup/mslookup_client_mdns.h>
|
||||||
#include <osmocom/gsupclient/gsup_client.h>
|
#include <osmocom/gsupclient/gsup_client.h>
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
#include <osmocom/hlr/logging.h>
|
#include <osmocom/hlr/logging.h>
|
||||||
#include <osmocom/hlr/hlr.h>
|
#include <osmocom/hlr/hlr.h>
|
||||||
#include <osmocom/hlr/db.h>
|
#include <osmocom/hlr/db.h>
|
||||||
@@ -170,7 +170,7 @@ void dgsm_init(void *ctx)
|
|||||||
|
|
||||||
g_hlr->mslookup.server.local_attach_max_age = 60 * 60;
|
g_hlr->mslookup.server.local_attach_max_age = 60 * 60;
|
||||||
|
|
||||||
g_hlr->mslookup.client.result_timeout_milliseconds = OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS;
|
g_hlr->mslookup.client.result_timeout_milliseconds = 2000;
|
||||||
|
|
||||||
g_hlr->gsup_unit_name.unit_name = "HLR";
|
g_hlr->gsup_unit_name.unit_name = "HLR";
|
||||||
g_hlr->gsup_unit_name.serno = "unnamed-HLR";
|
g_hlr->gsup_unit_name.serno = "unnamed-HLR";
|
||||||
@@ -191,7 +191,7 @@ void dgsm_start(void *ctx)
|
|||||||
dgsm_mdns_client_config_apply();
|
dgsm_mdns_client_config_apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dgsm_stop(void)
|
void dgsm_stop()
|
||||||
{
|
{
|
||||||
g_hlr->mslookup.allow_startup = false;
|
g_hlr->mslookup.allow_startup = false;
|
||||||
mslookup_server_mdns_config_apply();
|
mslookup_server_mdns_config_apply();
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#include <osmocom/hlr/hlr_vty.h>
|
#include <osmocom/hlr/hlr_vty.h>
|
||||||
#include <osmocom/hlr/mslookup_server.h>
|
#include <osmocom/hlr/mslookup_server.h>
|
||||||
#include <osmocom/hlr/mslookup_server_mdns.h>
|
#include <osmocom/hlr/mslookup_server_mdns.h>
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
|
|
||||||
struct cmd_node mslookup_node = {
|
struct cmd_node mslookup_node = {
|
||||||
MSLOOKUP_NODE,
|
MSLOOKUP_NODE,
|
||||||
@@ -119,7 +119,7 @@ DEFUN(cfg_mslookup_mdns_domain_suffix,
|
|||||||
|
|
||||||
DEFUN(cfg_mslookup_no_mdns,
|
DEFUN(cfg_mslookup_no_mdns,
|
||||||
cfg_mslookup_no_mdns_cmd,
|
cfg_mslookup_no_mdns_cmd,
|
||||||
"no mdns bind",
|
"no mdns",
|
||||||
NO_STR "Disable both server and client for mDNS mslookup\n")
|
NO_STR "Disable both server and client for mDNS mslookup\n")
|
||||||
{
|
{
|
||||||
g_hlr->mslookup.server.mdns.enable = false;
|
g_hlr->mslookup.server.mdns.enable = false;
|
||||||
@@ -178,9 +178,9 @@ DEFUN(cfg_mslookup_server_mdns_domain_suffix,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN(cfg_mslookup_server_no_mdns_bind,
|
DEFUN(cfg_mslookup_server_no_mdns,
|
||||||
cfg_mslookup_server_no_mdns_bind_cmd,
|
cfg_mslookup_server_no_mdns_cmd,
|
||||||
"no mdns bind",
|
"no mdns",
|
||||||
NO_STR "Disable server for mDNS mslookup (do not answer remote requests)\n")
|
NO_STR "Disable server for mDNS mslookup (do not answer remote requests)\n")
|
||||||
{
|
{
|
||||||
g_hlr->mslookup.server.mdns.enable = false;
|
g_hlr->mslookup.server.mdns.enable = false;
|
||||||
@@ -196,9 +196,8 @@ struct cmd_node mslookup_server_msc_node = {
|
|||||||
|
|
||||||
DEFUN(cfg_mslookup_server_msc,
|
DEFUN(cfg_mslookup_server_msc,
|
||||||
cfg_mslookup_server_msc_cmd,
|
cfg_mslookup_server_msc_cmd,
|
||||||
"msc ipa-name .IPA_NAME",
|
"msc .UNIT_NAME",
|
||||||
"Configure services for individual local MSCs\n"
|
"Configure services for individual local MSCs\n"
|
||||||
"Identify locally connected MSC by IPA Unit Name\n"
|
|
||||||
"IPA Unit Name of the local MSC to configure\n")
|
"IPA Unit Name of the local MSC to configure\n")
|
||||||
{
|
{
|
||||||
struct osmo_ipa_name msc_name;
|
struct osmo_ipa_name msc_name;
|
||||||
@@ -366,8 +365,8 @@ DEFUN(cfg_mslookup_client_timeout,
|
|||||||
vty_out(vty, "%% 'exit' this node to apply changes%s", VTY_NEWLINE)
|
vty_out(vty, "%% 'exit' this node to apply changes%s", VTY_NEWLINE)
|
||||||
|
|
||||||
|
|
||||||
DEFUN(cfg_mslookup_client_mdns_bind,
|
DEFUN(cfg_mslookup_client_mdns,
|
||||||
cfg_mslookup_client_mdns_bind_cmd,
|
cfg_mslookup_client_mdns_cmd,
|
||||||
"mdns bind [IP] [<1-65535>]",
|
"mdns bind [IP] [<1-65535>]",
|
||||||
MDNS_STR
|
MDNS_STR
|
||||||
"Enable mDNS client, and configure multicast address to send mDNS mslookup requests to\n"
|
"Enable mDNS client, and configure multicast address to send mDNS mslookup requests to\n"
|
||||||
@@ -388,9 +387,9 @@ DEFUN(cfg_mslookup_client_mdns_domain_suffix,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN(cfg_mslookup_client_no_mdns_bind,
|
DEFUN(cfg_mslookup_client_no_mdns,
|
||||||
cfg_mslookup_client_no_mdns_bind_cmd,
|
cfg_mslookup_client_no_mdns_cmd,
|
||||||
"no mdns bind",
|
"no mdns",
|
||||||
NO_STR "Disable mDNS client, do not query remote services by mDNS\n")
|
NO_STR "Disable mDNS client, do not query remote services by mDNS\n")
|
||||||
{
|
{
|
||||||
g_hlr->mslookup.client.mdns.enable = false;
|
g_hlr->mslookup.client.mdns.enable = false;
|
||||||
@@ -447,7 +446,7 @@ int config_write_mslookup(struct vty *vty)
|
|||||||
llist_for_each_entry(msc, &g_hlr->mslookup.server.local_site_services, entry) {
|
llist_for_each_entry(msc, &g_hlr->mslookup.server.local_site_services, entry) {
|
||||||
if (!osmo_ipa_name_cmp(&mslookup_server_msc_wildcard, &msc->name))
|
if (!osmo_ipa_name_cmp(&mslookup_server_msc_wildcard, &msc->name))
|
||||||
continue;
|
continue;
|
||||||
vty_out(vty, " msc ipa-name %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE);
|
vty_out(vty, " msc %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE);
|
||||||
config_write_msc_services(vty, " ", msc);
|
config_write_msc_services(vty, " ", msc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,7 +466,7 @@ int config_write_mslookup(struct vty *vty)
|
|||||||
|
|
||||||
if (g_hlr->mslookup.client.mdns.enable
|
if (g_hlr->mslookup.client.mdns.enable
|
||||||
&& osmo_sockaddr_str_is_nonzero(&g_hlr->mslookup.client.mdns.query_addr))
|
&& osmo_sockaddr_str_is_nonzero(&g_hlr->mslookup.client.mdns.query_addr))
|
||||||
vty_out(vty, " mdns bind %s %u%s",
|
vty_out(vty, " mdns to %s %u%s",
|
||||||
g_hlr->mslookup.client.mdns.query_addr.ip,
|
g_hlr->mslookup.client.mdns.query_addr.ip,
|
||||||
g_hlr->mslookup.client.mdns.query_addr.port,
|
g_hlr->mslookup.client.mdns.query_addr.port,
|
||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
@@ -475,10 +474,6 @@ int config_write_mslookup(struct vty *vty)
|
|||||||
vty_out(vty, " mdns domain-suffix %s%s",
|
vty_out(vty, " mdns domain-suffix %s%s",
|
||||||
g_hlr->mslookup.client.mdns.domain_suffix,
|
g_hlr->mslookup.client.mdns.domain_suffix,
|
||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
if (g_hlr->mslookup.client.result_timeout_milliseconds != OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS)
|
|
||||||
vty_out(vty, " timeout %u%s",
|
|
||||||
g_hlr->mslookup.client.result_timeout_milliseconds,
|
|
||||||
VTY_NEWLINE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
@@ -539,7 +534,7 @@ DEFUN(do_mslookup_show_services,
|
|||||||
llist_for_each_entry(msc, &g_hlr->mslookup.server.local_site_services, entry) {
|
llist_for_each_entry(msc, &g_hlr->mslookup.server.local_site_services, entry) {
|
||||||
if (!osmo_ipa_name_cmp(&mslookup_server_msc_wildcard, &msc->name))
|
if (!osmo_ipa_name_cmp(&mslookup_server_msc_wildcard, &msc->name))
|
||||||
continue;
|
continue;
|
||||||
vty_out(vty, "msc ipa-name %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE);
|
vty_out(vty, "msc %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE);
|
||||||
config_write_msc_services(vty, " ", msc);
|
config_write_msc_services(vty, " ", msc);
|
||||||
}
|
}
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
@@ -559,7 +554,7 @@ void dgsm_vty_init(void)
|
|||||||
install_node(&mslookup_server_node, NULL);
|
install_node(&mslookup_server_node, NULL);
|
||||||
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_mdns_bind_cmd);
|
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_mdns_bind_cmd);
|
||||||
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_mdns_domain_suffix_cmd);
|
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_mdns_domain_suffix_cmd);
|
||||||
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_no_mdns_bind_cmd);
|
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_no_mdns_cmd);
|
||||||
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_service_cmd);
|
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_cmd);
|
||||||
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_no_service_addr_cmd);
|
install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_no_service_addr_cmd);
|
||||||
@@ -574,9 +569,9 @@ void dgsm_vty_init(void)
|
|||||||
install_element(MSLOOKUP_NODE, &cfg_mslookup_no_client_cmd);
|
install_element(MSLOOKUP_NODE, &cfg_mslookup_no_client_cmd);
|
||||||
install_node(&mslookup_client_node, NULL);
|
install_node(&mslookup_client_node, NULL);
|
||||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_timeout_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_cmd);
|
||||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_mdns_domain_suffix_cmd);
|
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_mdns_domain_suffix_cmd);
|
||||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_mdns_bind_cmd);
|
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_mdns_cmd);
|
||||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_gateway_proxy_cmd);
|
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_gateway_proxy_cmd);
|
||||||
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_gateway_proxy_cmd);
|
install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_gateway_proxy_cmd);
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
#include <osmocom/core/logging.h>
|
#include <osmocom/core/logging.h>
|
||||||
@@ -32,7 +30,6 @@
|
|||||||
|
|
||||||
#include <osmocom/hlr/gsup_server.h>
|
#include <osmocom/hlr/gsup_server.h>
|
||||||
#include <osmocom/hlr/gsup_router.h>
|
#include <osmocom/hlr/gsup_router.h>
|
||||||
#include <osmocom/hlr/hlr.h>
|
|
||||||
|
|
||||||
#define LOG_GSUP_CONN(conn, level, fmt, args...) \
|
#define LOG_GSUP_CONN(conn, level, fmt, args...) \
|
||||||
LOGP(DLGSUP, level, "GSUP peer %s: " fmt, \
|
LOGP(DLGSUP, level, "GSUP peer %s: " fmt, \
|
||||||
@@ -68,13 +65,13 @@ int osmo_gsup_conn_send(struct osmo_gsup_conn *conn, struct msgb *msg)
|
|||||||
static void gsup_server_send_req_response(struct osmo_gsup_req *req, struct osmo_gsup_message *response)
|
static void gsup_server_send_req_response(struct osmo_gsup_req *req, struct osmo_gsup_message *response)
|
||||||
{
|
{
|
||||||
struct osmo_gsup_server *server = req->cb_data;
|
struct osmo_gsup_server *server = req->cb_data;
|
||||||
struct osmo_cni_peer_id *routing;
|
struct osmo_gsup_peer_id *routing;
|
||||||
struct osmo_gsup_conn *conn = NULL;
|
struct osmo_gsup_conn *conn = NULL;
|
||||||
struct msgb *msg = osmo_gsup_msgb_alloc("GSUP Tx");
|
struct msgb *msg = osmo_gsup_msgb_alloc("GSUP Tx");
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (response->message_type == OSMO_GSUP_MSGT_ROUTING_ERROR
|
if (response->message_type == OSMO_GSUP_MSGT_ROUTING_ERROR
|
||||||
&& !osmo_cni_peer_id_is_empty(&req->via_proxy)) {
|
&& !osmo_gsup_peer_id_is_empty(&req->via_proxy)) {
|
||||||
/* If a routing error occured, we need to route back via the immediate sending peer, not via the
|
/* If a routing error occured, we need to route back via the immediate sending peer, not via the
|
||||||
* intended final recipient -- because one source of routing errors is a duplicate name for a recipient.
|
* intended final recipient -- because one source of routing errors is a duplicate name for a recipient.
|
||||||
* If we resolve to req->source_name, we may send to a completely unrelated recipient. */
|
* If we resolve to req->source_name, we may send to a completely unrelated recipient. */
|
||||||
@@ -83,12 +80,12 @@ static void gsup_server_send_req_response(struct osmo_gsup_req *req, struct osmo
|
|||||||
routing = &req->source_name;
|
routing = &req->source_name;
|
||||||
}
|
}
|
||||||
switch (routing->type) {
|
switch (routing->type) {
|
||||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||||
conn = gsup_route_find_by_ipa_name(server, &routing->ipa_name);
|
conn = gsup_route_find_by_ipa_name(server, &routing->ipa_name);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_GSUP_REQ(req, LOGL_ERROR, "GSUP peer id kind not supported: %s\n",
|
LOG_GSUP_REQ(req, LOGL_ERROR, "GSUP peer id kind not supported: %s\n",
|
||||||
osmo_cni_peer_id_type_name(routing->type));
|
osmo_gsup_peer_id_type_name(routing->type));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,22 +111,22 @@ static void gsup_server_send_req_response(struct osmo_gsup_req *req, struct osmo
|
|||||||
struct osmo_gsup_req *osmo_gsup_conn_rx(struct osmo_gsup_conn *conn, struct msgb *msg)
|
struct osmo_gsup_req *osmo_gsup_conn_rx(struct osmo_gsup_conn *conn, struct msgb *msg)
|
||||||
{
|
{
|
||||||
struct osmo_gsup_req *req;
|
struct osmo_gsup_req *req;
|
||||||
struct osmo_cni_peer_id cpi = {
|
struct osmo_gsup_peer_id gpi = {
|
||||||
.type = OSMO_CNI_PEER_ID_IPA_NAME,
|
.type = OSMO_GSUP_PEER_ID_IPA_NAME,
|
||||||
.ipa_name = conn->peer_name,
|
.ipa_name = conn->peer_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
req = osmo_gsup_req_new(conn->server, &cpi, msg, gsup_server_send_req_response, conn->server, NULL);
|
req = osmo_gsup_req_new(conn->server, &gpi, msg, gsup_server_send_req_response, conn->server, NULL);
|
||||||
if (!req)
|
if (!req)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!osmo_cni_peer_id_is_empty(&req->via_proxy)) {
|
if (!osmo_gsup_peer_id_is_empty(&req->via_proxy)) {
|
||||||
switch (req->via_proxy.type) {
|
switch (req->via_proxy.type) {
|
||||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_GSUP_REQ(req, LOGL_ERROR, "GSUP peer id kind not supported: %s\n",
|
LOG_GSUP_REQ(req, LOGL_ERROR, "GSUP peer id kind not supported: %s\n",
|
||||||
osmo_cni_peer_id_type_name(req->source_name.type));
|
osmo_gsup_peer_id_type_name(req->source_name.type));
|
||||||
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);
|
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -140,7 +137,7 @@ struct osmo_gsup_req *osmo_gsup_conn_rx(struct osmo_gsup_conn *conn, struct msgb
|
|||||||
LOG_GSUP_REQ(req, LOGL_ERROR,
|
LOG_GSUP_REQ(req, LOGL_ERROR,
|
||||||
"GSUP message received from %s via peer %s, but there already exists a"
|
"GSUP message received from %s via peer %s, but there already exists a"
|
||||||
" different route to this source, message is not routable\n",
|
" different route to this source, message is not routable\n",
|
||||||
osmo_cni_peer_id_to_str(&req->source_name),
|
osmo_gsup_peer_id_to_str(&req->source_name),
|
||||||
osmo_ipa_name_to_str(&conn->peer_name));
|
osmo_ipa_name_to_str(&conn->peer_name));
|
||||||
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);
|
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -180,9 +177,11 @@ static int osmo_gsup_server_read_cb(struct ipa_server_conn *conn,
|
|||||||
|
|
||||||
if (hh->proto == IPAC_PROTO_IPACCESS) {
|
if (hh->proto == IPAC_PROTO_IPACCESS) {
|
||||||
rc = ipa_server_conn_ccm(conn, msg);
|
rc = ipa_server_conn_ccm(conn, msg);
|
||||||
msgb_free(msg);
|
if (rc < 0) {
|
||||||
if (rc < 0) /* conn is already invalid here! */
|
/* conn is already invalid here! */
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
msgb_free(msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +274,7 @@ static int osmo_gsup_server_ccm_cb(struct ipa_server_conn *conn,
|
|||||||
{
|
{
|
||||||
struct osmo_gsup_conn *clnt = (struct osmo_gsup_conn *)conn->data;
|
struct osmo_gsup_conn *clnt = (struct osmo_gsup_conn *)conn->data;
|
||||||
uint8_t *addr = NULL;
|
uint8_t *addr = NULL;
|
||||||
int addr_len;
|
size_t addr_len;
|
||||||
|
|
||||||
LOGP(DLGSUP, LOGL_INFO, "CCM Callback\n");
|
LOGP(DLGSUP, LOGL_INFO, "CCM Callback\n");
|
||||||
|
|
||||||
@@ -316,17 +315,41 @@ static int osmo_gsup_server_closed_cb(struct ipa_server_conn *conn)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_fd_settings(int fd)
|
/* Add conn to the clients list in a way that conn->auc_3g_ind takes the lowest
|
||||||
|
* unused integer and the list of clients remains sorted by auc_3g_ind.
|
||||||
|
* Keep this function non-static to allow linking in a unit test. */
|
||||||
|
void osmo_gsup_server_add_conn(struct llist_head *clients,
|
||||||
|
struct osmo_gsup_conn *conn)
|
||||||
{
|
{
|
||||||
int ret;
|
struct osmo_gsup_conn *c;
|
||||||
int val;
|
struct osmo_gsup_conn *prev_conn;
|
||||||
|
|
||||||
/*TODO: Set keepalive settings here. See OS#4312 */
|
c = llist_first_entry_or_null(clients, struct osmo_gsup_conn, list);
|
||||||
|
|
||||||
val = 1;
|
/* Is the first index, 0, unused? */
|
||||||
ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
if (!c || c->auc_3g_ind > 0) {
|
||||||
if (ret < 0)
|
conn->auc_3g_ind = 0;
|
||||||
LOGP(DLGSUP, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
|
llist_add(&conn->list, clients);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look for a gap later on */
|
||||||
|
prev_conn = NULL;
|
||||||
|
llist_for_each_entry(c, clients, list) {
|
||||||
|
/* skip first item, we know it has auc_3g_ind == 0. */
|
||||||
|
if (!prev_conn) {
|
||||||
|
prev_conn = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c->auc_3g_ind > prev_conn->auc_3g_ind + 1)
|
||||||
|
break;
|
||||||
|
prev_conn = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSMO_ASSERT(prev_conn);
|
||||||
|
|
||||||
|
conn->auc_3g_ind = prev_conn->auc_3g_ind + 1;
|
||||||
|
llist_add(&conn->list, &prev_conn->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* a client has connected to the server socket and we have accept()ed it */
|
/* a client has connected to the server socket and we have accept()ed it */
|
||||||
@@ -348,11 +371,10 @@ static int osmo_gsup_server_accept_cb(struct ipa_server_link *link, int fd)
|
|||||||
|
|
||||||
/* link data structure with server structure */
|
/* link data structure with server structure */
|
||||||
conn->server = gsups;
|
conn->server = gsups;
|
||||||
llist_add_tail(&conn->list, &gsups->clients);
|
osmo_gsup_server_add_conn(&gsups->clients, conn);
|
||||||
|
|
||||||
LOGP(DLGSUP, LOGL_INFO, "New GSUP client %s:%d\n", conn->conn->addr, conn->conn->port);
|
LOGP(DLGSUP, LOGL_INFO, "New GSUP client %s:%d (IND=%u)\n",
|
||||||
|
conn->conn->addr, conn->conn->port, conn->auc_3g_ind);
|
||||||
update_fd_settings(fd);
|
|
||||||
|
|
||||||
/* request the identity of the client */
|
/* request the identity of the client */
|
||||||
rc = ipa_ccm_send_id_req(fd);
|
rc = ipa_ccm_send_id_req(fd);
|
||||||
@@ -437,24 +459,28 @@ int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate a gsup message structure with an Insert Subscriber Data Message.
|
* Populate a gsup message structure with an Insert Subscriber Data Message.
|
||||||
* All required memory buffers for data pointed to by pointers in struct osmo_gsup_message
|
* All required memory buffers for data pointed to by pointers in struct omso_gsup_message
|
||||||
* must be allocated by the caller and should have the same lifetime as the gsup parameter.
|
* must be allocated by the caller and should have the same lifetime as the gsup parameter.
|
||||||
*
|
*
|
||||||
* \param[out] gsup The gsup message to populate.
|
* \param[out] gsup The gsup message to populate.
|
||||||
* \param[in] imsi The subscriber's IMSI.
|
* \param[in] imsi The subscriber's IMSI.
|
||||||
* \param[in] msisdn The subscriber's MSISDN.
|
* \param[in] msisdn The subscriber's MSISDN.
|
||||||
|
* \param[out] msisdn_enc A buffer large enough to store the MSISDN in encoded form.
|
||||||
|
* \param[in] msisdn_enc_size Size of the buffer (must be >= OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN).
|
||||||
|
* \param[out] apn_buf A buffer large enough to store an APN (required if cn_domain is OSMO_GSUP_CN_DOMAIN_PS).
|
||||||
|
* \param[in] apn_buf_size Size of APN buffer (must be >= APN_MAXLEN).
|
||||||
* \param[in] cn_domain The CN Domain of the subscriber connection.
|
* \param[in] cn_domain The CN Domain of the subscriber connection.
|
||||||
* \param[in] talloc_ctx To allocation memory for dynamic fields (msisdn, apn) in the gsup field
|
|
||||||
* \returns 0 on success, and negative on error.
|
* \returns 0 on success, and negative on error.
|
||||||
*/
|
*/
|
||||||
int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
|
int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
|
||||||
enum osmo_gsup_cn_domain cn_domain,
|
uint8_t *msisdn_enc, size_t msisdn_enc_size,
|
||||||
void *talloc_ctx)
|
uint8_t *apn_buf, size_t apn_buf_size,
|
||||||
|
enum osmo_gsup_cn_domain cn_domain)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
uint8_t *msisdn_buf = talloc_size(talloc_ctx, OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN);
|
|
||||||
|
|
||||||
OSMO_ASSERT(gsup);
|
OSMO_ASSERT(gsup);
|
||||||
*gsup = (struct osmo_gsup_message){
|
*gsup = (struct osmo_gsup_message){
|
||||||
@@ -463,35 +489,33 @@ int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup,
|
|||||||
|
|
||||||
osmo_strlcpy(gsup->imsi, imsi, sizeof(gsup->imsi));
|
osmo_strlcpy(gsup->imsi, imsi, sizeof(gsup->imsi));
|
||||||
|
|
||||||
len = gsm48_encode_bcd_number(msisdn_buf, OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN, 0, msisdn);
|
if (msisdn_enc_size < OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN)
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
|
OSMO_ASSERT(msisdn_enc);
|
||||||
|
len = gsm48_encode_bcd_number(msisdn_enc, msisdn_enc_size, 0, msisdn);
|
||||||
if (len < 1) {
|
if (len < 1) {
|
||||||
LOGP(DLGSUP, LOGL_ERROR, "%s: Error: cannot encode MSISDN '%s'\n", imsi, msisdn);
|
LOGP(DLGSUP, LOGL_ERROR, "%s: Error: cannot encode MSISDN '%s'\n", imsi, msisdn);
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
}
|
||||||
gsup->msisdn_enc = msisdn_buf;
|
gsup->msisdn_enc = msisdn_enc;
|
||||||
gsup->msisdn_enc_len = len;
|
gsup->msisdn_enc_len = len;
|
||||||
|
|
||||||
#pragma message "FIXME: deal with encoding the following data: gsup.hlr_enc"
|
#pragma message "FIXME: deal with encoding the following data: gsup.hlr_enc"
|
||||||
|
|
||||||
gsup->cn_domain = cn_domain;
|
gsup->cn_domain = cn_domain;
|
||||||
if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS) {
|
if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS) {
|
||||||
if (g_hlr->ps.pdp_profile.enabled) {
|
OSMO_ASSERT(apn_buf_size >= APN_MAXLEN);
|
||||||
OSMO_ASSERT(g_hlr->ps.pdp_profile.num_pdp_infos <= ARRAY_SIZE(g_hlr->ps.pdp_profile.pdp_infos));
|
OSMO_ASSERT(apn_buf);
|
||||||
OSMO_ASSERT(g_hlr->ps.pdp_profile.num_pdp_infos <= ARRAY_SIZE(gsup->pdp_infos));
|
/* FIXME: PDP infos - use more fine-grained access control
|
||||||
memcpy(gsup->pdp_infos,
|
instead of wildcard APN */
|
||||||
g_hlr->ps.pdp_profile.pdp_infos,
|
osmo_gsup_configure_wildcard_apn(gsup, apn_buf, apn_buf_size);
|
||||||
sizeof(struct osmo_gsup_pdp_info) * g_hlr->ps.pdp_profile.num_pdp_infos);
|
|
||||||
gsup->num_pdp_infos = g_hlr->ps.pdp_profile.num_pdp_infos;
|
|
||||||
} else {
|
|
||||||
uint8_t *apn_buf = talloc_size(talloc_ctx, APN_MAXLEN);
|
|
||||||
osmo_gsup_configure_wildcard_apn(gsup, apn_buf, APN_MAXLEN);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_cni_peer_id *to_peer,
|
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_gsup_peer_id *to_peer,
|
||||||
struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup)
|
struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -500,22 +524,22 @@ int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struc
|
|||||||
* is required to return this as gsup->destination_name so that the reply gets routed to the original sender. */
|
* is required to return this as gsup->destination_name so that the reply gets routed to the original sender. */
|
||||||
struct osmo_gsup_message forward = *(modified_gsup? : &req->gsup);
|
struct osmo_gsup_message forward = *(modified_gsup? : &req->gsup);
|
||||||
|
|
||||||
if (req->source_name.type != OSMO_CNI_PEER_ID_IPA_NAME) {
|
if (req->source_name.type != OSMO_GSUP_PEER_ID_IPA_NAME) {
|
||||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",
|
||||||
osmo_cni_peer_id_type_name(req->source_name.type));
|
osmo_gsup_peer_id_type_name(req->source_name.type));
|
||||||
rc = -ENOTSUP;
|
rc = -ENOTSUP;
|
||||||
goto routing_error;
|
goto routing_error;
|
||||||
}
|
}
|
||||||
forward.source_name = req->source_name.ipa_name.val;
|
forward.source_name = req->source_name.ipa_name.val;
|
||||||
forward.source_name_len = req->source_name.ipa_name.len;
|
forward.source_name_len = req->source_name.ipa_name.len;
|
||||||
|
|
||||||
if (to_peer->type != OSMO_CNI_PEER_ID_IPA_NAME) {
|
if (to_peer->type != OSMO_GSUP_PEER_ID_IPA_NAME) {
|
||||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",
|
||||||
osmo_cni_peer_id_type_name(to_peer->type));
|
osmo_gsup_peer_id_type_name(to_peer->type));
|
||||||
rc = -ENOTSUP;
|
rc = -ENOTSUP;
|
||||||
goto routing_error;
|
goto routing_error;
|
||||||
}
|
}
|
||||||
LOG_GSUP_REQ(req, LOGL_INFO, "Forwarding to %s\n", osmo_cni_peer_id_to_str(to_peer));
|
LOG_GSUP_REQ(req, LOGL_INFO, "Forwarding to %s\n", osmo_gsup_peer_id_to_str(to_peer));
|
||||||
rc = osmo_gsup_enc_send_to_ipa_name(server, &to_peer->ipa_name, &forward);
|
rc = osmo_gsup_enc_send_to_ipa_name(server, &to_peer->ipa_name, &forward);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto routing_error;
|
goto routing_error;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# This is _NOT_ the library release version, it's an API version.
|
# This is _NOT_ the library release version, it's an API version.
|
||||||
# Please read chapter "Library interface versions" of the libtool documentation
|
# 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
|
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
|
||||||
LIBVERSION=1:0:1
|
LIBVERSION=0:0:0
|
||||||
|
|
||||||
AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include \
|
AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include \
|
||||||
$(TALLOC_CFLAGS) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOABIS_CFLAGS)
|
$(TALLOC_CFLAGS) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOABIS_CFLAGS)
|
||||||
@@ -9,7 +9,7 @@ AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/incl
|
|||||||
lib_LTLIBRARIES = libosmo-gsup-client.la
|
lib_LTLIBRARIES = libosmo-gsup-client.la
|
||||||
|
|
||||||
libosmo_gsup_client_la_SOURCES = \
|
libosmo_gsup_client_la_SOURCES = \
|
||||||
cni_peer_id.c \
|
gsup_peer_id.c \
|
||||||
gsup_client.c \
|
gsup_client.c \
|
||||||
gsup_req.c \
|
gsup_req.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|||||||
@@ -31,8 +31,6 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <netinet/tcp.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
static void start_test_procedure(struct osmo_gsup_client *gsupc);
|
static void start_test_procedure(struct osmo_gsup_client *gsupc);
|
||||||
|
|
||||||
@@ -131,19 +129,6 @@ static void gsup_client_oap_register(struct osmo_gsup_client *gsupc)
|
|||||||
client_send(gsupc, IPAC_PROTO_EXT_OAP, msg_tx);
|
client_send(gsupc, IPAC_PROTO_EXT_OAP, msg_tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_fd_settings(int fd)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
/*TODO: Set keepalive settings here. See OS#4312 */
|
|
||||||
|
|
||||||
val = 1;
|
|
||||||
ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
|
||||||
if (ret < 0)
|
|
||||||
LOGP(DLGSUP, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gsup_client_updown_cb(struct ipa_client_conn *link, int up)
|
static void gsup_client_updown_cb(struct ipa_client_conn *link, int up)
|
||||||
{
|
{
|
||||||
struct osmo_gsup_client *gsupc = link->data;
|
struct osmo_gsup_client *gsupc = link->data;
|
||||||
@@ -154,7 +139,6 @@ static void gsup_client_updown_cb(struct ipa_client_conn *link, int up)
|
|||||||
gsupc->is_connected = up;
|
gsupc->is_connected = up;
|
||||||
|
|
||||||
if (up) {
|
if (up) {
|
||||||
update_fd_settings(link->ofd->fd);
|
|
||||||
start_test_procedure(gsupc);
|
start_test_procedure(gsupc);
|
||||||
|
|
||||||
if (gsupc->oap_state.state == OSMO_OAP_INITIALIZED)
|
if (gsupc->oap_state.state == OSMO_OAP_INITIALIZED)
|
||||||
|
|||||||
@@ -19,9 +19,9 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
|
|
||||||
bool osmo_ipa_name_is_empty(const struct osmo_ipa_name *ipa_name)
|
bool osmo_ipa_name_is_empty(struct osmo_ipa_name *ipa_name)
|
||||||
{
|
{
|
||||||
return (!ipa_name) || (!ipa_name->len);
|
return (!ipa_name) || (!ipa_name->len);
|
||||||
}
|
}
|
||||||
@@ -90,61 +90,55 @@ int osmo_ipa_name_cmp(const struct osmo_ipa_name *a, const struct osmo_ipa_name
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call osmo_ipa_name_to_str_c with OTC_SELECT. */
|
|
||||||
const char *osmo_ipa_name_to_str(const struct osmo_ipa_name *ipa_name)
|
|
||||||
{
|
|
||||||
return osmo_ipa_name_to_str_c(OTC_SELECT, ipa_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return an unquoted string, not including the terminating zero. Used for writing VTY config. */
|
/* Return an unquoted string, not including the terminating zero. Used for writing VTY config. */
|
||||||
const char *osmo_ipa_name_to_str_c(void *ctx, const struct osmo_ipa_name *ipa_name)
|
const char *osmo_ipa_name_to_str(const struct osmo_ipa_name *ipa_name)
|
||||||
{
|
{
|
||||||
size_t len = ipa_name->len;
|
size_t len = ipa_name->len;
|
||||||
if (!len)
|
if (!len)
|
||||||
return talloc_strdup(ctx, "");
|
return "";
|
||||||
if (ipa_name->val[len-1] == '\0')
|
if (ipa_name->val[len-1] == '\0')
|
||||||
len--;
|
len--;
|
||||||
return osmo_escape_str_c(ctx, (char*)ipa_name->val, len);
|
return osmo_escape_str_c(OTC_SELECT, (char*)ipa_name->val, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool osmo_cni_peer_id_is_empty(const struct osmo_cni_peer_id *cni_peer_id)
|
bool osmo_gsup_peer_id_is_empty(struct osmo_gsup_peer_id *gsup_peer_id)
|
||||||
{
|
{
|
||||||
if (!cni_peer_id)
|
if (!gsup_peer_id)
|
||||||
return true;
|
return true;
|
||||||
switch (cni_peer_id->type) {
|
switch (gsup_peer_id->type) {
|
||||||
case OSMO_CNI_PEER_ID_EMPTY:
|
case OSMO_GSUP_PEER_ID_EMPTY:
|
||||||
return true;
|
return true;
|
||||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||||
return osmo_ipa_name_is_empty(&cni_peer_id->ipa_name);
|
return osmo_ipa_name_is_empty(&gsup_peer_id->ipa_name);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int osmo_cni_peer_id_set(struct osmo_cni_peer_id *cni_peer_id, enum osmo_cni_peer_id_type type,
|
int osmo_gsup_peer_id_set(struct osmo_gsup_peer_id *gsup_peer_id, enum osmo_gsup_peer_id_type type,
|
||||||
const uint8_t *val, size_t len)
|
const uint8_t *val, size_t len)
|
||||||
{
|
{
|
||||||
cni_peer_id->type = type;
|
gsup_peer_id->type = type;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||||
return osmo_ipa_name_set(&cni_peer_id->ipa_name, val, len);
|
return osmo_ipa_name_set(&gsup_peer_id->ipa_name, val, len);
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int osmo_cni_peer_id_set_str(struct osmo_cni_peer_id *cni_peer_id, enum osmo_cni_peer_id_type type,
|
int osmo_gsup_peer_id_set_str(struct osmo_gsup_peer_id *gsup_peer_id, enum osmo_gsup_peer_id_type type,
|
||||||
const char *str_fmt, ...)
|
const char *str_fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
*cni_peer_id = (struct osmo_cni_peer_id){};
|
*gsup_peer_id = (struct osmo_gsup_peer_id){};
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||||
cni_peer_id->type = OSMO_CNI_PEER_ID_IPA_NAME;
|
gsup_peer_id->type = OSMO_GSUP_PEER_ID_IPA_NAME;
|
||||||
va_start(ap, str_fmt);
|
va_start(ap, str_fmt);
|
||||||
rc = osmo_ipa_name_set_str_va(&cni_peer_id->ipa_name, str_fmt, ap);
|
rc = osmo_ipa_name_set_str_va(&gsup_peer_id->ipa_name, str_fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return rc;
|
return rc;
|
||||||
default:
|
default:
|
||||||
@@ -152,42 +146,30 @@ int osmo_cni_peer_id_set_str(struct osmo_cni_peer_id *cni_peer_id, enum osmo_cni
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int osmo_cni_peer_id_cmp(const struct osmo_cni_peer_id *a, const struct osmo_cni_peer_id *b)
|
int osmo_gsup_peer_id_cmp(const struct osmo_gsup_peer_id *a, const struct osmo_gsup_peer_id *b)
|
||||||
{
|
{
|
||||||
if (a == b)
|
|
||||||
return 0;
|
|
||||||
if (!a)
|
|
||||||
return -1;
|
|
||||||
if (!b)
|
|
||||||
return 1;
|
|
||||||
if (a->type != b->type)
|
if (a->type != b->type)
|
||||||
return OSMO_CMP(a->type, b->type);
|
return OSMO_CMP(a->type, b->type);
|
||||||
switch (a->type) {
|
switch (a->type) {
|
||||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||||
return osmo_ipa_name_cmp(&a->ipa_name, &b->ipa_name);
|
return osmo_ipa_name_cmp(&a->ipa_name, &b->ipa_name);
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct value_string osmo_cni_peer_id_type_names[] = {
|
const struct value_string osmo_gsup_peer_id_type_names[] = {
|
||||||
{ OSMO_CNI_PEER_ID_IPA_NAME, "IPA-name" },
|
{ OSMO_GSUP_PEER_ID_IPA_NAME, "IPA-name" },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Call osmo_cni_peer_id_to_str_c with OTC_SELECT */
|
|
||||||
const char *osmo_cni_peer_id_to_str(const struct osmo_cni_peer_id *cpi)
|
|
||||||
{
|
|
||||||
return osmo_cni_peer_id_to_str_c(OTC_SELECT, cpi);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return an unquoted string, not including the terminating zero. Used for writing VTY config. */
|
/* Return an unquoted string, not including the terminating zero. Used for writing VTY config. */
|
||||||
const char *osmo_cni_peer_id_to_str_c(void *ctx, const struct osmo_cni_peer_id *cpi)
|
const char *osmo_gsup_peer_id_to_str(const struct osmo_gsup_peer_id *gpi)
|
||||||
{
|
{
|
||||||
switch (cpi->type) {
|
switch (gpi->type) {
|
||||||
case OSMO_CNI_PEER_ID_IPA_NAME:
|
case OSMO_GSUP_PEER_ID_IPA_NAME:
|
||||||
return osmo_ipa_name_to_str_c(ctx, &cpi->ipa_name);
|
return osmo_ipa_name_to_str(&gpi->ipa_name);
|
||||||
default:
|
default:
|
||||||
return talloc_strdup(ctx, osmo_cni_peer_id_type_name(cpi->type));
|
return osmo_gsup_peer_id_type_name(gpi->type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,81 +25,26 @@
|
|||||||
#include <osmocom/gsupclient/gsup_req.h>
|
#include <osmocom/gsupclient/gsup_req.h>
|
||||||
|
|
||||||
/*! Create a new osmo_gsup_req record, decode GSUP and add to a provided list of requests.
|
/*! Create a new osmo_gsup_req record, decode GSUP and add to a provided list of requests.
|
||||||
*
|
|
||||||
* Rationales:
|
|
||||||
*
|
|
||||||
* - osmo_gsup_req makes it easy to handle GSUP requests asynchronously. Before this, a GSUP message struct would be
|
|
||||||
* valid only within a read callback function, and would not survive asynchronous handling, because the struct often
|
|
||||||
* points directly into the received msgb. An osmo_gsup_req takes ownership of the msgb and ensures that the data
|
|
||||||
* remains valid, so that it can easily be queued for later handling.
|
|
||||||
* - osmo_gsup_req unifies the composition of response messages to ensure that all IEs that identify it to belong to
|
|
||||||
* the initial request are preserved / derived, like the source_name, destination_name, session_id, etc (see
|
|
||||||
* osmo_gsup_make_response() for details).
|
|
||||||
* - Deallocation of an osmo_gsup_req is implicit upon sending a response. The idea is that msgb memory leaks are a
|
|
||||||
* recurring source of bugs. By enforcing a request-response relation with implicit deallocation, osmo_gsup_req aims
|
|
||||||
* to help avoid most such memory leaks implicitly.
|
|
||||||
*
|
|
||||||
* The typical GSUP message sequence is:
|
|
||||||
* -> rx request,
|
|
||||||
* <- tx response.
|
|
||||||
*
|
|
||||||
* With osmo_gsup_req we can easily expand to:
|
|
||||||
* -> rx request,
|
|
||||||
* ... wait asynchronously,
|
|
||||||
* <- tx response.
|
|
||||||
*
|
|
||||||
* Only few GSUP conversations go beyond a 1:1 request-response match. But some have a session (e.g. USSD) or more
|
|
||||||
* negotiation may happen before the initial request is completed (e.g. Update Location with interleaved Insert
|
|
||||||
* Subscriber Data), so osmo_gsup_req also allows passing non-final responses.
|
|
||||||
* The final_response flag allows for:
|
|
||||||
* -> rx request,
|
|
||||||
* ... wait async,
|
|
||||||
* <- tx intermediate message to same peer (final_response = false, req remains open),
|
|
||||||
* ... wait async,
|
|
||||||
* -> rx intermediate response,
|
|
||||||
* ... wait async,
|
|
||||||
* <- tx final response (final_response = true, req is deallocated).
|
|
||||||
*
|
|
||||||
* This function takes ownership of the msgb, which will, on success, be owned by the returned osmo_gsup_req instance
|
* This function takes ownership of the msgb, which will, on success, be owned by the returned osmo_gsup_req instance
|
||||||
* until osmo_gsup_req_free(). If a decoding error occurs, send an error response immediately, and return NULL.
|
* until osmo_gsup_req_free(). If a decoding error occurs, send an error response immediately, and return NULL.
|
||||||
*
|
*
|
||||||
* The original CNI entity that sent the message is found in req->source_name. If the message was passed on by an
|
* When this function returns, the original sender is found in req->source_name. If this is not the immediate peer name,
|
||||||
* intermediate CNI peer, then req->via_proxy is set to the immediate peer, and it is the responsibility of the caller
|
* then req->via_proxy is set to the immediate peer, and it is the responsibility of the caller to add req->source_name
|
||||||
* to add req->source_name to the GSUP routes that are serviced by req->via_proxy (usually not relevant for clients with
|
* to the GSUP routes that are serviced by req->via_proxy (usually not relevant for clients with a single GSUP conn).
|
||||||
* a single GSUP conn).
|
|
||||||
* Examples:
|
|
||||||
*
|
|
||||||
* "msc" ---> here
|
|
||||||
* source_name = "msc"
|
|
||||||
* via_proxy = <empty>
|
|
||||||
*
|
|
||||||
* "msc" ---> "proxy-HLR" ---> here (e.g. home HLR)
|
|
||||||
* source_name = "msc"
|
|
||||||
* via_proxy = "proxy-HLR"
|
|
||||||
*
|
|
||||||
* "msc" ---> "proxy-HLR" ---> "home-HLR" ---> here (e.g. EUSE)
|
|
||||||
* source_name = "msc"
|
|
||||||
* via_proxy = "home-HLR"
|
|
||||||
*
|
|
||||||
* An osmo_gsup_req must be concluded (and deallocated) by calling one of the osmo_gsup_req_respond* functions.
|
|
||||||
*
|
*
|
||||||
* Note: osmo_gsup_req API makes use of OTC_SELECT to allocate volatile buffers for logging. Use of
|
* Note: osmo_gsup_req API makes use of OTC_SELECT to allocate volatile buffers for logging. Use of
|
||||||
* osmo_select_main_ctx() is mandatory when using osmo_gsup_req.
|
* osmo_select_main_ctx() is mandatory when using osmo_gsup_req.
|
||||||
*
|
*
|
||||||
* \param[in] ctx Talloc context for allocation of the new request.
|
* \param[in] ctx Talloc context for allocation of the new request.
|
||||||
* \param[in] from_peer The IPA unit name of the immediate GSUP peer from which this msgb was received.
|
* \param[in] from_peer The IPA unit name of the immediate GSUP peer from which this msgb was received.
|
||||||
* \param[in] msg The message buffer containing the received GSUP message, where msgb_l2() shall point to the GSUP
|
* \param[in] msg The GSUP message buffer.
|
||||||
* message start. The caller no longer owns the msgb when it is passed to this function: on error, the
|
|
||||||
* msgb is freed immediately, and on success, the msgb is owned by the returned osmo_gsup_req.
|
|
||||||
* \param[in] send_response_cb User specific method to send a GSUP response message, invoked upon
|
* \param[in] send_response_cb User specific method to send a GSUP response message, invoked upon
|
||||||
* osmo_gsup_req_respond*() functions. Typically this invokes encoding and transmitting the
|
* osmo_gsup_req_respond*() functions.
|
||||||
* GSUP message over a network socket. See for example gsup_server_send_req_response().
|
|
||||||
* \param[inout] cb_data Context data to be used freely by the caller.
|
* \param[inout] cb_data Context data to be used freely by the caller.
|
||||||
* \param[inout] add_to_list List to which to append this request, or NULL for no list.
|
* \param[inout] add_to_list List to which to append this request, or NULL for no list.
|
||||||
* \return a newly allocated osmo_gsup_req, or NULL on error. If NULL is returned, an error response has already been
|
* \return a newly allocated osmo_gsup_req, or NULL on error.
|
||||||
* dispatched to the send_response_cb.
|
|
||||||
*/
|
*/
|
||||||
struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id *from_peer, struct msgb *msg,
|
struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_gsup_peer_id *from_peer, struct msgb *msg,
|
||||||
osmo_gsup_req_send_response_t send_response_cb, void *cb_data,
|
osmo_gsup_req_send_response_t send_response_cb, void *cb_data,
|
||||||
struct llist_head *add_to_list)
|
struct llist_head *add_to_list)
|
||||||
{
|
{
|
||||||
@@ -107,15 +52,9 @@ struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id
|
|||||||
struct osmo_gsup_req *req;
|
struct osmo_gsup_req *req;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!from_peer) {
|
|
||||||
LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from NULL peer is not allowed\n");
|
|
||||||
msgb_free(msg);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!msgb_l2(msg) || !msgb_l2len(msg)) {
|
if (!msgb_l2(msg) || !msgb_l2len(msg)) {
|
||||||
LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from %s: missing or empty L2 data\n",
|
LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from %s: missing or empty L2 data\n",
|
||||||
osmo_cni_peer_id_to_str(from_peer));
|
osmo_gsup_peer_id_to_str(from_peer));
|
||||||
msgb_free(msg);
|
msgb_free(msg);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -127,10 +66,11 @@ struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id
|
|||||||
req->msg = msg;
|
req->msg = msg;
|
||||||
req->send_response_cb = send_response_cb;
|
req->send_response_cb = send_response_cb;
|
||||||
req->cb_data = cb_data;
|
req->cb_data = cb_data;
|
||||||
|
if (from_peer)
|
||||||
req->source_name = *from_peer;
|
req->source_name = *from_peer;
|
||||||
rc = osmo_gsup_decode(msgb_l2(req->msg), msgb_l2len(req->msg), (struct osmo_gsup_message*)&req->gsup);
|
rc = osmo_gsup_decode(msgb_l2(req->msg), msgb_l2len(req->msg), (struct osmo_gsup_message*)&req->gsup);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from %s: cannot decode (rc=%d)\n", osmo_cni_peer_id_to_str(from_peer), rc);
|
LOGP(DLGSUP, LOGL_ERROR, "Rx GSUP from %s: cannot decode (rc=%d)\n", osmo_gsup_peer_id_to_str(from_peer), rc);
|
||||||
osmo_gsup_req_free(req);
|
osmo_gsup_req_free(req);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -138,18 +78,18 @@ struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id
|
|||||||
LOG_GSUP_REQ(req, LOGL_DEBUG, "new request: {%s}\n", osmo_gsup_message_to_str_c(OTC_SELECT, &req->gsup));
|
LOG_GSUP_REQ(req, LOGL_DEBUG, "new request: {%s}\n", osmo_gsup_message_to_str_c(OTC_SELECT, &req->gsup));
|
||||||
|
|
||||||
if (req->gsup.source_name_len) {
|
if (req->gsup.source_name_len) {
|
||||||
if (osmo_cni_peer_id_set(&req->source_name, OSMO_CNI_PEER_ID_IPA_NAME,
|
if (osmo_gsup_peer_id_set(&req->source_name, OSMO_GSUP_PEER_ID_IPA_NAME,
|
||||||
req->gsup.source_name, req->gsup.source_name_len)) {
|
req->gsup.source_name, req->gsup.source_name_len)) {
|
||||||
LOGP(DLGSUP, LOGL_ERROR,
|
LOGP(DLGSUP, LOGL_ERROR,
|
||||||
"Rx GSUP from %s: failed to decode source_name, message is not routable\n",
|
"Rx GSUP from %s: failed to decode source_name, message is not routable\n",
|
||||||
osmo_cni_peer_id_to_str(from_peer));
|
osmo_gsup_peer_id_to_str(from_peer));
|
||||||
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);
|
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_ROUTING_ERROR, true);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The source of the GSUP message is not the immediate GSUP peer; the peer is our proxy for that source.
|
/* The source of the GSUP message is not the immediate GSUP peer; the peer is our proxy for that source.
|
||||||
*/
|
*/
|
||||||
if (osmo_cni_peer_id_cmp(&req->source_name, from_peer))
|
if (osmo_gsup_peer_id_cmp(&req->source_name, from_peer))
|
||||||
req->via_proxy = *from_peer;
|
req->via_proxy = *from_peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,8 +104,6 @@ struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id
|
|||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Free an osmo_gsup_req and its msgb -- this is usually implicit in osmo_gsup_req_resond_*(), it should not be
|
|
||||||
* necessary to call this directly. */
|
|
||||||
void osmo_gsup_req_free(struct osmo_gsup_req *req)
|
void osmo_gsup_req_free(struct osmo_gsup_req *req)
|
||||||
{
|
{
|
||||||
LOG_GSUP_REQ(req, LOGL_DEBUG, "free\n");
|
LOG_GSUP_REQ(req, LOGL_DEBUG, "free\n");
|
||||||
@@ -176,25 +114,6 @@ void osmo_gsup_req_free(struct osmo_gsup_req *req)
|
|||||||
talloc_free(req);
|
talloc_free(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Send a response to a GSUP request.
|
|
||||||
*
|
|
||||||
* Ensure that the response message contains all GSUP IEs that identify it as a response for the request req, by calling
|
|
||||||
* osmo_gsup_make_response().
|
|
||||||
*
|
|
||||||
* The final complete response message is passed to req->send_response_cb() to take care of the transmission.
|
|
||||||
*
|
|
||||||
* \param req Request as previously initialized by osmo_gsup_req_new().
|
|
||||||
* \param response Buffer to compose the response, possibly with some pre-configured IEs.
|
|
||||||
* Any missing IEs are added via osmo_gsup_make_response().
|
|
||||||
* Must not be NULL. Does not need to remain valid memory beyond the function call,
|
|
||||||
* i.e. this can just be a local variable in the calling function.
|
|
||||||
* \param error True when the response message indicates an error response (error message type).
|
|
||||||
* \param final_response True when the request is concluded by this response, which deallocates the req.
|
|
||||||
* False when the request should remain open after this response.
|
|
||||||
* For most plain request->response GSUP messages, this should be True.
|
|
||||||
* \param file Source file for logging as in __FILE__, added by osmo_gsup_req_respond() macro.
|
|
||||||
* \param line Source line for logging as in __LINE__, added by osmo_gsup_req_respond() macro.
|
|
||||||
*/
|
|
||||||
int _osmo_gsup_req_respond(struct osmo_gsup_req *req, struct osmo_gsup_message *response,
|
int _osmo_gsup_req_respond(struct osmo_gsup_req *req, struct osmo_gsup_message *response,
|
||||||
bool error, bool final_response, const char *file, int line)
|
bool error, bool final_response, const char *file, int line)
|
||||||
{
|
{
|
||||||
@@ -225,18 +144,6 @@ exit_cleanup:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Shorthand for _osmo_gsup_req_respond() with no additional IEs and a fixed message type.
|
|
||||||
* Set the message type in a local osmo_gsup_message and feed it to _osmo_gsup_req_respond().
|
|
||||||
* That will ensure to add all IEs that identify it as a response to req.
|
|
||||||
*
|
|
||||||
* \param req Request as previously initialized by osmo_gsup_req_new().
|
|
||||||
* \param message_type The GSUP message type discriminator to respond with.
|
|
||||||
* \param final_response True when the request is concluded by this response, which deallocates the req.
|
|
||||||
* False when the request should remain open after this response.
|
|
||||||
* For most plain request->response GSUP messages, this should be True.
|
|
||||||
* \param file Source file for logging as in __FILE__, added by osmo_gsup_req_respond_msgt() macro.
|
|
||||||
* \param line Source line for logging as in __LINE__, added by osmo_gsup_req_respond_msgt() macro.
|
|
||||||
*/
|
|
||||||
int _osmo_gsup_req_respond_msgt(struct osmo_gsup_req *req, enum osmo_gsup_message_type message_type,
|
int _osmo_gsup_req_respond_msgt(struct osmo_gsup_req *req, enum osmo_gsup_message_type message_type,
|
||||||
bool final_response, const char *file, int line)
|
bool final_response, const char *file, int line)
|
||||||
{
|
{
|
||||||
@@ -247,17 +154,6 @@ int _osmo_gsup_req_respond_msgt(struct osmo_gsup_req *req, enum osmo_gsup_messag
|
|||||||
file, line);
|
file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Shorthand for _osmo_gsup_req_respond() with an error cause IEs and using the req's matched error message type.
|
|
||||||
* Set the error cause in a local osmo_gsup_message and feed it to _osmo_gsup_req_respond().
|
|
||||||
* That will ensure to add all IEs that identify it as a response to req.
|
|
||||||
*
|
|
||||||
* Responding with an error always implies a final response: req is implicitly deallocated.
|
|
||||||
*
|
|
||||||
* \param req Request as previously initialized by osmo_gsup_req_new().
|
|
||||||
* \param cause The error cause to include in a OSMO_GSUP_CAUSE_IE.
|
|
||||||
* \param file Source file for logging as in __FILE__, added by osmo_gsup_req_respond_err() macro.
|
|
||||||
* \param line Source line for logging as in __LINE__, added by osmo_gsup_req_respond_err() macro.
|
|
||||||
*/
|
|
||||||
void _osmo_gsup_req_respond_err(struct osmo_gsup_req *req, enum gsm48_gmm_cause cause,
|
void _osmo_gsup_req_respond_err(struct osmo_gsup_req *req, enum gsm48_gmm_cause cause,
|
||||||
const char *file, int line)
|
const char *file, int line)
|
||||||
{
|
{
|
||||||
|
|||||||
89
src/hlr.c
89
src/hlr.c
@@ -31,7 +31,6 @@
|
|||||||
#include <osmocom/vty/command.h>
|
#include <osmocom/vty/command.h>
|
||||||
#include <osmocom/vty/telnet_interface.h>
|
#include <osmocom/vty/telnet_interface.h>
|
||||||
#include <osmocom/vty/ports.h>
|
#include <osmocom/vty/ports.h>
|
||||||
#include <osmocom/vty/cpu_sched_vty.h>
|
|
||||||
#include <osmocom/ctrl/control_vty.h>
|
#include <osmocom/ctrl/control_vty.h>
|
||||||
#include <osmocom/gsm/apn.h>
|
#include <osmocom/gsm/apn.h>
|
||||||
#include <osmocom/gsm/gsm48_ie.h>
|
#include <osmocom/gsm/gsm48_ie.h>
|
||||||
@@ -39,7 +38,7 @@
|
|||||||
#include <osmocom/gsm/gsm23003.h>
|
#include <osmocom/gsm/gsm23003.h>
|
||||||
#include <osmocom/mslookup/mslookup_client.h>
|
#include <osmocom/mslookup/mslookup_client.h>
|
||||||
|
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
#include <osmocom/hlr/db.h>
|
#include <osmocom/hlr/db.h>
|
||||||
#include <osmocom/hlr/hlr.h>
|
#include <osmocom/hlr/hlr.h>
|
||||||
#include <osmocom/hlr/ctrl.h>
|
#include <osmocom/hlr/ctrl.h>
|
||||||
@@ -52,6 +51,7 @@
|
|||||||
#include <osmocom/hlr/dgsm.h>
|
#include <osmocom/hlr/dgsm.h>
|
||||||
#include <osmocom/hlr/proxy.h>
|
#include <osmocom/hlr/proxy.h>
|
||||||
#include <osmocom/hlr/lu_fsm.h>
|
#include <osmocom/hlr/lu_fsm.h>
|
||||||
|
#include <osmocom/hlr/sms_over_gsup.h>
|
||||||
#include <osmocom/mslookup/mdns.h>
|
#include <osmocom/mslookup/mdns.h>
|
||||||
|
|
||||||
struct hlr *g_hlr;
|
struct hlr *g_hlr;
|
||||||
@@ -85,6 +85,8 @@ osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
|
|||||||
|
|
||||||
llist_for_each_entry(co, &g_hlr->gs->clients, list) {
|
llist_for_each_entry(co, &g_hlr->gs->clients, list) {
|
||||||
struct osmo_gsup_message gsup = { };
|
struct osmo_gsup_message gsup = { };
|
||||||
|
uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];
|
||||||
|
uint8_t apn[APN_MAXLEN];
|
||||||
struct msgb *msg_out;
|
struct msgb *msg_out;
|
||||||
uint8_t *peer;
|
uint8_t *peer;
|
||||||
int peer_len;
|
int peer_len;
|
||||||
@@ -129,7 +131,8 @@ osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
|
|||||||
subscr->imsi, cn_domain == OSMO_GSUP_CN_DOMAIN_PS ? "PS" : "CS",
|
subscr->imsi, cn_domain == OSMO_GSUP_CN_DOMAIN_PS ? "PS" : "CS",
|
||||||
osmo_quote_str(peer_compare, -1));
|
osmo_quote_str(peer_compare, -1));
|
||||||
|
|
||||||
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi, subscr->msisdn, cn_domain, OTC_SELECT) != 0) {
|
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi, subscr->msisdn, msisdn_enc,
|
||||||
|
sizeof(msisdn_enc), apn, sizeof(apn), cn_domain) != 0) {
|
||||||
LOGP(DLGSUP, LOGL_ERROR,
|
LOGP(DLGSUP, LOGL_ERROR,
|
||||||
"IMSI='%s': Cannot notify GSUP client; could not create gsup message "
|
"IMSI='%s': Cannot notify GSUP client; could not create gsup message "
|
||||||
"for %s:%u\n", subscr->imsi,
|
"for %s:%u\n", subscr->imsi,
|
||||||
@@ -266,9 +269,9 @@ int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val,
|
|||||||
if (nam_val)
|
if (nam_val)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (subscr->vlr_number[0] && !osmo_ipa_name_set_str(&vlr_name, subscr->vlr_number))
|
if (subscr->vlr_number && osmo_ipa_name_set_str(&vlr_name, subscr->vlr_number))
|
||||||
osmo_gsup_enc_send_to_ipa_name(g_hlr->gs, &vlr_name, &gsup_del_data);
|
osmo_gsup_enc_send_to_ipa_name(g_hlr->gs, &vlr_name, &gsup_del_data);
|
||||||
if (subscr->sgsn_number[0] && !osmo_ipa_name_set_str(&vlr_name, subscr->sgsn_number))
|
if (subscr->sgsn_number && osmo_ipa_name_set_str(&vlr_name, subscr->sgsn_number))
|
||||||
osmo_gsup_enc_send_to_ipa_name(g_hlr->gs, &vlr_name, &gsup_del_data);
|
osmo_gsup_enc_send_to_ipa_name(g_hlr->gs, &vlr_name, &gsup_del_data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -284,7 +287,6 @@ static int rx_send_auth_info(struct osmo_gsup_req *req)
|
|||||||
.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT,
|
.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT,
|
||||||
};
|
};
|
||||||
bool separation_bit = false;
|
bool separation_bit = false;
|
||||||
int num_auth_vectors = OSMO_GSUP_MAX_NUM_AUTH_INFO;
|
|
||||||
unsigned int auc_3g_ind;
|
unsigned int auc_3g_ind;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -293,21 +295,18 @@ static int rx_send_auth_info(struct osmo_gsup_req *req)
|
|||||||
if (req->gsup.current_rat_type == OSMO_RAT_EUTRAN_SGS)
|
if (req->gsup.current_rat_type == OSMO_RAT_EUTRAN_SGS)
|
||||||
separation_bit = true;
|
separation_bit = true;
|
||||||
|
|
||||||
if (req->gsup.num_auth_vectors > 0 &&
|
|
||||||
req->gsup.num_auth_vectors <= OSMO_GSUP_MAX_NUM_AUTH_INFO)
|
|
||||||
num_auth_vectors = req->gsup.num_auth_vectors;
|
|
||||||
rc = db_ind(g_hlr->dbc, &req->source_name, &auc_3g_ind);
|
rc = db_ind(g_hlr->dbc, &req->source_name, &auc_3g_ind);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
LOG_GSUP_REQ(req, LOGL_ERROR,
|
LOG_GSUP_REQ(req, LOGL_ERROR,
|
||||||
"Unable to determine 3G auth IND for source %s (rc=%d),"
|
"Unable to determine 3G auth IND for source %s (rc=%d),"
|
||||||
" generating tuples with IND = 0\n",
|
" generating tuples with IND = 0\n",
|
||||||
osmo_cni_peer_id_to_str(&req->source_name), rc);
|
osmo_gsup_peer_id_to_str(&req->source_name), rc);
|
||||||
auc_3g_ind = 0;
|
auc_3g_ind = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = db_get_auc(g_hlr->dbc, req->gsup.imsi, auc_3g_ind,
|
rc = db_get_auc(g_hlr->dbc, req->gsup.imsi, auc_3g_ind,
|
||||||
gsup_out.auth_vectors,
|
gsup_out.auth_vectors,
|
||||||
num_auth_vectors,
|
ARRAY_SIZE(gsup_out.auth_vectors),
|
||||||
req->gsup.rand, req->gsup.auts, separation_bit);
|
req->gsup.rand, req->gsup.auts, separation_bit);
|
||||||
|
|
||||||
if (rc <= 0) {
|
if (rc <= 0) {
|
||||||
@@ -321,7 +320,7 @@ static int rx_send_auth_info(struct osmo_gsup_req *req)
|
|||||||
" Returning slightly inaccurate cause 'IMSI Unknown' via GSUP");
|
" Returning slightly inaccurate cause 'IMSI Unknown' via GSUP");
|
||||||
return rc;
|
return rc;
|
||||||
case -ENOENT:
|
case -ENOENT:
|
||||||
osmo_gsup_req_respond_err(req, g_hlr->reject_cause, "IMSI unknown");
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_ROAMING_NOTALLOWED, "IMSI unknown");
|
||||||
return rc;
|
return rc;
|
||||||
default:
|
default:
|
||||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "failure to look up IMSI in db");
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "failure to look up IMSI in db");
|
||||||
@@ -373,7 +372,7 @@ static int rx_purge_ms_req(struct osmo_gsup_req *req)
|
|||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_PURGE_MS_RESULT, true);
|
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_PURGE_MS_RESULT, true);
|
||||||
else if (rc == -ENOENT)
|
else if (rc == -ENOENT)
|
||||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "IMSI unknown");
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_ROAMING_NOTALLOWED, "IMSI unknown");
|
||||||
else
|
else
|
||||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "db error");
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "db error");
|
||||||
return rc;
|
return rc;
|
||||||
@@ -455,8 +454,8 @@ static int read_cb_forward(struct osmo_gsup_req *req)
|
|||||||
struct osmo_ipa_name destination_name;
|
struct osmo_ipa_name destination_name;
|
||||||
|
|
||||||
/* Check for routing IEs */
|
/* Check for routing IEs */
|
||||||
if (!req->gsup.source_name || !req->gsup.source_name_len
|
if (!req->gsup.source_name[0] || !req->gsup.source_name_len
|
||||||
|| !req->gsup.destination_name || !req->gsup.destination_name_len) {
|
|| !req->gsup.destination_name[0] || !req->gsup.destination_name_len) {
|
||||||
LOGP_GSUP_FWD(&req->gsup, LOGL_ERROR, "missing routing IEs\n");
|
LOGP_GSUP_FWD(&req->gsup, LOGL_ERROR, "missing routing IEs\n");
|
||||||
goto routing_error;
|
goto routing_error;
|
||||||
}
|
}
|
||||||
@@ -510,6 +509,10 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SMS over GSUP */
|
||||||
|
if (sms_over_gsup_check_handle_msg(req))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Distributed GSM: check whether to proxy for / lookup a remote HLR.
|
/* Distributed GSM: check whether to proxy for / lookup a remote HLR.
|
||||||
* It would require less database hits to do this only if a local-only operation fails with "unknown IMSI", but
|
* It would require less database hits to do this only if a local-only operation fails with "unknown IMSI", but
|
||||||
* it becomes semantically easier if we do this once-off ahead of time. */
|
* it becomes semantically easier if we do this once-off ahead of time. */
|
||||||
@@ -565,12 +568,12 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_usage(void)
|
static void print_usage()
|
||||||
{
|
{
|
||||||
printf("Usage: osmo-hlr\n");
|
printf("Usage: osmo-hlr\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_help(void)
|
static void print_help()
|
||||||
{
|
{
|
||||||
printf(" -h --help This text.\n");
|
printf(" -h --help This text.\n");
|
||||||
printf(" -c --config-file filename The config file to use.\n");
|
printf(" -c --config-file filename The config file to use.\n");
|
||||||
@@ -583,10 +586,6 @@ static void print_help(void)
|
|||||||
printf(" -U --db-upgrade Allow HLR database schema upgrades.\n");
|
printf(" -U --db-upgrade Allow HLR database schema upgrades.\n");
|
||||||
printf(" -C --db-check Quit after opening (and upgrading) the database.\n");
|
printf(" -C --db-check Quit after opening (and upgrading) the database.\n");
|
||||||
printf(" -V --version Print the version of OsmoHLR.\n");
|
printf(" -V --version Print the version of OsmoHLR.\n");
|
||||||
|
|
||||||
printf("\nVTY reference generation:\n");
|
|
||||||
printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n");
|
|
||||||
printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
@@ -602,37 +601,10 @@ static struct {
|
|||||||
.db_upgrade = false,
|
.db_upgrade = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void handle_long_options(const char *prog_name, const int long_option)
|
|
||||||
{
|
|
||||||
static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
|
|
||||||
|
|
||||||
switch (long_option) {
|
|
||||||
case 1:
|
|
||||||
vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
|
|
||||||
if (vty_ref_mode < 0) {
|
|
||||||
fprintf(stderr, "%s: Unknown VTY reference generation "
|
|
||||||
"mode '%s'\n", prog_name, optarg);
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
|
|
||||||
get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
|
|
||||||
get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
|
|
||||||
vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
|
|
||||||
exit(0);
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_options(int argc, char **argv)
|
static void handle_options(int argc, char **argv)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0, c;
|
int option_index = 0, c;
|
||||||
static int long_option = 0;
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"help", 0, 0, 'h'},
|
{"help", 0, 0, 'h'},
|
||||||
{"config-file", 1, 0, 'c'},
|
{"config-file", 1, 0, 'c'},
|
||||||
@@ -645,8 +617,6 @@ static void handle_options(int argc, char **argv)
|
|||||||
{"db-upgrade", 0, 0, 'U' },
|
{"db-upgrade", 0, 0, 'U' },
|
||||||
{"db-check", 0, 0, 'C' },
|
{"db-check", 0, 0, 'C' },
|
||||||
{"version", 0, 0, 'V' },
|
{"version", 0, 0, 'V' },
|
||||||
{"vty-ref-mode", 1, &long_option, 1},
|
|
||||||
{"vty-ref-xml", 0, &long_option, 2},
|
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -656,9 +626,6 @@ static void handle_options(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 0:
|
|
||||||
handle_long_options(argv[0], long_option);
|
|
||||||
break;
|
|
||||||
case 'h':
|
case 'h':
|
||||||
print_usage();
|
print_usage();
|
||||||
print_help();
|
print_help();
|
||||||
@@ -724,7 +691,7 @@ static void signal_hdlr(int signal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char vlr_copyright[] =
|
static const char vlr_copyright[] =
|
||||||
"Copyright (C) 2016-2023 by Harald Welte, sysmocom s.f.m.c. GmbH\r\n"
|
"Copyright (C) 2016, 2017 by Harald Welte, sysmocom s.f.m.c. GmbH\r\n"
|
||||||
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
|
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
|
||||||
"This is free software: you are free to change and redistribute it.\r\n"
|
"This is free software: you are free to change and redistribute it.\r\n"
|
||||||
"There is NO WARRANTY, to the extent permitted by law.\r\n";
|
"There is NO WARRANTY, to the extent permitted by law.\r\n";
|
||||||
@@ -750,18 +717,19 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
g_hlr = talloc_zero(hlr_ctx, struct hlr);
|
g_hlr = talloc_zero(hlr_ctx, struct hlr);
|
||||||
INIT_LLIST_HEAD(&g_hlr->euse_list);
|
INIT_LLIST_HEAD(&g_hlr->euse_list);
|
||||||
|
INIT_LLIST_HEAD(&g_hlr->iuse_list);
|
||||||
INIT_LLIST_HEAD(&g_hlr->ss_sessions);
|
INIT_LLIST_HEAD(&g_hlr->ss_sessions);
|
||||||
INIT_LLIST_HEAD(&g_hlr->ussd_routes);
|
INIT_LLIST_HEAD(&g_hlr->ussd_routes);
|
||||||
INIT_LLIST_HEAD(&g_hlr->mslookup.server.local_site_services);
|
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->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.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->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;
|
|
||||||
|
|
||||||
/* Init default (call independent) SS session guard timeout value */
|
/* Init default (call independent) SS session guard timeout value */
|
||||||
g_hlr->ncss_guard_timeout = NCSS_GUARD_TIMEOUT_DEFAULT;
|
g_hlr->ncss_guard_timeout = NCSS_GUARD_TIMEOUT_DEFAULT;
|
||||||
|
|
||||||
|
g_hlr->sms_over_gsup.try_direct_delivery = true;
|
||||||
|
|
||||||
rc = osmo_init_logging2(hlr_ctx, &hlr_log_info);
|
rc = osmo_init_logging2(hlr_ctx, &hlr_log_info);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
fprintf(stderr, "Error initializing logging\n");
|
fprintf(stderr, "Error initializing logging\n");
|
||||||
@@ -774,10 +742,9 @@ int main(int argc, char **argv)
|
|||||||
osmo_stats_init(hlr_ctx);
|
osmo_stats_init(hlr_ctx);
|
||||||
vty_init(&vty_info);
|
vty_init(&vty_info);
|
||||||
ctrl_vty_init(hlr_ctx);
|
ctrl_vty_init(hlr_ctx);
|
||||||
hlr_vty_init(hlr_ctx);
|
|
||||||
dgsm_vty_init();
|
|
||||||
osmo_cpu_sched_vty_init(hlr_ctx);
|
|
||||||
handle_options(argc, argv);
|
handle_options(argc, argv);
|
||||||
|
hlr_vty_init();
|
||||||
|
dgsm_vty_init();
|
||||||
|
|
||||||
rc = vty_read_config_file(cmdline_opts.config_file, NULL);
|
rc = vty_read_config_file(cmdline_opts.config_file, NULL);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
@@ -815,7 +782,8 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* start telnet after reading config for vty_get_bind_addr() */
|
/* start telnet after reading config for vty_get_bind_addr() */
|
||||||
rc = telnet_init_default(hlr_ctx, NULL, OSMO_VTY_PORT_HLR);
|
rc = telnet_init_dynif(hlr_ctx, NULL, vty_get_bind_addr(),
|
||||||
|
OSMO_VTY_PORT_HLR);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@@ -828,6 +796,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
proxy_init(g_hlr->gs);
|
proxy_init(g_hlr->gs);
|
||||||
|
|
||||||
|
g_hlr->ctrl_bind_addr = ctrl_vty_get_bind_addr();
|
||||||
g_hlr->ctrl = hlr_controlif_setup(g_hlr);
|
g_hlr->ctrl = hlr_controlif_setup(g_hlr);
|
||||||
|
|
||||||
dgsm_start(hlr_ctx);
|
dgsm_start(hlr_ctx);
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <osmocom/core/logging.h>
|
#include <osmocom/core/logging.h>
|
||||||
#include <osmocom/core/application.h>
|
#include <osmocom/core/application.h>
|
||||||
@@ -51,7 +50,7 @@ static struct {
|
|||||||
.db_upgrade = false,
|
.db_upgrade = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void print_help(void)
|
static void print_help()
|
||||||
{
|
{
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Usage: osmo-hlr-db-tool [-l <hlr.db>] [create|import-nitb-db <nitb.db>]\n");
|
printf("Usage: osmo-hlr-db-tool [-l <hlr.db>] [create|import-nitb-db <nitb.db>]\n");
|
||||||
@@ -71,9 +70,8 @@ static void print_help(void)
|
|||||||
printf(" (All commands imply this if none exists yet.)\n");
|
printf(" (All commands imply this if none exists yet.)\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" import-nitb-db <nitb.db> Add OsmoNITB db's subscribers to OsmoHLR db.\n");
|
printf(" import-nitb-db <nitb.db> Add OsmoNITB db's subscribers to OsmoHLR db.\n");
|
||||||
printf(" Be aware that the import is somewhat lossy, only the IMSI,\n");
|
printf(" Be aware that the import is lossy, only the\n");
|
||||||
printf(" MSISDN, IMEI, nam_cs/ps, 2G auth data and last seen LU are set.\n");
|
printf(" IMSI, MSISDN, nam_cs/ps and 2G auth data are set.\n");
|
||||||
printf(" The most recently associated IMEI from the Equipment table is used.\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_version(int print_copyright)
|
static void print_version(int print_copyright)
|
||||||
@@ -214,15 +212,9 @@ enum nitb_stmt {
|
|||||||
|
|
||||||
static const char *nitb_stmt_sql[] = {
|
static const char *nitb_stmt_sql[] = {
|
||||||
[NITB_SELECT_SUBSCR] =
|
[NITB_SELECT_SUBSCR] =
|
||||||
"SELECT s.imsi, s.id, s.extension, s.authorized,"
|
"SELECT imsi, id, extension, authorized"
|
||||||
" SUBSTR(e.imei,0,15), STRFTIME('%s', s.expire_lu)"
|
" FROM Subscriber"
|
||||||
" FROM Subscriber s LEFT JOIN"
|
" ORDER BY id",
|
||||||
" (SELECT imei, subscriber_id, MAX(Equipment.updated) AS updated"
|
|
||||||
" FROM Equipment,EquipmentWatch"
|
|
||||||
" WHERE Equipment.id = EquipmentWatch.equipment_id"
|
|
||||||
" GROUP BY EquipmentWatch.subscriber_id) e"
|
|
||||||
" ON e.subscriber_id = s.id"
|
|
||||||
" ORDER by s.id",
|
|
||||||
[NITB_SELECT_AUTH_KEYS] =
|
[NITB_SELECT_AUTH_KEYS] =
|
||||||
"SELECT algorithm_id, a3a8_ki from authkeys"
|
"SELECT algorithm_id, a3a8_ki from authkeys"
|
||||||
" WHERE subscriber_id = $subscr_id",
|
" WHERE subscriber_id = $subscr_id",
|
||||||
@@ -230,65 +222,8 @@ static const char *nitb_stmt_sql[] = {
|
|||||||
|
|
||||||
sqlite3_stmt *nitb_stmt[ARRAY_SIZE(nitb_stmt_sql)] = {};
|
sqlite3_stmt *nitb_stmt[ARRAY_SIZE(nitb_stmt_sql)] = {};
|
||||||
|
|
||||||
enum hlr_db_stmt {
|
|
||||||
HLR_DB_STMT_SET_IMPLICIT_LU_BY_IMSI,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *hlr_db_stmt_sql[] = {
|
|
||||||
[HLR_DB_STMT_SET_IMPLICIT_LU_BY_IMSI] =
|
|
||||||
"UPDATE subscriber SET last_lu_seen = datetime($last_lu, 'unixepoch') WHERE imsi = $imsi",
|
|
||||||
};
|
|
||||||
|
|
||||||
sqlite3_stmt *hlr_db_stmt[ARRAY_SIZE(hlr_db_stmt_sql)] = {};
|
|
||||||
|
|
||||||
size_t _dbd_decode_binary(const unsigned char *in, unsigned char *out);
|
size_t _dbd_decode_binary(const unsigned char *in, unsigned char *out);
|
||||||
|
|
||||||
/*! Set a subscriber's LU timestamp in the HLR database.
|
|
||||||
* In normal operations there is never any need to explicitly
|
|
||||||
* update the value of last_lu_seen, so this function can live here.
|
|
||||||
*
|
|
||||||
* \param[in,out] dbc database context.
|
|
||||||
* \param[in] imsi ASCII string of IMSI digits
|
|
||||||
* \param[in] imei ASCII string of identifier digits, or NULL to remove the IMEI.
|
|
||||||
* \returns 0 on success, -ENOENT when the given subscriber does not exist,
|
|
||||||
* -EIO on database errors.
|
|
||||||
*/
|
|
||||||
int db_subscr_update_lu_by_imsi(struct db_context *dbc, const char* imsi, const int last_lu)
|
|
||||||
{
|
|
||||||
int rc, ret = 0;
|
|
||||||
|
|
||||||
sqlite3_stmt *stmt = hlr_db_stmt[HLR_DB_STMT_SET_IMPLICIT_LU_BY_IMSI];
|
|
||||||
|
|
||||||
if (!db_bind_text(stmt, "$imsi", imsi))
|
|
||||||
return -EIO;
|
|
||||||
if (last_lu && !db_bind_int(stmt, "$last_lu", last_lu))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
/* execute the statement */
|
|
||||||
rc = sqlite3_step(stmt);
|
|
||||||
if (rc != SQLITE_DONE) {
|
|
||||||
LOGP(DAUC, LOGL_ERROR, "Update last_lu_seen for subscriber IMSI='%s': SQL Error: %s\n", imsi,
|
|
||||||
sqlite3_errmsg(dbc->db));
|
|
||||||
ret = -EIO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* verify execution result */
|
|
||||||
rc = sqlite3_changes(dbc->db);
|
|
||||||
if (!rc) {
|
|
||||||
LOGP(DAUC, LOGL_ERROR, "Cannot update last_lu_seen for subscriber IMSI='%s': no such subscriber\n", imsi);
|
|
||||||
ret = -ENOENT;
|
|
||||||
} else if (rc != 1) {
|
|
||||||
LOGP(DAUC, LOGL_ERROR, "Update last_lu_seen for subscriber IMSI='%s': SQL modified %d rows (expected 1)\n",
|
|
||||||
imsi, rc);
|
|
||||||
ret = -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
db_remove_reset(stmt);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void import_nitb_subscr_aud(sqlite3 *nitb_db, const char *imsi, int64_t nitb_id, int64_t hlr_id)
|
void import_nitb_subscr_aud(sqlite3 *nitb_db, const char *imsi, int64_t nitb_id, int64_t hlr_id)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -362,7 +297,6 @@ void import_nitb_subscr(sqlite3 *nitb_db, sqlite3_stmt *stmt)
|
|||||||
int64_t imsi;
|
int64_t imsi;
|
||||||
char imsi_str[32];
|
char imsi_str[32];
|
||||||
bool authorized;
|
bool authorized;
|
||||||
int last_lu_int;
|
|
||||||
|
|
||||||
imsi = sqlite3_column_int64(stmt, 0);
|
imsi = sqlite3_column_int64(stmt, 0);
|
||||||
|
|
||||||
@@ -381,18 +315,8 @@ void import_nitb_subscr(sqlite3 *nitb_db, sqlite3_stmt *stmt)
|
|||||||
nitb_id = sqlite3_column_int64(stmt, 1);
|
nitb_id = sqlite3_column_int64(stmt, 1);
|
||||||
copy_sqlite3_text_to_buf(subscr.msisdn, stmt, 2);
|
copy_sqlite3_text_to_buf(subscr.msisdn, stmt, 2);
|
||||||
authorized = sqlite3_column_int(stmt, 3) ? true : false;
|
authorized = sqlite3_column_int(stmt, 3) ? true : false;
|
||||||
copy_sqlite3_text_to_buf(subscr.imei, stmt, 4);
|
|
||||||
/* Default periodic LU was 30 mins and the expire_lu
|
|
||||||
* was twice that + 1 min
|
|
||||||
*/
|
|
||||||
last_lu_int = sqlite3_column_int(stmt, 5) - 3660;
|
|
||||||
|
|
||||||
db_subscr_update_msisdn_by_imsi(dbc, imsi_str, subscr.msisdn);
|
db_subscr_update_msisdn_by_imsi(dbc, imsi_str, subscr.msisdn);
|
||||||
/* In case the subscriber was somehow never seen, invent an IMEI */
|
|
||||||
if (strlen(subscr.imei) == 14)
|
|
||||||
db_subscr_update_imei_by_imsi(dbc, imsi_str, subscr.imei);
|
|
||||||
db_subscr_update_lu_by_imsi(dbc, imsi_str, last_lu_int);
|
|
||||||
|
|
||||||
db_subscr_nam(dbc, imsi_str, authorized, true);
|
db_subscr_nam(dbc, imsi_str, authorized, true);
|
||||||
db_subscr_nam(dbc, imsi_str, authorized, false);
|
db_subscr_nam(dbc, imsi_str, authorized, false);
|
||||||
|
|
||||||
@@ -437,17 +361,6 @@ int import_nitb_db(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(hlr_db_stmt_sql); i++) {
|
|
||||||
sql = hlr_db_stmt_sql[i];
|
|
||||||
rc = sqlite3_prepare_v2(g_hlr_db_tool_ctx->dbc->db, hlr_db_stmt_sql[i], -1,
|
|
||||||
&hlr_db_stmt[i], NULL);
|
|
||||||
if (rc != SQLITE_OK) {
|
|
||||||
LOGP(DDB, LOGL_ERROR, "OsmoHLR DB: Unable to prepare SQL statement '%s'\n", sql);
|
|
||||||
ret = -1;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stmt = nitb_stmt[NITB_SELECT_SUBSCR];
|
stmt = nitb_stmt[NITB_SELECT_SUBSCR];
|
||||||
|
|
||||||
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
|
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||||
@@ -474,7 +387,6 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
int (*main_action)(void);
|
int (*main_action)(void);
|
||||||
int i;
|
|
||||||
main_action = NULL;
|
main_action = NULL;
|
||||||
|
|
||||||
g_hlr_db_tool_ctx = talloc_zero(NULL, struct hlr_db_tool_ctx);
|
g_hlr_db_tool_ctx = talloc_zero(NULL, struct hlr_db_tool_ctx);
|
||||||
@@ -518,11 +430,6 @@ int main(int argc, char **argv)
|
|||||||
if (main_action)
|
if (main_action)
|
||||||
rc = (*main_action)();
|
rc = (*main_action)();
|
||||||
|
|
||||||
/* db_close will only finalize statments in g_hlr_db_tool_ctx->dbc->stmt
|
|
||||||
* it is ok to call finalize on NULL */
|
|
||||||
for (i = 0; i < ARRAY_SIZE(hlr_db_stmt); i++) {
|
|
||||||
sqlite3_finalize(hlr_db_stmt[i]);
|
|
||||||
}
|
|
||||||
db_close(g_hlr_db_tool_ctx->dbc);
|
db_close(g_hlr_db_tool_ctx->dbc);
|
||||||
log_fini();
|
log_fini();
|
||||||
exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
|
exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
|
|||||||
322
src/hlr_ussd.c
322
src/hlr_ussd.c
@@ -122,40 +122,9 @@ void ussd_route_del(struct hlr_ussd_route *rt)
|
|||||||
talloc_free(rt);
|
talloc_free(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hlr_ussd_route *ussd_route_lookup_for_req(struct hlr *hlr, const struct ss_request *req)
|
static struct hlr_ussd_route *ussd_route_lookup_7bit(struct hlr *hlr, const char *ussd_code)
|
||||||
{
|
{
|
||||||
const uint8_t cgroup = req->ussd_data_dcs >> 4;
|
|
||||||
const uint8_t lang = req->ussd_data_dcs & 0x0f;
|
|
||||||
char ussd_code[GSM0480_USSD_7BIT_STRING_LEN];
|
|
||||||
struct hlr_ussd_route *rt;
|
struct hlr_ussd_route *rt;
|
||||||
|
|
||||||
ussd_code[0] = '\0';
|
|
||||||
|
|
||||||
/* We support only the Coding Group 0 (GSM 7-bit default alphabeet). In fact,
|
|
||||||
* the USSD request is usually limited to [*#0-9], so we don't really need to
|
|
||||||
* support other coding groups and languages. */
|
|
||||||
switch (cgroup) {
|
|
||||||
case 0:
|
|
||||||
/* The Language is usually set to '1111'B (unspecified), but some UEs
|
|
||||||
* are known to indicate '0000'B (German). */
|
|
||||||
if (lang != 0x0f) {
|
|
||||||
LOGP(DSS, LOGL_NOTICE, "USSD DataCodingScheme (0x%02x): "
|
|
||||||
"the Language is usually set to 15 (unspecified), "
|
|
||||||
"but the request indicates %u - ignoring this\n",
|
|
||||||
req->ussd_data_dcs, lang);
|
|
||||||
/* do not abort, attempt to decode as if it was '1111'B */
|
|
||||||
}
|
|
||||||
|
|
||||||
gsm_7bit_decode_n_ussd(&ussd_code[0], sizeof(ussd_code),
|
|
||||||
req->ussd_data, (req->ussd_data_len * 8) / 7);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOGP(DSS, LOGL_ERROR, "USSD DataCodingScheme (0x%02x): "
|
|
||||||
"Coding Group %u is not supported, expecting Coding Group 0\n",
|
|
||||||
req->ussd_data_dcs, cgroup);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
llist_for_each_entry(rt, &hlr->ussd_routes, list) {
|
llist_for_each_entry(rt, &hlr->ussd_routes, list) {
|
||||||
if (!strncmp(ussd_code, rt->prefix, strlen(rt->prefix))) {
|
if (!strncmp(ussd_code, rt->prefix, strlen(rt->prefix))) {
|
||||||
LOGP(DSS, LOGL_DEBUG, "Found %s '%s' (prefix '%s') for USSD "
|
LOGP(DSS, LOGL_DEBUG, "Found %s '%s' (prefix '%s') for USSD "
|
||||||
@@ -283,7 +252,6 @@ static int ss_gsup_send_to_ms(struct ss_session *ss, struct osmo_gsup_server *gs
|
|||||||
rc = osmo_gsup_encode(msg, gsup);
|
rc = osmo_gsup_encode(msg, gsup);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
LOGPSS(ss, LOGL_ERROR, "Failed to encode GSUP message\n");
|
LOGPSS(ss, LOGL_ERROR, "Failed to encode GSUP message\n");
|
||||||
msgb_free(msg);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,20 +278,20 @@ static int ss_gsup_send_to_ms(struct ss_session *ss, struct osmo_gsup_server *gs
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ss_tx_to_ms(struct ss_session *ss, enum osmo_gsup_message_type gsup_msg_type,
|
static int ss_tx_to_ms(struct ss_session *ss, enum osmo_gsup_message_type gsup_msg_type,
|
||||||
struct msgb *ss_msg)
|
bool final, struct msgb *ss_msg)
|
||||||
|
|
||||||
{
|
{
|
||||||
struct osmo_gsup_message resp;
|
struct osmo_gsup_message resp = {
|
||||||
int rc;
|
|
||||||
|
|
||||||
resp = (struct osmo_gsup_message) {
|
|
||||||
.message_type = gsup_msg_type,
|
.message_type = gsup_msg_type,
|
||||||
.session_id = ss->session_id,
|
.session_id = ss->session_id,
|
||||||
.session_state = ss->state,
|
|
||||||
};
|
};
|
||||||
|
int rc;
|
||||||
|
|
||||||
OSMO_STRLCPY_ARRAY(resp.imsi, ss->imsi);
|
OSMO_STRLCPY_ARRAY(resp.imsi, ss->imsi);
|
||||||
|
if (final)
|
||||||
|
resp.session_state = OSMO_GSUP_SESSION_STATE_END;
|
||||||
|
else
|
||||||
|
resp.session_state = OSMO_GSUP_SESSION_STATE_CONTINUE;
|
||||||
if (ss_msg) {
|
if (ss_msg) {
|
||||||
resp.ss_info = msgb_data(ss_msg);
|
resp.ss_info = msgb_data(ss_msg);
|
||||||
resp.ss_info_len = msgb_length(ss_msg);
|
resp.ss_info_len = msgb_length(ss_msg);
|
||||||
@@ -343,8 +311,7 @@ static int ss_tx_reject(struct ss_session *ss, int invoke_id, uint8_t problem_ta
|
|||||||
LOGPSS(ss, LOGL_NOTICE, "Tx Reject(%u, 0x%02x, 0x%02x)\n", invoke_id,
|
LOGPSS(ss, LOGL_NOTICE, "Tx Reject(%u, 0x%02x, 0x%02x)\n", invoke_id,
|
||||||
problem_tag, problem_code);
|
problem_tag, problem_code);
|
||||||
OSMO_ASSERT(msg);
|
OSMO_ASSERT(msg);
|
||||||
ss->state = OSMO_GSUP_SESSION_STATE_END;
|
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, true, msg);
|
||||||
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, msg);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -353,16 +320,15 @@ static int ss_tx_to_ms_error(struct ss_session *ss, uint8_t invoke_id, uint8_t e
|
|||||||
struct msgb *msg = gsm0480_gen_return_error(invoke_id, error_code);
|
struct msgb *msg = gsm0480_gen_return_error(invoke_id, error_code);
|
||||||
LOGPSS(ss, LOGL_NOTICE, "Tx ReturnError(%u, 0x%02x)\n", invoke_id, error_code);
|
LOGPSS(ss, LOGL_NOTICE, "Tx ReturnError(%u, 0x%02x)\n", invoke_id, error_code);
|
||||||
OSMO_ASSERT(msg);
|
OSMO_ASSERT(msg);
|
||||||
ss->state = OSMO_GSUP_SESSION_STATE_END;
|
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, true, msg);
|
||||||
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ss_tx_to_ms_ussd_7bit(struct ss_session *ss, uint8_t invoke_id, const char *text)
|
static int ss_tx_to_ms_ussd_7bit(struct ss_session *ss, bool final, uint8_t invoke_id, const char *text)
|
||||||
{
|
{
|
||||||
struct msgb *msg = gsm0480_gen_ussd_resp_7bit(invoke_id, text);
|
struct msgb *msg = gsm0480_gen_ussd_resp_7bit(invoke_id, text);
|
||||||
LOGPSS(ss, LOGL_INFO, "Tx USSD '%s'\n", text);
|
LOGPSS(ss, LOGL_INFO, "Tx USSD '%s'\n", text);
|
||||||
OSMO_ASSERT(msg);
|
OSMO_ASSERT(msg);
|
||||||
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, msg);
|
return ss_tx_to_ms(ss, OSMO_GSUP_MSGT_PROC_SS_RESULT, final, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
@@ -378,8 +344,6 @@ static int handle_ussd_own_msisdn(struct ss_session *ss,
|
|||||||
char buf[GSM0480_USSD_7BIT_STRING_LEN+1];
|
char buf[GSM0480_USSD_7BIT_STRING_LEN+1];
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
ss->state = OSMO_GSUP_SESSION_STATE_END;
|
|
||||||
|
|
||||||
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -387,7 +351,7 @@ static int handle_ussd_own_msisdn(struct ss_session *ss,
|
|||||||
snprintf(buf, sizeof(buf), "You have no MSISDN!");
|
snprintf(buf, sizeof(buf), "You have no MSISDN!");
|
||||||
else
|
else
|
||||||
snprintf(buf, sizeof(buf), "Your extension is %s", subscr.msisdn);
|
snprintf(buf, sizeof(buf), "Your extension is %s", subscr.msisdn);
|
||||||
ss_tx_to_ms_ussd_7bit(ss, req->invoke_id, buf);
|
ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id, buf);
|
||||||
break;
|
break;
|
||||||
case -ENOENT:
|
case -ENOENT:
|
||||||
ss_tx_to_ms_error(ss, req->invoke_id, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
ss_tx_to_ms_error(ss, req->invoke_id, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||||
@@ -405,22 +369,208 @@ static int handle_ussd_own_imsi(struct ss_session *ss,
|
|||||||
{
|
{
|
||||||
char buf[GSM0480_USSD_7BIT_STRING_LEN+1];
|
char buf[GSM0480_USSD_7BIT_STRING_LEN+1];
|
||||||
snprintf(buf, sizeof(buf), "Your IMSI is %s", ss->imsi);
|
snprintf(buf, sizeof(buf), "Your IMSI is %s", ss->imsi);
|
||||||
ss->state = OSMO_GSUP_SESSION_STATE_END;
|
ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id, buf);
|
||||||
ss_tx_to_ms_ussd_7bit(ss, req->invoke_id, buf);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This handler just keeps the session idle unless the guard timer expires. */
|
static int handle_ussd_get_ran(struct ss_session *ss,
|
||||||
static int handle_ussd_test_idle(struct ss_session *ss,
|
|
||||||
const struct osmo_gsup_message *gsup,
|
const struct osmo_gsup_message *gsup,
|
||||||
const struct ss_request *req)
|
const struct ss_request *req)
|
||||||
{
|
{
|
||||||
char buf[GSM0480_USSD_7BIT_STRING_LEN + 1];
|
struct hlr_subscriber subscr;
|
||||||
snprintf(buf, sizeof(buf), "Keeping your session idle, it will expire "
|
char response[512];
|
||||||
"at most in %u seconds.", g_hlr->ncss_guard_timeout);
|
int rc;
|
||||||
ss->state = OSMO_GSUP_SESSION_STATE_CONTINUE;
|
const char *rat;
|
||||||
ss_tx_to_ms_ussd_7bit(ss, req->invoke_id, buf);
|
|
||||||
return 0;
|
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||||
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
if (!*subscr.last_lu_rat_cs)
|
||||||
|
rat = "nothing, you don't exist";
|
||||||
|
else if (!strcmp(subscr.last_lu_rat_cs, "GERAN-A"))
|
||||||
|
rat = "2G";
|
||||||
|
else if (!strcmp(subscr.last_lu_rat_cs, "UTRAN-Iu"))
|
||||||
|
rat = "3G";
|
||||||
|
else if (!strcmp(subscr.last_lu_rat_cs, "EUTRAN-SGs"))
|
||||||
|
rat = "4G";
|
||||||
|
else
|
||||||
|
rat = subscr.last_lu_rat_cs;
|
||||||
|
|
||||||
|
snprintf(response, sizeof(response),
|
||||||
|
"Now on %s. Available:%s%s%s.",
|
||||||
|
rat,
|
||||||
|
subscr.rat_types[OSMO_RAT_GERAN_A]? " 2G" : "",
|
||||||
|
subscr.rat_types[OSMO_RAT_UTRAN_IU]? " 3G" : "",
|
||||||
|
subscr.rat_types[OSMO_RAT_EUTRAN_SGS]? " 4G" : "");
|
||||||
|
|
||||||
|
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id, response);
|
||||||
|
break;
|
||||||
|
case -ENOENT:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||||
|
break;
|
||||||
|
case -EIO:
|
||||||
|
default:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_ussd_gsm_on(struct ss_session *ss,
|
||||||
|
const struct osmo_gsup_message *gsup,
|
||||||
|
const struct ss_request *req)
|
||||||
|
{
|
||||||
|
struct hlr_subscriber subscr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||||
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_GERAN_A, true);
|
||||||
|
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
|
||||||
|
"Enabled GERAN-A (2G)");
|
||||||
|
break;
|
||||||
|
case -ENOENT:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||||
|
break;
|
||||||
|
case -EIO:
|
||||||
|
default:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_ussd_gsm_off(struct ss_session *ss,
|
||||||
|
const struct osmo_gsup_message *gsup,
|
||||||
|
const struct ss_request *req)
|
||||||
|
{
|
||||||
|
struct hlr_subscriber subscr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||||
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_GERAN_A, false);
|
||||||
|
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
|
||||||
|
"Disabled GERAN-A (2G)");
|
||||||
|
break;
|
||||||
|
case -ENOENT:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||||
|
break;
|
||||||
|
case -EIO:
|
||||||
|
default:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_ussd_umts_on(struct ss_session *ss,
|
||||||
|
const struct osmo_gsup_message *gsup,
|
||||||
|
const struct ss_request *req)
|
||||||
|
{
|
||||||
|
struct hlr_subscriber subscr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||||
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_UTRAN_IU, true);
|
||||||
|
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
|
||||||
|
"Enabled UTRAN-Iu (3G)");
|
||||||
|
break;
|
||||||
|
case -ENOENT:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||||
|
break;
|
||||||
|
case -EIO:
|
||||||
|
default:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_ussd_umts_off(struct ss_session *ss,
|
||||||
|
const struct osmo_gsup_message *gsup,
|
||||||
|
const struct ss_request *req)
|
||||||
|
{
|
||||||
|
struct hlr_subscriber subscr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||||
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_UTRAN_IU, false);
|
||||||
|
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
|
||||||
|
"Disabled UTRAN-Iu (3G)");
|
||||||
|
break;
|
||||||
|
case -ENOENT:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||||
|
break;
|
||||||
|
case -EIO:
|
||||||
|
default:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_ussd_lte_on(struct ss_session *ss,
|
||||||
|
const struct osmo_gsup_message *gsup,
|
||||||
|
const struct ss_request *req)
|
||||||
|
{
|
||||||
|
struct hlr_subscriber subscr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||||
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_EUTRAN_SGS, true);
|
||||||
|
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
|
||||||
|
"Enabled EUTRAN-SGs (4G)");
|
||||||
|
break;
|
||||||
|
case -ENOENT:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||||
|
break;
|
||||||
|
case -EIO:
|
||||||
|
default:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_ussd_lte_off(struct ss_session *ss,
|
||||||
|
const struct osmo_gsup_message *gsup,
|
||||||
|
const struct ss_request *req)
|
||||||
|
{
|
||||||
|
struct hlr_subscriber subscr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||||
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_EUTRAN_SGS, false);
|
||||||
|
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
|
||||||
|
"Disabled EUTRAN-SGs (4G)");
|
||||||
|
break;
|
||||||
|
case -ENOENT:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||||
|
break;
|
||||||
|
case -EIO:
|
||||||
|
default:
|
||||||
|
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -434,8 +584,32 @@ static const struct hlr_iuse hlr_iuses[] = {
|
|||||||
.handle_ussd = handle_ussd_own_imsi,
|
.handle_ussd = handle_ussd_own_imsi,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "test-idle",
|
.name = "get-ran",
|
||||||
.handle_ussd = handle_ussd_test_idle,
|
.handle_ussd = handle_ussd_get_ran,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "gsm-on",
|
||||||
|
.handle_ussd = handle_ussd_gsm_on,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "gsm-off",
|
||||||
|
.handle_ussd = handle_ussd_gsm_off,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "umts-on",
|
||||||
|
.handle_ussd = handle_ussd_umts_on,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "umts-off",
|
||||||
|
.handle_ussd = handle_ussd_umts_off,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "lte-on",
|
||||||
|
.handle_ussd = handle_ussd_lte_on,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "lte-off",
|
||||||
|
.handle_ussd = handle_ussd_lte_off,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -470,22 +644,22 @@ static bool ss_op_is_ussd(uint8_t opcode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* is this GSUP connection an EUSE (true) or not (false)? */
|
/* is this GSUP connection an EUSE (true) or not (false)? */
|
||||||
static bool peer_name_is_euse(const struct osmo_cni_peer_id *peer_name)
|
static bool peer_name_is_euse(const struct osmo_gsup_peer_id *peer_name)
|
||||||
{
|
{
|
||||||
if (peer_name->type != OSMO_CNI_PEER_ID_IPA_NAME)
|
if (peer_name->type != OSMO_GSUP_PEER_ID_IPA_NAME)
|
||||||
return false;
|
return false;
|
||||||
if (peer_name->ipa_name.len <= 5)
|
if (peer_name->ipa_name.len <= 5)
|
||||||
return false;
|
return false;
|
||||||
return strncmp((char *)(peer_name->ipa_name.val), "EUSE-", 5) == 0;
|
return strncmp((char *)(peer_name->ipa_name.val), "EUSE-", 5) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hlr_euse *euse_by_name(const struct osmo_cni_peer_id *peer_name)
|
static struct hlr_euse *euse_by_name(const struct osmo_gsup_peer_id *peer_name)
|
||||||
{
|
{
|
||||||
if (!peer_name_is_euse(peer_name))
|
if (!peer_name_is_euse(peer_name))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* above peer_name_is_euse() ensures this: */
|
/* above peer_name_is_euse() ensures this: */
|
||||||
OSMO_ASSERT(peer_name->type == OSMO_CNI_PEER_ID_IPA_NAME);
|
OSMO_ASSERT(peer_name->type == OSMO_GSUP_PEER_ID_IPA_NAME);
|
||||||
|
|
||||||
return euse_find(g_hlr, (const char*)(peer_name->ipa_name.val)+5);
|
return euse_find(g_hlr, (const char*)(peer_name->ipa_name.val)+5);
|
||||||
}
|
}
|
||||||
@@ -550,9 +724,9 @@ static int handle_ussd(struct ss_session *ss, bool is_euse_originated, const str
|
|||||||
} else {
|
} else {
|
||||||
/* Handle internally */
|
/* Handle internally */
|
||||||
ss->u.iuse->handle_ussd(ss, gsup, req);
|
ss->u.iuse->handle_ussd(ss, gsup, req);
|
||||||
/* Release session if the handler has changed its state to END */
|
/* Release session immediately */
|
||||||
if (ss->state == OSMO_GSUP_SESSION_STATE_END)
|
|
||||||
ss_session_free(ss);
|
ss_session_free(ss);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,10 +750,10 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
|
|||||||
LOGP(DSS, LOGL_DEBUG, "%s/0x%08x: Process SS (%s)\n", gsup->imsi, gsup->session_id,
|
LOGP(DSS, LOGL_DEBUG, "%s/0x%08x: Process SS (%s)\n", gsup->imsi, gsup->session_id,
|
||||||
osmo_gsup_session_state_name(gsup->session_state));
|
osmo_gsup_session_state_name(gsup->session_state));
|
||||||
|
|
||||||
if (gsup_req->source_name.type != OSMO_CNI_PEER_ID_IPA_NAME) {
|
if (gsup_req->source_name.type != OSMO_GSUP_PEER_ID_IPA_NAME) {
|
||||||
LOGP(DSS, LOGL_ERROR, "%s/0x%082x: Unable to process SS request: Unsupported GSUP peer id type%s\n",
|
LOGP(DSS, LOGL_ERROR, "%s/0x%082x: Unable to process SS request: Unsupported GSUP peer id type%s\n",
|
||||||
gsup->imsi, gsup->session_id,
|
gsup->imsi, gsup->session_id,
|
||||||
osmo_cni_peer_id_type_name(gsup_req->source_name.type));
|
osmo_gsup_peer_id_type_name(gsup_req->source_name.type));
|
||||||
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_PROTO_ERR_UNSPEC, "error processing SS request");
|
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_PROTO_ERR_UNSPEC, "error processing SS request");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -621,7 +795,7 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
|
|||||||
if (!is_euse_originated) {
|
if (!is_euse_originated) {
|
||||||
ss->initial_req_from_ms = gsup_req;
|
ss->initial_req_from_ms = gsup_req;
|
||||||
free_gsup_req = NULL;
|
free_gsup_req = NULL;
|
||||||
OSMO_ASSERT(gsup_req->source_name.type == OSMO_CNI_PEER_ID_IPA_NAME); /* checked above */
|
OSMO_ASSERT(gsup_req->source_name.type == OSMO_GSUP_PEER_ID_IPA_NAME); /* checked above */
|
||||||
ss->vlr_name = gsup_req->source_name.ipa_name;
|
ss->vlr_name = gsup_req->source_name.ipa_name;
|
||||||
} else {
|
} else {
|
||||||
ss->initial_req_from_euse = gsup_req;
|
ss->initial_req_from_euse = gsup_req;
|
||||||
@@ -634,7 +808,7 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
|
|||||||
} else {
|
} else {
|
||||||
/* VLR->EUSE: MO USSD. VLR is known ('conn'), EUSE is to be resolved */
|
/* VLR->EUSE: MO USSD. VLR is known ('conn'), EUSE is to be resolved */
|
||||||
struct hlr_ussd_route *rt;
|
struct hlr_ussd_route *rt;
|
||||||
rt = ussd_route_lookup_for_req(hlr, &req);
|
rt = ussd_route_lookup_7bit(hlr, (const char *) req.ussd_text);
|
||||||
if (rt) {
|
if (rt) {
|
||||||
if (rt->is_external) {
|
if (rt->is_external) {
|
||||||
ss->is_external = true;
|
ss->is_external = true;
|
||||||
@@ -662,8 +836,7 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
|
|||||||
if (!ss) {
|
if (!ss) {
|
||||||
LOGP(DSS, LOGL_ERROR, "%s/0x%08x: CONTINUE for unknown SS session\n",
|
LOGP(DSS, LOGL_ERROR, "%s/0x%08x: CONTINUE for unknown SS session\n",
|
||||||
gsup->imsi, gsup->session_id);
|
gsup->imsi, gsup->session_id);
|
||||||
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_MSGT_INCOMP_P_STATE,
|
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_INV_MAND_INFO, "CONTINUE for unknown SS session");
|
||||||
"CONTINUE for unknown SS session");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,8 +857,6 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
|
|||||||
if (!ss) {
|
if (!ss) {
|
||||||
LOGP(DSS, LOGL_ERROR, "%s/0x%08x: END for unknown SS session\n",
|
LOGP(DSS, LOGL_ERROR, "%s/0x%08x: END for unknown SS session\n",
|
||||||
gsup->imsi, gsup->session_id);
|
gsup->imsi, gsup->session_id);
|
||||||
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_MSGT_INCOMP_P_STATE,
|
|
||||||
"END for unknown SS session");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,5 +887,4 @@ void rx_proc_ss_error(struct osmo_gsup_req *req)
|
|||||||
{
|
{
|
||||||
LOGP(DSS, LOGL_NOTICE, "%s/0x%08x: Process SS ERROR (%s)\n", req->gsup.imsi, req->gsup.session_id,
|
LOGP(DSS, LOGL_NOTICE, "%s/0x%08x: Process SS ERROR (%s)\n", req->gsup.imsi, req->gsup.session_id,
|
||||||
osmo_gsup_session_state_name(req->gsup.session_state));
|
osmo_gsup_session_state_name(req->gsup.session_state));
|
||||||
osmo_gsup_req_free(req);
|
|
||||||
}
|
}
|
||||||
|
|||||||
318
src/hlr_vty.c
318
src/hlr_vty.c
@@ -25,13 +25,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <osmocom/core/talloc.h>
|
#include <osmocom/core/talloc.h>
|
||||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
|
||||||
#include <osmocom/gsm/apn.h>
|
|
||||||
|
|
||||||
#include <osmocom/vty/vty.h>
|
#include <osmocom/vty/vty.h>
|
||||||
#include <osmocom/vty/stats.h>
|
#include <osmocom/vty/stats.h>
|
||||||
#include <osmocom/vty/command.h>
|
#include <osmocom/vty/command.h>
|
||||||
@@ -46,36 +40,6 @@
|
|||||||
#include <osmocom/hlr/hlr_ussd.h>
|
#include <osmocom/hlr/hlr_ussd.h>
|
||||||
#include <osmocom/hlr/gsup_server.h>
|
#include <osmocom/hlr/gsup_server.h>
|
||||||
|
|
||||||
static const struct value_string gsm48_gmm_cause_vty_names[] = {
|
|
||||||
{ GMM_CAUSE_IMSI_UNKNOWN, "imsi-unknown" },
|
|
||||||
{ GMM_CAUSE_ILLEGAL_MS, "illegal-ms" },
|
|
||||||
{ GMM_CAUSE_PLMN_NOTALLOWED, "plmn-not-allowed" },
|
|
||||||
{ GMM_CAUSE_LA_NOTALLOWED, "la-not-allowed" },
|
|
||||||
{ GMM_CAUSE_ROAMING_NOTALLOWED, "roaming-not-allowed" },
|
|
||||||
{ GMM_CAUSE_NO_SUIT_CELL_IN_LA, "no-suitable-cell-in-la" },
|
|
||||||
{ GMM_CAUSE_NET_FAIL, "net-fail" },
|
|
||||||
{ GMM_CAUSE_CONGESTION, "congestion" },
|
|
||||||
{ GMM_CAUSE_GSM_AUTH_UNACCEPT, "auth-unacceptable" },
|
|
||||||
{ GMM_CAUSE_PROTO_ERR_UNSPEC, "proto-error-unspec" },
|
|
||||||
{ 0, NULL },
|
|
||||||
};
|
|
||||||
|
|
||||||
/* TS 24.008 4.4.4.7 */
|
|
||||||
static const struct value_string gsm48_gmm_cause_vty_descs[] = {
|
|
||||||
{ GMM_CAUSE_IMSI_UNKNOWN, " #02: (IMSI unknown in HLR)" },
|
|
||||||
{ GMM_CAUSE_ILLEGAL_MS, " #03 (Illegal MS)" },
|
|
||||||
{ GMM_CAUSE_PLMN_NOTALLOWED, " #11: (PLMN not allowed)" },
|
|
||||||
{ GMM_CAUSE_LA_NOTALLOWED, " #12: (Location Area not allowed)" },
|
|
||||||
{ GMM_CAUSE_ROAMING_NOTALLOWED, " #13: (Roaming not allowed in this location area)" },
|
|
||||||
{ GMM_CAUSE_NO_SUIT_CELL_IN_LA, " #15: (No Suitable Cells In Location Area [continue search in PLMN])." },
|
|
||||||
{ GMM_CAUSE_NET_FAIL, " #17: (Network Failure)" },
|
|
||||||
{ GMM_CAUSE_CONGESTION, " #22: (Congestion)" },
|
|
||||||
{ GMM_CAUSE_GSM_AUTH_UNACCEPT, " #23: (GSM authentication unacceptable [UMTS])" },
|
|
||||||
{ GMM_CAUSE_PROTO_ERR_UNSPEC, "#111: (Protocol error, unspecified)" },
|
|
||||||
{ 0, NULL },
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct cmd_node hlr_node = {
|
struct cmd_node hlr_node = {
|
||||||
HLR_NODE,
|
HLR_NODE,
|
||||||
"%s(config-hlr)# ",
|
"%s(config-hlr)# ",
|
||||||
@@ -106,194 +70,9 @@ DEFUN(cfg_gsup,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd_node ps_node = {
|
|
||||||
PS_NODE,
|
|
||||||
"%s(config-hlr-ps)# ",
|
|
||||||
1,
|
|
||||||
};
|
|
||||||
|
|
||||||
DEFUN(cfg_ps,
|
|
||||||
cfg_ps_cmd,
|
|
||||||
"ps",
|
|
||||||
"Configure the PS options")
|
|
||||||
{
|
|
||||||
vty->node = PS_NODE;
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct cmd_node ps_pdp_profiles_node = {
|
|
||||||
PS_PDP_PROFILES_NODE,
|
|
||||||
"%s(config-hlr-ps-pdp-profiles)# ",
|
|
||||||
1,
|
|
||||||
};
|
|
||||||
|
|
||||||
DEFUN(cfg_ps_pdp_profiles,
|
|
||||||
cfg_ps_pdp_profiles_cmd,
|
|
||||||
"pdp-profiles default",
|
|
||||||
"Define a PDP profile set.\n"
|
|
||||||
"Define the global default profile.\n")
|
|
||||||
{
|
|
||||||
g_hlr->ps.pdp_profile.enabled = true;
|
|
||||||
|
|
||||||
vty->node = PS_PDP_PROFILES_NODE;
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(cfg_no_ps_pdp_profiles,
|
|
||||||
cfg_no_ps_pdp_profiles_cmd,
|
|
||||||
"no pdp-profiles default",
|
|
||||||
NO_STR
|
|
||||||
"Delete PDP profile.\n"
|
|
||||||
"Unique identifier for this PDP profile set.\n")
|
|
||||||
{
|
|
||||||
g_hlr->ps.pdp_profile.enabled = false;
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct cmd_node ps_pdp_profiles_profile_node = {
|
|
||||||
PS_PDP_PROFILES_PROFILE_NODE,
|
|
||||||
"%s(config-hlr-ps-pdp-profile)# ",
|
|
||||||
1,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* context_id == 0 means the slot is free */
|
|
||||||
struct osmo_gsup_pdp_info *get_pdp_profile(uint8_t context_id)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < OSMO_GSUP_MAX_NUM_PDP_INFO; i++) {
|
|
||||||
struct osmo_gsup_pdp_info *info = &g_hlr->ps.pdp_profile.pdp_infos[i];
|
|
||||||
if (info->context_id == context_id)
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct osmo_gsup_pdp_info *create_pdp_profile(uint8_t context_id)
|
|
||||||
{
|
|
||||||
struct osmo_gsup_pdp_info *info = get_pdp_profile(0);
|
|
||||||
if (!info)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memset(info, 0, sizeof(*info));
|
|
||||||
info->context_id = context_id;
|
|
||||||
info->have_info = 1;
|
|
||||||
|
|
||||||
g_hlr->ps.pdp_profile.num_pdp_infos++;
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy_pdp_profile(struct osmo_gsup_pdp_info *info)
|
|
||||||
{
|
|
||||||
info->context_id = 0;
|
|
||||||
if (info->apn_enc)
|
|
||||||
talloc_free((void *) info->apn_enc);
|
|
||||||
|
|
||||||
g_hlr->ps.pdp_profile.num_pdp_infos--;
|
|
||||||
memset(info, 0, sizeof(*info));
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(cfg_ps_pdp_profiles_profile,
|
|
||||||
cfg_ps_pdp_profiles_profile_cmd,
|
|
||||||
"profile <1-10>",
|
|
||||||
"Configure a PDP profile\n"
|
|
||||||
"Unique PDP context identifier. The lowest profile will be used as default context.\n")
|
|
||||||
{
|
|
||||||
struct osmo_gsup_pdp_info *info;
|
|
||||||
uint8_t context_id = atoi(argv[0]);
|
|
||||||
|
|
||||||
info = get_pdp_profile(context_id);
|
|
||||||
if (!info) {
|
|
||||||
info = create_pdp_profile(context_id);
|
|
||||||
if (!info) {
|
|
||||||
vty_out(vty, "Failed to create profile %d!%s", context_id, VTY_NEWLINE);
|
|
||||||
return CMD_ERR_INCOMPLETE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vty->node = PS_PDP_PROFILES_PROFILE_NODE;
|
|
||||||
vty->index = info;
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(cfg_no_ps_pdp_profiles_profile,
|
|
||||||
cfg_no_ps_pdp_profiles_profile_cmd,
|
|
||||||
"no profile <1-10>",
|
|
||||||
NO_STR
|
|
||||||
"Delete a PDP profile\n"
|
|
||||||
"Unique PDP context identifier. The lowest profile will be used as default context.\n")
|
|
||||||
{
|
|
||||||
struct osmo_gsup_pdp_info *info;
|
|
||||||
uint8_t context_id = atoi(argv[0]);
|
|
||||||
|
|
||||||
info = get_pdp_profile(context_id);
|
|
||||||
if (info)
|
|
||||||
destroy_pdp_profile(info);
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(cfg_ps_pdp_profile_apn, cfg_ps_pdp_profile_apn_cmd,
|
|
||||||
"apn ID",
|
|
||||||
"Configure the APN.\n"
|
|
||||||
"APN name or * for wildcard apn.\n")
|
|
||||||
{
|
|
||||||
struct osmo_gsup_pdp_info *info = vty->index;
|
|
||||||
const char *apn_name = argv[0];
|
|
||||||
|
|
||||||
/* apn encoded takes one more byte than strlen() */
|
|
||||||
size_t apn_enc_len = strlen(apn_name) + 1;
|
|
||||||
uint8_t *apn_enc;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (apn_enc_len > APN_MAXLEN) {
|
|
||||||
vty_out(vty, "APN name is too long '%s'. Max is %d!%s", apn_name, APN_MAXLEN, VTY_NEWLINE);
|
|
||||||
return CMD_ERR_INCOMPLETE;
|
|
||||||
}
|
|
||||||
|
|
||||||
info->apn_enc = apn_enc = (uint8_t *) talloc_zero_size(g_hlr, apn_enc_len);
|
|
||||||
ret = info->apn_enc_len = osmo_apn_from_str(apn_enc, apn_enc_len, apn_name);
|
|
||||||
if (ret < 0) {
|
|
||||||
talloc_free(apn_enc);
|
|
||||||
info->apn_enc = NULL;
|
|
||||||
info->apn_enc_len = 0;
|
|
||||||
vty_out(vty, "Invalid APN name %s!", apn_name);
|
|
||||||
return CMD_WARNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(cfg_no_ps_pdp_profile_apn, cfg_no_ps_pdp_profile_apn_cmd,
|
|
||||||
"no apn",
|
|
||||||
NO_STR
|
|
||||||
"Delete the APN.\n")
|
|
||||||
{
|
|
||||||
struct osmo_gsup_pdp_info *info = vty->index;
|
|
||||||
if (info->apn_enc) {
|
|
||||||
talloc_free((void *) info->apn_enc);
|
|
||||||
info->apn_enc = NULL;
|
|
||||||
info->apn_enc_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int config_write_hlr(struct vty *vty)
|
static int config_write_hlr(struct vty *vty)
|
||||||
{
|
{
|
||||||
vty_out(vty, "hlr%s", VTY_NEWLINE);
|
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",
|
|
||||||
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",
|
|
||||||
get_value_string_or_null(gsm48_gmm_cause_vty_names,
|
|
||||||
(uint32_t) g_hlr->no_proxy_reject_cause), VTY_NEWLINE);
|
|
||||||
if (g_hlr->store_imei)
|
if (g_hlr->store_imei)
|
||||||
vty_out(vty, " store-imei%s", VTY_NEWLINE);
|
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))
|
if (g_hlr->db_file_path && strcmp(g_hlr->db_file_path, HLR_DEFAULT_DB_FILE_PATH))
|
||||||
@@ -323,39 +102,6 @@ static int config_write_hlr_gsup(struct vty *vty)
|
|||||||
vty_out(vty, " gsup%s", VTY_NEWLINE);
|
vty_out(vty, " gsup%s", VTY_NEWLINE);
|
||||||
if (g_hlr->gsup_bind_addr)
|
if (g_hlr->gsup_bind_addr)
|
||||||
vty_out(vty, " bind ip %s%s", g_hlr->gsup_bind_addr, VTY_NEWLINE);
|
vty_out(vty, " bind ip %s%s", g_hlr->gsup_bind_addr, VTY_NEWLINE);
|
||||||
if (g_hlr->gsup_unit_name.serno)
|
|
||||||
vty_out(vty, " ipa-name %s%s", g_hlr->gsup_unit_name.serno, VTY_NEWLINE);
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int config_write_hlr_ps(struct vty *vty)
|
|
||||||
{
|
|
||||||
vty_out(vty, " ps%s", VTY_NEWLINE);
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int config_write_hlr_ps_pdp_profiles(struct vty *vty)
|
|
||||||
{
|
|
||||||
char apn[APN_MAXLEN + 1] = {};
|
|
||||||
|
|
||||||
if (!g_hlr->ps.pdp_profile.enabled)
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
|
|
||||||
vty_out(vty, " pdp-profiles default%s", VTY_NEWLINE);
|
|
||||||
for (int i = 0; i < g_hlr->ps.pdp_profile.num_pdp_infos; i++) {
|
|
||||||
struct osmo_gsup_pdp_info *pdp_info = &g_hlr->ps.pdp_profile.pdp_infos[i];
|
|
||||||
if (!pdp_info->context_id)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
vty_out(vty, " profile %d%s", pdp_info->context_id, VTY_NEWLINE);
|
|
||||||
if (!pdp_info->have_info)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pdp_info->apn_enc && pdp_info->apn_enc_len) {
|
|
||||||
osmo_apn_to_str(apn, pdp_info->apn_enc, pdp_info->apn_enc_len);
|
|
||||||
vty_out(vty, " apn %s%s", apn, VTY_NEWLINE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,8 +114,8 @@ static void show_one_conn(struct vty *vty, const struct osmo_gsup_conn *conn)
|
|||||||
rc = osmo_gsup_conn_ccm_get(conn, (uint8_t **) &name, IPAC_IDTAG_SERNR);
|
rc = osmo_gsup_conn_ccm_get(conn, (uint8_t **) &name, IPAC_IDTAG_SERNR);
|
||||||
OSMO_ASSERT(rc);
|
OSMO_ASSERT(rc);
|
||||||
|
|
||||||
vty_out(vty, " '%s' from %s:%5u, CS=%u, PS=%u%s",
|
vty_out(vty, " '%s' from %s:%5u, CS=%u, PS=%u, 3G_IND=%u%s",
|
||||||
name, isc->addr, isc->port, conn->supports_cs, conn->supports_ps,
|
name, isc->addr, isc->port, conn->supports_cs, conn->supports_ps, conn->auc_3g_ind,
|
||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,7 +156,7 @@ DEFUN(cfg_hlr_gsup_ipa_name,
|
|||||||
{
|
{
|
||||||
if (vty->type != VTY_FILE) {
|
if (vty->type != VTY_FILE) {
|
||||||
vty_out(vty, "gsup/ipa-name: The GSUP IPA name cannot be changed at run-time; "
|
vty_out(vty, "gsup/ipa-name: The GSUP IPA name cannot be changed at run-time; "
|
||||||
"It can only be set in the configuration file.%s", VTY_NEWLINE);
|
"It can only be set in the configuraton file.%s", VTY_NEWLINE);
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,11 +174,17 @@ DEFUN(cfg_hlr_gsup_ipa_name,
|
|||||||
#define UROUTE_STR "Routing Configuration\n"
|
#define UROUTE_STR "Routing Configuration\n"
|
||||||
#define PREFIX_STR "Prefix-Matching Route\n" "USSD Prefix\n"
|
#define PREFIX_STR "Prefix-Matching Route\n" "USSD Prefix\n"
|
||||||
|
|
||||||
#define INT_CHOICE "(own-msisdn|own-imsi|test-idle)"
|
#define INT_CHOICE "(own-msisdn|own-imsi|get-ran|gsm-on|gsm-off|umts-on|umts-off|lte-on|lte-off)"
|
||||||
#define INT_STR "Internal USSD Handler\n" \
|
#define INT_STR "Internal USSD Handler\n" \
|
||||||
"Respond with subscribers' own MSISDN\n" \
|
"Respond with subscribers' own MSISDN\n" \
|
||||||
"Respond with subscribers' own IMSI\n" \
|
"Respond with subscribers' own IMSI\n" \
|
||||||
"Keep the session idle (useful for testing)\n"
|
"Respond with available RAN types\n" \
|
||||||
|
"Enable GSM service\n" \
|
||||||
|
"Disable GSM service\n" \
|
||||||
|
"Enable UMTS service\n" \
|
||||||
|
"Disable UMTS service\n" \
|
||||||
|
"Enable LTE service\n" \
|
||||||
|
"Disable LTE service\n"
|
||||||
|
|
||||||
#define EXT_STR "External USSD Handler\n" \
|
#define EXT_STR "External USSD Handler\n" \
|
||||||
"Name of External USSD Handler (IPA CCM ID)\n"
|
"Name of External USSD Handler (IPA CCM ID)\n"
|
||||||
@@ -560,7 +312,7 @@ DEFUN(cfg_no_euse, cfg_no_euse_cmd,
|
|||||||
{
|
{
|
||||||
struct hlr_euse *euse = euse_find(g_hlr, argv[0]);
|
struct hlr_euse *euse = euse_find(g_hlr, argv[0]);
|
||||||
if (!euse) {
|
if (!euse) {
|
||||||
vty_out(vty, "%% Cannot remove non-existent EUSE %s%s", argv[0], VTY_NEWLINE);
|
vty_out(vty, "%% Cannot remove non-existant EUSE %s%s", argv[0], VTY_NEWLINE);
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
if (g_hlr->euse_default == euse) {
|
if (g_hlr->euse_default == euse) {
|
||||||
@@ -610,21 +362,6 @@ DEFUN(cfg_ncss_guard_timeout, cfg_ncss_guard_timeout_cmd,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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]);
|
|
||||||
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;
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(cfg_store_imei, cfg_store_imei_cmd,
|
DEFUN(cfg_store_imei, cfg_store_imei_cmd,
|
||||||
"store-imei",
|
"store-imei",
|
||||||
"Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send"
|
"Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send"
|
||||||
@@ -717,22 +454,8 @@ int hlr_vty_is_config_node(struct vty *vty, int node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hlr_vty_init(void *hlr_ctx)
|
void hlr_vty_init(void)
|
||||||
{
|
{
|
||||||
cfg_reject_cause_cmd.string =
|
|
||||||
vty_cmd_string_from_valstr(hlr_ctx,
|
|
||||||
gsm48_gmm_cause_vty_names,
|
|
||||||
"reject-cause (not-found|no-proxy) (", "|", ")",
|
|
||||||
VTY_DO_LOWER);
|
|
||||||
|
|
||||||
cfg_reject_cause_cmd.doc =
|
|
||||||
vty_cmd_string_from_valstr(hlr_ctx,
|
|
||||||
gsm48_gmm_cause_vty_descs,
|
|
||||||
"GSUP/GMM cause to be sent\n"
|
|
||||||
"in the case the IMSI could not be found in the database\n"
|
|
||||||
"in the case no remote HLR reponded to mslookup GSUP request\n",
|
|
||||||
"\n", "", 0);
|
|
||||||
|
|
||||||
logging_vty_add_cmds();
|
logging_vty_add_cmds();
|
||||||
osmo_talloc_vty_add_cmds();
|
osmo_talloc_vty_add_cmds();
|
||||||
osmo_stats_vty_add_cmds();
|
osmo_stats_vty_add_cmds();
|
||||||
@@ -748,20 +471,6 @@ void hlr_vty_init(void *hlr_ctx)
|
|||||||
install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
|
install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
|
||||||
install_element(GSUP_NODE, &cfg_hlr_gsup_ipa_name_cmd);
|
install_element(GSUP_NODE, &cfg_hlr_gsup_ipa_name_cmd);
|
||||||
|
|
||||||
/* PS */
|
|
||||||
install_node(&ps_node, config_write_hlr_ps);
|
|
||||||
install_element(HLR_NODE, &cfg_ps_cmd);
|
|
||||||
|
|
||||||
install_node(&ps_pdp_profiles_node, config_write_hlr_ps_pdp_profiles);
|
|
||||||
install_element(PS_NODE, &cfg_ps_pdp_profiles_cmd);
|
|
||||||
install_element(PS_NODE, &cfg_no_ps_pdp_profiles_cmd);
|
|
||||||
|
|
||||||
install_node(&ps_pdp_profiles_profile_node, NULL);
|
|
||||||
install_element(PS_PDP_PROFILES_NODE, &cfg_ps_pdp_profiles_profile_cmd);
|
|
||||||
install_element(PS_PDP_PROFILES_NODE, &cfg_no_ps_pdp_profiles_profile_cmd);
|
|
||||||
install_element(PS_PDP_PROFILES_PROFILE_NODE, &cfg_ps_pdp_profile_apn_cmd);
|
|
||||||
install_element(PS_PDP_PROFILES_PROFILE_NODE, &cfg_no_ps_pdp_profile_apn_cmd);
|
|
||||||
|
|
||||||
install_element(HLR_NODE, &cfg_database_cmd);
|
install_element(HLR_NODE, &cfg_database_cmd);
|
||||||
|
|
||||||
install_element(HLR_NODE, &cfg_euse_cmd);
|
install_element(HLR_NODE, &cfg_euse_cmd);
|
||||||
@@ -773,7 +482,6 @@ void hlr_vty_init(void *hlr_ctx)
|
|||||||
install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
|
install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
|
||||||
install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd);
|
install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd);
|
||||||
install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd);
|
install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd);
|
||||||
install_element(HLR_NODE, &cfg_reject_cause_cmd);
|
|
||||||
install_element(HLR_NODE, &cfg_store_imei_cmd);
|
install_element(HLR_NODE, &cfg_store_imei_cmd);
|
||||||
install_element(HLR_NODE, &cfg_no_store_imei_cmd);
|
install_element(HLR_NODE, &cfg_no_store_imei_cmd);
|
||||||
install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd);
|
install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* OsmoHLR subscriber management VTY implementation */
|
/* OsmoHLR subscriber management VTY implementation */
|
||||||
/* (C) 2017-2023 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
/* (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -27,11 +27,11 @@
|
|||||||
#include <osmocom/vty/vty.h>
|
#include <osmocom/vty/vty.h>
|
||||||
#include <osmocom/vty/command.h>
|
#include <osmocom/vty/command.h>
|
||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/gsm/gsm_utils.h>
|
||||||
|
|
||||||
#include <osmocom/hlr/hlr.h>
|
#include <osmocom/hlr/hlr.h>
|
||||||
#include <osmocom/hlr/db.h>
|
#include <osmocom/hlr/db.h>
|
||||||
#include <osmocom/hlr/timestamp.h>
|
#include <osmocom/hlr/timestamp.h>
|
||||||
#include <osmocom/hlr/hlr_vty.h>
|
|
||||||
|
|
||||||
struct vty;
|
struct vty;
|
||||||
|
|
||||||
@@ -39,22 +39,25 @@ struct vty;
|
|||||||
|
|
||||||
static char *get_datestr(const time_t *t, char *buf, size_t bufsize)
|
static char *get_datestr(const time_t *t, char *buf, size_t bufsize)
|
||||||
{
|
{
|
||||||
struct tm tm;
|
struct tm *tm;
|
||||||
gmtime_r(t, &tm);
|
|
||||||
strftime(buf, bufsize, "%FT%T+00:00", &tm);
|
tm = gmtime(t);
|
||||||
|
if (!tm)
|
||||||
|
return "UNKNOWN";
|
||||||
|
|
||||||
|
strftime(buf, bufsize, "%FT%T+00:00", tm);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t last_lu_seen, bool only_age)
|
static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t last_lu_seen, const char *last_lu_rat)
|
||||||
{
|
{
|
||||||
uint32_t age;
|
uint32_t age;
|
||||||
char datebuf[32];
|
char datebuf[32];
|
||||||
if (!last_lu_seen)
|
if (!last_lu_seen)
|
||||||
return;
|
return;
|
||||||
if (!only_age)
|
|
||||||
vty_out(vty, " last LU seen on %s: %s", domain_label, get_datestr(&last_lu_seen, datebuf, sizeof(datebuf)));
|
vty_out(vty, " last LU seen on %s: %s", domain_label, get_datestr(&last_lu_seen, datebuf, sizeof(datebuf)));
|
||||||
if (!timestamp_age(&last_lu_seen, &age))
|
if (!timestamp_age(&last_lu_seen, &age))
|
||||||
vty_out(vty, " (invalid timestamp)%s", VTY_NEWLINE);
|
vty_out(vty, " (invalid timestamp)");
|
||||||
else {
|
else {
|
||||||
vty_out(vty, " (");
|
vty_out(vty, " (");
|
||||||
#define UNIT_AGO(UNITNAME, UNITVAL) \
|
#define UNIT_AGO(UNITNAME, UNITVAL) \
|
||||||
@@ -66,19 +69,20 @@ static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t
|
|||||||
UNIT_AGO("h", 60*60);
|
UNIT_AGO("h", 60*60);
|
||||||
UNIT_AGO("m", 60);
|
UNIT_AGO("m", 60);
|
||||||
UNIT_AGO("s", 1);
|
UNIT_AGO("s", 1);
|
||||||
if (!only_age)
|
|
||||||
vty_out(vty, " ago)%s", VTY_NEWLINE);
|
|
||||||
else
|
|
||||||
vty_out(vty, " ago)");
|
vty_out(vty, " ago)");
|
||||||
#undef UNIT_AGO
|
#undef UNIT_AGO
|
||||||
}
|
}
|
||||||
|
if (last_lu_rat && *last_lu_rat != '\0')
|
||||||
|
vty_out(vty, " on %s", last_lu_rat);
|
||||||
|
vty_out(vty, "%s", VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct osmo_sub_auth_data2 aud2g;
|
int i;
|
||||||
struct osmo_sub_auth_data2 aud3g;
|
struct osmo_sub_auth_data aud2g;
|
||||||
|
struct osmo_sub_auth_data aud3g;
|
||||||
|
|
||||||
vty_out(vty, " ID: %"PRIu64"%s", subscr->id, VTY_NEWLINE);
|
vty_out(vty, " ID: %"PRIu64"%s", subscr->id, VTY_NEWLINE);
|
||||||
|
|
||||||
@@ -113,8 +117,12 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
|||||||
vty_out(vty, " PS disabled%s", VTY_NEWLINE);
|
vty_out(vty, " PS disabled%s", VTY_NEWLINE);
|
||||||
if (subscr->ms_purged_ps)
|
if (subscr->ms_purged_ps)
|
||||||
vty_out(vty, " PS purged%s", VTY_NEWLINE);
|
vty_out(vty, " PS purged%s", VTY_NEWLINE);
|
||||||
dump_last_lu_seen(vty, "CS", subscr->last_lu_seen, false);
|
dump_last_lu_seen(vty, "CS", subscr->last_lu_seen, subscr->last_lu_rat_cs);
|
||||||
dump_last_lu_seen(vty, "PS", subscr->last_lu_seen_ps, false);
|
dump_last_lu_seen(vty, "PS", subscr->last_lu_seen_ps, subscr->last_lu_rat_ps);
|
||||||
|
for (i = OSMO_RAT_UNKNOWN + 1; i < ARRAY_SIZE(subscr->rat_types); i++) {
|
||||||
|
vty_out(vty, " %s: %s%s", osmo_rat_type_name(i), subscr->rat_types[i] ? "allowed" : "forbidden",
|
||||||
|
VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
if (!*subscr->imsi)
|
if (!*subscr->imsi)
|
||||||
return;
|
return;
|
||||||
@@ -137,12 +145,12 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
|||||||
|
|
||||||
if (aud2g.type != OSMO_AUTH_TYPE_NONE && aud2g.type != OSMO_AUTH_TYPE_GSM) {
|
if (aud2g.type != OSMO_AUTH_TYPE_NONE && aud2g.type != OSMO_AUTH_TYPE_GSM) {
|
||||||
vty_out(vty, "%% Error: 2G auth data is not of type 'GSM'%s", VTY_NEWLINE);
|
vty_out(vty, "%% Error: 2G auth data is not of type 'GSM'%s", VTY_NEWLINE);
|
||||||
aud2g = (struct osmo_sub_auth_data2){};
|
aud2g = (struct osmo_sub_auth_data){};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aud3g.type != OSMO_AUTH_TYPE_NONE && aud3g.type != OSMO_AUTH_TYPE_UMTS) {
|
if (aud3g.type != OSMO_AUTH_TYPE_NONE && aud3g.type != OSMO_AUTH_TYPE_UMTS) {
|
||||||
vty_out(vty, "%% Error: 3G auth data is not of type 'UMTS'%s", VTY_NEWLINE);
|
vty_out(vty, "%% Error: 3G auth data is not of type 'UMTS'%s", VTY_NEWLINE);
|
||||||
aud3g = (struct osmo_sub_auth_data2){};
|
aud3g = (struct osmo_sub_auth_data){};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aud2g.algo != OSMO_AUTH_ALG_NONE && aud2g.type != OSMO_AUTH_TYPE_NONE) {
|
if (aud2g.algo != OSMO_AUTH_ALG_NONE && aud2g.type != OSMO_AUTH_TYPE_NONE) {
|
||||||
@@ -154,10 +162,9 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
|||||||
|
|
||||||
if (aud3g.algo != OSMO_AUTH_ALG_NONE && aud3g.type != OSMO_AUTH_TYPE_NONE) {
|
if (aud3g.algo != OSMO_AUTH_ALG_NONE && aud3g.type != OSMO_AUTH_TYPE_NONE) {
|
||||||
vty_out(vty, " 3G auth: %s%s", osmo_auth_alg_name(aud3g.algo), VTY_NEWLINE);
|
vty_out(vty, " 3G auth: %s%s", osmo_auth_alg_name(aud3g.algo), VTY_NEWLINE);
|
||||||
vty_out(vty, " K=%s%s",
|
vty_out(vty, " K=%s%s", hexdump_buf(aud3g.u.umts.k), VTY_NEWLINE);
|
||||||
osmo_hexdump_nospc(aud3g.u.umts.k, aud3g.u.umts.k_len), VTY_NEWLINE);
|
|
||||||
vty_out(vty, " %s=%s%s", aud3g.u.umts.opc_is_op? "OP" : "OPC",
|
vty_out(vty, " %s=%s%s", aud3g.u.umts.opc_is_op? "OP" : "OPC",
|
||||||
osmo_hexdump_nospc(aud3g.u.umts.opc, aud3g.u.umts.opc_len), VTY_NEWLINE);
|
hexdump_buf(aud3g.u.umts.opc), VTY_NEWLINE);
|
||||||
vty_out(vty, " IND-bitlen=%u", aud3g.u.umts.ind_bitlen);
|
vty_out(vty, " IND-bitlen=%u", aud3g.u.umts.ind_bitlen);
|
||||||
if (aud3g.u.umts.sqn)
|
if (aud3g.u.umts.sqn)
|
||||||
vty_out(vty, " last-SQN=%"PRIu64, aud3g.u.umts.sqn);
|
vty_out(vty, " last-SQN=%"PRIu64, aud3g.u.umts.sqn);
|
||||||
@@ -165,28 +172,6 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subscr_dump_summary_vty(struct hlr_subscriber *subscr, void *data)
|
|
||||||
{
|
|
||||||
struct vty *vty = data;
|
|
||||||
vty_out(vty, "%-5"PRIu64" %-12s %-16s", subscr->id,
|
|
||||||
*subscr->msisdn ? subscr->msisdn : "none",
|
|
||||||
*subscr->imsi ? subscr->imsi : "none");
|
|
||||||
|
|
||||||
if (*subscr->imei) {
|
|
||||||
char checksum = osmo_luhn(subscr->imei, 14);
|
|
||||||
if (checksum == -EINVAL)
|
|
||||||
vty_out(vty, " %-14s (INVALID LENGTH!)", subscr->imei);
|
|
||||||
else
|
|
||||||
vty_out(vty, " %-14s%c", subscr->imei, checksum);
|
|
||||||
} else {
|
|
||||||
vty_out(vty," ------------- ");
|
|
||||||
}
|
|
||||||
vty_out(vty, " %-2s%-2s ", subscr->nam_cs ? "CS" : "", subscr->nam_ps ? "PS" : "");
|
|
||||||
if (subscr->last_lu_seen)
|
|
||||||
dump_last_lu_seen(vty, "CS", subscr->last_lu_seen, true);
|
|
||||||
vty_out_newline(vty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id, struct hlr_subscriber *subscr)
|
static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id, struct hlr_subscriber *subscr)
|
||||||
{
|
{
|
||||||
char imei_buf[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1];
|
char imei_buf[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1];
|
||||||
@@ -214,52 +199,10 @@ static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_summary_table_vty(struct vty *vty, bool header, bool show_ls)
|
|
||||||
{
|
|
||||||
const char *texts = "ID MSISDN IMSI IMEI NAM";
|
|
||||||
const char *lines = "----- ------------ ---------------- ---------------- -----";
|
|
||||||
const char *ls_text = " LAST SEEN";
|
|
||||||
const char *ls_line = " ------------";
|
|
||||||
if (header) {
|
|
||||||
if (!show_ls)
|
|
||||||
vty_out(vty, "%s%s%s%s", texts, VTY_NEWLINE, lines, VTY_NEWLINE);
|
|
||||||
else
|
|
||||||
vty_out(vty, "%s%s%s%s%s%s", texts, ls_text, VTY_NEWLINE, lines, ls_line, VTY_NEWLINE);
|
|
||||||
} else {
|
|
||||||
if (!show_ls)
|
|
||||||
vty_out(vty, "%s%s%s%s", lines, VTY_NEWLINE, texts, VTY_NEWLINE);
|
|
||||||
else
|
|
||||||
vty_out(vty, "%s%s%s%s%s%s", lines, ls_line, VTY_NEWLINE, texts, ls_text, VTY_NEWLINE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_subscrs(struct vty *vty, const char *filter_type, const char *filter)
|
|
||||||
{
|
|
||||||
int rc = -1;
|
|
||||||
int count = 0;
|
|
||||||
const char *err;
|
|
||||||
bool show_ls = (filter_type && strcmp(filter_type, "last_lu_seen") == 0);
|
|
||||||
dump_summary_table_vty(vty, true, show_ls);
|
|
||||||
rc = db_subscrs_get(g_hlr->dbc, filter_type, filter, subscr_dump_summary_vty, vty, &count, &err);
|
|
||||||
if (count > 40) {
|
|
||||||
dump_summary_table_vty(vty, false, show_ls);
|
|
||||||
}
|
|
||||||
if (count > 0)
|
|
||||||
vty_out(vty, " Subscribers Shown: %d%s", count, VTY_NEWLINE);
|
|
||||||
if (rc)
|
|
||||||
vty_out(vty, "%% %s%s", err, VTY_NEWLINE);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define SUBSCR_CMD "subscriber "
|
#define SUBSCR_CMD "subscriber "
|
||||||
#define SUBSCR_CMD_HELP "Subscriber management commands\n"
|
#define SUBSCR_CMD_HELP "Subscriber management commands\n"
|
||||||
#define SUBSCR_SHOW_HELP "Show subscriber information\n"
|
|
||||||
#define SUBSCRS_SHOW_HELP "Show all subscribers (with filter possibility)\n"
|
|
||||||
|
|
||||||
#define SUBSCR_ID "(imsi|msisdn|id|imei) IDENT"
|
#define SUBSCR_ID "(imsi|msisdn|id|imei) IDENT"
|
||||||
#define SUBSCR_FILTER "(imei|imsi|msisdn) FILTER"
|
|
||||||
|
|
||||||
#define SUBSCR_ID_HELP \
|
#define SUBSCR_ID_HELP \
|
||||||
"Identify subscriber by IMSI\n" \
|
"Identify subscriber by IMSI\n" \
|
||||||
"Identify subscriber by MSISDN (phone number)\n" \
|
"Identify subscriber by MSISDN (phone number)\n" \
|
||||||
@@ -277,7 +220,7 @@ static int get_subscrs(struct vty *vty, const char *filter_type, const char *fil
|
|||||||
DEFUN(subscriber_show,
|
DEFUN(subscriber_show,
|
||||||
subscriber_show_cmd,
|
subscriber_show_cmd,
|
||||||
SUBSCR "show",
|
SUBSCR "show",
|
||||||
SUBSCR_HELP SUBSCR_SHOW_HELP)
|
SUBSCR_HELP "Show subscriber information\n")
|
||||||
{
|
{
|
||||||
struct hlr_subscriber subscr;
|
struct hlr_subscriber subscr;
|
||||||
const char *id_type = argv[0];
|
const char *id_type = argv[0];
|
||||||
@@ -292,50 +235,7 @@ DEFUN(subscriber_show,
|
|||||||
|
|
||||||
ALIAS(subscriber_show, show_subscriber_cmd,
|
ALIAS(subscriber_show, show_subscriber_cmd,
|
||||||
"show " SUBSCR_CMD SUBSCR_ID,
|
"show " SUBSCR_CMD SUBSCR_ID,
|
||||||
SHOW_STR SUBSCR_SHOW_HELP SUBSCR_ID_HELP);
|
SHOW_STR SUBSCR_CMD_HELP SUBSCR_ID_HELP);
|
||||||
|
|
||||||
DEFUN(show_subscriber_all,
|
|
||||||
show_subscriber_all_cmd,
|
|
||||||
"show subscribers all",
|
|
||||||
SHOW_STR SUBSCRS_SHOW_HELP "Show summary of all subscribers\n")
|
|
||||||
{
|
|
||||||
if (get_subscrs(vty, NULL, NULL))
|
|
||||||
return CMD_WARNING;
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(show_subscriber_filtered,
|
|
||||||
show_subscriber_filtered_cmd,
|
|
||||||
"show subscribers " SUBSCR_FILTER,
|
|
||||||
SHOW_STR SUBSCRS_SHOW_HELP
|
|
||||||
"Filter Subscribers by IMEI\n" "Filter Subscribers by IMSI\n" "Filter Subscribers by MSISDN\n"
|
|
||||||
"String to match in imei, imsi or msisdn\n")
|
|
||||||
{
|
|
||||||
const char *filter_type = argv[0];
|
|
||||||
const char *filter = argv[1];
|
|
||||||
|
|
||||||
if (get_subscrs(vty, filter_type, filter))
|
|
||||||
return CMD_WARNING;
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
ALIAS(show_subscriber_filtered, show_subscriber_filtered_cmd2,
|
|
||||||
"show subscribers (cs|ps) (on|off)",
|
|
||||||
SHOW_STR SUBSCR_SHOW_HELP
|
|
||||||
"Filter Subscribers by CS Network Access Mode\n" "Filter Subscribers by PS Network Access Mode\n"
|
|
||||||
"Authorised\n" "Not Authorised\n");
|
|
||||||
|
|
||||||
DEFUN(show_subscriber_order_last_seen, show_subscriber_order_last_seen_cmd,
|
|
||||||
"show subscribers last-seen",
|
|
||||||
SHOW_STR SUBSCR_SHOW_HELP "Show Subscribers Ordered by Last Seen Time\n")
|
|
||||||
{
|
|
||||||
if (get_subscrs(vty, "last_lu_seen", NULL))
|
|
||||||
return CMD_WARNING;
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(subscriber_create,
|
DEFUN(subscriber_create,
|
||||||
subscriber_create_cmd,
|
subscriber_create_cmd,
|
||||||
@@ -461,27 +361,26 @@ static bool is_hexkey_valid(struct vty *vty, const char *label,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define AUTH_ALG_TYPES_2G "(comp128v1|comp128v2|comp128v3|xor-2g)"
|
#define AUTH_ALG_TYPES_2G "(comp128v1|comp128v2|comp128v3|xor)"
|
||||||
#define AUTH_ALG_TYPES_2G_HELP \
|
#define AUTH_ALG_TYPES_2G_HELP \
|
||||||
"Use COMP128v1 algorithm\n" \
|
"Use COMP128v1 algorithm\n" \
|
||||||
"Use COMP128v2 algorithm\n" \
|
"Use COMP128v2 algorithm\n" \
|
||||||
"Use COMP128v3 algorithm\n" \
|
"Use COMP128v3 algorithm\n" \
|
||||||
"Use XOR-2G algorithm\n"
|
"Use XOR algorithm\n"
|
||||||
|
|
||||||
#define AUTH_ALG_TYPES_3G "(milenage|tuak)"
|
#define AUTH_ALG_TYPES_3G "milenage"
|
||||||
#define AUTH_ALG_TYPES_3G_HELP \
|
#define AUTH_ALG_TYPES_3G_HELP \
|
||||||
"Use Milenage algorithm\n" \
|
"Use Milenage algorithm\n"
|
||||||
"Use TUAK algorithm\n"
|
|
||||||
|
|
||||||
bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
|
#define A38_XOR_MIN_KEY_LEN 12
|
||||||
int *minlen, int *maxlen, int *minlen_opc, int *maxlen_opc)
|
#define A38_XOR_MAX_KEY_LEN 16
|
||||||
|
#define A38_COMP128_KEY_LEN 16
|
||||||
|
|
||||||
|
#define MILENAGE_KEY_LEN 16
|
||||||
|
|
||||||
|
static bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
|
||||||
|
int *minlen, int *maxlen)
|
||||||
{
|
{
|
||||||
/* Default: no OP[c]. True for all 2G algorithms, and 3G-XOR. Overridden below for real 3G AKA algorithms. */
|
|
||||||
if (minlen_opc)
|
|
||||||
*minlen_opc = 0;
|
|
||||||
if (maxlen_opc)
|
|
||||||
*maxlen_opc = 0;
|
|
||||||
|
|
||||||
if (!strcasecmp(alg_str, "none")) {
|
if (!strcasecmp(alg_str, "none")) {
|
||||||
*algo = OSMO_AUTH_ALG_NONE;
|
*algo = OSMO_AUTH_ALG_NONE;
|
||||||
*minlen = *maxlen = 0;
|
*minlen = *maxlen = 0;
|
||||||
@@ -494,28 +393,13 @@ bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
|
|||||||
} else if (!strcasecmp(alg_str, "comp128v3")) {
|
} else if (!strcasecmp(alg_str, "comp128v3")) {
|
||||||
*algo = OSMO_AUTH_ALG_COMP128v3;
|
*algo = OSMO_AUTH_ALG_COMP128v3;
|
||||||
*minlen = *maxlen = A38_COMP128_KEY_LEN;
|
*minlen = *maxlen = A38_COMP128_KEY_LEN;
|
||||||
} else if (!strcasecmp(alg_str, "xor-3g")) {
|
} else if (!strcasecmp(alg_str, "xor")) {
|
||||||
*algo = OSMO_AUTH_ALG_XOR_3G;
|
*algo = OSMO_AUTH_ALG_XOR;
|
||||||
*minlen = A38_XOR_MIN_KEY_LEN;
|
*minlen = A38_XOR_MIN_KEY_LEN;
|
||||||
*maxlen = A38_XOR_MAX_KEY_LEN;
|
*maxlen = A38_XOR_MAX_KEY_LEN;
|
||||||
} else if (!strcasecmp(alg_str, "xor-2g")) {
|
|
||||||
*algo = OSMO_AUTH_ALG_XOR_2G;
|
|
||||||
*minlen = *maxlen = A38_XOR2G_KEY_LEN;
|
|
||||||
} else if (!strcasecmp(alg_str, "milenage")) {
|
} else if (!strcasecmp(alg_str, "milenage")) {
|
||||||
*algo = OSMO_AUTH_ALG_MILENAGE;
|
*algo = OSMO_AUTH_ALG_MILENAGE;
|
||||||
*minlen = *maxlen = MILENAGE_KEY_LEN;
|
*minlen = *maxlen = MILENAGE_KEY_LEN;
|
||||||
if (minlen_opc)
|
|
||||||
*minlen_opc = MILENAGE_KEY_LEN;
|
|
||||||
if (maxlen_opc)
|
|
||||||
*maxlen_opc = MILENAGE_KEY_LEN;
|
|
||||||
} else if (!strcasecmp(alg_str, "tuak")) {
|
|
||||||
*algo = OSMO_AUTH_ALG_TUAK;
|
|
||||||
*minlen = 16;
|
|
||||||
*maxlen = 32;
|
|
||||||
if (minlen_opc)
|
|
||||||
*minlen_opc = 32;
|
|
||||||
if (maxlen_opc)
|
|
||||||
*maxlen_opc = 32;
|
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
@@ -571,7 +455,7 @@ DEFUN(subscriber_aud2g,
|
|||||||
.u.gsm.ki = ki,
|
.u.gsm.ki = ki,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!auth_algo_parse(alg_type, &aud2g.algo, &minlen, &maxlen, NULL, NULL)) {
|
if (!auth_algo_parse(alg_type, &aud2g.algo, &minlen, &maxlen)) {
|
||||||
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE);
|
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE);
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
@@ -630,21 +514,21 @@ DEFUN(subscriber_aud3g,
|
|||||||
SUBSCR_UPDATE_HELP
|
SUBSCR_UPDATE_HELP
|
||||||
"Set UMTS authentication data (3G, and 2G with UMTS AKA)\n"
|
"Set UMTS authentication data (3G, and 2G with UMTS AKA)\n"
|
||||||
AUTH_ALG_TYPES_3G_HELP
|
AUTH_ALG_TYPES_3G_HELP
|
||||||
"Set Encryption Key K\n" "K as 32/64 hexadecimal characters\n"
|
"Set Encryption Key K\n" "K as 32 hexadecimal characters\n"
|
||||||
"Set OP key\n" "Set OPC key\n" "OP or OPC as 32/64 hexadecimal characters\n"
|
"Set OP key\n" "Set OPC key\n" "OP or OPC as 32 hexadecimal characters\n"
|
||||||
"Set IND bit length\n" "IND bit length value (default: 5)\n")
|
"Set IND bit length\n" "IND bit length value (default: 5)\n")
|
||||||
{
|
{
|
||||||
struct hlr_subscriber subscr;
|
struct hlr_subscriber subscr;
|
||||||
int minlen = 0, minlen_opc = 0;
|
int minlen = 0;
|
||||||
int maxlen = 0, maxlen_opc = 0;
|
int maxlen = 0;
|
||||||
int rc;
|
int rc;
|
||||||
const char *id_type = argv[0];
|
const char *id_type = argv[0];
|
||||||
const char *id = argv[1];
|
const char *id = argv[1];
|
||||||
const char *alg_type = argv[2];
|
const char *alg_type = AUTH_ALG_TYPES_3G;
|
||||||
const char *k = argv[3];
|
const char *k = argv[2];
|
||||||
bool opc_is_op = (strcasecmp("op", argv[4]) == 0);
|
bool opc_is_op = (strcasecmp("op", argv[3]) == 0);
|
||||||
const char *op_opc = argv[5];
|
const char *op_opc = argv[4];
|
||||||
int ind_bitlen = argc > 7 ? atoi(argv[7]) : 5;
|
int ind_bitlen = argc > 6? atoi(argv[6]) : 5;
|
||||||
struct sub_auth_data_str aud3g = {
|
struct sub_auth_data_str aud3g = {
|
||||||
.type = OSMO_AUTH_TYPE_UMTS,
|
.type = OSMO_AUTH_TYPE_UMTS,
|
||||||
.u.umts = {
|
.u.umts = {
|
||||||
@@ -655,7 +539,7 @@ DEFUN(subscriber_aud3g,
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!auth_algo_parse(alg_type, &aud3g.algo, &minlen, &maxlen, &minlen_opc, &maxlen_opc)) {
|
if (!auth_algo_parse(alg_type, &aud3g.algo, &minlen, &maxlen)) {
|
||||||
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE);
|
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE);
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
@@ -663,56 +547,8 @@ DEFUN(subscriber_aud3g,
|
|||||||
if (!is_hexkey_valid(vty, "K", aud3g.u.umts.k, minlen, maxlen))
|
if (!is_hexkey_valid(vty, "K", aud3g.u.umts.k, minlen, maxlen))
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
|
|
||||||
if (!is_hexkey_valid(vty, opc_is_op ? "OP" : "OPC", aud3g.u.umts.opc, minlen_opc, maxlen_opc))
|
if (!is_hexkey_valid(vty, opc_is_op ? "OP" : "OPC", aud3g.u.umts.opc,
|
||||||
return CMD_WARNING;
|
MILENAGE_KEY_LEN, MILENAGE_KEY_LEN))
|
||||||
|
|
||||||
if (get_subscr_by_argv(vty, id_type, id, &subscr))
|
|
||||||
return CMD_WARNING;
|
|
||||||
|
|
||||||
rc = db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud3g);
|
|
||||||
|
|
||||||
if (rc) {
|
|
||||||
vty_out(vty, "%% Error: cannot set 3G auth data for IMSI='%s'%s",
|
|
||||||
subscr.imsi, VTY_NEWLINE);
|
|
||||||
return CMD_WARNING;
|
|
||||||
}
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(subscriber_aud3g_xor,
|
|
||||||
subscriber_aud3g_xor_cmd,
|
|
||||||
SUBSCR_UPDATE "aud3g xor-3g k K"
|
|
||||||
" [ind-bitlen] [<0-28>]",
|
|
||||||
SUBSCR_UPDATE_HELP
|
|
||||||
"Set UMTS authentication data (3G, and 2G with UMTS AKA)\n"
|
|
||||||
"Use XOR-3G algorithm\n"
|
|
||||||
"Set Encryption Key K\n" "K as 32 hexadecimal characters\n"
|
|
||||||
"Set IND bit length\n" "IND bit length value (default: 5)\n")
|
|
||||||
{
|
|
||||||
struct hlr_subscriber subscr;
|
|
||||||
int minlen = 0;
|
|
||||||
int maxlen = 0;
|
|
||||||
int rc;
|
|
||||||
const char *id_type = argv[0];
|
|
||||||
const char *id = argv[1];
|
|
||||||
const char *k = argv[2];
|
|
||||||
int ind_bitlen = argc > 4? atoi(argv[4]) : 5;
|
|
||||||
struct sub_auth_data_str aud3g = {
|
|
||||||
.type = OSMO_AUTH_TYPE_UMTS,
|
|
||||||
.u.umts = {
|
|
||||||
.k = k,
|
|
||||||
.opc_is_op = 0,
|
|
||||||
.opc = "00000000000000000000000000000000",
|
|
||||||
.ind_bitlen = ind_bitlen,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!auth_algo_parse("xor-3g", &aud3g.algo, &minlen, &maxlen, NULL, NULL)) {
|
|
||||||
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", "xor-3g", VTY_NEWLINE);
|
|
||||||
return CMD_WARNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_hexkey_valid(vty, "K", aud3g.u.umts.k, minlen, maxlen))
|
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
|
|
||||||
if (get_subscr_by_argv(vty, id_type, id, &subscr))
|
if (get_subscr_by_argv(vty, id_type, id, &subscr))
|
||||||
@@ -803,12 +639,50 @@ DEFUN(subscriber_nam,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEFUN(subscriber_rat,
|
||||||
|
subscriber_rat_cmd,
|
||||||
|
SUBSCR_UPDATE "rat (geran-a|utran-iu|eutran-sgs) (allowed|forbidden)",
|
||||||
|
SUBSCR_UPDATE_HELP
|
||||||
|
"Allow or forbid specific Radio Access Types\n"
|
||||||
|
"Set access to GERAN-A\n"
|
||||||
|
"Set access to UTRAN-Iu\n"
|
||||||
|
"Set access to EUTRAN-SGs\n"
|
||||||
|
"Allow access\n"
|
||||||
|
"Forbid access\n")
|
||||||
|
{
|
||||||
|
struct hlr_subscriber subscr;
|
||||||
|
const char *id_type = argv[0];
|
||||||
|
const char *id = argv[1];
|
||||||
|
const char *rat_str = argv[2];
|
||||||
|
const char *allowed_forbidden = argv[3];
|
||||||
|
enum osmo_rat_type rat = OSMO_RAT_UNKNOWN;
|
||||||
|
bool allowed;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (strcmp(rat_str, "geran-a") == 0)
|
||||||
|
rat = OSMO_RAT_GERAN_A;
|
||||||
|
else if (strcmp(rat_str, "utran-iu") == 0)
|
||||||
|
rat = OSMO_RAT_UTRAN_IU;
|
||||||
|
else if (strcmp(rat_str, "eutran-sgs") == 0)
|
||||||
|
rat = OSMO_RAT_EUTRAN_SGS;
|
||||||
|
|
||||||
|
allowed = (strcmp(allowed_forbidden, "allowed") == 0);
|
||||||
|
|
||||||
|
if (get_subscr_by_argv(vty, id_type, id, &subscr))
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
rc = hlr_subscr_rat_flag(g_hlr, &subscr, rat, allowed);
|
||||||
|
|
||||||
|
if (rc && rc != -ENOEXEC) {
|
||||||
|
vty_out(vty, "%% Error: cannot set %s to %s%s",
|
||||||
|
osmo_rat_type_name(rat), allowed ? "allowed" : "forbidden", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
void hlr_vty_subscriber_init(void)
|
void hlr_vty_subscriber_init(void)
|
||||||
{
|
{
|
||||||
install_element_ve(&show_subscriber_all_cmd);
|
|
||||||
install_element_ve(&show_subscriber_filtered_cmd);
|
|
||||||
install_element_ve(&show_subscriber_filtered_cmd2);
|
|
||||||
install_element_ve(&show_subscriber_order_last_seen_cmd);
|
|
||||||
install_element_ve(&subscriber_show_cmd);
|
install_element_ve(&subscriber_show_cmd);
|
||||||
install_element_ve(&show_subscriber_cmd);
|
install_element_ve(&show_subscriber_cmd);
|
||||||
install_element(ENABLE_NODE, &subscriber_create_cmd);
|
install_element(ENABLE_NODE, &subscriber_create_cmd);
|
||||||
@@ -818,7 +692,7 @@ void hlr_vty_subscriber_init(void)
|
|||||||
install_element(ENABLE_NODE, &subscriber_aud2g_cmd);
|
install_element(ENABLE_NODE, &subscriber_aud2g_cmd);
|
||||||
install_element(ENABLE_NODE, &subscriber_no_aud3g_cmd);
|
install_element(ENABLE_NODE, &subscriber_no_aud3g_cmd);
|
||||||
install_element(ENABLE_NODE, &subscriber_aud3g_cmd);
|
install_element(ENABLE_NODE, &subscriber_aud3g_cmd);
|
||||||
install_element(ENABLE_NODE, &subscriber_aud3g_xor_cmd);
|
|
||||||
install_element(ENABLE_NODE, &subscriber_imei_cmd);
|
install_element(ENABLE_NODE, &subscriber_imei_cmd);
|
||||||
install_element(ENABLE_NODE, &subscriber_nam_cmd);
|
install_element(ENABLE_NODE, &subscriber_nam_cmd);
|
||||||
|
install_element(ENABLE_NODE, &subscriber_rat_cmd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,12 +43,6 @@ const struct log_info_cat hlr_log_info_cat[] = {
|
|||||||
.color = "\033[1;35m",
|
.color = "\033[1;35m",
|
||||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
},
|
},
|
||||||
[DCTRL] = {
|
|
||||||
.name = "DCTRL",
|
|
||||||
.description = "Osmocom CTRL interface",
|
|
||||||
.color = "\033[1;30m",
|
|
||||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct log_info hlr_log_info = {
|
const struct log_info hlr_log_info = {
|
||||||
|
|||||||
68
src/lu_fsm.c
68
src/lu_fsm.c
@@ -26,7 +26,7 @@
|
|||||||
#include <osmocom/gsm/apn.h>
|
#include <osmocom/gsm/apn.h>
|
||||||
#include <osmocom/gsm/gsm48_ie.h>
|
#include <osmocom/gsm/gsm48_ie.h>
|
||||||
|
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
#include <osmocom/gsupclient/gsup_req.h>
|
#include <osmocom/gsupclient/gsup_req.h>
|
||||||
#include <osmocom/hlr/logging.h>
|
#include <osmocom/hlr/logging.h>
|
||||||
#include <osmocom/hlr/hlr.h>
|
#include <osmocom/hlr/hlr.h>
|
||||||
@@ -52,11 +52,11 @@ struct lu {
|
|||||||
bool is_ps;
|
bool is_ps;
|
||||||
|
|
||||||
/* VLR requesting the LU. */
|
/* VLR requesting the LU. */
|
||||||
struct osmo_cni_peer_id vlr_name;
|
struct osmo_gsup_peer_id vlr_name;
|
||||||
|
|
||||||
/* If the LU request was received via a proxy and not immediately from a local VLR, this indicates the closest
|
/* If the LU request was received via a proxy and not immediately from a local VLR, this indicates the closest
|
||||||
* peer that forwarded the GSUP message. */
|
* peer that forwarded the GSUP message. */
|
||||||
struct osmo_cni_peer_id via_proxy;
|
struct osmo_gsup_peer_id via_proxy;
|
||||||
};
|
};
|
||||||
LLIST_HEAD(g_all_lu);
|
LLIST_HEAD(g_all_lu);
|
||||||
|
|
||||||
@@ -108,6 +108,8 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
|
|||||||
{
|
{
|
||||||
struct osmo_fsm_inst *fi;
|
struct osmo_fsm_inst *fi;
|
||||||
struct lu *lu;
|
struct lu *lu;
|
||||||
|
bool any_rat_allowed;
|
||||||
|
int i;
|
||||||
|
|
||||||
OSMO_ASSERT(update_location_req);
|
OSMO_ASSERT(update_location_req);
|
||||||
OSMO_ASSERT(update_location_req->gsup.message_type == OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST);
|
OSMO_ASSERT(update_location_req->gsup.message_type == OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST);
|
||||||
@@ -130,13 +132,13 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
|
|||||||
|
|
||||||
osmo_fsm_inst_update_id_f_sanitize(fi, '_', "%s:IMSI-%s", lu->is_ps ? "PS" : "CS", update_location_req->gsup.imsi);
|
osmo_fsm_inst_update_id_f_sanitize(fi, '_', "%s:IMSI-%s", lu->is_ps ? "PS" : "CS", update_location_req->gsup.imsi);
|
||||||
|
|
||||||
if (osmo_cni_peer_id_is_empty(&lu->vlr_name)) {
|
if (osmo_gsup_peer_id_is_empty(&lu->vlr_name)) {
|
||||||
lu_failure(lu, GMM_CAUSE_NET_FAIL, "LU without a VLR");
|
lu_failure(lu, GMM_CAUSE_NET_FAIL, "LU without a VLR");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (db_subscr_get_by_imsi(g_hlr->dbc, update_location_req->gsup.imsi, &lu->subscr) < 0) {
|
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, GMM_CAUSE_ROAMING_NOTALLOWED, "Subscriber does not exist");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,10 +153,32 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if any available RAT type is allowed. See 3GPP TS 29.010 3.2 'Routeing area updating' and 3.8 'Location
|
||||||
|
* update' for the "No Suitable cells in location area" error code. */
|
||||||
|
any_rat_allowed = false;
|
||||||
|
for (i = 0; i < update_location_req->gsup.supported_rat_types_len; i++) {
|
||||||
|
enum osmo_rat_type rat = update_location_req->gsup.supported_rat_types[i];
|
||||||
|
if (rat <= 0 || rat >= OSMO_RAT_COUNT) {
|
||||||
|
lu_failure(lu, GMM_CAUSE_COND_IE_ERR, "Invalid RAT type in GSUP request: %s",
|
||||||
|
osmo_rat_type_name(rat));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (lu->subscr.rat_types[rat]) {
|
||||||
|
any_rat_allowed = true;
|
||||||
|
LOG_LU(lu, LOGL_DEBUG, "subscriber allowed on %s\n", osmo_rat_type_name(rat));
|
||||||
|
} else {
|
||||||
|
LOG_LU(lu, LOGL_DEBUG, "subscriber not allowed on %s\n", osmo_rat_type_name(rat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!any_rat_allowed && update_location_req->gsup.supported_rat_types_len > 0) {
|
||||||
|
lu_failure(lu, GMM_CAUSE_NO_SUIT_CELL_IN_LA, "subscriber not allowed on any available RAT type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: Set subscriber tracing = deactive in VLR/SGSN */
|
/* TODO: Set subscriber tracing = deactive in VLR/SGSN */
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* Cancel in old VLR/SGSN, if new VLR/SGSN differs from old (FIXME: OS#4491) */
|
/* Cancel in old VLR/SGSN, if new VLR/SGSN differs from old */
|
||||||
if (!lu->is_ps && strcmp(subscr->vlr_number, vlr_number)) {
|
if (!lu->is_ps && strcmp(subscr->vlr_number, vlr_number)) {
|
||||||
lu_op_tx_cancel_old(lu);
|
lu_op_tx_cancel_old(lu);
|
||||||
} else if (lu->is_ps && strcmp(subscr->sgsn_number, sgsn_number)) {
|
} else if (lu->is_ps && strcmp(subscr->sgsn_number, sgsn_number)) {
|
||||||
@@ -163,30 +187,31 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Store the VLR / SGSN number with the subscriber, so we know where it was last seen. */
|
/* Store the VLR / SGSN number with the subscriber, so we know where it was last seen. */
|
||||||
if (!osmo_cni_peer_id_is_empty(&lu->via_proxy)) {
|
if (!osmo_gsup_peer_id_is_empty(&lu->via_proxy)) {
|
||||||
LOG_GSUP_REQ(update_location_req, LOGL_DEBUG, "storing %s = %s, via proxy %s\n",
|
LOG_GSUP_REQ(update_location_req, LOGL_DEBUG, "storing %s = %s, via proxy %s\n",
|
||||||
lu->is_ps ? "SGSN number" : "VLR number",
|
lu->is_ps ? "SGSN number" : "VLR number",
|
||||||
osmo_cni_peer_id_to_str(&lu->vlr_name),
|
osmo_gsup_peer_id_to_str(&lu->vlr_name),
|
||||||
osmo_cni_peer_id_to_str(&lu->via_proxy));
|
osmo_gsup_peer_id_to_str(&lu->via_proxy));
|
||||||
} else {
|
} else {
|
||||||
LOG_GSUP_REQ(update_location_req, LOGL_DEBUG, "storing %s = %s\n",
|
LOG_GSUP_REQ(update_location_req, LOGL_DEBUG, "storing %s = %s\n",
|
||||||
lu->is_ps ? "SGSN number" : "VLR number",
|
lu->is_ps ? "SGSN number" : "VLR number",
|
||||||
osmo_cni_peer_id_to_str(&lu->vlr_name));
|
osmo_gsup_peer_id_to_str(&lu->vlr_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (osmo_cni_peer_id_is_empty(&lu->vlr_name)
|
if (osmo_gsup_peer_id_is_empty(&lu->vlr_name)
|
||||||
|| (lu->vlr_name.type != OSMO_CNI_PEER_ID_IPA_NAME)) {
|
|| (lu->vlr_name.type != OSMO_GSUP_PEER_ID_IPA_NAME)) {
|
||||||
lu_failure(lu, GMM_CAUSE_PROTO_ERR_UNSPEC, "Unsupported GSUP peer id type for vlr_name: %s",
|
lu_failure(lu, GMM_CAUSE_PROTO_ERR_UNSPEC, "Unsupported GSUP peer id type for vlr_name: %s",
|
||||||
osmo_cni_peer_id_type_name(lu->vlr_name.type));
|
osmo_gsup_peer_id_type_name(lu->vlr_name.type));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!osmo_cni_peer_id_is_empty(&lu->via_proxy) && (lu->via_proxy.type != OSMO_CNI_PEER_ID_IPA_NAME)) {
|
if (!osmo_gsup_peer_id_is_empty(&lu->via_proxy) && (lu->via_proxy.type != OSMO_GSUP_PEER_ID_IPA_NAME)) {
|
||||||
lu_failure(lu, GMM_CAUSE_PROTO_ERR_UNSPEC, "Unsupported GSUP peer id type for via_proxy: %s",
|
lu_failure(lu, GMM_CAUSE_PROTO_ERR_UNSPEC, "Unsupported GSUP peer id type for via_proxy: %s",
|
||||||
osmo_cni_peer_id_type_name(lu->via_proxy.type));
|
osmo_gsup_peer_id_type_name(lu->via_proxy.type));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (db_subscr_lu(g_hlr->dbc, lu->subscr.id, &lu->vlr_name.ipa_name, lu->is_ps,
|
if (db_subscr_lu(g_hlr->dbc, lu->subscr.id, &lu->vlr_name.ipa_name, lu->is_ps,
|
||||||
osmo_cni_peer_id_is_empty(&lu->via_proxy)? NULL : &lu->via_proxy.ipa_name)) {
|
osmo_gsup_peer_id_is_empty(&lu->via_proxy)? NULL : &lu->via_proxy.ipa_name,
|
||||||
|
update_location_req->gsup.supported_rat_types, update_location_req->gsup.supported_rat_types_len)) {
|
||||||
lu_failure(lu, GMM_CAUSE_NET_FAIL, "Cannot update %s in the database",
|
lu_failure(lu, GMM_CAUSE_NET_FAIL, "Cannot update %s in the database",
|
||||||
lu->is_ps ? "SGSN number" : "VLR number");
|
lu->is_ps ? "SGSN number" : "VLR number");
|
||||||
return;
|
return;
|
||||||
@@ -241,11 +266,13 @@ static void lu_fsm_wait_insert_data_result_onenter(struct osmo_fsm_inst *fi, uin
|
|||||||
struct lu *lu = fi->priv;
|
struct lu *lu = fi->priv;
|
||||||
struct hlr_subscriber *subscr = &lu->subscr;
|
struct hlr_subscriber *subscr = &lu->subscr;
|
||||||
struct osmo_gsup_message gsup;
|
struct osmo_gsup_message gsup;
|
||||||
|
uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];
|
||||||
|
uint8_t apn[APN_MAXLEN];
|
||||||
|
|
||||||
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi,
|
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi,
|
||||||
subscr->msisdn,
|
subscr->msisdn, msisdn_enc, sizeof(msisdn_enc),
|
||||||
lu->is_ps ? OSMO_GSUP_CN_DOMAIN_PS : OSMO_GSUP_CN_DOMAIN_CS,
|
apn, sizeof(apn),
|
||||||
OTC_SELECT)) {
|
lu->is_ps? OSMO_GSUP_CN_DOMAIN_PS : OSMO_GSUP_CN_DOMAIN_CS)) {
|
||||||
lu_failure(lu, GMM_CAUSE_NET_FAIL, "cannot encode Insert Subscriber Data message");
|
lu_failure(lu, GMM_CAUSE_NET_FAIL, "cannot encode Insert Subscriber Data message");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -275,7 +302,6 @@ void lu_fsm_wait_insert_data_result(struct osmo_fsm_inst *fi, uint32_t event, vo
|
|||||||
|
|
||||||
case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
|
case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
|
||||||
lu_failure(lu, GMM_CAUSE_NET_FAIL, "Rx %s", osmo_gsup_message_type_name(req->gsup.message_type));
|
lu_failure(lu, GMM_CAUSE_NET_FAIL, "Rx %s", osmo_gsup_message_type_name(req->gsup.message_type));
|
||||||
osmo_gsup_req_free(req);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -313,7 +339,7 @@ static struct osmo_fsm lu_fsm = {
|
|||||||
.cleanup = lu_fsm_cleanup,
|
.cleanup = lu_fsm_cleanup,
|
||||||
};
|
};
|
||||||
|
|
||||||
static __attribute__((constructor)) void lu_fsm_init(void)
|
static __attribute__((constructor)) void lu_fsm_init()
|
||||||
{
|
{
|
||||||
OSMO_ASSERT(osmo_fsm_register(&lu_fsm) == 0);
|
OSMO_ASSERT(osmo_fsm_register(&lu_fsm) == 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# This is _NOT_ the library release version, it's an API version.
|
# This is _NOT_ the library release version, it's an API version.
|
||||||
# Please read chapter "Library interface versions" of the libtool documentation
|
# 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
|
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
|
||||||
LIBVERSION=1:1:0
|
LIBVERSION=0:0:0
|
||||||
|
|
||||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include
|
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include
|
||||||
AM_CFLAGS = -fPIC -Wall $(PCSC_CFLAGS) $(TALLOC_CFLAGS) $(LIBOSMOCORE_CFLAGS)
|
AM_CFLAGS = -fPIC -Wall $(PCSC_CFLAGS) $(TALLOC_CFLAGS) $(LIBOSMOCORE_CFLAGS)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ int osmo_mdns_msg_request_encode(void *ctx, struct msgb *msg, const struct osmo_
|
|||||||
qst.domain = req->domain;
|
qst.domain = req->domain;
|
||||||
qst.qtype = req->type;
|
qst.qtype = req->type;
|
||||||
qst.qclass = OSMO_MDNS_RFC_CLASS_IN;
|
qst.qclass = OSMO_MDNS_RFC_CLASS_IN;
|
||||||
if (osmo_mdns_rfc_question_encode(msg, &qst) != 0)
|
if (osmo_mdns_rfc_question_encode(ctx, msg, &qst) != 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -106,7 +106,7 @@ int osmo_mdns_msg_answer_encode(void *ctx, struct msgb *msg, const struct osmo_m
|
|||||||
rec.rdlength = ans_record->length;
|
rec.rdlength = ans_record->length;
|
||||||
rec.rdata = ans_record->data;
|
rec.rdata = ans_record->data;
|
||||||
|
|
||||||
if (osmo_mdns_rfc_record_encode(msg, &rec) != 0)
|
if (osmo_mdns_rfc_record_encode(ctx, msg, &rec) != 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,9 +213,9 @@ struct osmo_mdns_record *osmo_mdns_record_txt_keyval_encode(void *ctx, const cha
|
|||||||
|
|
||||||
va_start(ap, value_fmt);
|
va_start(ap, value_fmt);
|
||||||
value = talloc_vasprintf(ctx, value_fmt, ap);
|
value = talloc_vasprintf(ctx, value_fmt, ap);
|
||||||
va_end(ap);
|
|
||||||
if (!value)
|
if (!value)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
va_end(ap);
|
||||||
r = _osmo_mdns_record_txt_encode(ctx, key, value);
|
r = _osmo_mdns_record_txt_encode(ctx, key, value);
|
||||||
talloc_free(value);
|
talloc_free(value);
|
||||||
return r;
|
return r;
|
||||||
|
|||||||
@@ -27,9 +27,86 @@
|
|||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
#include <osmocom/core/bitvec.h>
|
#include <osmocom/core/bitvec.h>
|
||||||
#include <osmocom/core/logging.h>
|
#include <osmocom/core/logging.h>
|
||||||
#include <osmocom/gsm/apn.h>
|
|
||||||
#include <osmocom/mslookup/mdns_rfc.h>
|
#include <osmocom/mslookup/mdns_rfc.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode/decode IEs
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! Encode a domain string as qname (RFC 1035 4.1.2).
|
||||||
|
* \param[in] domain multiple labels separated by dots, e.g. "sip.voice.1234.msisdn".
|
||||||
|
* \returns allocated buffer with length-value pairs for each label (e.g. 0x03 "sip" 0x05 "voice" ...), NULL on error.
|
||||||
|
*/
|
||||||
|
char *osmo_mdns_rfc_qname_encode(void *ctx, const char *domain)
|
||||||
|
{
|
||||||
|
char *domain_dup;
|
||||||
|
char *domain_iter;
|
||||||
|
char buf[OSMO_MDNS_RFC_MAX_NAME_LEN + 2] = ""; /* len(qname) is len(domain) +1 */
|
||||||
|
struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
|
||||||
|
char *label;
|
||||||
|
|
||||||
|
if (strlen(domain) > OSMO_MDNS_RFC_MAX_NAME_LEN)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
domain_iter = domain_dup = talloc_strdup(ctx, domain);
|
||||||
|
while ((label = strsep(&domain_iter, "."))) {
|
||||||
|
size_t len = strlen(label);
|
||||||
|
|
||||||
|
/* Empty domain, dot at start, two dots in a row, or ending with a dot */
|
||||||
|
if (!len)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
OSMO_STRBUF_PRINTF(sb, "%c%s", (char)len, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
talloc_free(domain_dup);
|
||||||
|
return talloc_strdup(ctx, buf);
|
||||||
|
|
||||||
|
error:
|
||||||
|
talloc_free(domain_dup);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Decode a domain string from a qname (RFC 1035 4.1.2).
|
||||||
|
* \param[in] qname buffer with length-value pairs for each label (e.g. 0x03 "sip" 0x05 "voice" ...)
|
||||||
|
* \param[in] qname_max_len amount of bytes that can be read at most from the memory location that qname points to.
|
||||||
|
* \returns allocated buffer with domain string, multiple labels separated by dots (e.g. "sip.voice.1234.msisdn"),
|
||||||
|
* NULL on error.
|
||||||
|
*/
|
||||||
|
char *osmo_mdns_rfc_qname_decode(void *ctx, const char *qname, size_t qname_max_len)
|
||||||
|
{
|
||||||
|
const char *next_label, *qname_end = qname + qname_max_len;
|
||||||
|
char buf[OSMO_MDNS_RFC_MAX_NAME_LEN + 1];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (qname_max_len < 1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (*qname) {
|
||||||
|
size_t len = *qname;
|
||||||
|
next_label = qname + len + 1;
|
||||||
|
|
||||||
|
if (next_label >= qname_end || i + len > OSMO_MDNS_RFC_MAX_NAME_LEN)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (i) {
|
||||||
|
/* Two dots in a row is not allowed */
|
||||||
|
if (buf[i - 1] == '.')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
buf[i] = '.';
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf + i, qname + 1, len);
|
||||||
|
i += len;
|
||||||
|
qname = next_label;
|
||||||
|
}
|
||||||
|
buf[i] = '\0';
|
||||||
|
|
||||||
|
return talloc_strdup(ctx, buf);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Encode/decode message sections
|
* Encode/decode message sections
|
||||||
*/
|
*/
|
||||||
@@ -69,17 +146,20 @@ int osmo_mdns_rfc_header_decode(const uint8_t *data, size_t data_len, struct osm
|
|||||||
/*! Encode question section (RFC 1035 4.1.2).
|
/*! Encode question section (RFC 1035 4.1.2).
|
||||||
* \param[in] msgb mesage buffer to which the encoded data will be appended.
|
* \param[in] msgb mesage buffer to which the encoded data will be appended.
|
||||||
*/
|
*/
|
||||||
int osmo_mdns_rfc_question_encode(struct msgb *msg, const struct osmo_mdns_rfc_question *qst)
|
int osmo_mdns_rfc_question_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_question *qst)
|
||||||
{
|
{
|
||||||
uint8_t *buf;
|
char *qname;
|
||||||
size_t buf_len;
|
size_t qname_len;
|
||||||
|
uint8_t *qname_buf;
|
||||||
|
|
||||||
/* qname */
|
/* qname */
|
||||||
buf_len = strlen(qst->domain) + 1;
|
qname = osmo_mdns_rfc_qname_encode(ctx, qst->domain);
|
||||||
buf = msgb_put(msg, buf_len);
|
if (!qname)
|
||||||
if (osmo_apn_from_str(buf, buf_len, qst->domain) < 0)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
msgb_put_u8(msg, 0x00);
|
qname_len = strlen(qname) + 1;
|
||||||
|
qname_buf = msgb_put(msg, qname_len);
|
||||||
|
memcpy(qname_buf, qname, qname_len);
|
||||||
|
talloc_free(qname);
|
||||||
|
|
||||||
/* qtype and qclass */
|
/* qtype and qclass */
|
||||||
msgb_put_u16(msg, qst->qtype);
|
msgb_put_u16(msg, qst->qtype);
|
||||||
@@ -97,25 +177,21 @@ struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const ui
|
|||||||
if (data_len < 6)
|
if (data_len < 6)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
/* qname */
|
||||||
ret = talloc_zero(ctx, struct osmo_mdns_rfc_question);
|
ret = talloc_zero(ctx, struct osmo_mdns_rfc_question);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
ret->domain = osmo_mdns_rfc_qname_decode(ret, (const char *)data, qname_len);
|
||||||
/* qname */
|
if (!ret->domain) {
|
||||||
ret->domain = talloc_size(ret, qname_len - 1);
|
talloc_free(ret);
|
||||||
if (!ret->domain)
|
return NULL;
|
||||||
goto error;
|
}
|
||||||
if (!osmo_apn_to_str(ret->domain, data, qname_len - 1))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* qtype and qclass */
|
/* qtype and qclass */
|
||||||
ret->qtype = osmo_load16be(data + qname_len);
|
ret->qtype = osmo_load16be(data + qname_len);
|
||||||
ret->qclass = osmo_load16be(data + qname_len + 2);
|
ret->qclass = osmo_load16be(data + qname_len + 2);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
error:
|
|
||||||
talloc_free(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -125,17 +201,20 @@ error:
|
|||||||
/*! Encode one resource record (RFC 1035 4.1.3).
|
/*! Encode one resource record (RFC 1035 4.1.3).
|
||||||
* \param[in] msgb mesage buffer to which the encoded data will be appended.
|
* \param[in] msgb mesage buffer to which the encoded data will be appended.
|
||||||
*/
|
*/
|
||||||
int osmo_mdns_rfc_record_encode(struct msgb *msg, const struct osmo_mdns_rfc_record *rec)
|
int osmo_mdns_rfc_record_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_record *rec)
|
||||||
{
|
{
|
||||||
|
char *name;
|
||||||
|
size_t name_len;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
size_t buf_len;
|
|
||||||
|
|
||||||
/* name */
|
/* name */
|
||||||
buf_len = strlen(rec->domain) + 1;
|
name = osmo_mdns_rfc_qname_encode(ctx, rec->domain);
|
||||||
buf = msgb_put(msg, buf_len);
|
if (!name)
|
||||||
if (osmo_apn_from_str(buf, buf_len, rec->domain) < 0)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
msgb_put_u8(msg, 0x00);
|
name_len = strlen(name) + 1;
|
||||||
|
buf = msgb_put(msg, name_len);
|
||||||
|
memcpy(buf, name, name_len);
|
||||||
|
talloc_free(name);
|
||||||
|
|
||||||
/* type, class, ttl, rdlength */
|
/* type, class, ttl, rdlength */
|
||||||
msgb_put_u16(msg, rec->type);
|
msgb_put_u16(msg, rec->type);
|
||||||
@@ -153,26 +232,15 @@ int osmo_mdns_rfc_record_encode(struct msgb *msg, const struct osmo_mdns_rfc_rec
|
|||||||
struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len,
|
struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len,
|
||||||
size_t *record_len)
|
size_t *record_len)
|
||||||
{
|
{
|
||||||
struct osmo_mdns_rfc_record *ret;
|
struct osmo_mdns_rfc_record *ret = talloc_zero(ctx, struct osmo_mdns_rfc_record);
|
||||||
size_t name_len;
|
size_t name_len;
|
||||||
|
|
||||||
/* name length: represented as a series of labels, and terminated by a
|
/* name */
|
||||||
* label with zero length (RFC 1035 3.3). A label with zero length is a
|
ret->domain = osmo_mdns_rfc_qname_decode(ret, (const char *)data, data_len - 10);
|
||||||
* NUL byte. */
|
|
||||||
name_len = strnlen((const char *)data, data_len - 10) + 1;
|
|
||||||
if (data[name_len])
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* allocate ret + ret->domain */
|
|
||||||
ret = talloc_zero(ctx, struct osmo_mdns_rfc_record);
|
|
||||||
if (!ret)
|
|
||||||
return NULL;
|
|
||||||
ret->domain = talloc_size(ctx, name_len - 1);
|
|
||||||
if (!ret->domain)
|
if (!ret->domain)
|
||||||
goto error;
|
goto error;
|
||||||
|
name_len = strlen(ret->domain) + 2;
|
||||||
/* name */
|
if (name_len + 10 > data_len)
|
||||||
if (!osmo_apn_to_str(ret->domain, data, name_len - 1))
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* type, class, ttl, rdlength */
|
/* type, class, ttl, rdlength */
|
||||||
@@ -186,7 +254,7 @@ struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_
|
|||||||
/* rdata */
|
/* rdata */
|
||||||
ret->rdata = talloc_memdup(ret, data + name_len + 10, ret->rdlength);
|
ret->rdata = talloc_memdup(ret, data + name_len + 10, ret->rdlength);
|
||||||
if (!ret->rdata)
|
if (!ret->rdata)
|
||||||
goto error;
|
return NULL;
|
||||||
|
|
||||||
*record_len = name_len + 10 + ret->rdlength;
|
*record_len = name_len + 10 + ret->rdlength;
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ struct osmo_mdns_sock *osmo_mdns_sock_init(void *ctx, const char *ip, unsigned i
|
|||||||
rc = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char*)&iface, sizeof(iface));
|
rc = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char*)&iface, sizeof(iface));
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: setsockopt: %s\n", strerror(errno));
|
LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: setsockopt: %s\n", strerror(errno));
|
||||||
goto error_sock;
|
goto error;
|
||||||
}
|
}
|
||||||
memcpy(&multicast_req.imr_multiaddr, &((struct sockaddr_in*)(ret->ai->ai_addr))->sin_addr,
|
memcpy(&multicast_req.imr_multiaddr, &((struct sockaddr_in*)(ret->ai->ai_addr))->sin_addr,
|
||||||
sizeof(multicast_req.imr_multiaddr));
|
sizeof(multicast_req.imr_multiaddr));
|
||||||
@@ -92,7 +92,7 @@ struct osmo_mdns_sock *osmo_mdns_sock_init(void *ctx, const char *ip, unsigned i
|
|||||||
rc = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multicast_req, sizeof(multicast_req));
|
rc = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multicast_req, sizeof(multicast_req));
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: setsockopt: %s\n", strerror(errno));
|
LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: setsockopt: %s\n", strerror(errno));
|
||||||
goto error_sock;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Always allow binding the same IP and port twice. This is needed in OsmoHLR (where the code becomes cleaner by
|
/* Always allow binding the same IP and port twice. This is needed in OsmoHLR (where the code becomes cleaner by
|
||||||
@@ -102,22 +102,20 @@ struct osmo_mdns_sock *osmo_mdns_sock_init(void *ctx, const char *ip, unsigned i
|
|||||||
rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&y, sizeof(y));
|
rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&y, sizeof(y));
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: setsockopt: %s\n", strerror(errno));
|
LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: setsockopt: %s\n", strerror(errno));
|
||||||
goto error_sock;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bind and register osmo_fd callback */
|
/* Bind and register osmo_fd callback */
|
||||||
rc = bind(sock, ret->ai->ai_addr, ret->ai->ai_addrlen);
|
rc = bind(sock, ret->ai->ai_addr, ret->ai->ai_addrlen);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: bind: %s\n", strerror(errno));
|
LOGP(DMSLOOKUP, LOGL_ERROR, "osmo_mdns_sock_init: bind: %s\n", strerror(errno));
|
||||||
goto error_sock;
|
goto error;
|
||||||
}
|
}
|
||||||
osmo_fd_setup(&ret->osmo_fd, sock, OSMO_FD_READ, cb, data, priv_nr);
|
osmo_fd_setup(&ret->osmo_fd, sock, OSMO_FD_READ, cb, data, priv_nr);
|
||||||
if (osmo_fd_register(&ret->osmo_fd) != 0)
|
if (osmo_fd_register(&ret->osmo_fd) != 0)
|
||||||
goto error_sock;
|
goto error;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
error_sock:
|
|
||||||
close(sock);
|
|
||||||
error:
|
error:
|
||||||
if (ret->ai)
|
if (ret->ai)
|
||||||
freeaddrinfo(ret->ai);
|
freeaddrinfo(ret->ai);
|
||||||
|
|||||||
@@ -205,9 +205,9 @@ size_t osmo_mslookup_result_to_str_buf(char *buf, size_t buflen,
|
|||||||
if (result && result->rc == OSMO_MSLOOKUP_RC_NONE)
|
if (result && result->rc == OSMO_MSLOOKUP_RC_NONE)
|
||||||
result = NULL;
|
result = NULL;
|
||||||
if (result) {
|
if (result) {
|
||||||
if (result->rc != OSMO_MSLOOKUP_RC_RESULT) {
|
if (result->rc != OSMO_MSLOOKUP_RC_RESULT)
|
||||||
OSMO_STRBUF_PRINTF(sb, " %s", osmo_mslookup_result_code_name(result->rc));
|
OSMO_STRBUF_PRINTF(sb, " %s", osmo_mslookup_result_code_name(result->rc));
|
||||||
} else {
|
if (result->rc == OSMO_MSLOOKUP_RC_RESULT) {
|
||||||
if (result->host_v4.ip[0]) {
|
if (result->host_v4.ip[0]) {
|
||||||
OSMO_STRBUF_PRINTF(sb, " -> ipv4: " OSMO_SOCKADDR_STR_FMT,
|
OSMO_STRBUF_PRINTF(sb, " -> ipv4: " OSMO_SOCKADDR_STR_FMT,
|
||||||
OSMO_SOCKADDR_STR_FMT_ARGS(&result->host_v4));
|
OSMO_SOCKADDR_STR_FMT_ARGS(&result->host_v4));
|
||||||
@@ -260,8 +260,6 @@ static int token(char *dest, size_t dest_size, const char *start, const char *en
|
|||||||
|
|
||||||
/*! Parse a string like "foo.moo.goo.123456789012345.msisdn" into service="foo.moo.goo", id="123456789012345" and
|
/*! Parse a string like "foo.moo.goo.123456789012345.msisdn" into service="foo.moo.goo", id="123456789012345" and
|
||||||
* id_type="msisdn", placed in a struct osmo_mslookup_query.
|
* id_type="msisdn", placed in a struct osmo_mslookup_query.
|
||||||
* \param q Write parsed query to this osmo_mslookup_query.
|
|
||||||
* \param domain Human readable domain string like "sip.voice.12345678.msisdn".
|
|
||||||
* \returns 0 on success, negative on error.
|
* \returns 0 on success, negative on error.
|
||||||
*/
|
*/
|
||||||
int osmo_mslookup_query_init_from_domain_str(struct osmo_mslookup_query *q, const char *domain)
|
int osmo_mslookup_query_init_from_domain_str(struct osmo_mslookup_query *q, const char *domain)
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ void osmo_mslookup_client_rx_result(struct osmo_mslookup_client *client, uint32_
|
|||||||
if (!req) {
|
if (!req) {
|
||||||
LOGP(DMSLOOKUP, LOGL_ERROR,
|
LOGP(DMSLOOKUP, LOGL_ERROR,
|
||||||
"Internal error: Got mslookup result for a request that does not exist (handle %u)\n",
|
"Internal error: Got mslookup result for a request that does not exist (handle %u)\n",
|
||||||
request_handle);
|
req->request_handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,6 @@ static void mdns_method_request(struct osmo_mslookup_client_method *method, cons
|
|||||||
if (!msg) {
|
if (!msg) {
|
||||||
LOGP(DMSLOOKUP, LOGL_ERROR, "Cannot encode request: %s\n",
|
LOGP(DMSLOOKUP, LOGL_ERROR, "Cannot encode request: %s\n",
|
||||||
osmo_mslookup_result_name_b(buf, sizeof(buf), query, NULL));
|
osmo_mslookup_result_name_b(buf, sizeof(buf), query, NULL));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send over the wire */
|
/* Send over the wire */
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ static void print_version(void)
|
|||||||
"\n");
|
"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_help(void)
|
static void print_help()
|
||||||
{
|
{
|
||||||
print_version();
|
print_version();
|
||||||
printf(
|
printf(
|
||||||
@@ -315,18 +315,17 @@ int do_send(int argc, char ** argv)
|
|||||||
struct msgb *msg = osmo_mdns_result_encode(ctx, 0, &q, &r, cmdline_opts.mdns_domain_suffix);
|
struct msgb *msg = osmo_mdns_result_encode(ctx, 0, &q, &r, cmdline_opts.mdns_domain_suffix);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
print_error("unable to encode mDNS response\n");
|
print_error("unable to encode mDNS response\n");
|
||||||
goto exit_cleanup_sock;
|
goto exit_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (osmo_mdns_sock_send(sock, msg)) {
|
if (osmo_mdns_sock_send(sock, msg)) {
|
||||||
print_error("unable to send mDNS message\n");
|
print_error("unable to send mDNS message\n");
|
||||||
goto exit_cleanup_sock;
|
goto exit_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
exit_cleanup_sock:
|
|
||||||
osmo_mdns_sock_cleanup(sock);
|
|
||||||
exit_cleanup:
|
exit_cleanup:
|
||||||
|
osmo_mdns_sock_cleanup(sock);
|
||||||
talloc_free(ctx);
|
talloc_free(ctx);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -419,9 +418,9 @@ static void socket_client_close(struct socket_client *c)
|
|||||||
{
|
{
|
||||||
struct osmo_fd *ofd = &c->ofd;
|
struct osmo_fd *ofd = &c->ofd;
|
||||||
|
|
||||||
osmo_fd_unregister(ofd);
|
|
||||||
close(ofd->fd);
|
close(ofd->fd);
|
||||||
ofd->fd = -1;
|
ofd->fd = -1;
|
||||||
|
osmo_fd_unregister(ofd);
|
||||||
|
|
||||||
llist_del(&c->entry);
|
llist_del(&c->entry);
|
||||||
talloc_free(c);
|
talloc_free(c);
|
||||||
@@ -456,11 +455,6 @@ static int socket_read_cb(struct osmo_fd *ofd)
|
|||||||
|
|
||||||
rxbuf[rc] = '\0';
|
rxbuf[rc] = '\0';
|
||||||
query_with_timeout = strtok(rxbuf, "\r\n");
|
query_with_timeout = strtok(rxbuf, "\r\n");
|
||||||
if (!query_with_timeout) {
|
|
||||||
print_error("ERROR: failed to read line from socket\n");
|
|
||||||
goto close;
|
|
||||||
}
|
|
||||||
|
|
||||||
at = strchr(query_with_timeout, '@');
|
at = strchr(query_with_timeout, '@');
|
||||||
query_str = at ? at + 1 : query_with_timeout;
|
query_str = at ? at + 1 : query_with_timeout;
|
||||||
|
|
||||||
@@ -487,7 +481,7 @@ static int socket_cb(struct osmo_fd *ofd, unsigned int flags)
|
|||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (flags & OSMO_FD_READ)
|
if (flags & BSC_FD_READ)
|
||||||
rc = socket_read_cb(ofd);
|
rc = socket_read_cb(ofd);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
@@ -512,7 +506,7 @@ int socket_accept(struct osmo_fd *ofd, unsigned int flags)
|
|||||||
c = talloc_zero(globals.ctx, struct socket_client);
|
c = talloc_zero(globals.ctx, struct socket_client);
|
||||||
OSMO_ASSERT(c);
|
OSMO_ASSERT(c);
|
||||||
c->ofd.fd = rc;
|
c->ofd.fd = rc;
|
||||||
c->ofd.when = OSMO_FD_READ;
|
c->ofd.when = BSC_FD_READ;
|
||||||
c->ofd.cb = socket_cb;
|
c->ofd.cb = socket_cb;
|
||||||
c->ofd.data = c;
|
c->ofd.data = c;
|
||||||
|
|
||||||
@@ -543,7 +537,7 @@ int socket_init(const char *sock_path)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ofd->when = OSMO_FD_READ;
|
ofd->when = BSC_FD_READ;
|
||||||
ofd->cb = socket_accept;
|
ofd->cb = socket_accept;
|
||||||
|
|
||||||
rc = osmo_fd_register(ofd);
|
rc = osmo_fd_register(ofd);
|
||||||
@@ -555,15 +549,15 @@ int socket_init(const char *sock_path)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void socket_close(void)
|
void socket_close()
|
||||||
{
|
{
|
||||||
struct socket_client *c, *n;
|
struct socket_client *c, *n;
|
||||||
llist_for_each_entry_safe(c, n, &globals.socket_clients, entry)
|
llist_for_each_entry_safe(c, n, &globals.socket_clients, entry)
|
||||||
socket_client_close(c);
|
socket_client_close(c);
|
||||||
if (osmo_fd_is_registered(&globals.socket_ofd)) {
|
if (osmo_fd_is_registered(&globals.socket_ofd)) {
|
||||||
osmo_fd_unregister(&globals.socket_ofd);
|
|
||||||
close(globals.socket_ofd.fd);
|
close(globals.socket_ofd.fd);
|
||||||
globals.socket_ofd.fd = -1;
|
globals.socket_ofd.fd = -1;
|
||||||
|
osmo_fd_unregister(&globals.socket_ofd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,11 +578,11 @@ void respond_result(const char *query_str, const struct osmo_mslookup_result *r)
|
|||||||
llist_for_each_entry_safe(c, n, &globals.socket_clients, entry) {
|
llist_for_each_entry_safe(c, n, &globals.socket_clients, entry) {
|
||||||
if (!strcmp(query_str, c->query_str)) {
|
if (!strcmp(query_str, c->query_str)) {
|
||||||
socket_client_respond_result(c, g_buf);
|
socket_client_respond_result(c, g_buf);
|
||||||
if (!r || r->last)
|
if (r->last)
|
||||||
socket_client_close(c);
|
socket_client_close(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!r || r->last)
|
if (r->last)
|
||||||
globals.requests_handled++;
|
globals.requests_handled++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ static void set_result(struct osmo_mslookup_result *result,
|
|||||||
result->age = age;
|
result->age = age;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct mslookup_service_host *mslookup_server_get_local_gsup_addr(void)
|
const struct mslookup_service_host *mslookup_server_get_local_gsup_addr()
|
||||||
{
|
{
|
||||||
static struct mslookup_service_host gsup_bind = {};
|
static struct mslookup_service_host gsup_bind = {};
|
||||||
struct mslookup_service_host *host;
|
struct mslookup_service_host *host;
|
||||||
@@ -261,7 +261,6 @@ static bool subscriber_has_done_lu_here_hlr(const struct osmo_mslookup_query *qu
|
|||||||
if (!subscr->vlr_number[0]) {
|
if (!subscr->vlr_number[0]) {
|
||||||
LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: not attached (vlr_number unset)\n",
|
LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: not attached (vlr_number unset)\n",
|
||||||
osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));
|
osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subscr->vlr_via_proxy.len) {
|
if (subscr->vlr_via_proxy.len) {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ static int osmo_mslookup_server_mdns_rx(struct osmo_fd *osmo_fd, unsigned int wh
|
|||||||
|
|
||||||
/* Parse the message and print it */
|
/* Parse the message and print it */
|
||||||
n = read(osmo_fd->fd, buffer, sizeof(buffer));
|
n = read(osmo_fd->fd, buffer, sizeof(buffer));
|
||||||
if (n <= 0)
|
if (n < 0)
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
ctx = talloc_named_const(server, 0, __func__);
|
ctx = talloc_named_const(server, 0, __func__);
|
||||||
@@ -121,7 +121,7 @@ void osmo_mslookup_server_mdns_stop(struct osmo_mslookup_server_mdns *server)
|
|||||||
talloc_free(server);
|
talloc_free(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mslookup_server_mdns_config_apply(void)
|
void mslookup_server_mdns_config_apply()
|
||||||
{
|
{
|
||||||
/* Check whether to start/stop/restart mDNS server */
|
/* Check whether to start/stop/restart mDNS server */
|
||||||
bool should_run;
|
bool should_run;
|
||||||
@@ -148,7 +148,7 @@ void mslookup_server_mdns_config_apply(void)
|
|||||||
g_hlr->mslookup.server.mdns.domain_suffix);
|
g_hlr->mslookup.server.mdns.domain_suffix);
|
||||||
if (!g_hlr->mslookup.server.mdns.running)
|
if (!g_hlr->mslookup.server.mdns.running)
|
||||||
LOGP(DMSLOOKUP, LOGL_ERROR, "Failed to start mslookup mDNS server on " OSMO_SOCKADDR_STR_FMT "\n",
|
LOGP(DMSLOOKUP, LOGL_ERROR, "Failed to start mslookup mDNS server on " OSMO_SOCKADDR_STR_FMT "\n",
|
||||||
OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.server.mdns.bind_addr));
|
OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.server.mdns.running->bind_addr));
|
||||||
else
|
else
|
||||||
LOGP(DMSLOOKUP, LOGL_NOTICE, "Started mslookup mDNS server, receiving mDNS requests at multicast "
|
LOGP(DMSLOOKUP, LOGL_NOTICE, "Started mslookup mDNS server, receiving mDNS requests at multicast "
|
||||||
OSMO_SOCKADDR_STR_FMT "\n",
|
OSMO_SOCKADDR_STR_FMT "\n",
|
||||||
|
|||||||
30
src/proxy.c
30
src/proxy.c
@@ -29,7 +29,6 @@
|
|||||||
#include <osmocom/gsupclient/gsup_client.h>
|
#include <osmocom/gsupclient/gsup_client.h>
|
||||||
#include <osmocom/gsupclient/gsup_req.h>
|
#include <osmocom/gsupclient/gsup_req.h>
|
||||||
|
|
||||||
#include <osmocom/hlr/hlr.h>
|
|
||||||
#include <osmocom/hlr/logging.h>
|
#include <osmocom/hlr/logging.h>
|
||||||
#include <osmocom/hlr/proxy.h>
|
#include <osmocom/hlr/proxy.h>
|
||||||
#include <osmocom/hlr/remote_hlr.h>
|
#include <osmocom/hlr/remote_hlr.h>
|
||||||
@@ -81,19 +80,7 @@ static void proxy_deferred_gsup_req_add(struct proxy *proxy, struct osmo_gsup_re
|
|||||||
static void proxy_pending_req_remote_hlr_connect_result(struct osmo_gsup_req *req, struct remote_hlr *remote_hlr)
|
static void proxy_pending_req_remote_hlr_connect_result(struct osmo_gsup_req *req, struct remote_hlr *remote_hlr)
|
||||||
{
|
{
|
||||||
if (!remote_hlr || !remote_hlr_is_up(remote_hlr)) {
|
if (!remote_hlr || !remote_hlr_is_up(remote_hlr)) {
|
||||||
/* Do not respond with an error to a CHECK_IMEI_REQUEST as osmo-msc will send a LU Reject Cause #6
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_ROAMING_NOTALLOWED, "Proxy: Failed to connect to home HLR");
|
||||||
* Just respond ACK and deal with the IMSI check that comes next. */
|
|
||||||
if (req->gsup.message_type == OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST) {
|
|
||||||
/* Accept all IMEIs */
|
|
||||||
struct osmo_gsup_message gsup_reply = (struct osmo_gsup_message){
|
|
||||||
.message_type = OSMO_GSUP_MSGT_CHECK_IMEI_RESULT,
|
|
||||||
.imei_result = OSMO_GSUP_IMEI_RESULT_ACK,
|
|
||||||
};
|
|
||||||
osmo_gsup_req_respond(req, &gsup_reply, false, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
osmo_gsup_req_respond_err(req, g_hlr->no_proxy_reject_cause,
|
|
||||||
"Proxy: Failed to connect to home HLR");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +190,6 @@ int proxy_subscr_create_or_update(struct proxy *proxy, const struct proxy_subscr
|
|||||||
int _proxy_subscr_del(struct proxy_subscr_listentry *e)
|
int _proxy_subscr_del(struct proxy_subscr_listentry *e)
|
||||||
{
|
{
|
||||||
llist_del(&e->entry);
|
llist_del(&e->entry);
|
||||||
talloc_free(e);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,10 +263,10 @@ static int proxy_acknowledge_gsup_to_remote_hlr(struct proxy *proxy, const struc
|
|||||||
bool cs;
|
bool cs;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (req->source_name.type != OSMO_CNI_PEER_ID_IPA_NAME) {
|
if (req->source_name.type != OSMO_GSUP_PEER_ID_IPA_NAME) {
|
||||||
LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_ERROR,
|
LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_ERROR,
|
||||||
"Unsupported GSUP peer id type: %s\n",
|
"Unsupported GSUP peer id type: %s\n",
|
||||||
osmo_cni_peer_id_type_name(req->source_name.type));
|
osmo_gsup_peer_id_type_name(req->source_name.type));
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +303,7 @@ static int proxy_acknowledge_gsup_to_remote_hlr(struct proxy *proxy, const struc
|
|||||||
"%s: preliminary VLR name for%s%s to %s\n",
|
"%s: preliminary VLR name for%s%s to %s\n",
|
||||||
rc ? "failed to update" : "updated",
|
rc ? "failed to update" : "updated",
|
||||||
cs ? " CS" : "", ps ? " PS" : "",
|
cs ? " CS" : "", ps ? " PS" : "",
|
||||||
osmo_cni_peer_id_to_str(&req->source_name));
|
osmo_gsup_peer_id_to_str(&req->source_name));
|
||||||
break;
|
break;
|
||||||
/* TODO: delete proxy entry in case of a Purge Request? */
|
/* TODO: delete proxy entry in case of a Purge Request? */
|
||||||
default:
|
default:
|
||||||
@@ -497,13 +483,13 @@ int proxy_subscr_forward_to_remote_hlr(struct proxy *proxy, const struct proxy_s
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!osmo_cni_peer_id_is_empty(&req->via_proxy)) {
|
if (!osmo_gsup_peer_id_is_empty(&req->via_proxy)) {
|
||||||
LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_INFO, "VLR->HLR: forwarding from %s via proxy %s\n",
|
LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_INFO, "VLR->HLR: forwarding from %s via proxy %s\n",
|
||||||
osmo_cni_peer_id_to_str(&req->source_name),
|
osmo_gsup_peer_id_to_str(&req->source_name),
|
||||||
osmo_cni_peer_id_to_str(&req->via_proxy));
|
osmo_gsup_peer_id_to_str(&req->via_proxy));
|
||||||
} else {
|
} else {
|
||||||
LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_INFO, "VLR->HLR: forwarding from %s\n",
|
LOG_PROXY_SUBSCR_MSG(proxy_subscr, &req->gsup, LOGL_INFO, "VLR->HLR: forwarding from %s\n",
|
||||||
osmo_cni_peer_id_to_str(&req->source_name));
|
osmo_gsup_peer_id_to_str(&req->source_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We could always store in the defer queue and empty the queue if the connection is already up.
|
/* We could always store in the defer queue and empty the queue if the connection is already up.
|
||||||
|
|||||||
@@ -233,9 +233,9 @@ void remote_hlr_gsup_forward_to_remote_hlr(struct remote_hlr *remote_hlr, struct
|
|||||||
else
|
else
|
||||||
forward = req->gsup;
|
forward = req->gsup;
|
||||||
|
|
||||||
if (req->source_name.type != OSMO_CNI_PEER_ID_IPA_NAME) {
|
if (req->source_name.type != OSMO_GSUP_PEER_ID_IPA_NAME) {
|
||||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Unsupported GSUP peer id type: %s",
|
||||||
osmo_cni_peer_id_type_name(req->source_name.type));
|
osmo_gsup_peer_id_type_name(req->source_name.type));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
forward.source_name = req->source_name.ipa_name.val;
|
forward.source_name = req->source_name.ipa_name.val;
|
||||||
|
|||||||
423
src/sms_over_gsup.c
Normal file
423
src/sms_over_gsup.c
Normal file
@@ -0,0 +1,423 @@
|
|||||||
|
#include <osmocom/core/linuxlist.h>
|
||||||
|
#include <osmocom/gsm/gsm48_ie.h>
|
||||||
|
#include <osmocom/gsm/gsm23003.h>
|
||||||
|
|
||||||
|
#include <osmocom/gsm/gsm0411_utils.h>
|
||||||
|
#include <osmocom/gsm/protocol/gsm_04_11.h>
|
||||||
|
|
||||||
|
#include <osmocom/mslookup/mslookup_client.h>
|
||||||
|
|
||||||
|
#include <osmocom/hlr/hlr.h>
|
||||||
|
#include <osmocom/hlr/remote_hlr.h>
|
||||||
|
#include <osmocom/hlr/mslookup_server.h>
|
||||||
|
#include <osmocom/hlr/db.h>
|
||||||
|
#include <osmocom/hlr/sms_over_gsup.h>
|
||||||
|
|
||||||
|
static int sms_extract_destination_msisdn(char *msisdn, size_t msisdn_size, struct osmo_gsup_req *req)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
if (req->gsup.sm_rp_da_type == OSMO_GSUP_SMS_SM_RP_ODA_MSISDN
|
||||||
|
&& req->gsup.sm_rp_da_len > 0) {
|
||||||
|
LOG_GSUP_REQ(req, LOGL_INFO, "Extracting destination MSISDN from GSUP SM_RP_DA IE: %s\n",
|
||||||
|
osmo_hexdump(req->gsup.sm_rp_da, req->gsup.sm_rp_da_len));
|
||||||
|
rc = gsm48_decode_bcd_number2(msisdn, msisdn_size, req->gsup.sm_rp_da, req->gsup.sm_rp_da_len, 0);
|
||||||
|
if (!rc)
|
||||||
|
LOG_GSUP_REQ(req, LOGL_INFO, "success -> %s\n", msisdn);
|
||||||
|
else
|
||||||
|
LOG_GSUP_REQ(req, LOGL_ERROR, "fail %d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The DA was not an MSISDN -- get from inside the SMS PDU */
|
||||||
|
if (req->gsup.sm_rp_ui_len > 3) {
|
||||||
|
const uint8_t *da = req->gsup.sm_rp_ui + 2;
|
||||||
|
uint8_t da_len = *da;
|
||||||
|
uint8_t da_len_bytes;
|
||||||
|
uint8_t address_lv[12] = {};
|
||||||
|
|
||||||
|
da_len_bytes = 2 + da_len/2 + da_len%2;
|
||||||
|
|
||||||
|
if (da_len_bytes < 4 || da_len_bytes > 12
|
||||||
|
|| da_len_bytes > req->gsup.sm_rp_ui_len - 2) {
|
||||||
|
LOG_GSUP_REQ(req, LOGL_ERROR, "Invalid da_len_bytes %u\n", da_len_bytes);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(address_lv, da, da_len_bytes);
|
||||||
|
address_lv[0] = da_len_bytes - 1;
|
||||||
|
|
||||||
|
LOG_GSUP_REQ(req, LOGL_INFO, "Extracting destination MSISDN from SMS PDU DA: %s\n",
|
||||||
|
osmo_hexdump(address_lv, da_len_bytes));
|
||||||
|
rc = gsm48_decode_bcd_number2(msisdn, msisdn_size, address_lv, da_len_bytes, 1);
|
||||||
|
if (!rc)
|
||||||
|
LOG_GSUP_REQ(req, LOGL_INFO, "success -> %s\n", msisdn);
|
||||||
|
else
|
||||||
|
LOG_GSUP_REQ(req, LOGL_ERROR, "fail %d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_GSUP_REQ(req, LOGL_ERROR, "fail: no SM_RP_DA nor SMS PDU (sm_rp_ui_len > 3)\n");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sms_extract_sender_msisdn(char *msisdn, size_t msisdn_size, struct osmo_gsup_req *req)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
if (req->gsup.sm_rp_oa_type == OSMO_GSUP_SMS_SM_RP_ODA_MSISDN
|
||||||
|
&& req->gsup.sm_rp_oa_len > 0) {
|
||||||
|
LOG_GSUP_REQ(req, LOGL_INFO, "Extracting sender MSISDN from GSUP SM_RP_OA IE: %s\n",
|
||||||
|
osmo_hexdump(req->gsup.sm_rp_oa, req->gsup.sm_rp_oa_len));
|
||||||
|
rc = gsm48_decode_bcd_number2(msisdn, msisdn_size, req->gsup.sm_rp_oa, req->gsup.sm_rp_oa_len, 0);
|
||||||
|
if (!rc)
|
||||||
|
LOG_GSUP_REQ(req, LOGL_INFO, "success -> %s\n", msisdn);
|
||||||
|
else
|
||||||
|
LOG_GSUP_REQ(req, LOGL_ERROR, "fail %d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_GSUP_REQ(req, LOGL_ERROR, "fail: no MSISDN obtained from SM_RP_OA\n");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct msgb *sms_mo_pdu_to_mt_pdu(const uint8_t *mo_pdu, size_t mo_pdu_len, const char *sender_msisdn)
|
||||||
|
{
|
||||||
|
/* Hacky shortened copy-paste of osmo-msc's gsm340_rx_tpdu() */
|
||||||
|
|
||||||
|
uint8_t protocol_id;
|
||||||
|
uint8_t data_coding_scheme;
|
||||||
|
uint8_t user_data_len;
|
||||||
|
uint8_t user_data_octet_len;
|
||||||
|
const uint8_t *user_data;
|
||||||
|
uint8_t status_rep_req;
|
||||||
|
uint8_t ud_hdr_ind;
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint8_t *smsp = mo_pdu;
|
||||||
|
enum sms_alphabet sms_alphabet;
|
||||||
|
uint8_t sms_vpf;
|
||||||
|
uint8_t da_len_bytes;
|
||||||
|
|
||||||
|
sms_vpf = (*smsp & 0x18) >> 3;
|
||||||
|
status_rep_req = (*smsp & 0x20) >> 5;
|
||||||
|
ud_hdr_ind = (*smsp & 0x40);
|
||||||
|
|
||||||
|
smsp += 2;
|
||||||
|
|
||||||
|
/* length in bytes of the destination address */
|
||||||
|
da_len_bytes = 2 + *smsp/2 + *smsp%2;
|
||||||
|
if (da_len_bytes < 4 || da_len_bytes > 12)
|
||||||
|
return NULL;
|
||||||
|
smsp += da_len_bytes;
|
||||||
|
|
||||||
|
protocol_id = *smsp++;
|
||||||
|
data_coding_scheme = *smsp++;
|
||||||
|
|
||||||
|
sms_alphabet = gsm338_get_sms_alphabet(data_coding_scheme);
|
||||||
|
if (sms_alphabet == 0xffffffff)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
switch (sms_vpf) {
|
||||||
|
case GSM340_TP_VPF_RELATIVE:
|
||||||
|
smsp++;
|
||||||
|
break;
|
||||||
|
case GSM340_TP_VPF_ABSOLUTE:
|
||||||
|
case GSM340_TP_VPF_ENHANCED:
|
||||||
|
/* the additional functionality indicator... */
|
||||||
|
if (sms_vpf == GSM340_TP_VPF_ENHANCED && *smsp & (1<<7))
|
||||||
|
smsp++;
|
||||||
|
smsp += 7;
|
||||||
|
break;
|
||||||
|
case GSM340_TP_VPF_NONE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* As per 3GPP TS 03.40, section 9.2.3.16, TP-User-Data-Length (TP-UDL)
|
||||||
|
* may indicate either the number of septets, or the number of octets,
|
||||||
|
* depending on Data Coding Scheme. We store TP-UDL value as-is,
|
||||||
|
* so this should be kept in mind to avoid buffer overruns. */
|
||||||
|
user_data_len = *smsp++;
|
||||||
|
user_data = smsp;
|
||||||
|
if (user_data_len > 0) {
|
||||||
|
if (sms_alphabet == DCS_7BIT_DEFAULT) {
|
||||||
|
/* TP-UDL is indicated in septets (up to 160) */
|
||||||
|
if (user_data_len > GSM340_UDL_SPT_MAX) {
|
||||||
|
user_data_len = GSM340_UDL_SPT_MAX;
|
||||||
|
}
|
||||||
|
user_data_octet_len = gsm_get_octet_len(user_data_len);
|
||||||
|
} else {
|
||||||
|
/* TP-UDL is indicated in octets (up to 140) */
|
||||||
|
if (user_data_len > GSM340_UDL_OCT_MAX) {
|
||||||
|
user_data_len = GSM340_UDL_OCT_MAX;
|
||||||
|
}
|
||||||
|
user_data_octet_len = user_data_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
/* The following is a hacky copy pasted and shortened version of osmo-msc's gsm340_gen_sms_deliver_tpdu() */
|
||||||
|
struct msgb *msg = gsm411_msgb_alloc();
|
||||||
|
uint8_t *smsp;
|
||||||
|
uint8_t oa[12]; /* max len per 03.40 */
|
||||||
|
int oa_len;
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* generate first octet with masked bits */
|
||||||
|
smsp = msgb_put(msg, 1);
|
||||||
|
/* TP-MTI (message type indicator) */
|
||||||
|
*smsp = GSM340_SMS_DELIVER_SC2MS;
|
||||||
|
/* TP-MMS (more messages to send) */
|
||||||
|
if (0 /* FIXME */)
|
||||||
|
*smsp |= 0x04;
|
||||||
|
/* TP-SRI(deliver)/SRR(submit) */
|
||||||
|
if (status_rep_req)
|
||||||
|
*smsp |= 0x20;
|
||||||
|
/* TP-UDHI (indicating TP-UD contains a header) */
|
||||||
|
if (ud_hdr_ind)
|
||||||
|
*smsp |= 0x40;
|
||||||
|
|
||||||
|
/* generate originator address */
|
||||||
|
oa_len = gsm340_gen_oa(oa, sizeof(oa), 0, 0, sender_msisdn);
|
||||||
|
if (oa_len < 0) {
|
||||||
|
msgb_free(msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
smsp = msgb_put(msg, oa_len);
|
||||||
|
memcpy(smsp, oa, oa_len);
|
||||||
|
|
||||||
|
/* generate TP-PID */
|
||||||
|
smsp = msgb_put(msg, 1);
|
||||||
|
*smsp = protocol_id;
|
||||||
|
|
||||||
|
/* generate TP-DCS */
|
||||||
|
smsp = msgb_put(msg, 1);
|
||||||
|
*smsp = data_coding_scheme;
|
||||||
|
|
||||||
|
/* generate TP-SCTS */
|
||||||
|
smsp = msgb_put(msg, 7);
|
||||||
|
gsm340_gen_scts(smsp, time(NULL));
|
||||||
|
|
||||||
|
/* generate TP-UDL */
|
||||||
|
smsp = msgb_put(msg, 1);
|
||||||
|
*smsp = user_data_len;
|
||||||
|
smsp = msgb_put(msg, user_data_octet_len);
|
||||||
|
memcpy(smsp, user_data, user_data_octet_len);
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void sms_recipient_up_cb(const struct osmo_sockaddr_str *addr, struct remote_hlr *remote_hlr, void *data)
|
||||||
|
{
|
||||||
|
struct osmo_gsup_req *req = data;
|
||||||
|
struct osmo_gsup_message modified_gsup = req->gsup;
|
||||||
|
// struct msgb *mt_pdu = NULL;
|
||||||
|
if (!remote_hlr) {
|
||||||
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_MSC_TEMP_NOTREACH,
|
||||||
|
"Failed to connect to SMS recipient: " OSMO_SOCKADDR_STR_FMT,
|
||||||
|
OSMO_SOCKADDR_STR_FMT_ARGS(addr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* We must not send out another MO request, to make sure we don't send the request in an infinite loop. */
|
||||||
|
#if 0
|
||||||
|
if (req->gsup.message_type == OSMO_GSUP_MSGT_MO_FORWARD_SM_REQUEST) {
|
||||||
|
char sender_msisdn[GSM23003_MSISDN_MAX_DIGITS+1];
|
||||||
|
if (sms_extract_sender_msisdn(sender_msisdn, sizeof(sender_msisdn), req)) {
|
||||||
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO, "Cannot find sender MSISDN");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mt_pdu = sms_mo_pdu_to_mt_pdu(req->gsup.sm_rp_ui, req->gsup.sm_rp_ui_len, sender_msisdn);
|
||||||
|
if (!mt_pdu) {
|
||||||
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO,
|
||||||
|
"Cannot translate PDU to a DELIVER PDU");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modified_gsup.message_type = OSMO_GSUP_MSGT_MT_FORWARD_SM_REQUEST;
|
||||||
|
modified_gsup.sm_rp_ui = mt_pdu->data;
|
||||||
|
modified_gsup.sm_rp_ui_len = mt_pdu->len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
LOG_GSUP_REQ(req, LOGL_INFO, "Forwarding to remote HLR " OSMO_SOCKADDR_STR_FMT "\n",
|
||||||
|
OSMO_SOCKADDR_STR_FMT_ARGS(&remote_hlr->addr));
|
||||||
|
remote_hlr_gsup_forward_to_remote_hlr(remote_hlr, req, &modified_gsup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sms_over_gsup_mt(struct osmo_gsup_req *req)
|
||||||
|
{
|
||||||
|
/* Find a locally connected MSC that knows this MSISDN. */
|
||||||
|
uint32_t lu_age;
|
||||||
|
struct osmo_gsup_peer_id local_msc_id;
|
||||||
|
struct osmo_mslookup_query query = {
|
||||||
|
.service = OSMO_MSLOOKUP_SERVICE_SMS_GSUP,
|
||||||
|
.id = {
|
||||||
|
.type = OSMO_MSLOOKUP_ID_MSISDN,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
struct osmo_gsup_message modified_gsup = req->gsup;
|
||||||
|
struct msgb *mt_pdu = NULL;
|
||||||
|
|
||||||
|
if (sms_extract_destination_msisdn(query.id.msisdn, sizeof(query.id.msisdn), req)) {
|
||||||
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO, "invalid MSISDN");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_GSUP_REQ(req, LOGL_NOTICE, "SMS to MSISDN: %s\n", query.id.msisdn);
|
||||||
|
|
||||||
|
/* If a local attach is found, write the subscriber's IMSI to the modified_gsup buffer */
|
||||||
|
if (!subscriber_has_done_lu_here(&query, &lu_age, &local_msc_id.ipa_name,
|
||||||
|
modified_gsup.imsi, sizeof(modified_gsup.imsi))) {
|
||||||
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_MSC_TEMP_NOTREACH,
|
||||||
|
"SMS recipient not reachable: %s\n",
|
||||||
|
osmo_mslookup_result_name_c(OTC_SELECT, &query, NULL));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
local_msc_id.type = OSMO_GSUP_PEER_ID_IPA_NAME;
|
||||||
|
/* A local MSC indeed has an active subscription for the recipient. Deliver there. */
|
||||||
|
|
||||||
|
if (modified_gsup.message_type == OSMO_GSUP_MSGT_MO_FORWARD_SM_REQUEST) {
|
||||||
|
/* This is a direct local delivery, and sms_over_gsup_mo_directly_to_mt() just passed the MO request
|
||||||
|
* altough here we are on the MT side. We must not send out another MO request, to make sure we don't
|
||||||
|
* send the request in an infinite loop.
|
||||||
|
* Also patch in the recipient's IMSI.
|
||||||
|
*/
|
||||||
|
char sender_msisdn[GSM23003_MSISDN_MAX_DIGITS+1];
|
||||||
|
if (sms_extract_sender_msisdn(sender_msisdn, sizeof(sender_msisdn), req)) {
|
||||||
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO, "Cannot find sender MSISDN");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mt_pdu = sms_mo_pdu_to_mt_pdu(req->gsup.sm_rp_ui, req->gsup.sm_rp_ui_len, sender_msisdn);
|
||||||
|
if (!mt_pdu) {
|
||||||
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO,
|
||||||
|
"Cannot translate PDU to a DELIVER PDU");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modified_gsup.message_type = OSMO_GSUP_MSGT_MT_FORWARD_SM_REQUEST;
|
||||||
|
modified_gsup.sm_rp_ui = mt_pdu->data;
|
||||||
|
modified_gsup.sm_rp_ui_len = mt_pdu->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
osmo_gsup_forward_to_local_peer(g_hlr->gs, &local_msc_id, req, &modified_gsup);
|
||||||
|
|
||||||
|
if (mt_pdu)
|
||||||
|
msgb_free(mt_pdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resolve_sms_recipient_cb(struct osmo_mslookup_client *client,
|
||||||
|
uint32_t request_handle,
|
||||||
|
const struct osmo_mslookup_query *query,
|
||||||
|
const struct osmo_mslookup_result *result)
|
||||||
|
{
|
||||||
|
struct osmo_gsup_req *req = query->priv;
|
||||||
|
const struct osmo_sockaddr_str *remote_hlr_addr = NULL;
|
||||||
|
const struct mslookup_service_host *local_gsup;
|
||||||
|
|
||||||
|
if (result->rc == OSMO_MSLOOKUP_RC_RESULT) {
|
||||||
|
if (osmo_sockaddr_str_is_nonzero(&result->host_v4))
|
||||||
|
remote_hlr_addr = &result->host_v4;
|
||||||
|
else if (osmo_sockaddr_str_is_nonzero(&result->host_v6))
|
||||||
|
remote_hlr_addr = &result->host_v6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!remote_hlr_addr) {
|
||||||
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_MSC_TEMP_NOTREACH,
|
||||||
|
"Failed to resolve SMS recipient: %s\n",
|
||||||
|
osmo_mslookup_result_name_c(OTC_SELECT, query, result));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Possibly, this HLR here has responded to itself via mslookup. Don't make a GSUP connection to ourselves,
|
||||||
|
* instead go directly to the MT path. */
|
||||||
|
local_gsup = mslookup_server_get_local_gsup_addr();
|
||||||
|
LOG_GSUP_REQ(req, LOGL_NOTICE, "local_gsup " OSMO_SOCKADDR_STR_FMT " " OSMO_SOCKADDR_STR_FMT
|
||||||
|
" remote_hlr_addr " OSMO_SOCKADDR_STR_FMT "\n",
|
||||||
|
OSMO_SOCKADDR_STR_FMT_ARGS(&local_gsup->host_v4),
|
||||||
|
OSMO_SOCKADDR_STR_FMT_ARGS(&local_gsup->host_v6),
|
||||||
|
OSMO_SOCKADDR_STR_FMT_ARGS(remote_hlr_addr));
|
||||||
|
if (local_gsup
|
||||||
|
&& (!osmo_sockaddr_str_cmp(&local_gsup->host_v4, remote_hlr_addr)
|
||||||
|
|| !osmo_sockaddr_str_cmp(&local_gsup->host_v6, remote_hlr_addr))) {
|
||||||
|
sms_over_gsup_mt(req);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
remote_hlr_get_or_connect(remote_hlr_addr, true, sms_recipient_up_cb, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sms_over_gsup_mo_directly_to_mt(struct osmo_gsup_req *req)
|
||||||
|
{
|
||||||
|
/* Figure out the location of the SMS recipient by mslookup */
|
||||||
|
if (osmo_mslookup_client_active(g_hlr->mslookup.client.client)) {
|
||||||
|
/* D-GSM is active. Kick off an mslookup for the current location of the MSISDN. */
|
||||||
|
uint32_t request_handle;
|
||||||
|
struct osmo_mslookup_query_handling handling = {
|
||||||
|
.min_wait_milliseconds = g_hlr->mslookup.client.result_timeout_milliseconds,
|
||||||
|
.result_cb = resolve_sms_recipient_cb,
|
||||||
|
};
|
||||||
|
struct osmo_mslookup_query query = {
|
||||||
|
.id = {
|
||||||
|
.type = OSMO_MSLOOKUP_ID_MSISDN,
|
||||||
|
},
|
||||||
|
.priv = req,
|
||||||
|
};
|
||||||
|
if (sms_extract_destination_msisdn(query.id.msisdn, sizeof(query.id.msisdn), req)
|
||||||
|
|| !osmo_msisdn_str_valid(query.id.msisdn)) {
|
||||||
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_INV_MAND_INFO, "invalid MSISDN");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OSMO_STRLCPY_ARRAY(query.service, OSMO_MSLOOKUP_SERVICE_SMS_GSUP);
|
||||||
|
|
||||||
|
request_handle = osmo_mslookup_client_request(g_hlr->mslookup.client.client, &query, &handling);
|
||||||
|
if (request_handle) {
|
||||||
|
/* Querying succeeded. Wait for resolve_sms_recipient_cb() to be called. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Querying failed. Try whether delivering to a locally connected MSC works out. */
|
||||||
|
LOG_DGSM(req->gsup.imsi, LOGL_ERROR,
|
||||||
|
"Error dispatching mslookup query for SMS: %s -- trying local delivery\n",
|
||||||
|
osmo_mslookup_result_name_c(OTC_SELECT, &query, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempt direct delivery */
|
||||||
|
sms_over_gsup_mt(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sms_over_gsup_mo(struct osmo_gsup_req *req)
|
||||||
|
{
|
||||||
|
if (!osmo_gsup_peer_id_is_empty(&g_hlr->sms_over_gsup.smsc)) {
|
||||||
|
/* Forward to SMSC */
|
||||||
|
/* FIXME actually use branch fixeria/sms for this */
|
||||||
|
osmo_gsup_forward_to_local_peer(g_hlr->gs, &g_hlr->sms_over_gsup.smsc, req, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_hlr->sms_over_gsup.try_direct_delivery) {
|
||||||
|
osmo_gsup_req_respond_err(req, GMM_CAUSE_PROTO_ERR_UNSPEC,
|
||||||
|
"cannot deliver SMS over GSUP: No SMSC (and direct delivery disabled)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sms_over_gsup_mo_directly_to_mt(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sms_over_gsup_check_handle_msg(struct osmo_gsup_req *req)
|
||||||
|
{
|
||||||
|
switch (req->gsup.message_type) {
|
||||||
|
case OSMO_GSUP_MSGT_MO_FORWARD_SM_REQUEST:
|
||||||
|
sms_over_gsup_mo(req);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case OSMO_GSUP_MSGT_MT_FORWARD_SM_REQUEST:
|
||||||
|
sms_over_gsup_mt(req);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
auc \
|
auc \
|
||||||
|
gsup_server \
|
||||||
db \
|
db \
|
||||||
gsup \
|
gsup \
|
||||||
db_upgrade \
|
db_upgrade \
|
||||||
@@ -69,9 +70,6 @@ vty-test:
|
|||||||
|
|
||||||
CTRL_TEST_DB = hlr_ctrl_test.db
|
CTRL_TEST_DB = hlr_ctrl_test.db
|
||||||
|
|
||||||
# Run a specific test with: 'make ctrl-test CTRL_TEST=test_subscriber.ctrl'
|
|
||||||
CTRL_TEST ?= *.ctrl
|
|
||||||
|
|
||||||
# To update the CTRL script from current application behavior,
|
# To update the CTRL script from current application behavior,
|
||||||
# pass -u to ctrl_script_runner.py by doing:
|
# pass -u to ctrl_script_runner.py by doing:
|
||||||
# make ctrl-test U=-u
|
# make ctrl-test U=-u
|
||||||
@@ -82,7 +80,7 @@ ctrl-test:
|
|||||||
osmo_verify_transcript_ctrl.py -v \
|
osmo_verify_transcript_ctrl.py -v \
|
||||||
-p 4259 \
|
-p 4259 \
|
||||||
-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l $(CTRL_TEST_DB)" \
|
-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l $(CTRL_TEST_DB)" \
|
||||||
$(U) $(srcdir)/$(CTRL_TEST)
|
$(U) $(srcdir)/*.ctrl
|
||||||
-rm -f $(CTRL_TEST_DB)
|
-rm -f $(CTRL_TEST_DB)
|
||||||
-rm $(CTRL_TEST_DB)-*
|
-rm $(CTRL_TEST_DB)-*
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ SUBDIRS = gen_ts_55_205_test_sets
|
|||||||
|
|
||||||
AM_CPPFLAGS = \
|
AM_CPPFLAGS = \
|
||||||
$(all_includes) \
|
$(all_includes) \
|
||||||
-I$(top_srcdir)/include \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
AM_CFLAGS = \
|
AM_CFLAGS = \
|
||||||
-Wall \
|
-Wall \
|
||||||
-ggdb3 \
|
-ggdb3 \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
$(LIBOSMOCORE_CFLAGS) \
|
$(LIBOSMOCORE_CFLAGS) \
|
||||||
$(LIBOSMOGSM_CFLAGS) \
|
$(LIBOSMOGSM_CFLAGS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
@@ -23,15 +23,17 @@ EXTRA_DIST = \
|
|||||||
auc_ts_55_205_test_sets.err \
|
auc_ts_55_205_test_sets.err \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
check_PROGRAMS = auc_test auc_ts_55_205_test_sets
|
check_PROGRAMS = auc_ts_55_205_test_sets
|
||||||
|
|
||||||
|
noinst_PROGRAMS = auc_test
|
||||||
|
|
||||||
auc_test_SOURCES = \
|
auc_test_SOURCES = \
|
||||||
auc_test.c \
|
auc_test.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
auc_test_LDADD = \
|
auc_test_LDADD = \
|
||||||
$(top_builddir)/src/auc.o \
|
$(top_srcdir)/src/auc.c \
|
||||||
$(top_builddir)/src/logging.o \
|
$(top_srcdir)/src/logging.c \
|
||||||
$(LIBOSMOCORE_LIBS) \
|
$(LIBOSMOCORE_LIBS) \
|
||||||
$(LIBOSMOGSM_LIBS) \
|
$(LIBOSMOGSM_LIBS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
@@ -41,8 +43,8 @@ auc_ts_55_205_test_sets_SOURCES = \
|
|||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
auc_ts_55_205_test_sets_LDADD = \
|
auc_ts_55_205_test_sets_LDADD = \
|
||||||
$(top_builddir)/src/auc.o \
|
$(top_srcdir)/src/auc.c \
|
||||||
$(top_builddir)/src/logging.o \
|
$(top_srcdir)/src/logging.c \
|
||||||
$(LIBOSMOCORE_LIBS) \
|
$(LIBOSMOCORE_LIBS) \
|
||||||
$(LIBOSMOGSM_LIBS) \
|
$(LIBOSMOGSM_LIBS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|||||||
@@ -113,17 +113,16 @@ int rand_get(uint8_t *rand, unsigned int len)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subscriber with 2G-only (COMP128v1) authentication data */
|
|
||||||
static void test_gen_vectors_2g_only(void)
|
static void test_gen_vectors_2g_only(void)
|
||||||
{
|
{
|
||||||
struct osmo_sub_auth_data2 aud2g;
|
struct osmo_sub_auth_data aud2g;
|
||||||
struct osmo_sub_auth_data2 aud3g;
|
struct osmo_sub_auth_data aud3g;
|
||||||
struct osmo_auth_vector vec;
|
struct osmo_auth_vector vec;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
comment_start();
|
comment_start();
|
||||||
|
|
||||||
aud2g = (struct osmo_sub_auth_data2){
|
aud2g = (struct osmo_sub_auth_data){
|
||||||
.type = OSMO_AUTH_TYPE_GSM,
|
.type = OSMO_AUTH_TYPE_GSM,
|
||||||
.algo = OSMO_AUTH_ALG_COMP128v1,
|
.algo = OSMO_AUTH_ALG_COMP128v1,
|
||||||
};
|
};
|
||||||
@@ -131,7 +130,7 @@ static void test_gen_vectors_2g_only(void)
|
|||||||
osmo_hexparse("EB215756028D60E3275E613320AEC880",
|
osmo_hexparse("EB215756028D60E3275E613320AEC880",
|
||||||
aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
|
aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
|
||||||
|
|
||||||
aud3g = (struct osmo_sub_auth_data2){ 0 };
|
aud3g = (struct osmo_sub_auth_data){ 0 };
|
||||||
|
|
||||||
next_rand("39fa2f4e3d523d8619a73b4f65c3e14d", true);
|
next_rand("39fa2f4e3d523d8619a73b4f65c3e14d", true);
|
||||||
|
|
||||||
@@ -175,18 +174,16 @@ static void test_gen_vectors_2g_only(void)
|
|||||||
comment_end();
|
comment_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subscriber with separate 2G (COMP128v1) and 3G (MILENAGE) authentication data,
|
|
||||||
* reflects the default configuration of sysmoUSIM-SJS1 */
|
|
||||||
static void test_gen_vectors_2g_plus_3g(void)
|
static void test_gen_vectors_2g_plus_3g(void)
|
||||||
{
|
{
|
||||||
struct osmo_sub_auth_data2 aud2g;
|
struct osmo_sub_auth_data aud2g;
|
||||||
struct osmo_sub_auth_data2 aud3g;
|
struct osmo_sub_auth_data aud3g;
|
||||||
struct osmo_auth_vector vec;
|
struct osmo_auth_vector vec;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
comment_start();
|
comment_start();
|
||||||
|
|
||||||
aud2g = (struct osmo_sub_auth_data2){
|
aud2g = (struct osmo_sub_auth_data){
|
||||||
.type = OSMO_AUTH_TYPE_GSM,
|
.type = OSMO_AUTH_TYPE_GSM,
|
||||||
.algo = OSMO_AUTH_ALG_COMP128v1,
|
.algo = OSMO_AUTH_ALG_COMP128v1,
|
||||||
};
|
};
|
||||||
@@ -194,11 +191,9 @@ static void test_gen_vectors_2g_plus_3g(void)
|
|||||||
osmo_hexparse("EB215756028D60E3275E613320AEC880",
|
osmo_hexparse("EB215756028D60E3275E613320AEC880",
|
||||||
aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
|
aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
|
||||||
|
|
||||||
aud3g = (struct osmo_sub_auth_data2){
|
aud3g = (struct osmo_sub_auth_data){
|
||||||
.type = OSMO_AUTH_TYPE_UMTS,
|
.type = OSMO_AUTH_TYPE_UMTS,
|
||||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||||
.u.umts.k_len = 16,
|
|
||||||
.u.umts.opc_len = 16,
|
|
||||||
.u.umts.sqn = 31,
|
.u.umts.sqn = 31,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -289,13 +284,10 @@ void _test_gen_vectors_3g_only__expect_vecs(struct osmo_auth_vector vecs[3])
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subscriber with only 3G (MILENAGE) authentication data,
|
|
||||||
* reflects the default configuration of sysmoISIM-SJA2. Resulting
|
|
||||||
* tuples are suitable for both 2G and 3G authentication */
|
|
||||||
static void test_gen_vectors_3g_only(void)
|
static void test_gen_vectors_3g_only(void)
|
||||||
{
|
{
|
||||||
struct osmo_sub_auth_data2 aud2g;
|
struct osmo_sub_auth_data aud2g;
|
||||||
struct osmo_sub_auth_data2 aud3g;
|
struct osmo_sub_auth_data aud3g;
|
||||||
struct osmo_auth_vector vec;
|
struct osmo_auth_vector vec;
|
||||||
struct osmo_auth_vector vecs[3];
|
struct osmo_auth_vector vecs[3];
|
||||||
uint8_t auts[14];
|
uint8_t auts[14];
|
||||||
@@ -304,13 +296,11 @@ static void test_gen_vectors_3g_only(void)
|
|||||||
|
|
||||||
comment_start();
|
comment_start();
|
||||||
|
|
||||||
aud2g = (struct osmo_sub_auth_data2){ 0 };
|
aud2g = (struct osmo_sub_auth_data){ 0 };
|
||||||
|
|
||||||
aud3g = (struct osmo_sub_auth_data2){
|
aud3g = (struct osmo_sub_auth_data){
|
||||||
.type = OSMO_AUTH_TYPE_UMTS,
|
.type = OSMO_AUTH_TYPE_UMTS,
|
||||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||||
.u.umts.k_len = 16,
|
|
||||||
.u.umts.opc_len = 16,
|
|
||||||
.u.umts.sqn = 31,
|
.u.umts.sqn = 31,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -464,58 +454,7 @@ static void test_gen_vectors_3g_only(void)
|
|||||||
comment_end();
|
comment_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subscriber with only 3G (XOR) authentication data,
|
void test_gen_vectors_bad_args()
|
||||||
* reflects the default configuration of sysmoTSIM-SJAx as well
|
|
||||||
* as many "Test USIM" cards. Resulting tuples are suitable for both
|
|
||||||
* 2G and 3G authentication */
|
|
||||||
static void test_gen_vectors_3g_xor(void)
|
|
||||||
{
|
|
||||||
struct osmo_sub_auth_data2 aud2g;
|
|
||||||
struct osmo_sub_auth_data2 aud3g;
|
|
||||||
struct osmo_auth_vector vec;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
comment_start();
|
|
||||||
|
|
||||||
aud2g = (struct osmo_sub_auth_data2){ 0 };
|
|
||||||
|
|
||||||
aud3g = (struct osmo_sub_auth_data2){
|
|
||||||
.type = OSMO_AUTH_TYPE_UMTS,
|
|
||||||
.algo = OSMO_AUTH_ALG_XOR_3G,
|
|
||||||
.u.umts.k_len = 16,
|
|
||||||
.u.umts.opc_len = 16,
|
|
||||||
.u.umts.sqn = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
osmo_hexparse("000102030405060708090a0b0c0d0e0f",
|
|
||||||
aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
|
|
||||||
osmo_hexparse("00000000000000000000000000000000",
|
|
||||||
aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
|
|
||||||
next_rand("b5039c57e4a75051551d1a390a71ce48", true);
|
|
||||||
|
|
||||||
vec = (struct osmo_auth_vector){ {0} };
|
|
||||||
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 0, "%"PRIu64);
|
|
||||||
rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
|
|
||||||
VERBOSE_ASSERT(rc, == 1, "%d");
|
|
||||||
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 0, "%"PRIu64);
|
|
||||||
|
|
||||||
VEC_IS(&vec,
|
|
||||||
" rand: b5039c57e4a75051551d1a390a71ce48\n"
|
|
||||||
" autn: 54e0a256565d0000b5029e54e0a25656\n"
|
|
||||||
" ck: 029e54e0a256565d141032067cc047b5\n"
|
|
||||||
" ik: 9e54e0a256565d141032067cc047b502\n"
|
|
||||||
" res: b5029e54e0a256565d141032067cc047\n"
|
|
||||||
" res_len: 10\n"
|
|
||||||
" kc: 98e880384887f9fe\n"
|
|
||||||
" sres: 0ec81877\n"
|
|
||||||
" auth_types: 03000000\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
comment_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Test a variety of invalid authentication data combinations */
|
|
||||||
void test_gen_vectors_bad_args(void)
|
|
||||||
{
|
{
|
||||||
struct osmo_auth_vector vec;
|
struct osmo_auth_vector vec;
|
||||||
uint8_t auts[14];
|
uint8_t auts[14];
|
||||||
@@ -523,43 +462,39 @@ void test_gen_vectors_bad_args(void)
|
|||||||
int rc;
|
int rc;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
struct osmo_sub_auth_data2 aud2g = {
|
struct osmo_sub_auth_data aud2g = {
|
||||||
.type = OSMO_AUTH_TYPE_GSM,
|
.type = OSMO_AUTH_TYPE_GSM,
|
||||||
.algo = OSMO_AUTH_ALG_COMP128v1,
|
.algo = OSMO_AUTH_ALG_COMP128v1,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osmo_sub_auth_data2 aud3g = {
|
struct osmo_sub_auth_data aud3g = {
|
||||||
.type = OSMO_AUTH_TYPE_UMTS,
|
.type = OSMO_AUTH_TYPE_UMTS,
|
||||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||||
.u.umts.k_len = 16,
|
|
||||||
.u.umts.opc_len = 16,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osmo_sub_auth_data2 aud2g_noalg = {
|
struct osmo_sub_auth_data aud2g_noalg = {
|
||||||
.type = OSMO_AUTH_TYPE_GSM,
|
.type = OSMO_AUTH_TYPE_GSM,
|
||||||
.algo = OSMO_AUTH_ALG_NONE,
|
.algo = OSMO_AUTH_ALG_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osmo_sub_auth_data2 aud3g_noalg = {
|
struct osmo_sub_auth_data aud3g_noalg = {
|
||||||
.type = OSMO_AUTH_TYPE_UMTS,
|
.type = OSMO_AUTH_TYPE_UMTS,
|
||||||
.algo = OSMO_AUTH_ALG_NONE,
|
.algo = OSMO_AUTH_ALG_NONE,
|
||||||
.u.umts.k_len = 16,
|
|
||||||
.u.umts.opc_len = 16,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osmo_sub_auth_data2 aud_notype = {
|
struct osmo_sub_auth_data aud_notype = {
|
||||||
.type = OSMO_AUTH_TYPE_NONE,
|
.type = OSMO_AUTH_TYPE_NONE,
|
||||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osmo_sub_auth_data2 no_aud = {
|
struct osmo_sub_auth_data no_aud = {
|
||||||
.type = OSMO_AUTH_TYPE_NONE,
|
.type = OSMO_AUTH_TYPE_NONE,
|
||||||
.algo = OSMO_AUTH_ALG_NONE,
|
.algo = OSMO_AUTH_ALG_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct osmo_sub_auth_data2 *aud2g;
|
struct osmo_sub_auth_data *aud2g;
|
||||||
struct osmo_sub_auth_data2 *aud3g;
|
struct osmo_sub_auth_data *aud3g;
|
||||||
uint8_t *rand_auts;
|
uint8_t *rand_auts;
|
||||||
uint8_t *auts;
|
uint8_t *auts;
|
||||||
const char *label;
|
const char *label;
|
||||||
@@ -678,20 +613,15 @@ int main(int argc, char **argv)
|
|||||||
void *tall_ctx = talloc_named_const(NULL, 1, "auc_test");
|
void *tall_ctx = talloc_named_const(NULL, 1, "auc_test");
|
||||||
|
|
||||||
osmo_init_logging2(tall_ctx, &hlr_log_info);
|
osmo_init_logging2(tall_ctx, &hlr_log_info);
|
||||||
log_set_print_filename2(osmo_stderr_target,
|
log_set_print_filename(osmo_stderr_target, cmdline_opts.verbose);
|
||||||
cmdline_opts.verbose ?
|
|
||||||
LOG_FILENAME_BASENAME :
|
|
||||||
LOG_FILENAME_NONE);
|
|
||||||
log_set_print_timestamp(osmo_stderr_target, 0);
|
log_set_print_timestamp(osmo_stderr_target, 0);
|
||||||
log_set_use_color(osmo_stderr_target, 0);
|
log_set_use_color(osmo_stderr_target, 0);
|
||||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
|
||||||
log_set_print_category(osmo_stderr_target, 1);
|
log_set_print_category(osmo_stderr_target, 1);
|
||||||
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
|
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
|
||||||
|
|
||||||
test_gen_vectors_2g_only();
|
test_gen_vectors_2g_only();
|
||||||
test_gen_vectors_2g_plus_3g();
|
test_gen_vectors_2g_plus_3g();
|
||||||
test_gen_vectors_3g_only();
|
test_gen_vectors_3g_only();
|
||||||
test_gen_vectors_3g_xor();
|
|
||||||
test_gen_vectors_bad_args();
|
test_gen_vectors_bad_args();
|
||||||
|
|
||||||
printf("Done\n");
|
printf("Done\n");
|
||||||
|
|||||||
@@ -217,29 +217,6 @@ DAUC vector [2]: auth_types = 0x3
|
|||||||
===== test_gen_vectors_3g_only: SUCCESS
|
===== test_gen_vectors_3g_only: SUCCESS
|
||||||
|
|
||||||
|
|
||||||
===== test_gen_vectors_3g_xor
|
|
||||||
aud3g.u.umts.sqn == 0
|
|
||||||
DAUC Computing 1 auth vector: 3G only (2G derived from 3G keys)
|
|
||||||
DAUC 3G: k = 000102030405060708090a0b0c0d0e0f
|
|
||||||
DAUC 3G: opc = 00000000000000000000000000000000
|
|
||||||
DAUC 3G: for sqn ind 0, previous sqn was 0
|
|
||||||
DAUC vector [0]: rand = b5039c57e4a75051551d1a390a71ce48
|
|
||||||
DAUC vector [0]: sqn = 0
|
|
||||||
DAUC vector [0]: autn = 54e0a256565d0000b5029e54e0a25656
|
|
||||||
DAUC vector [0]: ck = 029e54e0a256565d141032067cc047b5
|
|
||||||
DAUC vector [0]: ik = 9e54e0a256565d141032067cc047b502
|
|
||||||
DAUC vector [0]: res = b5029e54e0a256565d141032067cc047
|
|
||||||
DAUC vector [0]: res_len = 16
|
|
||||||
DAUC vector [0]: deriving 2G from 3G
|
|
||||||
DAUC vector [0]: kc = 98e880384887f9fe
|
|
||||||
DAUC vector [0]: sres = 0ec81877
|
|
||||||
DAUC vector [0]: auth_types = 0x3
|
|
||||||
rc == 1
|
|
||||||
aud3g.u.umts.sqn == 0
|
|
||||||
vector matches expectations
|
|
||||||
===== test_gen_vectors_3g_xor: SUCCESS
|
|
||||||
|
|
||||||
|
|
||||||
===== test_gen_vectors_bad_args
|
===== test_gen_vectors_bad_args
|
||||||
|
|
||||||
- no auth data (a)
|
- no auth data (a)
|
||||||
|
|||||||
@@ -24,20 +24,18 @@
|
|||||||
|
|
||||||
static void {func_name}(void)
|
static void {func_name}(void)
|
||||||
{{
|
{{
|
||||||
struct osmo_sub_auth_data2 aud2g;
|
struct osmo_sub_auth_data aud2g;
|
||||||
struct osmo_sub_auth_data2 aud3g;
|
struct osmo_sub_auth_data aud3g;
|
||||||
struct osmo_auth_vector vec;
|
struct osmo_auth_vector vec;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
comment_start();
|
comment_start();
|
||||||
|
|
||||||
aud2g = (struct osmo_sub_auth_data2){{ 0 }};
|
aud2g = (struct osmo_sub_auth_data){{ 0 }};
|
||||||
|
|
||||||
aud3g = (struct osmo_sub_auth_data2){{
|
aud3g = (struct osmo_sub_auth_data){{
|
||||||
.type = OSMO_AUTH_TYPE_UMTS,
|
.type = OSMO_AUTH_TYPE_UMTS,
|
||||||
.algo = OSMO_AUTH_ALG_MILENAGE,
|
.algo = OSMO_AUTH_ALG_MILENAGE,
|
||||||
.u.umts.k_len = 16,
|
|
||||||
.u.umts.opc_len = 16,
|
|
||||||
.u.umts.sqn = 31,
|
.u.umts.sqn = 31,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -50,7 +48,6 @@ static void {func_name}(void)
|
|||||||
fake_rand, sizeof(fake_rand));
|
fake_rand, sizeof(fake_rand));
|
||||||
|
|
||||||
vec = (struct osmo_auth_vector){{ {{0}} }};
|
vec = (struct osmo_auth_vector){{ {{0}} }};
|
||||||
vec.res_len = 8;
|
|
||||||
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64);
|
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64);
|
||||||
rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
|
rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
|
||||||
VERBOSE_ASSERT(rc, == 1, "%d");
|
VERBOSE_ASSERT(rc, == 1, "%d");
|
||||||
|
|||||||
@@ -100,16 +100,15 @@ int rand_get(uint8_t *rand, unsigned int len)
|
|||||||
|
|
||||||
FUNCTIONS
|
FUNCTIONS
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main()
|
||||||
{
|
{
|
||||||
printf("3GPP TS 55.205 Test Sets\n");
|
printf("3GPP TS 55.205 Test Sets\n");
|
||||||
void *tall_ctx = talloc_named_const(NULL, 1, "test");
|
void *tall_ctx = talloc_named_const(NULL, 1, "test");
|
||||||
msgb_talloc_ctx_init(tall_ctx, 0);
|
msgb_talloc_ctx_init(tall_ctx, 0);
|
||||||
osmo_init_logging2(tall_ctx, &hlr_log_info);
|
osmo_init_logging2(tall_ctx, &hlr_log_info);
|
||||||
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
|
log_set_print_filename(osmo_stderr_target, 0);
|
||||||
log_set_print_timestamp(osmo_stderr_target, 0);
|
log_set_print_timestamp(osmo_stderr_target, 0);
|
||||||
log_set_use_color(osmo_stderr_target, 0);
|
log_set_use_color(osmo_stderr_target, 0);
|
||||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
|
||||||
log_set_print_category(osmo_stderr_target, 1);
|
log_set_print_category(osmo_stderr_target, 1);
|
||||||
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
|
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
AM_CPPFLAGS = \
|
AM_CFLAGS = \
|
||||||
$(all_includes) \
|
$(all_includes) \
|
||||||
-I$(top_srcdir)/include \
|
-I$(top_srcdir)/include \
|
||||||
-I$(top_builddir)/include \
|
-I$(top_builddir)/include \
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
AM_CFLAGS = \
|
|
||||||
-Wall \
|
-Wall \
|
||||||
-ggdb3 \
|
-ggdb3 \
|
||||||
$(LIBOSMOCORE_CFLAGS) \
|
$(LIBOSMOCORE_CFLAGS) \
|
||||||
@@ -33,7 +30,7 @@ db_test_LDADD = \
|
|||||||
$(top_builddir)/src/db_auc.o \
|
$(top_builddir)/src/db_auc.o \
|
||||||
$(top_builddir)/src/db_hlr.o \
|
$(top_builddir)/src/db_hlr.o \
|
||||||
$(top_builddir)/src/db.o \
|
$(top_builddir)/src/db.o \
|
||||||
$(top_builddir)/src/cni_peer_id.o \
|
$(top_builddir)/src/gsup_peer_id.o \
|
||||||
$(LIBOSMOCORE_LIBS) \
|
$(LIBOSMOCORE_LIBS) \
|
||||||
$(LIBOSMOGSM_LIBS) \
|
$(LIBOSMOGSM_LIBS) \
|
||||||
$(LIBOSMOABIS_LIBS) \
|
$(LIBOSMOABIS_LIBS) \
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include <osmocom/core/utils.h>
|
#include <osmocom/core/utils.h>
|
||||||
#include <osmocom/core/logging.h>
|
#include <osmocom/core/logging.h>
|
||||||
|
|
||||||
#include <osmocom/gsupclient/cni_peer_id.h>
|
#include <osmocom/gsupclient/gsup_peer_id.h>
|
||||||
#include <osmocom/hlr/db.h>
|
#include <osmocom/hlr/db.h>
|
||||||
#include <osmocom/hlr/logging.h>
|
#include <osmocom/hlr/logging.h>
|
||||||
|
|
||||||
@@ -122,16 +122,16 @@ static void _fill_invalid(void *dest, size_t size)
|
|||||||
/* Not linking the real auc_compute_vectors(), just returning num_vec.
|
/* Not linking the real auc_compute_vectors(), just returning num_vec.
|
||||||
* This gets called by db_get_auc(), but we're only interested in its rc. */
|
* This gets called by db_get_auc(), but we're only interested in its rc. */
|
||||||
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
|
||||||
struct osmo_sub_auth_data2 *aud2g,
|
struct osmo_sub_auth_data *aud2g,
|
||||||
struct osmo_sub_auth_data2 *aud3g,
|
struct osmo_sub_auth_data *aud3g,
|
||||||
const uint8_t *rand_auts, const uint8_t *auts)
|
const uint8_t *rand_auts, const uint8_t *auts)
|
||||||
{ return num_vec; }
|
{ return num_vec; }
|
||||||
|
|
||||||
static struct db_context *dbc = NULL;
|
static struct db_context *dbc = NULL;
|
||||||
static void *ctx = NULL;
|
static void *ctx = NULL;
|
||||||
static struct hlr_subscriber g_subscr;
|
static struct hlr_subscriber g_subscr;
|
||||||
static struct osmo_sub_auth_data2 g_aud2g;
|
static struct osmo_sub_auth_data g_aud2g;
|
||||||
static struct osmo_sub_auth_data2 g_aud3g;
|
static struct osmo_sub_auth_data g_aud3g;
|
||||||
static int g_rc;
|
static int g_rc;
|
||||||
static int64_t g_id;
|
static int64_t g_id;
|
||||||
|
|
||||||
@@ -173,6 +173,8 @@ void dump_subscr(struct hlr_subscriber *subscr)
|
|||||||
Pfo(lmsi, "0x%x", subscr);
|
Pfo(lmsi, "0x%x", subscr);
|
||||||
Pb(true, ms_purged_cs);
|
Pb(true, ms_purged_cs);
|
||||||
Pb(true, ms_purged_ps);
|
Pb(true, ms_purged_ps);
|
||||||
|
Ps(last_lu_rat_cs);
|
||||||
|
Ps(last_lu_rat_ps);
|
||||||
fprintf(stderr, "}\n");
|
fprintf(stderr, "}\n");
|
||||||
#undef Ps
|
#undef Ps
|
||||||
#undef Pd
|
#undef Pd
|
||||||
@@ -180,21 +182,18 @@ void dump_subscr(struct hlr_subscriber *subscr)
|
|||||||
#undef Pb
|
#undef Pb
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_aud(const char *label, struct osmo_sub_auth_data2 *aud)
|
void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
|
||||||
{
|
{
|
||||||
if (aud->type == OSMO_AUTH_TYPE_NONE) {
|
if (aud->type == OSMO_AUTH_TYPE_NONE) {
|
||||||
fprintf(stderr, "%s: none\n", label);
|
fprintf(stderr, "%s: none\n", label);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "%s: struct osmo_sub_auth_data2 {\n", label);
|
fprintf(stderr, "%s: struct osmo_sub_auth_data {\n", label);
|
||||||
#define Pf(name, fmt) \
|
#define Pf(name, fmt) \
|
||||||
Pfo(name, fmt, aud)
|
Pfo(name, fmt, aud)
|
||||||
#define Phex(name) \
|
#define Phex(name) \
|
||||||
Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, sizeof(aud->name)))
|
Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, sizeof(aud->name)))
|
||||||
#define Phexl(name, len) \
|
|
||||||
Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, aud->len))
|
|
||||||
|
|
||||||
|
|
||||||
Pfv(type, "%s", osmo_sub_auth_type_name(aud->type));
|
Pfv(type, "%s", osmo_sub_auth_type_name(aud->type));
|
||||||
Pfv(algo, "%s", osmo_auth_alg_name(aud->algo));
|
Pfv(algo, "%s", osmo_auth_alg_name(aud->algo));
|
||||||
@@ -203,9 +202,9 @@ void dump_aud(const char *label, struct osmo_sub_auth_data2 *aud)
|
|||||||
Phex(u.gsm.ki);
|
Phex(u.gsm.ki);
|
||||||
break;
|
break;
|
||||||
case OSMO_AUTH_TYPE_UMTS:
|
case OSMO_AUTH_TYPE_UMTS:
|
||||||
Phexl(u.umts.opc, u.umts.opc_len);
|
Phex(u.umts.opc);
|
||||||
Pf(u.umts.opc_is_op, "%u");
|
Pf(u.umts.opc_is_op, "%u");
|
||||||
Phexl(u.umts.k, u.umts.k_len);
|
Phex(u.umts.k);
|
||||||
Phex(u.umts.amf);
|
Phex(u.umts.amf);
|
||||||
if (aud->u.umts.sqn) {
|
if (aud->u.umts.sqn) {
|
||||||
Pf(u.umts.sqn, "%"PRIu64);
|
Pf(u.umts.sqn, "%"PRIu64);
|
||||||
@@ -222,7 +221,6 @@ void dump_aud(const char *label, struct osmo_sub_auth_data2 *aud)
|
|||||||
|
|
||||||
#undef Pf
|
#undef Pf
|
||||||
#undef Phex
|
#undef Phex
|
||||||
#undef Phexl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void db_raw_sql(struct db_context *dbc, const char *sql)
|
void db_raw_sql(struct db_context *dbc, const char *sql)
|
||||||
@@ -247,10 +245,10 @@ static int db_subscr_lu_str(struct db_context *dbc, int64_t subscr_id,
|
|||||||
{
|
{
|
||||||
struct osmo_ipa_name vlr_nr;
|
struct osmo_ipa_name vlr_nr;
|
||||||
osmo_ipa_name_set_str(&vlr_nr, vlr_or_sgsn_number);
|
osmo_ipa_name_set_str(&vlr_nr, vlr_or_sgsn_number);
|
||||||
return db_subscr_lu(dbc, subscr_id, &vlr_nr, is_ps, NULL);
|
return db_subscr_lu(dbc, subscr_id, &vlr_nr, is_ps, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_subscr_create_update_sel_delete(void)
|
static void test_subscr_create_update_sel_delete()
|
||||||
{
|
{
|
||||||
int64_t id0, id1, id2, id_short;
|
int64_t id0, id1, id2, id_short;
|
||||||
comment_start();
|
comment_start();
|
||||||
@@ -266,13 +264,13 @@ static void test_subscr_create_update_sel_delete(void)
|
|||||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||||
ASSERT_SEL(imsi, imsi2, 0);
|
ASSERT_SEL(imsi, imsi2, 0);
|
||||||
id2 = g_subscr.id;
|
id2 = g_subscr.id;
|
||||||
ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
|
ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||||
ASSERT_SEL(imsi, imsi0, 0);
|
ASSERT_SEL(imsi, imsi0, 0);
|
||||||
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
|
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||||
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
|
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||||
ASSERT_SEL(imsi, imsi1, 0);
|
ASSERT_SEL(imsi, imsi1, 0);
|
||||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
|
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EEXIST);
|
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||||
ASSERT_SEL(imsi, imsi2, 0);
|
ASSERT_SEL(imsi, imsi2, 0);
|
||||||
|
|
||||||
ASSERT_RC(db_subscr_create(dbc, "123456789 000003", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EINVAL);
|
ASSERT_RC(db_subscr_create(dbc, "123456789 000003", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EINVAL);
|
||||||
@@ -545,7 +543,7 @@ static const struct sub_auth_data_str *mk_aud_3g(enum osmo_auth_algo algo,
|
|||||||
return &aud;
|
return &aud;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_subscr_aud(void)
|
static void test_subscr_aud()
|
||||||
{
|
{
|
||||||
int64_t id;
|
int64_t id;
|
||||||
|
|
||||||
@@ -590,7 +588,7 @@ static void test_subscr_aud(void)
|
|||||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||||
|
|
||||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||||
mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")),
|
mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")),
|
||||||
0);
|
0);
|
||||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||||
|
|
||||||
@@ -608,7 +606,7 @@ static void test_subscr_aud(void)
|
|||||||
-ENOENT);
|
-ENOENT);
|
||||||
|
|
||||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||||
mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")),
|
mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")),
|
||||||
0);
|
0);
|
||||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||||
|
|
||||||
@@ -711,12 +709,12 @@ static void test_subscr_aud(void)
|
|||||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||||
|
|
||||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||||
mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f000000000000f00000000000f000000f00000000")),
|
mk_aud_2g(OSMO_AUTH_ALG_XOR, "f000000000000f00000000000f000000f00000000")),
|
||||||
-EINVAL);
|
-EINVAL);
|
||||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||||
|
|
||||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||||
mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f00")),
|
mk_aud_2g(OSMO_AUTH_ALG_XOR, "f00")),
|
||||||
-EINVAL);
|
-EINVAL);
|
||||||
ASSERT_SEL_AUD(imsi0, 0, id);
|
ASSERT_SEL_AUD(imsi0, 0, id);
|
||||||
|
|
||||||
@@ -787,7 +785,7 @@ static void test_subscr_aud(void)
|
|||||||
|
|
||||||
/* Make each key too short in this test. Note that we can't set them longer than the allowed size without changing the
|
/* Make each key too short in this test. Note that we can't set them longer than the allowed size without changing the
|
||||||
* table structure. */
|
* table structure. */
|
||||||
static void test_subscr_aud_invalid_len(void)
|
static void test_subscr_aud_invalid_len()
|
||||||
{
|
{
|
||||||
int64_t id;
|
int64_t id;
|
||||||
|
|
||||||
@@ -849,7 +847,7 @@ static void test_subscr_aud_invalid_len(void)
|
|||||||
comment_end();
|
comment_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_subscr_sqn(void)
|
static void test_subscr_sqn()
|
||||||
{
|
{
|
||||||
int64_t id;
|
int64_t id;
|
||||||
|
|
||||||
@@ -922,22 +920,22 @@ static void test_subscr_sqn(void)
|
|||||||
comment_end();
|
comment_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_ind(void)
|
static void test_ind()
|
||||||
{
|
{
|
||||||
comment_start();
|
comment_start();
|
||||||
|
|
||||||
#define ASSERT_IND(VLR, IND) do { \
|
#define ASSERT_IND(VLR, IND) do { \
|
||||||
unsigned int ind; \
|
unsigned int ind; \
|
||||||
struct osmo_cni_peer_id vlr; \
|
struct osmo_gsup_peer_id vlr; \
|
||||||
OSMO_ASSERT(!osmo_cni_peer_id_set_str(&vlr, OSMO_CNI_PEER_ID_IPA_NAME, VLR)); \
|
OSMO_ASSERT(!osmo_gsup_peer_id_set_str(&vlr, OSMO_GSUP_PEER_ID_IPA_NAME, VLR)); \
|
||||||
ASSERT_RC(db_ind(dbc, &vlr, &ind), 0); \
|
ASSERT_RC(db_ind(dbc, &vlr, &ind), 0); \
|
||||||
fprintf(stderr, "%s ind = %u\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len), ind); \
|
fprintf(stderr, "%s ind = %u\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len), ind); \
|
||||||
if (ind != (IND)) \
|
if (ind != (IND)) \
|
||||||
fprintf(stderr, " ERROR: expected " #IND "\n"); \
|
fprintf(stderr, " ERROR: expected " #IND "\n"); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define IND_DEL(VLR) do { \
|
#define IND_DEL(VLR) do { \
|
||||||
struct osmo_cni_peer_id vlr; \
|
struct osmo_gsup_peer_id vlr; \
|
||||||
OSMO_ASSERT(!osmo_cni_peer_id_set_str(&vlr, OSMO_CNI_PEER_ID_IPA_NAME, VLR)); \
|
OSMO_ASSERT(!osmo_gsup_peer_id_set_str(&vlr, OSMO_GSUP_PEER_ID_IPA_NAME, VLR)); \
|
||||||
ASSERT_RC(db_ind_del(dbc, &vlr), 0); \
|
ASSERT_RC(db_ind_del(dbc, &vlr), 0); \
|
||||||
fprintf(stderr, "%s ind deleted\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len)); \
|
fprintf(stderr, "%s ind deleted\n\n", osmo_quote_str((char*)vlr.ipa_name.val, vlr.ipa_name.len)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -1028,13 +1026,9 @@ int main(int argc, char **argv)
|
|||||||
handle_options(argc, argv);
|
handle_options(argc, argv);
|
||||||
|
|
||||||
osmo_init_logging2(ctx, &hlr_log_info);
|
osmo_init_logging2(ctx, &hlr_log_info);
|
||||||
log_set_print_filename2(osmo_stderr_target,
|
log_set_print_filename(osmo_stderr_target, cmdline_opts.verbose);
|
||||||
cmdline_opts.verbose ?
|
|
||||||
LOG_FILENAME_BASENAME :
|
|
||||||
LOG_FILENAME_NONE);
|
|
||||||
log_set_print_timestamp(osmo_stderr_target, 0);
|
log_set_print_timestamp(osmo_stderr_target, 0);
|
||||||
log_set_use_color(osmo_stderr_target, 0);
|
log_set_use_color(osmo_stderr_target, 0);
|
||||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
|
||||||
log_set_print_category(osmo_stderr_target, 1);
|
log_set_print_category(osmo_stderr_target, 1);
|
||||||
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
|
log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ struct hlr_subscriber {
|
|||||||
.imsi = '123456789000002',
|
.imsi = '123456789000002',
|
||||||
}
|
}
|
||||||
|
|
||||||
db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
|
db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
|
||||||
DAUC IMSI='123456789000000': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
DAUC IMSI='123456789000000': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
||||||
|
|
||||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
||||||
@@ -36,10 +36,10 @@ struct hlr_subscriber {
|
|||||||
.imsi = '123456789000000',
|
.imsi = '123456789000000',
|
||||||
}
|
}
|
||||||
|
|
||||||
db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
|
db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
|
||||||
DAUC IMSI='123456789000001': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
DAUC IMSI='123456789000001': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
||||||
|
|
||||||
db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
|
db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
|
||||||
DAUC IMSI='123456789000001': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
DAUC IMSI='123456789000001': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
||||||
|
|
||||||
db_subscr_get_by_imsi(dbc, imsi1, &g_subscr) --> 0
|
db_subscr_get_by_imsi(dbc, imsi1, &g_subscr) --> 0
|
||||||
@@ -48,10 +48,10 @@ struct hlr_subscriber {
|
|||||||
.imsi = '123456789000001',
|
.imsi = '123456789000001',
|
||||||
}
|
}
|
||||||
|
|
||||||
db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
|
db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
|
||||||
DAUC IMSI='123456789000002': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
DAUC IMSI='123456789000002': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
||||||
|
|
||||||
db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EEXIST
|
db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EIO
|
||||||
DAUC IMSI='123456789000002': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
DAUC IMSI='123456789000002': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
|
||||||
|
|
||||||
db_subscr_get_by_imsi(dbc, imsi2, &g_subscr) --> 0
|
db_subscr_get_by_imsi(dbc, imsi2, &g_subscr) --> 0
|
||||||
@@ -824,7 +824,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "01234567
|
|||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v1,
|
.algo = COMP128v1,
|
||||||
.u.gsm.ki = '0123456789abcdef0123456789abcdef',
|
.u.gsm.ki = '0123456789abcdef0123456789abcdef',
|
||||||
@@ -841,7 +841,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "01234567
|
|||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v1,
|
.algo = COMP128v1,
|
||||||
.u.gsm.ki = '0123456789abcdef0123456789abcdef',
|
.u.gsm.ki = '0123456789abcdef0123456789abcdef',
|
||||||
@@ -853,7 +853,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v2, "BeadedBe
|
|||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v2,
|
.algo = COMP128v2,
|
||||||
.u.gsm.ki = 'beadedbeeaced1ebbeddefacedfacade',
|
.u.gsm.ki = 'beadedbeeaced1ebbeddefacedfacade',
|
||||||
@@ -865,21 +865,21 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v3, "DeafBedd
|
|||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'deafbeddedbabeacceededfadeddecaf',
|
.u.gsm.ki = 'deafbeddedbabeacceededfadeddecaf',
|
||||||
}
|
}
|
||||||
3G: none
|
3G: none
|
||||||
|
|
||||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")) --> 0
|
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0
|
||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = XOR-2G,
|
.algo = XOR,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: none
|
3G: none
|
||||||
@@ -900,14 +900,14 @@ DAUC IMSI='123456789000000': No 3G Auth Data
|
|||||||
|
|
||||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> -ENOENT
|
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> -ENOENT
|
||||||
|
|
||||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")) --> 0
|
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0
|
||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = XOR-2G,
|
.algo = XOR,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: none
|
3G: none
|
||||||
@@ -932,7 +932,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -954,7 +954,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -970,7 +970,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'deaf0ff1ced0d0dabbedd1ced1cef00d',
|
.u.umts.opc = 'deaf0ff1ced0d0dabbedd1ced1cef00d',
|
||||||
@@ -985,7 +985,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1001,7 +1001,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
|
.u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
|
||||||
@@ -1033,7 +1033,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
|
.u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
|
||||||
@@ -1069,12 +1069,12 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCaf
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1097,12 +1097,12 @@ DAUC Cannot update auth tokens: Unknown auth algo: 99999
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1112,17 +1112,17 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
.u.umts.ind_bitlen = 5,
|
.u.umts.ind_bitlen = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f000000000000f00000000000f000000f00000000")) --> -EINVAL
|
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "f000000000000f00000000000f000000f00000000")) --> -EINVAL
|
||||||
DAUC Cannot update auth tokens: Invalid KI: 'f000000000000f00000000000f000000f00000000'
|
DAUC Cannot update auth tokens: Invalid KI: 'f000000000000f00000000000f000000f00000000'
|
||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1132,17 +1132,17 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
.u.umts.ind_bitlen = 5,
|
.u.umts.ind_bitlen = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f00")) --> -EINVAL
|
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "f00")) --> -EINVAL
|
||||||
DAUC Cannot update auth tokens: Invalid KI: 'f00'
|
DAUC Cannot update auth tokens: Invalid KI: 'f00'
|
||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1157,12 +1157,12 @@ DAUC Cannot update auth tokens: auth algo not suited for 2G: MILENAGE
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1177,12 +1177,12 @@ DAUC Cannot update auth tokens: Invalid OP/OPC: '0f000000000000f00000000000f0000
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1197,12 +1197,12 @@ DAUC Cannot update auth tokens: Invalid K: '000000000000f00000000000f000000'
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1217,12 +1217,12 @@ DAUC Cannot update auth tokens: Invalid ind_bitlen: 29
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1237,12 +1237,12 @@ DAUC Cannot update auth tokens: Invalid OP/OPC: 'X000000000000f00000000000f00000
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1257,12 +1257,12 @@ DAUC Cannot update auth tokens: Invalid K: 'f000000000000 f00000000000 f000000'
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
||||||
|
|
||||||
2G: struct osmo_sub_auth_data2 {
|
2G: struct osmo_sub_auth_data {
|
||||||
.type = GSM,
|
.type = GSM,
|
||||||
.algo = COMP128v3,
|
.algo = COMP128v3,
|
||||||
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
|
||||||
}
|
}
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1338,7 +1338,7 @@ sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
|
|||||||
sqlite3_step(stmt) --> SQLITE_DONE
|
sqlite3_step(stmt) --> SQLITE_DONE
|
||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||||
DAUC IMSI='123456789000000': Error reading Ki, expected min length 16 but has length 15
|
DAUC IMSI='123456789000000': Error reading Ki, expected length 16 but has length 15
|
||||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||||
|
|
||||||
|
|
||||||
@@ -1359,7 +1359,7 @@ sqlite3_step(stmt) --> SQLITE_DONE
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
DAUC IMSI='123456789000000': Error reading K, expected min length 16 but has length 15
|
DAUC IMSI='123456789000000': Error reading K, expected length 16 but has length 15
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1374,7 +1374,7 @@ sqlite3_step(stmt) --> SQLITE_DONE
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
DAUC IMSI='123456789000000': Error reading OP, expected min length 16 but has length 15
|
DAUC IMSI='123456789000000': Error reading OP, expected length 16 but has length 15
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1389,7 +1389,7 @@ sqlite3_step(stmt) --> SQLITE_DONE
|
|||||||
|
|
||||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
DAUC IMSI='123456789000000': Error reading OPC, expected min length 16 but has length 15
|
DAUC IMSI='123456789000000': Error reading OPC, expected length 16 but has length 15
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1458,7 +1458,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1477,7 +1477,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1495,7 +1495,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1513,7 +1513,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1534,7 +1534,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1550,7 +1550,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1568,7 +1568,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
@@ -1586,7 +1586,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
|
|||||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||||
|
|
||||||
2G: none
|
2G: none
|
||||||
3G: struct osmo_sub_auth_data2 {
|
3G: struct osmo_sub_auth_data {
|
||||||
.type = UMTS,
|
.type = UMTS,
|
||||||
.algo = MILENAGE,
|
.algo = MILENAGE,
|
||||||
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ OsmoHLR# subscriber imsi 123456789012345 create
|
|||||||
ID: 1
|
ID: 1
|
||||||
IMSI: 123456789012345
|
IMSI: 123456789012345
|
||||||
MSISDN: none
|
MSISDN: none
|
||||||
|
GERAN-A: allowed
|
||||||
|
UTRAN-Iu: allowed
|
||||||
|
EUTRAN-SGs: allowed
|
||||||
OsmoHLR# subscriber imsi 123456789012345 update msisdn 098765432109876
|
OsmoHLR# subscriber imsi 123456789012345 update msisdn 098765432109876
|
||||||
% Updated subscriber IMSI='123456789012345' to MSISDN='098765432109876'
|
% Updated subscriber IMSI='123456789012345' to MSISDN='098765432109876'
|
||||||
OsmoHLR# subscriber imsi 123456789012345 update aud2g comp128v1 ki BeefedCafeFaceAcedAddedDecadeFee
|
OsmoHLR# subscriber imsi 123456789012345 update aud2g comp128v1 ki BeefedCafeFaceAcedAddedDecadeFee
|
||||||
@@ -13,11 +16,17 @@ OsmoHLR# subscriber imsi 111111111 create
|
|||||||
ID: 2
|
ID: 2
|
||||||
IMSI: 111111111
|
IMSI: 111111111
|
||||||
MSISDN: none
|
MSISDN: none
|
||||||
|
GERAN-A: allowed
|
||||||
|
UTRAN-Iu: allowed
|
||||||
|
EUTRAN-SGs: allowed
|
||||||
OsmoHLR# subscriber imsi 222222222 create
|
OsmoHLR# subscriber imsi 222222222 create
|
||||||
% Created subscriber 222222222
|
% Created subscriber 222222222
|
||||||
ID: 3
|
ID: 3
|
||||||
IMSI: 222222222
|
IMSI: 222222222
|
||||||
MSISDN: none
|
MSISDN: none
|
||||||
|
GERAN-A: allowed
|
||||||
|
UTRAN-Iu: allowed
|
||||||
|
EUTRAN-SGs: allowed
|
||||||
OsmoHLR# subscriber imsi 222222222 update msisdn 22222
|
OsmoHLR# subscriber imsi 222222222 update msisdn 22222
|
||||||
% Updated subscriber IMSI='222222222' to MSISDN='22222'
|
% Updated subscriber IMSI='222222222' to MSISDN='22222'
|
||||||
OsmoHLR# subscriber imsi 333333 create
|
OsmoHLR# subscriber imsi 333333 create
|
||||||
@@ -25,6 +34,9 @@ OsmoHLR# subscriber imsi 333333 create
|
|||||||
ID: 4
|
ID: 4
|
||||||
IMSI: 333333
|
IMSI: 333333
|
||||||
MSISDN: none
|
MSISDN: none
|
||||||
|
GERAN-A: allowed
|
||||||
|
UTRAN-Iu: allowed
|
||||||
|
EUTRAN-SGs: allowed
|
||||||
OsmoHLR# subscriber imsi 333333 update msisdn 3
|
OsmoHLR# subscriber imsi 333333 update msisdn 3
|
||||||
% Updated subscriber IMSI='333333' to MSISDN='3'
|
% Updated subscriber IMSI='333333' to MSISDN='3'
|
||||||
OsmoHLR# subscriber imsi 333333 update aud2g comp128v2 ki 33333333333333333333333333333333
|
OsmoHLR# subscriber imsi 333333 update aud2g comp128v2 ki 33333333333333333333333333333333
|
||||||
@@ -33,6 +45,9 @@ OsmoHLR# subscriber imsi 444444444444444 create
|
|||||||
ID: 5
|
ID: 5
|
||||||
IMSI: 444444444444444
|
IMSI: 444444444444444
|
||||||
MSISDN: none
|
MSISDN: none
|
||||||
|
GERAN-A: allowed
|
||||||
|
UTRAN-Iu: allowed
|
||||||
|
EUTRAN-SGs: allowed
|
||||||
OsmoHLR# subscriber imsi 444444444444444 update msisdn 4444
|
OsmoHLR# subscriber imsi 444444444444444 update msisdn 4444
|
||||||
% Updated subscriber IMSI='444444444444444' to MSISDN='4444'
|
% Updated subscriber IMSI='444444444444444' to MSISDN='4444'
|
||||||
OsmoHLR# subscriber imsi 444444444444444 update aud3g milenage k 44444444444444444444444444444444 op 44444444444444444444444444444444
|
OsmoHLR# subscriber imsi 444444444444444 update aud3g milenage k 44444444444444444444444444444444 op 44444444444444444444444444444444
|
||||||
@@ -41,7 +56,10 @@ OsmoHLR# subscriber imsi 5555555 create
|
|||||||
ID: 6
|
ID: 6
|
||||||
IMSI: 5555555
|
IMSI: 5555555
|
||||||
MSISDN: none
|
MSISDN: none
|
||||||
|
GERAN-A: allowed
|
||||||
|
UTRAN-Iu: allowed
|
||||||
|
EUTRAN-SGs: allowed
|
||||||
OsmoHLR# subscriber imsi 5555555 update msisdn 55555555555555
|
OsmoHLR# subscriber imsi 5555555 update msisdn 55555555555555
|
||||||
% Updated subscriber IMSI='5555555' to MSISDN='55555555555555'
|
% Updated subscriber IMSI='5555555' to MSISDN='55555555555555'
|
||||||
OsmoHLR# subscriber imsi 5555555 update aud2g xor-2g ki 55555555555555555555555555555555
|
OsmoHLR# subscriber imsi 5555555 update aud2g xor ki 55555555555555555555555555555555
|
||||||
OsmoHLR# subscriber imsi 5555555 update aud3g milenage k 55555555555555555555555555555555 opc 55555555555555555555555555555555
|
OsmoHLR# subscriber imsi 5555555 update aud3g milenage k 55555555555555555555555555555555 opc 55555555555555555555555555555555
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Table auc_2g contents:
|
|||||||
algo_id_2g|ki|subscriber_id
|
algo_id_2g|ki|subscriber_id
|
||||||
1|BeefedCafeFaceAcedAddedDecadeFee|1
|
1|BeefedCafeFaceAcedAddedDecadeFee|1
|
||||||
2|33333333333333333333333333333333|4
|
2|33333333333333333333333333333333|4
|
||||||
6|55555555555555555555555555555555|6
|
4|55555555555555555555555555555555|6
|
||||||
|
|
||||||
Table: auc_3g
|
Table: auc_3g
|
||||||
name|type|notnull|dflt_value|pk
|
name|type|notnull|dflt_value|pk
|
||||||
@@ -87,6 +87,7 @@ DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 4
|
|||||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 5
|
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 5
|
||||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 6
|
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 6
|
||||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 7
|
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 7
|
||||||
|
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 8
|
||||||
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
|
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
|
||||||
|
|
||||||
Resulting db:
|
Resulting db:
|
||||||
@@ -101,15 +102,15 @@ Table auc_2g contents:
|
|||||||
algo_id_2g|ki|subscriber_id
|
algo_id_2g|ki|subscriber_id
|
||||||
1|BeefedCafeFaceAcedAddedDecadeFee|1
|
1|BeefedCafeFaceAcedAddedDecadeFee|1
|
||||||
2|33333333333333333333333333333333|4
|
2|33333333333333333333333333333333|4
|
||||||
6|55555555555555555555555555555555|6
|
4|55555555555555555555555555555555|6
|
||||||
|
|
||||||
Table: auc_3g
|
Table: auc_3g
|
||||||
name|type|notnull|dflt_value|pk
|
name|type|notnull|dflt_value|pk
|
||||||
algo_id_3g|INTEGER|1||0
|
algo_id_3g|INTEGER|1||0
|
||||||
ind_bitlen|INTEGER|1|5|0
|
ind_bitlen|INTEGER|1|5|0
|
||||||
k|VARCHAR(64)|1||0
|
k|VARCHAR(32)|1||0
|
||||||
op|VARCHAR(64)|0||0
|
op|VARCHAR(32)|0||0
|
||||||
opc|VARCHAR(64)|0||0
|
opc|VARCHAR(32)|0||0
|
||||||
sqn|INTEGER|1|0|0
|
sqn|INTEGER|1|0|0
|
||||||
subscriber_id|INTEGER|0||1
|
subscriber_id|INTEGER|0||1
|
||||||
|
|
||||||
@@ -134,6 +135,8 @@ id|INTEGER|0||1
|
|||||||
imei|VARCHAR(14)|0||0
|
imei|VARCHAR(14)|0||0
|
||||||
imeisv|VARCHAR|0||0
|
imeisv|VARCHAR|0||0
|
||||||
imsi|VARCHAR(15)|1||0
|
imsi|VARCHAR(15)|1||0
|
||||||
|
last_lu_rat_cs|TEXT|0|NULL|0
|
||||||
|
last_lu_rat_ps|TEXT|0|NULL|0
|
||||||
last_lu_seen|TIMESTAMP|0|NULL|0
|
last_lu_seen|TIMESTAMP|0|NULL|0
|
||||||
last_lu_seen_ps|TIMESTAMP|0|NULL|0
|
last_lu_seen_ps|TIMESTAMP|0|NULL|0
|
||||||
lmsi|INTEGER|0||0
|
lmsi|INTEGER|0||0
|
||||||
@@ -153,13 +156,13 @@ vlr_number|VARCHAR(15)|0||0
|
|||||||
vlr_via_proxy|VARCHAR|0||0
|
vlr_via_proxy|VARCHAR|0||0
|
||||||
|
|
||||||
Table subscriber contents:
|
Table subscriber contents:
|
||||||
ggsn_number|gmlc_number|id|imei|imeisv|imsi|last_lu_seen|last_lu_seen_ps|lmsi|ms_purged_cs|ms_purged_ps|msc_number|msisdn|nam_cs|nam_ps|periodic_lu_tmr|periodic_rau_tau_tmr|sgsn_address|sgsn_number|sgsn_via_proxy|smsc_number|vlr_number|vlr_via_proxy
|
ggsn_number|gmlc_number|id|imei|imeisv|imsi|last_lu_rat_cs|last_lu_rat_ps|last_lu_seen|last_lu_seen_ps|lmsi|ms_purged_cs|ms_purged_ps|msc_number|msisdn|nam_cs|nam_ps|periodic_lu_tmr|periodic_rau_tau_tmr|sgsn_address|sgsn_number|sgsn_via_proxy|smsc_number|vlr_number|vlr_via_proxy
|
||||||
||1|||123456789012345||||0|0||098765432109876|1|1|||||||MSC-1|
|
||1|||123456789012345||||||0|0||098765432109876|1|1|||||||MSC-1|
|
||||||
||2|||111111111||||1|0|||1|1||||||||
|
||2|||111111111||||||1|0|||1|1||||||||
|
||||||
||3|||222222222||||0|1||22222|1|1||||||||
|
||3|||222222222||||||0|1||22222|1|1||||||||
|
||||||
||4|||333333||||0|0||3|0|1||||||||
|
||4|||333333||||||0|0||3|0|1||||||||
|
||||||
||5|||444444444444444||||0|0||4444|1|0||||||||
|
||5|||444444444444444||||||0|0||4444|1|0||||||||
|
||||||
||6|||5555555||||0|0||55555555555555|0|0||||||||
|
||6|||5555555||||||0|0||55555555555555|0|0||||||||
|
||||||
|
|
||||||
Table: subscriber_apn
|
Table: subscriber_apn
|
||||||
name|type|notnull|dflt_value|pk
|
name|type|notnull|dflt_value|pk
|
||||||
@@ -175,10 +178,18 @@ subscriber_id|INTEGER|0||0
|
|||||||
|
|
||||||
Table subscriber_multi_msisdn contents:
|
Table subscriber_multi_msisdn contents:
|
||||||
|
|
||||||
|
Table: subscriber_rat
|
||||||
|
name|type|notnull|dflt_value|pk
|
||||||
|
allowed|BOOLEAN|1|0|0
|
||||||
|
rat|TEXT|1||0
|
||||||
|
subscriber_id|INTEGER|0||0
|
||||||
|
|
||||||
|
Table subscriber_rat contents:
|
||||||
|
|
||||||
Verify that osmo-hlr can open it:
|
Verify that osmo-hlr can open it:
|
||||||
osmo-hlr --database $db --db-check --config-file $srcdir/osmo-hlr.cfg
|
osmo-hlr --database $db --db-check --config-file $srcdir/osmo-hlr.cfg
|
||||||
rc = 0
|
rc = 0
|
||||||
DMAIN hlr starting
|
DMAIN hlr starting
|
||||||
DDB using database: <PATH>test.db
|
DDB using database: <PATH>test.db
|
||||||
DDB Database <PATH>test.db' has HLR DB schema version 7
|
DDB Database <PATH>test.db' has HLR DB schema version 8
|
||||||
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
|
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ CREATE TABLE auc_2g (
|
|||||||
);
|
);
|
||||||
INSERT INTO auc_2g VALUES(1,1,'BeefedCafeFaceAcedAddedDecadeFee');
|
INSERT INTO auc_2g VALUES(1,1,'BeefedCafeFaceAcedAddedDecadeFee');
|
||||||
INSERT INTO auc_2g VALUES(4,2,'33333333333333333333333333333333');
|
INSERT INTO auc_2g VALUES(4,2,'33333333333333333333333333333333');
|
||||||
INSERT INTO auc_2g VALUES(6,6,'55555555555555555555555555555555');
|
INSERT INTO auc_2g VALUES(6,4,'55555555555555555555555555555555');
|
||||||
CREATE TABLE auc_3g (
|
CREATE TABLE auc_3g (
|
||||||
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
|
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
|
||||||
algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value
|
algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
AM_CPPFLAGS = \
|
AM_CPPFLAGS = \
|
||||||
$(all_includes) \
|
$(all_includes) \
|
||||||
-I$(top_srcdir)/include \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
AM_CFLAGS = \
|
AM_CFLAGS = \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
$(LIBOSMOCORE_CFLAGS) \
|
$(LIBOSMOCORE_CFLAGS) \
|
||||||
$(LIBOSMOGSM_CFLAGS) \
|
$(LIBOSMOGSM_CFLAGS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
@@ -17,7 +17,7 @@ EXTRA_DIST = \
|
|||||||
gsup_test.err \
|
gsup_test.err \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
check_PROGRAMS = \
|
noinst_PROGRAMS = \
|
||||||
gsup_test \
|
gsup_test \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
ctx = talloc_named_const(NULL, 0, "gsup_test");
|
ctx = talloc_named_const(NULL, 0, "gsup_test");
|
||||||
osmo_init_logging2(ctx, &info);
|
osmo_init_logging2(ctx, &info);
|
||||||
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
|
log_set_print_filename(osmo_stderr_target, 0);
|
||||||
log_set_print_timestamp(osmo_stderr_target, 0);
|
log_set_print_timestamp(osmo_stderr_target, 0);
|
||||||
log_set_use_color(osmo_stderr_target, 0);
|
log_set_use_color(osmo_stderr_target, 0);
|
||||||
log_set_print_category(osmo_stderr_target, 1);
|
log_set_print_category(osmo_stderr_target, 1);
|
||||||
|
|||||||
44
tests/gsup_server/Makefile.am
Normal file
44
tests/gsup_server/Makefile.am
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
AM_CPPFLAGS = \
|
||||||
|
$(all_includes) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
AM_CFLAGS = \
|
||||||
|
-Wall \
|
||||||
|
-ggdb3 \
|
||||||
|
-I$(top_srcdir)/include \
|
||||||
|
$(LIBOSMOCORE_CFLAGS) \
|
||||||
|
$(LIBOSMOGSM_CFLAGS) \
|
||||||
|
$(LIBOSMOABIS_CFLAGS) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
AM_LDFLAGS = \
|
||||||
|
-no-install \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
gsup_server_test.ok \
|
||||||
|
gsup_server_test.err \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
noinst_PROGRAMS = \
|
||||||
|
gsup_server_test \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
gsup_server_test_SOURCES = \
|
||||||
|
gsup_server_test.c \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
gsup_server_test_LDADD = \
|
||||||
|
$(top_srcdir)/src/gsup_server.c \
|
||||||
|
$(top_srcdir)/src/gsup_router.c \
|
||||||
|
$(top_srcdir)/src/gsup_send.c \
|
||||||
|
$(top_srcdir)/src/gsupclient/gsup_peer_id.c \
|
||||||
|
$(top_srcdir)/src/gsupclient/gsup_req.c \
|
||||||
|
$(LIBOSMOCORE_LIBS) \
|
||||||
|
$(LIBOSMOGSM_LIBS) \
|
||||||
|
$(LIBOSMOABIS_LIBS) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
.PHONY: update_exp
|
||||||
|
update_exp:
|
||||||
|
$(builddir)/gsup_server_test >"$(srcdir)/gsup_server_test.ok" 2>"$(srcdir)/gsup_server_test.err"
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user