mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
synced 2025-11-02 13:13:29 +00:00
Compare commits
75 Commits
fixeria/35
...
laforge/cc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5e9ca9045 | ||
|
|
94c38a9e03 | ||
|
|
05e888ed7c | ||
|
|
9eb10efb23 | ||
|
|
63450d990b | ||
|
|
d2d9f35835 | ||
|
|
80b7fe759f | ||
|
|
b984a6c995 | ||
|
|
3896888468 | ||
|
|
e9dd9c6282 | ||
|
|
277b2d642a | ||
|
|
f1949f7b99 | ||
|
|
f302de93dd | ||
|
|
28f0774e34 | ||
|
|
b07f33df41 | ||
|
|
8b860e54be | ||
|
|
9cf0030b6a | ||
|
|
b9b224c7bd | ||
|
|
e49391bfc4 | ||
|
|
fbd736ef37 | ||
|
|
dc30154fdf | ||
|
|
37642177f9 | ||
|
|
6401b90574 | ||
|
|
5b5cac7e94 | ||
|
|
937f583a7e | ||
|
|
4ca7f6a17e | ||
|
|
b64cb27003 | ||
|
|
3b33b01fb0 | ||
|
|
78abea6a0e | ||
|
|
9ac494f486 | ||
|
|
d62d401d07 | ||
|
|
103c11bd24 | ||
|
|
63de00cfc1 | ||
|
|
1a1398ed54 | ||
|
|
a8253a54ba | ||
|
|
29f371fddf | ||
|
|
2e403d6c3f | ||
|
|
c41572330d | ||
|
|
c7f1787c18 | ||
|
|
c13599dc69 | ||
|
|
6b73fd9678 | ||
|
|
cd2af5ead7 | ||
|
|
e21b45aecd | ||
|
|
5857c595b3 | ||
|
|
d9724f4298 | ||
|
|
c69a18bb3d | ||
|
|
8625cdaf2a | ||
|
|
609978d0ab | ||
|
|
28f0af872e | ||
|
|
9f6e558215 | ||
|
|
633fe291f5 | ||
|
|
7d53ae1db8 | ||
|
|
95abc2be17 | ||
|
|
f1fe94c8ca | ||
|
|
f7d3251d9a | ||
|
|
3cf87fe22c | ||
|
|
ee7c0cb8d9 | ||
|
|
c5044cfd80 | ||
|
|
20ddfdbc53 | ||
|
|
227834b6bc | ||
|
|
44a2180009 | ||
|
|
f9cf180ebe | ||
|
|
02078b7d91 | ||
|
|
ef64b231dc | ||
|
|
851814aa7c | ||
|
|
81db389fd4 | ||
|
|
7943e26938 | ||
|
|
e0c6fe5921 | ||
|
|
f58f44543f | ||
|
|
15f624ec53 | ||
|
|
d4e0e4d503 | ||
|
|
2dc7d960a1 | ||
|
|
52c4aa09b2 | ||
|
|
66106c0992 | ||
|
|
783ac81b9c |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,6 +2,8 @@
|
||||
*.lo
|
||||
*.la
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
*.pyc
|
||||
.*.sw?
|
||||
.version
|
||||
@@ -38,6 +40,7 @@ src/gsupclient/gsup-test-client
|
||||
tests/atconfig
|
||||
tests/testsuite
|
||||
tests/testsuite.log
|
||||
tests/testsuite.dir
|
||||
|
||||
tests/auc/auc_3g_test
|
||||
tests/auc/auc_ts_55_205_test_sets.c
|
||||
@@ -46,6 +49,7 @@ tests/auc/auc_test
|
||||
tests/gsup_server/gsup_server_test
|
||||
tests/gsup/gsup_test
|
||||
tests/db/db_test
|
||||
tests/hlr_vty_test.db*
|
||||
|
||||
# manuals
|
||||
doc/manuals/*.html
|
||||
|
||||
25
configure.ac
25
configure.ac
@@ -34,11 +34,11 @@ PKG_PROG_PKG_CONFIG([0.20])
|
||||
|
||||
PKG_CHECK_MODULES(TALLOC, [talloc >= 2.0.1])
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 0.11.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.5.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.2.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.2.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.2.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.2.0)
|
||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0)
|
||||
|
||||
PKG_CHECK_MODULES(SQLITE3, sqlite3)
|
||||
|
||||
@@ -59,6 +59,21 @@ then
|
||||
CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([sqlite_talloc],
|
||||
AC_HELP_STRING([--enable-sqlite-talloc],
|
||||
[Configure SQLite3 to use talloc memory allocator [default=no]]),
|
||||
[sqlite_talloc="$enableval"],[sqlite_talloc="no"])
|
||||
if test "x$sqlite_talloc" = "xyes" ; then
|
||||
# Older versions of SQLite3 (at least 3.8.2) become unstable with talloc.
|
||||
# Feel free to relax to 3.24.0 > VER > 3.8.2 if it works for you.
|
||||
# FIXME: PKG_CHECK_MODULES() may return cached result here!
|
||||
PKG_CHECK_MODULES(SQLITE3, sqlite3 >= 3.24.0)
|
||||
AC_DEFINE([SQLITE_USE_TALLOC], 1, [Use talloc for SQLite3])
|
||||
fi
|
||||
AC_MSG_CHECKING([whether to use talloc for SQLite3])
|
||||
AC_MSG_RESULT([$sqlite_talloc])
|
||||
AM_CONDITIONAL([DB_SQLITE_DEBUG], [test "x$sqlite_talloc" = "xyes"])
|
||||
|
||||
AC_ARG_ENABLE(werror,
|
||||
[AS_HELP_STRING(
|
||||
[--enable-werror],
|
||||
|
||||
@@ -58,4 +58,5 @@ if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
|
||||
make -C "$base/doc/manuals" publish
|
||||
fi
|
||||
|
||||
$MAKE maintainer-clean
|
||||
osmo-clean-workspace.sh
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
[Unit]
|
||||
Description=Osmocom Home Location Register (OsmoHLR)
|
||||
Documentation=https://osmocom.org/projects/osmo-hlr/wiki/OsmoHLR
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/osmo-hlr -c /etc/osmocom/osmo-hlr.cfg -l /var/lib/osmocom/hlr.db
|
||||
ExecStart=/usr/bin/osmo-hlr -U -c /etc/osmocom/osmo-hlr.cfg -l /var/lib/osmocom/hlr.db
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
|
||||
138
debian/changelog
vendored
138
debian/changelog
vendored
@@ -1,3 +1,141 @@
|
||||
osmo-hlr (1.1.0) unstable; urgency=medium
|
||||
|
||||
[ Oliver Smith ]
|
||||
* docs: running: document --db-upgrade
|
||||
* Add IMEI column to subscriber table
|
||||
* Optionally store IMEI in subscriber table
|
||||
* VTY tests: fill DB before running test
|
||||
* VTY: integrate IMEI
|
||||
* hlr.c: replace deprecated osmo_gsup_get_err_msg_type()
|
||||
* hlr.c: move hlr_ctx to the top
|
||||
* tests: use -no-install libtool flag to avoid ./lt-* scripts
|
||||
* Cosmetic: gsup_route_find: comment addr, addrlen
|
||||
* USSD: save MO USSD's originating MSC's vlr_number
|
||||
* USSD: don't use gsm0480_msgb_alloc_name()
|
||||
* hlr.c: forward GSUP messages between clients
|
||||
* db_hlr.c: db_subscr_create(): add flags argument
|
||||
* db_hlr.c: add db_subscr_exists_by_imsi()
|
||||
* Create subscribers on demand
|
||||
* Document subscribers create on demand feature
|
||||
* debian: create -doc subpackage with pdf manuals
|
||||
* db_test: set timezone to work around mktime bug
|
||||
* db_hlr: zero-initialize "struct tm"
|
||||
* rx_check_imei_req(): fix IMEI bounds checking
|
||||
* contrib/jenkins.sh: run "make maintainer-clean"
|
||||
* VTY: add subscriber update network-access-mode
|
||||
* manuals: improve subscribers create on demand
|
||||
* gitignore: ignore everything generated in db_test
|
||||
* db_auc.c: verify hex key sizes read from DB
|
||||
|
||||
[ Max ]
|
||||
* Log ip:port when adding GSUP routes
|
||||
* Add link to project wiki to .service file
|
||||
* Enable statsd support
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* hlr.c: properly terminate the process on SIGTERM
|
||||
* hlr.c: fix: also store the session state in read_cb_forward()
|
||||
* hlr.c: fix: properly print the original message type in read_cb_forward()
|
||||
* hlr.c: check the presence of msgb->l2h in read_cb()
|
||||
* hlr.c: fix possible msgb memleaks in read_cb()
|
||||
* db_hlr.c: add db_subscr_exists_by_msisdn()
|
||||
* src/db.h: use GSM23003_MSISDN_MAX_DIGITS for MSISDN buffer size
|
||||
* src/hlr.c: fix deprecation warning: use gsm48_decode_bcd_number2()
|
||||
* hlr_ussd.c: fix: properly pass invokeID in handle_ussd_own_msisdn()
|
||||
* hlr_ussd.c: rx_proc_ss_req(): fix NULL pointer dereference
|
||||
* build: fix mess with 'db_test_SOURCES' and 'db_test_LDADD'
|
||||
* tests/db_test: close the database when test is finished
|
||||
* src/db.c: integrate SQLite3 with talloc allocator
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* USSD: fix routing to multiple MSC
|
||||
* fix error logging for GSUP route
|
||||
* add missing error log: invalid IMSI
|
||||
* osmo-hlr: allow configuring db path from cfg file
|
||||
* use new OSMO_IMSI_BUF_SIZE
|
||||
|
||||
[ Daniel Willmann ]
|
||||
* manuals: Add script to update vty/counter documentation from docker
|
||||
* manuals: Update vty documentation
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* Remove undefined param passed to logging_vty_add_cmds
|
||||
* configure.ac: Require libosmocore 1.2.0
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 07 Aug 2019 16:14:23 +0200
|
||||
|
||||
osmo-hlr (1.0.0) unstable; urgency=medium
|
||||
|
||||
[ Stefan Sperling ]
|
||||
* move creation of insert subscriber data messages to a common function
|
||||
|
||||
[ Harald Welte ]
|
||||
* Return proper GSUP error in case of too short IMSI
|
||||
* disable blind subscriber insertion into every VLR/SGSN
|
||||
* gsup_server: Add "priv" pointer and make it point to 'struct hlr'
|
||||
* move osmo_gsup_addr_send() declaration from luop.h to gsup_router.h
|
||||
* gsup_router: Use "#pragma once" and add missing #includes
|
||||
* Add "show gsup-connections" VTY command
|
||||
* import gsup_client.c as new libosmo-gsup-client
|
||||
* gsup_client: rename gsup_client_* to osmo_gsup_client_*
|
||||
* GSUP: Log GSUP route add/remove
|
||||
* hlr: Export + Declare global g_hlr symbol
|
||||
* USSD: Add Core USSD handling + VTY routing config to HLR
|
||||
* USSD: Add basic dispatch + decode of GSUP-encapsulated SS/USSD
|
||||
* hlr_ussd: Introduce LOGPSS() macro
|
||||
* USSD: Send ReturnError component if USSD Code unknown / EUSE disconnected
|
||||
* USSD: Further unification of log output; Use LOGPSS when possible
|
||||
* osmo-hlr.cfg: Don't enable DEBUG logging by default
|
||||
* USSD: Add new "DSS" logging category and use it appropriately
|
||||
* USSD: fix null-pointer deref in "default-route" vty/config cmd
|
||||
* Add osmo-euse-demo as minimalistic test of a External USSD (EUSE) handler
|
||||
* USSD: Add support for internal USSD handlers
|
||||
* debian: Add sub-package for libosmo-gsup-client
|
||||
* pkg-config: Fix libosmo-gsup-client pkg-config file
|
||||
* gitignore: Add .tarball-version
|
||||
* debian: Make libosmo-gsup-client-dev depend on libosmo-gsup-client0
|
||||
* USSD: Fix "ussd default-route"
|
||||
* libosmo-gsup-client: License is GPLv2-or-later
|
||||
* osmo-hlr.cfg: Ensure well-formed config file example
|
||||
* test_nodes.vty: Since libosmocore 1.0.0, we only have one space
|
||||
|
||||
[ Martin Hauke ]
|
||||
* sql/Makefile.am: Make docsdir completely configurable
|
||||
* debian: Fix typo in package description
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* debian: Avoid installing duplicate cfg file in /etc
|
||||
* sql/Makefile: Install hlr_data.sql as example together with hlr.sql
|
||||
* sql/Makefile: Install sql files under doc/.../sql subdir
|
||||
* sql/Makefile: Create empty /var/lib/osmocom directory at install time
|
||||
* Install systemd services with autotools
|
||||
* Move doc/Makefile.am to doc/examples/Makefile.am
|
||||
* Install sample cfg file to /etc/osmocom
|
||||
|
||||
[ Vadim Yanitskiy ]
|
||||
* hlr.c: move deinitialization code from SIGINT handler
|
||||
* hlr.c: free root talloc context on exit
|
||||
* hlr.c: track the use of talloc NULL memory contexts
|
||||
* src/db.c: fix: make sure the database is properly closed
|
||||
* src/db.c: don't ignore the result of db_bootstrap()
|
||||
* hlr_vty_subscr.c: fix subscriber creation command help
|
||||
* Update .gitignore: add missing build products
|
||||
* tests/Makefile.am: also remove temporary sqlite files
|
||||
* hlr_ussd.h: add #pragma once include guard
|
||||
* hlr_ussd.h: use proper libc headers
|
||||
* Update .gitignore: ignore osmo-euse-demo
|
||||
* hlr_ussd.h: drop meaningless forward declaration
|
||||
* USSD/hlr_vty.c: print error if EUSE is not found
|
||||
* hlr_ussd.c: fix: properly print a EUSE / IUSE name
|
||||
* hlr_ussd.c: avoid using CR and NL in IUSE responses
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* fix build: adjust test_nodes.vty to logging change
|
||||
* tweak example config
|
||||
* make: always allow running python tests manually
|
||||
|
||||
-- Harald Welte <laforge@gnumonks.org> Sun, 20 Jan 2019 19:29:58 +0100
|
||||
|
||||
osmo-hlr (0.2.1) unstable; urgency=medium
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
|
||||
12
debian/control
vendored
12
debian/control
vendored
@@ -12,7 +12,8 @@ Build-Depends: debhelper (>= 9),
|
||||
libosmo-abis-dev,
|
||||
libosmo-netif-dev,
|
||||
libsqlite3-dev,
|
||||
sqlite3
|
||||
sqlite3,
|
||||
osmo-gsm-manuals-dev
|
||||
Standards-Version: 3.9.6
|
||||
Vcs-Browser: http://cgit.osmocom.org/osmo-hlr
|
||||
Vcs-Git: git://git.osmocom.org/osmo-hlr
|
||||
@@ -57,3 +58,12 @@ Description: Development headers of Osmocom GSUP client library
|
||||
and External USSD Entities (EUSEs) using this library to implement clients.
|
||||
.
|
||||
This package contains the development headers.
|
||||
|
||||
Package: osmo-hlr-doc
|
||||
Architecture: all
|
||||
Section: doc
|
||||
Priority: optional
|
||||
Depends: ${misc:Depends}
|
||||
Description: ${misc:Package} PDF documentation
|
||||
Various manuals: user manual, VTY reference manual and/or
|
||||
protocol/interface manuals.
|
||||
|
||||
1
debian/osmo-hlr-doc.install
vendored
Normal file
1
debian/osmo-hlr-doc.install
vendored
Normal file
@@ -0,0 +1 @@
|
||||
usr/share/doc/osmo-hlr-doc/*.pdf
|
||||
6
debian/rules
vendored
6
debian/rules
vendored
@@ -17,4 +17,8 @@ override_dh_auto_test:
|
||||
dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system
|
||||
dh_auto_configure -- --with-systemdsystemunitdir=/lib/systemd/system --enable-manuals
|
||||
|
||||
# Don't create .pdf.gz files (barely saves space and they can't be opened directly by most pdf readers)
|
||||
override_dh_compress:
|
||||
dh_compress -X.pdf
|
||||
|
||||
@@ -24,3 +24,8 @@ hlr
|
||||
bind ip 127.0.0.1
|
||||
ussd route prefix *#100# internal own-msisdn
|
||||
ussd route prefix *#101# internal own-imsi
|
||||
ussd route prefix *#102# internal get-ran
|
||||
ussd route prefix *#200# internal gsm-off
|
||||
ussd route prefix *#201# internal gsm-on
|
||||
ussd route prefix *#300# internal umts-off
|
||||
ussd route prefix *#301# internal umts-on
|
||||
|
||||
@@ -4,6 +4,7 @@ EXTRA_DIST = example_subscriber_add_update_delete.vty \
|
||||
osmohlr-usermanual.adoc \
|
||||
osmohlr-usermanual-docinfo.xml \
|
||||
osmohlr-vty-reference.xml \
|
||||
regen_doc.sh \
|
||||
chapters \
|
||||
vty
|
||||
|
||||
@@ -15,6 +16,7 @@ if BUILD_MANUALS
|
||||
VTY_REFERENCE = osmohlr-vty-reference.xml
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
||||
|
||||
OSMO_REPOSITORY = osmo-hlr
|
||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.common.inc
|
||||
endif
|
||||
|
||||
|
||||
@@ -5,24 +5,27 @@ arguments:
|
||||
|
||||
=== SYNOPSIS
|
||||
|
||||
*osmo-hlr* [-h|-V] [-d 'DBGMASK'] [-D] [-c 'CONFIGFILE'] [-s] [-T] [-e 'LOGLEVEL'] [-l 'DATABASE']
|
||||
*osmo-hlr* [-h] [-c 'CONFIGFILE'] [-l 'DATABASE'] [-d 'DBGMASK'] [-D] [-s] [-T] [-e 'LOGLEVEL'] [-U] [-V]
|
||||
|
||||
=== OPTIONS
|
||||
|
||||
// Keep the order the same as in osmo-hlr --help!
|
||||
|
||||
*-h, --help*::
|
||||
Print a short help message about the supported options
|
||||
*-V, --version*::
|
||||
Print the compile-time version number of the OsmoBTS program
|
||||
*-c, --config-file 'CONFIGFILE'*::
|
||||
Specify the file and path name of the configuration file to be
|
||||
used. If none is specified, use `osmo-hlr.cfg` in the current
|
||||
working directory.
|
||||
*-l, --database 'DATABASE'*::
|
||||
Specify the file name of the SQLite3 database to use as HLR/AUC
|
||||
storage
|
||||
*-d, --debug 'DBGMASK','DBGLEVELS'*::
|
||||
Set the log subsystems and levels for logging to stderr. This
|
||||
has mostly been superseded by VTY-based logging configuration,
|
||||
see <<logging>> for further information.
|
||||
*-D, --daemonize*::
|
||||
Fork the process as a daemon into background.
|
||||
*-c, --config-file 'CONFIGFILE'*::
|
||||
Specify the file and path name of the configuration file to be
|
||||
used. If none is specified, use `osmo-hlr.cfg` in the current
|
||||
working directory.
|
||||
*-s, --disable-color*::
|
||||
Disable colors for logging to stderr. This has mostly been
|
||||
deprecated by VTY based logging configuration, see <<logging>>
|
||||
@@ -35,9 +38,13 @@ arguments:
|
||||
Set the global log level for logging to stderr. This has mostly
|
||||
been deprecated by VTY based logging configuration, see
|
||||
<<logging>> for more information.
|
||||
*-l, --database 'DATABASE'*::
|
||||
Specify the file name of the SQLite3 database to use as HLR/AUC
|
||||
storage
|
||||
*-U, --db-upgrade*::
|
||||
Allow HLR database schema upgrades. If OsmoHLR was updated and
|
||||
requires a newer database schema, it will refuse to start unless
|
||||
this option is specified. The updated database can not be
|
||||
downgraded, make backups as necessary.
|
||||
*-V, --version*::
|
||||
Print the compile-time version number of the OsmoHLR program
|
||||
|
||||
=== Bootstrap the Database
|
||||
|
||||
|
||||
@@ -67,3 +67,63 @@ transceiving only RAND and SRES, may be applicable. (See 3GPP TS 33.102, chapter
|
||||
|ms_purged_ps|1|3GPP TS 23.008 chapter 2.7.6
|
||||
|===
|
||||
|
||||
=== Configuring the Subscribers Create on Demand Feature
|
||||
|
||||
Usually a HLR will only allow mobile equipment (ME) on the network, if the HLR
|
||||
has a subscriber entry with the ME's IMSI. But OsmoHLR can also be configured to
|
||||
automatically create new entries for new IMSIs, with the
|
||||
`subscriber-create-on-demand` VTY option. The obvious use case is creating the
|
||||
new subscriber entry and then allowing the ME to use both the CS
|
||||
(Circuit Switched) and PS (Packet Switched) NAM (Network Access Mode).
|
||||
|
||||
.osmo-hlr.cfg
|
||||
----
|
||||
hlr
|
||||
subscriber-create-on-demand 5 cs+ps
|
||||
----
|
||||
|
||||
On the other hand, operators might only want to give network access to IMSIs, of
|
||||
which they know the owner. In order to do that, one can set the default NAM to
|
||||
`none` and manually approve new subscribers by changing the NAM (e.g. over the
|
||||
VTY, see the example below).
|
||||
|
||||
Oftentimes it is hard to know, which IMSI belongs to which ME, but the IMEI is
|
||||
readily available. If you configure your MSC to send IMEI checking requests to
|
||||
the HLR, before sending location update requests, the subscribers created on
|
||||
demand can also have the IMEI stored in the HLR database. With OsmoMSC, this
|
||||
is done by writing `check-imei-rqd early` in the `msc` section of osmo-msc.cfg.
|
||||
Then enable storing the IMEI when receiving check IMEI requests with
|
||||
`store-imei` in the OsmoHLR configuration.
|
||||
|
||||
.osmo-msc.cfg
|
||||
----
|
||||
msc
|
||||
check-imei-rqd early
|
||||
----
|
||||
|
||||
.osmo-hlr.cfg
|
||||
----
|
||||
hlr
|
||||
subscriber-create-on-demand 5 none
|
||||
store-imei
|
||||
----
|
||||
|
||||
.Example: Enabling CS and PS NAM via VTY for a known IMEI
|
||||
----
|
||||
OsmoHLR> enable
|
||||
OsmoHLR# subscriber imei 35761300444848 show
|
||||
ID: 1
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 58192 <1>
|
||||
IMEI: 35761300444848
|
||||
CS disabled <2>
|
||||
PS disabled <2>
|
||||
OsmoHLR# subscriber imei 35761300444848 update network-access-mode cs+ps
|
||||
OsmoHLR# subscriber imei 35761300444848 show
|
||||
ID: 1
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 58192
|
||||
IMEI: 35761300444848
|
||||
----
|
||||
<1> Randomly generated 5 digit MSISDN
|
||||
<2> Disabled CS and PS NAM prevent the subscriber from accessing the network
|
||||
|
||||
17
doc/manuals/regen_doc.sh
Executable file
17
doc/manuals/regen_doc.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
if [ -z "$DOCKER_PLAYGROUND" ]; then
|
||||
echo "You need to set DOCKER_PLAYGROUND"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT=$(realpath "$0")
|
||||
MANUAL_DIR=$(dirname "$SCRIPT")
|
||||
|
||||
COMMIT=${COMMIT:-$(git log -1 --format=format:%H)}
|
||||
|
||||
cd "$DOCKER_PLAYGROUND/scripts" || exit 1
|
||||
|
||||
OSMO_HLR_BRANCH=$COMMIT ./regen_doc.sh osmo-hlr 4258 \
|
||||
"$MANUAL_DIR/chapters/counters_generated.adoc" \
|
||||
"$MANUAL_DIR/vty/hlr_vty_reference.xml"
|
||||
@@ -187,7 +187,7 @@
|
||||
<param name='MASK' doc='List of logging categories to log, e.g. 'abc:mno:xyz'. Available log categories depend on the specific application, refer to the 'logging level' command. Optionally add individual log levels like 'abc,1:mno,3:xyz,5', where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='logging level (main|db|auc|ss|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf) (debug|info|notice|error|fatal)'>
|
||||
<command id='logging level (main|db|auc|ss|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
|
||||
<params>
|
||||
<param name='logging' doc='Configure logging' />
|
||||
<param name='level' doc='Set the log level for a specified category' />
|
||||
@@ -213,6 +213,7 @@
|
||||
<param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
|
||||
<param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
|
||||
<param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
|
||||
<param name='lrspro' doc='Remote SIM protocol' />
|
||||
<param name='debug' doc='Log debug messages and higher levels' />
|
||||
<param name='info' doc='Log informational messages and higher levels' />
|
||||
<param name='notice' doc='Log noticeable messages and higher levels' />
|
||||
@@ -302,22 +303,63 @@
|
||||
<param name='REGEXP' doc='Regular expression' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show stats'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='stats' doc='Show statistical values' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show stats level (global|peer|subscriber)'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='stats' doc='Show statistical values' />
|
||||
<param name='level' doc='Set the maximum group level' />
|
||||
<param name='global' doc='Show global groups only' />
|
||||
<param name='peer' doc='Show global and network peer related groups' />
|
||||
<param name='subscriber' doc='Show global, peer, and subscriber groups' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show asciidoc counters'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='asciidoc' doc='Asciidoc generation' />
|
||||
<param name='counters' doc='Generate table of all registered counters' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show rate-counters'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='rate-counters' doc='Show all rate counters' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show gsup-connections'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='gsup-connections' doc='GSUP Connections from VLRs, SGSNs, EUSEs' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber (imsi|msisdn|id) IDENT show'>
|
||||
<command id='subscriber (imsi|msisdn|id|imei) IDENT show'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID of the subscriber' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
<param name='show' doc='Show subscriber information' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show subscriber (imsi|msisdn|id|imei) IDENT'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
</params>
|
||||
</command>
|
||||
</node>
|
||||
<node id='enable'>
|
||||
<name>enable</name>
|
||||
@@ -486,7 +528,7 @@
|
||||
<param name='MASK' doc='List of logging categories to log, e.g. 'abc:mno:xyz'. Available log categories depend on the specific application, refer to the 'logging level' command. Optionally add individual log levels like 'abc,1:mno,3:xyz,5', where the level numbers are LOGL_DEBUG=1 LOGL_INFO=3 LOGL_NOTICE=5 LOGL_ERROR=7 LOGL_FATAL=8' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='logging level (main|db|auc|ss|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf) (debug|info|notice|error|fatal)'>
|
||||
<command id='logging level (main|db|auc|ss|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
|
||||
<params>
|
||||
<param name='logging' doc='Configure logging' />
|
||||
<param name='level' doc='Set the log level for a specified category' />
|
||||
@@ -512,6 +554,7 @@
|
||||
<param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
|
||||
<param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
|
||||
<param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
|
||||
<param name='lrspro' doc='Remote SIM protocol' />
|
||||
<param name='debug' doc='Log debug messages and higher levels' />
|
||||
<param name='info' doc='Log informational messages and higher levels' />
|
||||
<param name='notice' doc='Log noticeable messages and higher levels' />
|
||||
@@ -521,8 +564,7 @@
|
||||
</command>
|
||||
<command id='logging level set-all (debug|info|notice|error|fatal)'>
|
||||
<params>
|
||||
<param name='logging' doc='Configure logging' />
|
||||
<param name='level' doc='Set the log level for a specified category' />
|
||||
<param name='logging' doc='Configure logging' /> <param name='level' doc='Set the log level for a specified category' />
|
||||
<param name='set-all' doc='Once-off set all categories to the given log level. There is no single command to take back these changes -- each category is set to the given level, period.' />
|
||||
<param name='debug' doc='Log debug messages and higher levels' />
|
||||
<param name='info' doc='Log informational messages and higher levels' />
|
||||
@@ -601,22 +643,63 @@
|
||||
<param name='REGEXP' doc='Regular expression' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show stats'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='stats' doc='Show statistical values' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show stats level (global|peer|subscriber)'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='stats' doc='Show statistical values' />
|
||||
<param name='level' doc='Set the maximum group level' />
|
||||
<param name='global' doc='Show global groups only' />
|
||||
<param name='peer' doc='Show global and network peer related groups' />
|
||||
<param name='subscriber' doc='Show global, peer, and subscriber groups' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show asciidoc counters'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='asciidoc' doc='Asciidoc generation' />
|
||||
<param name='counters' doc='Generate table of all registered counters' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show rate-counters'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='rate-counters' doc='Show all rate counters' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show gsup-connections'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='gsup-connections' doc='GSUP Connections from VLRs, SGSNs, EUSEs' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber (imsi|msisdn|id) IDENT show'>
|
||||
<command id='subscriber (imsi|msisdn|id|imei) IDENT show'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID of the subscriber' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
<param name='show' doc='Show subscriber information' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='show subscriber (imsi|msisdn|id|imei) IDENT'>
|
||||
<params>
|
||||
<param name='show' doc='Show running system information' />
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber imsi IDENT create'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
@@ -625,47 +708,52 @@
|
||||
<param name='create' doc='Create subscriber by IMSI' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber (imsi|msisdn|id) IDENT delete'>
|
||||
<command id='subscriber (imsi|msisdn|id|imei) IDENT delete'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID of the subscriber' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
<param name='delete' doc='Delete subscriber from database' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber (imsi|msisdn|id) IDENT update msisdn MSISDN'>
|
||||
<command id='subscriber (imsi|msisdn|id|imei) IDENT update msisdn (none|MSISDN)'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID of the subscriber' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
<param name='update' doc='Set or update subscriber data' />
|
||||
<param name='msisdn' doc='Set MSISDN (phone number) of the subscriber' />
|
||||
<param name='none' doc='Remove MSISDN (phone number)' />
|
||||
<param name='MSISDN' doc='New MSISDN (phone number)' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber (imsi|msisdn|id) IDENT update aud2g none'>
|
||||
<command id='subscriber (imsi|msisdn|id|imei) IDENT update aud2g none'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID of the subscriber' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
<param name='update' doc='Set or update subscriber data' />
|
||||
<param name='aud2g' doc='Set 2G authentication data' />
|
||||
<param name='none' doc='Delete 2G authentication data' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber (imsi|msisdn|id) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor) ki KI'>
|
||||
<command id='subscriber (imsi|msisdn|id|imei) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor) ki KI'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID of the subscriber' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
<param name='update' doc='Set or update subscriber data' />
|
||||
<param name='aud2g' doc='Set 2G authentication data' />
|
||||
<param name='comp128v1' doc='Use COMP128v1 algorithm' />
|
||||
@@ -676,25 +764,27 @@
|
||||
<param name='KI' doc='Ki as 32 hexadecimal characters' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber (imsi|msisdn|id) IDENT update aud3g none'>
|
||||
<command id='subscriber (imsi|msisdn|id|imei) IDENT update aud3g none'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID of the subscriber' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
<param name='update' doc='Set or update subscriber data' />
|
||||
<param name='aud3g' doc='Set UMTS authentication data (3G, and 2G with UMTS AKA)' />
|
||||
<param name='none' doc='Delete 3G authentication data' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber (imsi|msisdn|id) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>]'>
|
||||
<command id='subscriber (imsi|msisdn|id|imei) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>]'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID of the subscriber' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
<param name='update' doc='Set or update subscriber data' />
|
||||
<param name='aud3g' doc='Set UMTS authentication data (3G, and 2G with UMTS AKA)' />
|
||||
<param name='milenage' doc='Use Milenage algorithm' />
|
||||
@@ -707,6 +797,36 @@
|
||||
<param name='[<0-28>]' doc='IND bit length value (default: 5)' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber (imsi|msisdn|id|imei) IDENT update imei (none|IMEI)'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
<param name='update' doc='Set or update subscriber data' />
|
||||
<param name='imei' doc='Set IMEI of the subscriber (normally populated from MSC, no need to set this manually)' />
|
||||
<param name='none' doc='Forget IMEI' />
|
||||
<param name='IMEI' doc='Set IMEI (use for debug only!)' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber (imsi|msisdn|id|imei) IDENT update network-access-mode (none|cs|ps|cs+ps)'>
|
||||
<params>
|
||||
<param name='subscriber' doc='Subscriber management commands' />
|
||||
<param name='imsi' doc='Identify subscriber by IMSI' />
|
||||
<param name='msisdn' doc='Identify subscriber by MSISDN (phone number)' />
|
||||
<param name='id' doc='Identify subscriber by database ID' />
|
||||
<param name='imei' doc='Identify subscriber by IMEI' />
|
||||
<param name='IDENT' doc='IMSI/MSISDN/ID/IMEI of the subscriber' />
|
||||
<param name='update' doc='Set or update subscriber data' />
|
||||
<param name='network-access-mode' doc='Set Network Access Mode (NAM) of the subscriber' />
|
||||
<param name='none' doc='Do not allow access to circuit switched or packet switched services' />
|
||||
<param name='cs' doc='Allow access to circuit switched services only' />
|
||||
<param name='ps' doc='Allow access to packet switched services only' />
|
||||
<param name='cs+ps' doc='Allow access to both circuit and packet switched services' />
|
||||
</params>
|
||||
</command>
|
||||
</node>
|
||||
<node id='config'>
|
||||
<name>config</name>
|
||||
@@ -883,7 +1003,8 @@
|
||||
<param name='user' doc='Generic facility' />
|
||||
<param name='uucp' doc='UUCP facility' />
|
||||
</params>
|
||||
</command> <command id='log syslog local <0-7>'>
|
||||
</command>
|
||||
<command id='log syslog local <0-7>'>
|
||||
<params>
|
||||
<param name='log' doc='Configure logging sub-system' />
|
||||
<param name='syslog' doc='Logging via syslog' />
|
||||
@@ -905,6 +1026,43 @@
|
||||
<param name='[HOSTNAME]' doc='Host name to send the GSMTAP logging to (UDP port 4729)' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='stats reporter statsd'>
|
||||
<params>
|
||||
<param name='stats' doc='Configure stats sub-system' />
|
||||
<param name='reporter' doc='Configure a stats reporter' />
|
||||
<param name='statsd' doc='Report to a STATSD server' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='no stats reporter statsd'>
|
||||
<params>
|
||||
<param name='no' doc='Negate a command or set its defaults' />
|
||||
<param name='stats' doc='Configure stats sub-system' />
|
||||
<param name='reporter' doc='Configure a stats reporter' />
|
||||
<param name='statsd' doc='Report to a STATSD server' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='stats reporter log'>
|
||||
<params>
|
||||
<param name='stats' doc='Configure stats sub-system' />
|
||||
<param name='reporter' doc='Configure a stats reporter' />
|
||||
<param name='log' doc='Report to the logger' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='no stats reporter log'>
|
||||
<params>
|
||||
<param name='no' doc='Negate a command or set its defaults' />
|
||||
<param name='stats' doc='Configure stats sub-system' />
|
||||
<param name='reporter' doc='Configure a stats reporter' />
|
||||
<param name='log' doc='Report to the logger' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='stats interval <1-65535>'>
|
||||
<params>
|
||||
<param name='stats' doc='Configure stats sub-system' />
|
||||
<param name='interval' doc='Set the reporting interval' />
|
||||
<param name='<1-65535>' doc='Interval in seconds' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='hlr'>
|
||||
<params>
|
||||
<param name='hlr' doc='Configure the HLR' />
|
||||
@@ -985,7 +1143,7 @@
|
||||
<param name='[last]' doc='Log source file info at the end of a log line. If omitted, log source file info just before the log text.' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='logging level (main|db|auc|ss|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf) (debug|info|notice|error|fatal)'>
|
||||
<command id='logging level (main|db|auc|ss|lglobal|llapd|linp|lmux|lmi|lmib|lsms|lctrl|lgtp|lstats|lgsup|loap|lss7|lsccp|lsua|lm3ua|lmgcp|ljibuf|lrspro) (debug|info|notice|error|fatal)'>
|
||||
<params>
|
||||
<param name='logging' doc='Configure logging' />
|
||||
<param name='level' doc='Set the log level for a specified category' />
|
||||
@@ -1011,6 +1169,7 @@
|
||||
<param name='lm3ua' doc='libosmo-sigtran MTP3 User Adaptation' />
|
||||
<param name='lmgcp' doc='libosmo-mgcp Media Gateway Control Protocol' />
|
||||
<param name='ljibuf' doc='libosmo-netif Jitter Buffer' />
|
||||
<param name='lrspro' doc='Remote SIM protocol' />
|
||||
<param name='debug' doc='Log debug messages and higher levels' />
|
||||
<param name='info' doc='Log informational messages and higher levels' />
|
||||
<param name='notice' doc='Log noticeable messages and higher levels' />
|
||||
@@ -1051,6 +1210,75 @@
|
||||
</params>
|
||||
</command>
|
||||
</node>
|
||||
<node id='config-stats'>
|
||||
<name>config-stats</name>
|
||||
<command id='local-ip ADDR'>
|
||||
<params>
|
||||
<param name='local-ip' doc='Set the IP address to which we bind locally' />
|
||||
<param name='ADDR' doc='IP Address' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='no local-ip'>
|
||||
<params>
|
||||
<param name='no' doc='Negate a command or set its defaults' />
|
||||
<param name='local-ip' doc='Set the IP address to which we bind locally' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='remote-ip ADDR'>
|
||||
<params>
|
||||
<param name='remote-ip' doc='Set the remote IP address to which we connect' />
|
||||
<param name='ADDR' doc='IP Address' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='remote-port <1-65535>'>
|
||||
<params>
|
||||
<param name='remote-port' doc='Set the remote port to which we connect' />
|
||||
<param name='<1-65535>' doc='Remote port number' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='mtu <100-65535>'>
|
||||
<params>
|
||||
<param name='mtu' doc='Set the maximum packet size' />
|
||||
<param name='<100-65535>' doc='Size in byte' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='no mtu'>
|
||||
<params>
|
||||
<param name='no' doc='Negate a command or set its defaults' />
|
||||
<param name='mtu' doc='Set the maximum packet size' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='prefix PREFIX'>
|
||||
<params>
|
||||
<param name='prefix' doc='Set the item name prefix' />
|
||||
<param name='PREFIX' doc='The prefix string' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='no prefix'>
|
||||
<params>
|
||||
<param name='no' doc='Negate a command or set its defaults' />
|
||||
<param name='prefix' doc='Set the item name prefix' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='level (global|peer|subscriber)'>
|
||||
<params>
|
||||
<param name='level' doc='Set the maximum group level' />
|
||||
<param name='global' doc='Report global groups only' />
|
||||
<param name='peer' doc='Report global and network peer related groups' />
|
||||
<param name='subscriber' doc='Report global, peer, and subscriber groups' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='enable'>
|
||||
<params>
|
||||
<param name='enable' doc='Enable the reporter' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='disable'>
|
||||
<params>
|
||||
<param name='disable' doc='Disable the reporter' />
|
||||
</params>
|
||||
</command>
|
||||
</node>
|
||||
<node id='config-line'>
|
||||
<name>config-line</name>
|
||||
<command id='login'>
|
||||
@@ -1064,10 +1292,11 @@
|
||||
<param name='login' doc='Enable password checking' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='bind A.B.C.D'>
|
||||
<command id='bind A.B.C.D [<0-65535>]'>
|
||||
<params>
|
||||
<param name='bind' doc='Accept VTY telnet connections on local interface' />
|
||||
<param name='A.B.C.D' doc='Local interface IP address (default: 127.0.0.1)' />
|
||||
<param name='[<0-65535>]' doc='Local TCP port number' />
|
||||
</params>
|
||||
</command>
|
||||
</node>
|
||||
@@ -1087,6 +1316,12 @@
|
||||
<param name='gsup' doc='Configure GSUP options' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='database PATH'>
|
||||
<params>
|
||||
<param name='database' doc='Set the path to the HLR database file' />
|
||||
<param name='PATH' doc='Relative or absolute file system path to the database file (default is 'hlr.db')' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='euse NAME'>
|
||||
<params>
|
||||
<param name='euse' doc='Configure a particular External USSD Entity' />
|
||||
@@ -1145,6 +1380,40 @@
|
||||
<param name='default-route' doc='Remove the default-route for all USSD to unknown destinations' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='ncss-guard-timeout <0-255>'>
|
||||
<params>
|
||||
<param name='ncss-guard-timeout' doc='Set guard timer for NCSS (call independent SS) session activity' />
|
||||
<param name='<0-255>' doc='Guard timer value (sec.), or 0 to disable' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='store-imei'>
|
||||
<params>
|
||||
<param name='store-imei' doc='Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='no store-imei'>
|
||||
<params>
|
||||
<param name='no' doc='Do not save the IMEI in the database, when receiving Check IMEI requests.' />
|
||||
<param name='store-imei' doc='(null)' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)'>
|
||||
<params>
|
||||
<param name='subscriber-create-on-demand' doc='Make a new record when a subscriber is first seen.' />
|
||||
<param name='no-msisdn' doc='Do not automatically assign MSISDN.' />
|
||||
<param name='<3-15>' doc='Length of an automatically assigned MSISDN.' />
|
||||
<param name='none' doc='Do not allow any NAM (Network Access Mode) by default.' />
|
||||
<param name='cs' doc='Allow access to circuit switched NAM by default.' />
|
||||
<param name='ps' doc='Allow access to packet switched NAM by default.' />
|
||||
<param name='cs+ps' doc='Allow access to circuit and packet switched NAM by default.' />
|
||||
</params>
|
||||
</command>
|
||||
<command id='no subscriber-create-on-demand'>
|
||||
<params>
|
||||
<param name='no' doc='Do not make a new record when a subscriber is first seen.' />
|
||||
<param name='subscriber-create-on-demand' doc='(null)' />
|
||||
</params>
|
||||
</command>
|
||||
</node>
|
||||
<node id='config-hlr-gsup'>
|
||||
<name>config-hlr-gsup</name>
|
||||
|
||||
22
sql/hlr.sql
22
sql/hlr.sql
@@ -5,8 +5,10 @@ CREATE TABLE subscriber (
|
||||
imsi VARCHAR(15) UNIQUE NOT NULL,
|
||||
-- Chapter 2.1.2
|
||||
msisdn VARCHAR(15) UNIQUE,
|
||||
-- Chapter 2.2.3: Most recent / current IMEI
|
||||
-- Chapter 2.2.3: Most recent / current IMEISV
|
||||
imeisv VARCHAR,
|
||||
-- Chapter 2.1.9: Most recent / current IMEI
|
||||
imei VARCHAR(14),
|
||||
-- Chapter 2.4.5
|
||||
vlr_number VARCHAR(15),
|
||||
-- Chapter 2.4.6
|
||||
@@ -40,7 +42,12 @@ CREATE TABLE subscriber (
|
||||
|
||||
-- Timestamp of last location update seen from subscriber
|
||||
-- The value is a string which encodes a UTC timestamp in granularity of seconds.
|
||||
last_lu_seen TIMESTAMP default NULL
|
||||
last_lu_seen 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 TEXT default NULL
|
||||
);
|
||||
|
||||
CREATE TABLE subscriber_apn (
|
||||
@@ -70,8 +77,17 @@ CREATE TABLE auc_3g (
|
||||
ind_bitlen INTEGER NOT NULL DEFAULT 5 -- nr of index bits at lower SQN end
|
||||
);
|
||||
|
||||
-- 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')) NOT NULL, -- Radio Access Technology, see enum ran_type
|
||||
allowed BOOLEAN CHECK(allowed in (0, 1)) NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
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
|
||||
-- Note: This constant is currently duplicated in src/db.c and must be kept in sync!
|
||||
PRAGMA user_version = 1;
|
||||
PRAGMA user_version = 4;
|
||||
|
||||
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;
|
||||
@@ -87,21 +87,6 @@ osmo_hlr_db_tool_LDADD = \
|
||||
$(SQLITE3_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
db_test_SOURCES = \
|
||||
auc.c \
|
||||
db.c \
|
||||
db_auc.c \
|
||||
db_test.c \
|
||||
logging.c \
|
||||
rand_fake.c \
|
||||
$(NULL)
|
||||
|
||||
db_test_LDADD = \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(SQLITE3_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
osmo_euse_demo_SOURCES = \
|
||||
osmo-euse-demo.c \
|
||||
$(NULL)
|
||||
@@ -112,6 +97,11 @@ osmo_euse_demo_LDADD = \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
if DB_SQLITE_DEBUG
|
||||
osmo_hlr_SOURCES += db_debug.c
|
||||
osmo_hlr_db_tool_SOURCES += db_debug.c
|
||||
endif
|
||||
|
||||
BOOTSTRAP_SQL = $(top_srcdir)/sql/hlr.sql
|
||||
|
||||
db_bootstrap.h: $(BOOTSTRAP_SQL) $(srcdir)/db_sql2c.sed
|
||||
|
||||
@@ -95,7 +95,7 @@ static bool get_subscriber(struct db_context *dbc,
|
||||
cmd->reply = "No such subscriber.";
|
||||
return false;
|
||||
default:
|
||||
cmd->reply = "An unknown error has occured during get_subscriber().";
|
||||
cmd->reply = "An unknown error has occurred during get_subscriber().";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
182
src/db.c
182
src/db.c
@@ -28,12 +28,13 @@
|
||||
#include "db_bootstrap.h"
|
||||
|
||||
/* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */
|
||||
#define CURRENT_SCHEMA_VERSION 1
|
||||
#define CURRENT_SCHEMA_VERSION 4
|
||||
|
||||
#define SEL_COLUMNS \
|
||||
"id," \
|
||||
"imsi," \
|
||||
"msisdn," \
|
||||
"imei," \
|
||||
"vlr_number," \
|
||||
"sgsn_number," \
|
||||
"sgsn_address," \
|
||||
@@ -44,14 +45,17 @@
|
||||
"lmsi," \
|
||||
"ms_purged_cs," \
|
||||
"ms_purged_ps," \
|
||||
"last_lu_seen"
|
||||
"last_lu_seen," \
|
||||
"last_lu_rat"
|
||||
|
||||
static const char *stmt_sql[] = {
|
||||
[DB_STMT_SEL_BY_IMSI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imsi = ?",
|
||||
[DB_STMT_SEL_BY_MSISDN] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE msisdn = ?",
|
||||
[DB_STMT_SEL_BY_ID] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE id = ?",
|
||||
[DB_STMT_SEL_BY_IMEI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imei = ?",
|
||||
[DB_STMT_UPD_VLR_BY_ID] = "UPDATE subscriber SET vlr_number = $number WHERE id = $subscriber_id",
|
||||
[DB_STMT_UPD_SGSN_BY_ID] = "UPDATE subscriber SET sgsn_number = $number WHERE id = $subscriber_id",
|
||||
[DB_STMT_UPD_IMEI_BY_IMSI] = "UPDATE subscriber SET imei = $imei WHERE imsi = $imsi",
|
||||
[DB_STMT_AUC_BY_IMSI] =
|
||||
"SELECT id, algo_id_2g, ki, algo_id_3g, k, op, opc, sqn, ind_bitlen"
|
||||
" FROM subscriber"
|
||||
@@ -63,7 +67,7 @@ static const char *stmt_sql[] = {
|
||||
[DB_STMT_UPD_PURGE_PS_BY_IMSI] = "UPDATE subscriber SET ms_purged_ps = $val WHERE imsi = $imsi",
|
||||
[DB_STMT_UPD_NAM_CS_BY_IMSI] = "UPDATE subscriber SET nam_cs = $val WHERE imsi = $imsi",
|
||||
[DB_STMT_UPD_NAM_PS_BY_IMSI] = "UPDATE subscriber SET nam_ps = $val WHERE imsi = $imsi",
|
||||
[DB_STMT_SUBSCR_CREATE] = "INSERT INTO subscriber (imsi) VALUES ($imsi)",
|
||||
[DB_STMT_SUBSCR_CREATE] = "INSERT INTO subscriber (imsi, nam_cs, nam_ps) VALUES ($imsi, $nam_cs, $nam_ps)",
|
||||
[DB_STMT_DEL_BY_ID] = "DELETE FROM subscriber WHERE id = $subscriber_id",
|
||||
[DB_STMT_SET_MSISDN_BY_IMSI] = "UPDATE subscriber SET msisdn = $msisdn WHERE imsi = $imsi",
|
||||
[DB_STMT_DELETE_MSISDN_BY_IMSI] = "UPDATE subscriber SET msisdn = NULL WHERE imsi = $imsi",
|
||||
@@ -75,7 +79,16 @@ static const char *stmt_sql[] = {
|
||||
"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)",
|
||||
[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'), last_lu_rat = $rat"
|
||||
" WHERE id = $subscriber_id",
|
||||
[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_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)
|
||||
@@ -290,6 +303,119 @@ db_upgrade_v1(struct db_context *dbc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int db_upgrade_v2(struct db_context *dbc)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
int rc;
|
||||
const char *update_stmt_sql = "ALTER TABLE subscriber ADD COLUMN imei VARCHAR(14) default NULL";
|
||||
const char *set_schema_version_sql = "PRAGMA user_version = 2";
|
||||
|
||||
rc = sqlite3_prepare_v2(dbc->db, update_stmt_sql, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", update_stmt_sql);
|
||||
return rc;
|
||||
}
|
||||
rc = sqlite3_step(stmt);
|
||||
db_remove_reset(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version %d\n", 1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = sqlite3_prepare_v2(dbc->db, set_schema_version_sql, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", set_schema_version_sql);
|
||||
return rc;
|
||||
}
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc != SQLITE_DONE)
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version %d\n", 1);
|
||||
|
||||
db_remove_reset(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int db_upgrade_v3(struct db_context *dbc)
|
||||
{
|
||||
int i;
|
||||
const char *stmts[] = {
|
||||
"CREATE TABLE subscriber_rat",
|
||||
"CREATE UNIQUE INDEX idx_subscr_rat_flag",
|
||||
NULL
|
||||
};
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(stmts); i++) {
|
||||
int rc;
|
||||
int j;
|
||||
const char *stmt_sql = NULL;
|
||||
|
||||
if (stmts[i] != NULL) {
|
||||
for (j = 0; j < ARRAY_SIZE(stmt_bootstrap_sql); j++) {
|
||||
if (strstr(stmt_bootstrap_sql[j], stmts[i])) {
|
||||
/* make sure we have a unique match, hence also not break; here */
|
||||
OSMO_ASSERT(!stmt_sql);
|
||||
stmt_sql = stmt_bootstrap_sql[j];
|
||||
}
|
||||
}
|
||||
} else
|
||||
stmt_sql = "PRAGMA user_version = 3";
|
||||
OSMO_ASSERT(stmt_sql);
|
||||
|
||||
rc = sqlite3_prepare_v2(dbc->db, stmt_sql, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", stmt_sql);
|
||||
return rc;
|
||||
}
|
||||
rc = sqlite3_step(stmt);
|
||||
db_remove_reset(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 2: '%s'\n",
|
||||
stmt_sql);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
|
||||
static int db_upgrade_v4(struct db_context *dbc)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
int rc;
|
||||
const char *update_stmt_sql = "ALTER TABLE subscriber ADD COLUMN last_lu_rat TEXT default NULL";
|
||||
const char *set_schema_version_sql = "PRAGMA user_version = 4";
|
||||
|
||||
rc = sqlite3_prepare_v2(dbc->db, update_stmt_sql, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", update_stmt_sql);
|
||||
return rc;
|
||||
}
|
||||
rc = sqlite3_step(stmt);
|
||||
db_remove_reset(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version %d\n", 1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = sqlite3_prepare_v2(dbc->db, set_schema_version_sql, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", set_schema_version_sql);
|
||||
return rc;
|
||||
}
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc != SQLITE_DONE)
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 4\n");
|
||||
|
||||
db_remove_reset(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int db_get_user_version(struct db_context *dbc)
|
||||
{
|
||||
const char *user_version_sql = "PRAGMA user_version";
|
||||
@@ -326,6 +452,17 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logg
|
||||
LOGP(DDB, LOGL_INFO, "Compiled against SQLite3 lib version %s\n", SQLITE_VERSION);
|
||||
LOGP(DDB, LOGL_INFO, "Running with SQLite3 lib version %s\n", sqlite3_libversion());
|
||||
|
||||
#ifdef SQLITE_USE_TALLOC
|
||||
/* Configure SQLite3 to use talloc memory allocator */
|
||||
rc = db_sqlite3_use_talloc(ctx);
|
||||
if (rc == SQLITE_OK) {
|
||||
LOGP(DDB, LOGL_NOTICE, "SQLite3 is configured to use talloc\n");
|
||||
} else {
|
||||
LOGP(DDB, LOGL_ERROR, "Failed to configure SQLite3 "
|
||||
"to use talloc, using default memory allocator\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
dbc->fname = talloc_strdup(dbc, fname);
|
||||
|
||||
for (i = 0; i < 0xfffff; i++) {
|
||||
@@ -390,6 +527,8 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logg
|
||||
LOGP(DDB, LOGL_NOTICE, "Database '%s' has HLR DB schema version %d\n", dbc->fname, version);
|
||||
|
||||
if (version < CURRENT_SCHEMA_VERSION && allow_upgrade) {
|
||||
int orig_version = version;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
rc = db_upgrade_v1(dbc);
|
||||
@@ -400,21 +539,48 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logg
|
||||
}
|
||||
version = 1;
|
||||
/* fall through */
|
||||
case 1:
|
||||
rc = db_upgrade_v2(dbc);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DDB, LOGL_ERROR, "Failed to upgrade HLR DB schema to version 2: (rc=%d) %s\n",
|
||||
rc, sqlite3_errmsg(dbc->db));
|
||||
goto out_free;
|
||||
}
|
||||
version = 2;
|
||||
/* fall through */
|
||||
case 2:
|
||||
rc = db_upgrade_v3(dbc);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DDB, LOGL_ERROR, "Failed to upgrade HLR DB schema to version 2: (rc=%d) %s\n",
|
||||
rc, sqlite3_errmsg(dbc->db));
|
||||
goto out_free;
|
||||
}
|
||||
version = 3;
|
||||
/* fall through */
|
||||
case 3:
|
||||
rc = db_upgrade_v4(dbc);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DDB, LOGL_ERROR, "Failed to upgrade HLR DB schema to version 4: (rc=%d) %s\n",
|
||||
rc, sqlite3_errmsg(dbc->db));
|
||||
goto out_free;
|
||||
}
|
||||
version = 4;
|
||||
/* fall through */
|
||||
/* case N: ... */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
LOGP(DDB, LOGL_NOTICE, "Database '%s' has been upgraded to HLR DB schema version %d\n",
|
||||
dbc->fname, version);
|
||||
LOGP(DDB, LOGL_NOTICE, "Database '%s' has been upgraded from HLR DB schema version %d to %d\n",
|
||||
dbc->fname, orig_version, version);
|
||||
}
|
||||
|
||||
if (version != CURRENT_SCHEMA_VERSION) {
|
||||
if (version < CURRENT_SCHEMA_VERSION) {
|
||||
LOGP(DDB, LOGL_NOTICE, "HLR DB schema version %d is outdated\n", version);
|
||||
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",
|
||||
CURRENT_SCHEMA_VERSION);
|
||||
version, CURRENT_SCHEMA_VERSION);
|
||||
}
|
||||
} else
|
||||
LOGP(DDB, LOGL_ERROR, "HLR DB schema version %d is unknown\n", version);
|
||||
|
||||
41
src/db.h
41
src/db.h
@@ -3,14 +3,18 @@
|
||||
#include <stdbool.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
|
||||
struct hlr;
|
||||
|
||||
enum stmt_idx {
|
||||
DB_STMT_SEL_BY_IMSI,
|
||||
DB_STMT_SEL_BY_MSISDN,
|
||||
DB_STMT_SEL_BY_ID,
|
||||
DB_STMT_SEL_BY_IMEI,
|
||||
DB_STMT_UPD_VLR_BY_ID,
|
||||
DB_STMT_UPD_SGSN_BY_ID,
|
||||
DB_STMT_UPD_IMEI_BY_IMSI,
|
||||
DB_STMT_AUC_BY_IMSI,
|
||||
DB_STMT_AUC_UPD_SQN,
|
||||
DB_STMT_UPD_PURGE_CS_BY_IMSI,
|
||||
@@ -26,6 +30,10 @@ enum stmt_idx {
|
||||
DB_STMT_AUC_3G_INSERT,
|
||||
DB_STMT_AUC_3G_DELETE,
|
||||
DB_STMT_SET_LAST_LU_SEEN,
|
||||
DB_STMT_EXISTS_BY_IMSI,
|
||||
DB_STMT_EXISTS_BY_MSISDN,
|
||||
DB_STMT_UPD_RAT_FLAG,
|
||||
DB_STMT_RAT_BY_ID,
|
||||
_NUM_DB_STMT
|
||||
};
|
||||
|
||||
@@ -35,6 +43,11 @@ struct db_context {
|
||||
sqlite3_stmt *stmt[_NUM_DB_STMT];
|
||||
};
|
||||
|
||||
/* Optional feature to make SQLite3 using talloc */
|
||||
#ifdef SQLITE_USE_TALLOC
|
||||
int db_sqlite3_use_talloc(void *ctx);
|
||||
#endif
|
||||
|
||||
void db_remove_reset(sqlite3_stmt *stmt);
|
||||
bool db_bind_text(sqlite3_stmt *stmt, const char *param_name, const char *text);
|
||||
bool db_bind_int(sqlite3_stmt *stmt, const char *param_name, int nr);
|
||||
@@ -56,7 +69,7 @@ int db_update_sqn(struct db_context *dbc, int64_t id,
|
||||
int db_get_auc(struct db_context *dbc, const char *imsi,
|
||||
unsigned int auc_3g_ind, struct osmo_auth_vector *vec,
|
||||
unsigned int num_vec, const uint8_t *rand_auts,
|
||||
const uint8_t *auts);
|
||||
const uint8_t *auts, bool separation_bit);
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
||||
@@ -69,8 +82,9 @@ struct hlr_subscriber {
|
||||
|
||||
int64_t id;
|
||||
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
|
||||
char msisdn[GT_MAX_DIGITS+1];
|
||||
char msisdn[GSM23003_MSISDN_MAX_DIGITS+1];
|
||||
/* imeisv? */
|
||||
char imei[GSM23003_IMEI_NUM_DIGITS+1];
|
||||
char vlr_number[32];
|
||||
char sgsn_number[32];
|
||||
char sgsn_address[GT_MAX_DIGITS+1];
|
||||
@@ -85,8 +99,14 @@ struct hlr_subscriber {
|
||||
bool ms_purged_cs;
|
||||
bool ms_purged_ps;
|
||||
time_t last_lu_seen;
|
||||
char last_lu_rat[128];
|
||||
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
|
||||
* used to parse the last_lu_seen column stored in the HLR database.
|
||||
* See https://sqlite.org/lang_datefunc.html, function datetime(). */
|
||||
@@ -115,13 +135,20 @@ struct sub_auth_data_str {
|
||||
} u;
|
||||
};
|
||||
|
||||
int db_subscr_create(struct db_context *dbc, const char *imsi);
|
||||
#define DB_SUBSCR_FLAG_NAM_CS (1 << 1)
|
||||
#define DB_SUBSCR_FLAG_NAM_PS (1 << 2)
|
||||
|
||||
int db_subscr_create(struct db_context *dbc, const char *imsi, uint8_t flags);
|
||||
int db_subscr_delete_by_id(struct db_context *dbc, int64_t subscr_id);
|
||||
|
||||
int db_subscr_update_msisdn_by_imsi(struct db_context *dbc, const char *imsi,
|
||||
const char *msisdn);
|
||||
int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
|
||||
const struct sub_auth_data_str *aud);
|
||||
int db_subscr_update_imei_by_imsi(struct db_context *dbc, const char* imsi, const char *imei);
|
||||
|
||||
int db_subscr_exists_by_imsi(struct db_context *dbc, const char *imsi);
|
||||
int db_subscr_exists_by_msisdn(struct db_context *dbc, const char *msisdn);
|
||||
|
||||
int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
|
||||
struct hlr_subscriber *subscr);
|
||||
@@ -129,15 +156,21 @@ int db_subscr_get_by_msisdn(struct db_context *dbc, const char *msisdn,
|
||||
struct hlr_subscriber *subscr);
|
||||
int db_subscr_get_by_id(struct db_context *dbc, int64_t id,
|
||||
struct hlr_subscriber *subscr);
|
||||
int db_subscr_get_by_imei(struct db_context *dbc, const char *imei, struct hlr_subscriber *subscr);
|
||||
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,
|
||||
const char *vlr_or_sgsn_number, bool is_ps);
|
||||
const char *vlr_or_sgsn_number, bool is_ps,
|
||||
const enum osmo_rat_type rat_types[], size_t rat_types_len);
|
||||
|
||||
int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
|
||||
bool purge_val, bool is_ps);
|
||||
|
||||
int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val, bool is_ps);
|
||||
|
||||
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[].
|
||||
* \param[out] buf A char[] used as sizeof() arg(!) and osmo_strlcpy() target.
|
||||
* \param[in] stmt An sqlite3_stmt*.
|
||||
|
||||
77
src/db_auc.c
77
src/db_auc.c
@@ -73,6 +73,32 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* hexparse a specific column of a sqlite prepared statement into dst (with length check)
|
||||
* returns 0 for success, -EIO on error */
|
||||
static int hexparse_stmt(uint8_t *dst, size_t dst_len, sqlite3_stmt *stmt, int col, const char *col_name,
|
||||
const char *imsi)
|
||||
{
|
||||
const uint8_t *text;
|
||||
size_t col_len;
|
||||
|
||||
/* Bytes are stored as hex strings in database, hence divide length by two */
|
||||
col_len = sqlite3_column_bytes(stmt, col) / 2;
|
||||
|
||||
if (col_len != dst_len) {
|
||||
LOGAUC(imsi, LOGL_ERROR, "Error reading %s, expected length %lu but has length %lu\n", col_name,
|
||||
dst_len, col_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
text = sqlite3_column_text(stmt, col);
|
||||
if (!text) {
|
||||
LOGAUC(imsi, LOGL_ERROR, "Error reading %s\n", col_name);
|
||||
return -EIO;
|
||||
}
|
||||
osmo_hexparse((void *)text, dst, dst_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* obtain the authentication data for a given imsi
|
||||
* returns 0 for success, negative value on error:
|
||||
* -ENOENT if the IMSI is not known, -ENOKEY if the IMSI is known but has no auth data,
|
||||
@@ -113,49 +139,34 @@ int db_get_auth_data(struct db_context *dbc, const char *imsi,
|
||||
/* obtain result values using sqlite3_column_*() */
|
||||
if (sqlite3_column_type(stmt, 1) == SQLITE_INTEGER) {
|
||||
/* we do have some 2G authentication data */
|
||||
const uint8_t *ki;
|
||||
|
||||
aud2g->algo = sqlite3_column_int(stmt, 1);
|
||||
ki = sqlite3_column_text(stmt, 2);
|
||||
#if 0
|
||||
if (sqlite3_column_bytes(stmt, 2) != sizeof(aud2g->u.gsm.ki)) {
|
||||
LOGAUC(imsi, LOGL_ERROR, "Error reading Ki: %d\n", rc);
|
||||
if (hexparse_stmt(aud2g->u.gsm.ki, sizeof(aud2g->u.gsm.ki), stmt, 2, "Ki", imsi))
|
||||
goto end_2g;
|
||||
}
|
||||
#endif
|
||||
osmo_hexparse((void*)ki, (void*)&aud2g->u.gsm.ki, sizeof(aud2g->u.gsm.ki));
|
||||
aud2g->algo = sqlite3_column_int(stmt, 1);
|
||||
aud2g->type = OSMO_AUTH_TYPE_GSM;
|
||||
} else
|
||||
LOGAUC(imsi, LOGL_DEBUG, "No 2G Auth Data\n");
|
||||
//end_2g:
|
||||
end_2g:
|
||||
if (sqlite3_column_type(stmt, 3) == SQLITE_INTEGER) {
|
||||
/* we do have some 3G authentication data */
|
||||
const uint8_t *k, *op, *opc;
|
||||
|
||||
aud3g->algo = sqlite3_column_int(stmt, 3);
|
||||
k = sqlite3_column_text(stmt, 4);
|
||||
if (!k) {
|
||||
LOGAUC(imsi, LOGL_ERROR, "Error reading K: %d\n", rc);
|
||||
if (hexparse_stmt(aud3g->u.umts.k, sizeof(aud3g->u.umts.k), stmt, 4, "K", imsi)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
osmo_hexparse((void*)k, (void*)&aud3g->u.umts.k, sizeof(aud3g->u.umts.k));
|
||||
aud3g->algo = sqlite3_column_int(stmt, 3);
|
||||
|
||||
/* UMTS Subscribers can have either OP or OPC */
|
||||
op = sqlite3_column_text(stmt, 5);
|
||||
if (!op) {
|
||||
opc = sqlite3_column_text(stmt, 6);
|
||||
if (!opc) {
|
||||
LOGAUC(imsi, LOGL_ERROR, "Error reading OPC: %d\n", rc);
|
||||
if (sqlite3_column_text(stmt, 5)) {
|
||||
if (hexparse_stmt(aud3g->u.umts.opc, sizeof(aud3g->u.umts.opc), stmt, 5, "OP", imsi)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
osmo_hexparse((void*)opc, (void*)&aud3g->u.umts.opc,
|
||||
sizeof(aud3g->u.umts.opc));
|
||||
aud3g->u.umts.opc_is_op = 0;
|
||||
} else {
|
||||
osmo_hexparse((void*)op, (void*)&aud3g->u.umts.opc,
|
||||
sizeof(aud3g->u.umts.opc));
|
||||
aud3g->u.umts.opc_is_op = 1;
|
||||
} else {
|
||||
if (hexparse_stmt(aud3g->u.umts.opc, sizeof(aud3g->u.umts.opc), stmt, 6, "OPC", imsi)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
aud3g->u.umts.opc_is_op = 0;
|
||||
}
|
||||
aud3g->u.umts.sqn = sqlite3_column_int64(stmt, 7);
|
||||
aud3g->u.umts.ind_bitlen = sqlite3_column_int(stmt, 8);
|
||||
@@ -178,7 +189,7 @@ out:
|
||||
int db_get_auc(struct db_context *dbc, const char *imsi,
|
||||
unsigned int auc_3g_ind, struct osmo_auth_vector *vec,
|
||||
unsigned int num_vec, const uint8_t *rand_auts,
|
||||
const uint8_t *auts)
|
||||
const uint8_t *auts, bool separation_bit)
|
||||
{
|
||||
struct osmo_sub_auth_data aud2g, aud3g;
|
||||
int64_t subscr_id;
|
||||
@@ -198,6 +209,12 @@ int db_get_auc(struct db_context *dbc, const char *imsi,
|
||||
aud3g.u.umts.ind_bitlen, aud3g.u.umts.ind);
|
||||
aud3g.u.umts.ind &= (1U << aud3g.u.umts.ind_bitlen) - 1;
|
||||
}
|
||||
/* the first bit (bit0) cannot be used as AMF anymore, but has been
|
||||
* re-appropriated as the separation bit. See 3GPP TS 33.102 Annex H
|
||||
* together with 3GPP TS 33.401 / 33.402 / 33.501 */
|
||||
aud3g.u.umts.amf[0] = aud3g.u.umts.amf[0] & 0x7f;
|
||||
if (separation_bit)
|
||||
aud3g.u.umts.amf[0] |= 0x80;
|
||||
|
||||
LOGAUC(imsi, LOGL_DEBUG, "Calling to generate %u vectors\n", num_vec);
|
||||
rc = auc_compute_vectors(vec, num_vec, &aud2g, &aud3g, rand_auts, auts);
|
||||
|
||||
86
src/db_debug.c
Normal file
86
src/db_debug.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* libtalloc based memory allocator for SQLite3.
|
||||
*
|
||||
* (C) 2019 by Vadim Yanitskiy <axilirator@gmail.com>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <talloc.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Dedicated talloc context for SQLite */
|
||||
static void *db_sqlite_ctx = NULL;
|
||||
|
||||
static void *tall_xMalloc(int size)
|
||||
{
|
||||
return talloc_size(db_sqlite_ctx, size);
|
||||
}
|
||||
|
||||
static void tall_xFree(void *ptr)
|
||||
{
|
||||
talloc_free(ptr);
|
||||
}
|
||||
|
||||
static void *tall_xRealloc(void *ptr, int size)
|
||||
{
|
||||
return talloc_realloc_fn(db_sqlite_ctx, ptr, size);
|
||||
}
|
||||
|
||||
static int tall_xSize(void *ptr)
|
||||
{
|
||||
return talloc_total_size(ptr);
|
||||
}
|
||||
|
||||
/* DUMMY: talloc doesn't round up the allocation size */
|
||||
static int tall_xRoundup(int size) { return size; }
|
||||
|
||||
/* DUMMY: nothing to initialize */
|
||||
static int tall_xInit(void *data) { return 0; }
|
||||
|
||||
/* DUMMY: nothing to deinitialize */
|
||||
static void tall_xShutdown(void *data) { }
|
||||
|
||||
/* Interface between SQLite and talloc memory allocator */
|
||||
static const struct sqlite3_mem_methods tall_sqlite_if = {
|
||||
/* Memory allocation function */
|
||||
.xMalloc = &tall_xMalloc,
|
||||
/* Free a prior allocation */
|
||||
.xFree = &tall_xFree,
|
||||
/* Resize an allocation */
|
||||
.xRealloc = &tall_xRealloc,
|
||||
/* Return the size of an allocation */
|
||||
.xSize = &tall_xSize,
|
||||
/* Round up request size to allocation size */
|
||||
.xRoundup = &tall_xRoundup,
|
||||
/* Initialize the memory allocator */
|
||||
.xInit = &tall_xInit,
|
||||
/* Deinitialize the memory allocator */
|
||||
.xShutdown = &tall_xShutdown,
|
||||
/* Argument to xInit() and xShutdown() */
|
||||
.pAppData = NULL,
|
||||
};
|
||||
|
||||
int db_sqlite3_use_talloc(void *ctx)
|
||||
{
|
||||
if (db_sqlite_ctx != NULL)
|
||||
return -EEXIST;
|
||||
|
||||
db_sqlite_ctx = talloc_named_const(ctx, 0, "SQLite3");
|
||||
return sqlite3_config(SQLITE_CONFIG_MALLOC, &tall_sqlite_if);
|
||||
}
|
||||
299
src/db_hlr.c
299
src/db_hlr.c
@@ -44,9 +44,10 @@
|
||||
/*! Add new subscriber record to the HLR database.
|
||||
* \param[in,out] dbc database context.
|
||||
* \param[in] imsi ASCII string of IMSI digits, is validated.
|
||||
* \param[in] flags Bitmask of DB_SUBSCR_FLAG_*.
|
||||
* \returns 0 on success, -EINVAL on invalid IMSI, -EIO on database error.
|
||||
*/
|
||||
int db_subscr_create(struct db_context *dbc, const char *imsi)
|
||||
int db_subscr_create(struct db_context *dbc, const char *imsi, uint8_t flags)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
int rc;
|
||||
@@ -61,6 +62,10 @@ int db_subscr_create(struct db_context *dbc, const char *imsi)
|
||||
|
||||
if (!db_bind_text(stmt, "$imsi", imsi))
|
||||
return -EIO;
|
||||
if (!db_bind_int(stmt, "$nam_cs", (flags & DB_SUBSCR_FLAG_NAM_CS) != 0))
|
||||
return -EIO;
|
||||
if (!db_bind_int(stmt, "$nam_ps", (flags & DB_SUBSCR_FLAG_NAM_PS) != 0))
|
||||
return -EIO;
|
||||
|
||||
/* execute the statement */
|
||||
rc = sqlite3_step(stmt);
|
||||
@@ -141,8 +146,8 @@ int db_subscr_delete_by_id(struct db_context *dbc, int64_t subscr_id)
|
||||
|
||||
/*! Set a subscriber's MSISDN in the HLR database.
|
||||
* \param[in,out] dbc database context.
|
||||
* \param[in] imsi ASCII string of IMSI digits, or NULL to remove the MSISDN.
|
||||
* \param[in] msisdn ASCII string of MSISDN digits.
|
||||
* \param[in] imsi ASCII string of IMSI digits
|
||||
* \param[in] msisdn ASCII string of MSISDN digits, or NULL to remove the MSISDN.
|
||||
* \returns 0 on success, -EINVAL in case of invalid MSISDN string, -EIO on
|
||||
* database failure, -ENOENT if no such subscriber exists.
|
||||
*/
|
||||
@@ -386,6 +391,53 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Set a subscriber's IMEI in the HLR database.
|
||||
* \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_imei_by_imsi(struct db_context *dbc, const char* imsi, const char *imei)
|
||||
{
|
||||
int rc, ret = 0;
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_UPD_IMEI_BY_IMSI];
|
||||
|
||||
if (imei && !osmo_imei_str_valid(imei, false)) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Cannot update subscriber IMSI='%s': invalid IMEI: '%s'\n", imsi, imei);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!db_bind_text(stmt, "$imsi", imsi))
|
||||
return -EIO;
|
||||
if (imei && !db_bind_text(stmt, "$imei", imei))
|
||||
return -EIO;
|
||||
|
||||
/* execute the statement */
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Update IMEI 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 IMEI for subscriber IMSI='%s': no such subscriber\n", imsi);
|
||||
ret = -ENOENT;
|
||||
} else if (rc != 1) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Update IMEI for subscriber IMSI='%s': SQL modified %d rows (expected 1)\n",
|
||||
imsi, rc);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
out:
|
||||
db_remove_reset(stmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Common code for db_subscr_get_by_*() functions. */
|
||||
static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscriber *subscr,
|
||||
const char **err)
|
||||
@@ -393,7 +445,7 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
|
||||
int rc;
|
||||
int ret = 0;
|
||||
const char *last_lu_seen_str;
|
||||
struct tm tm;
|
||||
struct tm tm = {0};
|
||||
|
||||
/* execute the statement */
|
||||
rc = sqlite3_step(stmt);
|
||||
@@ -409,24 +461,25 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
|
||||
if (!subscr)
|
||||
goto out;
|
||||
|
||||
*subscr = (struct hlr_subscriber){};
|
||||
*subscr = hlr_subscriber_empty;
|
||||
|
||||
/* obtain the various columns */
|
||||
subscr->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);
|
||||
/* FIXME: These should all be BLOBs as they might contain NUL */
|
||||
copy_sqlite3_text_to_buf(subscr->vlr_number, stmt, 3);
|
||||
copy_sqlite3_text_to_buf(subscr->sgsn_number, stmt, 4);
|
||||
copy_sqlite3_text_to_buf(subscr->sgsn_address, stmt, 5);
|
||||
subscr->periodic_lu_timer = sqlite3_column_int(stmt, 6);
|
||||
subscr->periodic_rau_tau_timer = sqlite3_column_int(stmt, 7);
|
||||
subscr->nam_cs = sqlite3_column_int(stmt, 8);
|
||||
subscr->nam_ps = sqlite3_column_int(stmt, 9);
|
||||
subscr->lmsi = sqlite3_column_int(stmt, 10);
|
||||
subscr->ms_purged_cs = sqlite3_column_int(stmt, 11);
|
||||
subscr->ms_purged_ps = sqlite3_column_int(stmt, 12);
|
||||
last_lu_seen_str = (const char *)sqlite3_column_text(stmt, 13);
|
||||
copy_sqlite3_text_to_buf(subscr->vlr_number, stmt, 4);
|
||||
copy_sqlite3_text_to_buf(subscr->sgsn_number, stmt, 5);
|
||||
copy_sqlite3_text_to_buf(subscr->sgsn_address, stmt, 6);
|
||||
subscr->periodic_lu_timer = sqlite3_column_int(stmt, 7);
|
||||
subscr->periodic_rau_tau_timer = sqlite3_column_int(stmt, 8);
|
||||
subscr->nam_cs = sqlite3_column_int(stmt, 9);
|
||||
subscr->nam_ps = sqlite3_column_int(stmt, 10);
|
||||
subscr->lmsi = sqlite3_column_int(stmt, 11);
|
||||
subscr->ms_purged_cs = sqlite3_column_int(stmt, 12);
|
||||
subscr->ms_purged_ps = sqlite3_column_int(stmt, 13);
|
||||
last_lu_seen_str = (const char *)sqlite3_column_text(stmt, 14);
|
||||
if (last_lu_seen_str && last_lu_seen_str[0] != '\0') {
|
||||
if (strptime(last_lu_seen_str, DB_LAST_LU_SEEN_FMT, &tm) == NULL) {
|
||||
LOGP(DAUC, LOGL_ERROR, "Cannot parse last LU timestamp '%s' of subscriber with IMSI='%s': %s\n",
|
||||
@@ -440,10 +493,14 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
|
||||
}
|
||||
}
|
||||
}
|
||||
copy_sqlite3_text_to_buf(subscr->last_lu_rat, stmt, 15);
|
||||
|
||||
out:
|
||||
db_remove_reset(stmt);
|
||||
|
||||
if (ret == 0)
|
||||
db_subscr_get_rat_types(dbc, subscr);
|
||||
|
||||
switch (ret) {
|
||||
case 0:
|
||||
*err = NULL;
|
||||
@@ -458,6 +515,31 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Check if a subscriber exists in the HLR database.
|
||||
* \param[in, out] dbc database context.
|
||||
* \param[in] imsi ASCII string of IMSI digits.
|
||||
* \returns 0 if it exists, -ENOENT if it does not exist, -EIO on database error.
|
||||
*/
|
||||
int db_subscr_exists_by_imsi(struct db_context *dbc, const char *imsi) {
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_EXISTS_BY_IMSI];
|
||||
const char *err;
|
||||
int rc;
|
||||
|
||||
if (!db_bind_text(stmt, NULL, imsi))
|
||||
return -EIO;
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
db_remove_reset(stmt);
|
||||
if (rc == SQLITE_ROW)
|
||||
return 0; /* exists */
|
||||
if (rc == SQLITE_DONE)
|
||||
return -ENOENT; /* does not exist */
|
||||
|
||||
err = sqlite3_errmsg(dbc->db);
|
||||
LOGP(DAUC, LOGL_ERROR, "Failed to check if subscriber exists by IMSI='%s': %s\n", imsi, err);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! Retrieve subscriber data from the HLR database.
|
||||
* \param[in,out] dbc database context.
|
||||
* \param[in] imsi ASCII string of IMSI digits.
|
||||
@@ -482,6 +564,33 @@ int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! Check if a subscriber exists in the HLR database.
|
||||
* \param[in, out] dbc database context.
|
||||
* \param[in] msisdn ASCII string of MSISDN digits.
|
||||
* \returns 0 if it exists, -ENOENT if it does not exist, -EIO on database error.
|
||||
*/
|
||||
int db_subscr_exists_by_msisdn(struct db_context *dbc, const char *msisdn)
|
||||
{
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_EXISTS_BY_MSISDN];
|
||||
const char *err;
|
||||
int rc;
|
||||
|
||||
if (!db_bind_text(stmt, NULL, msisdn))
|
||||
return -EIO;
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
db_remove_reset(stmt);
|
||||
if (rc == SQLITE_ROW)
|
||||
return 0; /* exists */
|
||||
if (rc == SQLITE_DONE)
|
||||
return -ENOENT; /* does not exist */
|
||||
|
||||
err = sqlite3_errmsg(dbc->db);
|
||||
LOGP(DAUC, LOGL_ERROR, "Failed to check if subscriber exists "
|
||||
"by MSISDN='%s': %s\n", msisdn, err);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! Retrieve subscriber data from the HLR database.
|
||||
* \param[in,out] dbc database context.
|
||||
* \param[in] msisdn ASCII string of MSISDN digits.
|
||||
@@ -530,6 +639,28 @@ int db_subscr_get_by_id(struct db_context *dbc, int64_t id,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! Retrieve subscriber data from the HLR database.
|
||||
* \param[in,out] dbc database context.
|
||||
* \param[in] imei ASCII string of identifier digits
|
||||
* \param[out] subscr place retrieved data in this struct.
|
||||
* \returns 0 on success, -ENOENT if no such subscriber was found, -EIO on
|
||||
* database error.
|
||||
*/
|
||||
int db_subscr_get_by_imei(struct db_context *dbc, const char *imei, struct hlr_subscriber *subscr)
|
||||
{
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_SEL_BY_IMEI];
|
||||
const char *err;
|
||||
int rc;
|
||||
|
||||
if (!db_bind_text(stmt, NULL, imei))
|
||||
return -EIO;
|
||||
|
||||
rc = db_sel(dbc, stmt, subscr, &err);
|
||||
if (rc)
|
||||
LOGP(DAUC, LOGL_ERROR, "Cannot read subscriber from db: IMEI=%s: %s\n", imei, err);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! You should use hlr_subscr_nam() instead; enable or disable PS or CS for a
|
||||
* subscriber without notifying GSUP clients.
|
||||
* \param[in,out] dbc database context.
|
||||
@@ -595,11 +726,14 @@ out:
|
||||
* -EIO on database errors.
|
||||
*/
|
||||
int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
|
||||
const char *vlr_or_sgsn_number, bool is_ps)
|
||||
const char *vlr_or_sgsn_number, bool is_ps,
|
||||
const enum osmo_rat_type rat_types[], size_t rat_types_len)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
int rc, ret = 0;
|
||||
struct timespec localtime;
|
||||
char rat_types_str[128] = "";
|
||||
int i;
|
||||
|
||||
stmt = dbc->stmt[is_ps ? DB_STMT_UPD_SGSN_BY_ID
|
||||
: DB_STMT_UPD_VLR_BY_ID];
|
||||
@@ -653,6 +787,21 @@ int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
|
||||
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);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DAUC, LOGL_ERROR,
|
||||
@@ -782,3 +931,119 @@ int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -25,15 +25,15 @@
|
||||
|
||||
#include "logging.h"
|
||||
#include "gsup_server.h"
|
||||
#include "gsup_router.h"
|
||||
|
||||
struct gsup_route {
|
||||
struct llist_head list;
|
||||
|
||||
uint8_t *addr;
|
||||
struct osmo_gsup_conn *conn;
|
||||
};
|
||||
|
||||
/* find a route for the given address */
|
||||
/*! Find a route for the given address.
|
||||
* \param[in] gs gsup server
|
||||
* \param[in] addr IPA name of the client (SGSN, MSC/VLR). Although this is passed like a blob, together with the
|
||||
* length, it must be nul-terminated! This is for legacy reasons, see the discussion here:
|
||||
* https://gerrit.osmocom.org/#/c/osmo-hlr/+/13048/
|
||||
* \param[in] addrlen length of addr, *including the nul-byte* (strlen(addr) + 1).
|
||||
*/
|
||||
struct osmo_gsup_conn *gsup_route_find(struct osmo_gsup_server *gs,
|
||||
const uint8_t *addr, size_t addrlen)
|
||||
{
|
||||
@@ -47,6 +47,22 @@ struct osmo_gsup_conn *gsup_route_find(struct osmo_gsup_server *gs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Find a GSUP connection's route (to read the IPA address from the route).
|
||||
* \param[in] conn GSUP connection
|
||||
* \return GSUP route
|
||||
*/
|
||||
struct gsup_route *gsup_route_find_by_conn(const struct osmo_gsup_conn *conn)
|
||||
{
|
||||
struct gsup_route *gr;
|
||||
|
||||
llist_for_each_entry(gr, &conn->server->routes, list) {
|
||||
if (gr->conn == conn)
|
||||
return gr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* add a new route for the given address to the given conn */
|
||||
int gsup_route_add(struct osmo_gsup_conn *conn, const uint8_t *addr, size_t addrlen)
|
||||
{
|
||||
@@ -61,7 +77,7 @@ int gsup_route_add(struct osmo_gsup_conn *conn, const uint8_t *addr, size_t addr
|
||||
if (!gr)
|
||||
return -ENOMEM;
|
||||
|
||||
LOGP(DMAIN, LOGL_INFO, "Adding GSUP route for %s\n", addr);
|
||||
LOGP(DMAIN, LOGL_INFO, "Adding GSUP route for %s via %s:%u\n", addr, conn->conn->addr, conn->conn->port);
|
||||
|
||||
gr->addr = talloc_memdup(gr, addr, addrlen);
|
||||
gr->conn = conn;
|
||||
|
||||
@@ -3,9 +3,18 @@
|
||||
#include <stdint.h>
|
||||
#include "gsup_server.h"
|
||||
|
||||
struct gsup_route {
|
||||
struct llist_head list;
|
||||
|
||||
uint8_t *addr;
|
||||
struct osmo_gsup_conn *conn;
|
||||
};
|
||||
|
||||
struct osmo_gsup_conn *gsup_route_find(struct osmo_gsup_server *gs,
|
||||
const uint8_t *addr, size_t addrlen);
|
||||
|
||||
struct gsup_route *gsup_route_find_by_conn(const struct osmo_gsup_conn *conn);
|
||||
|
||||
/* add a new route for the given address to the given conn */
|
||||
int gsup_route_add(struct osmo_gsup_conn *conn, const uint8_t *addr, size_t addrlen);
|
||||
|
||||
|
||||
@@ -26,7 +26,14 @@
|
||||
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
/* Send a msgb to a given address using routing */
|
||||
/*! Send a msgb to a given address using routing.
|
||||
* \param[in] gs gsup server
|
||||
* \param[in] addr IPA name of the client (SGSN, MSC/VLR). Although this is passed like a blob, together with the
|
||||
* length, it must be nul-terminated! This is for legacy reasons, see the discussion here:
|
||||
* https://gerrit.osmocom.org/#/c/osmo-hlr/+/13048/
|
||||
* \param[in] addrlen length of addr, *including the nul-byte* (strlen(addr) + 1).
|
||||
* \param[in] msg message buffer
|
||||
*/
|
||||
int osmo_gsup_addr_send(struct osmo_gsup_server *gs,
|
||||
const uint8_t *addr, size_t addrlen,
|
||||
struct msgb *msg)
|
||||
@@ -35,7 +42,7 @@ int osmo_gsup_addr_send(struct osmo_gsup_server *gs,
|
||||
|
||||
conn = gsup_route_find(gs, addr, addrlen);
|
||||
if (!conn) {
|
||||
DEBUGP(DLGSUP, "Cannot find route for addr %s\n", addr);
|
||||
DEBUGP(DLGSUP, "Cannot find route for addr %s\n", osmo_quote_str((const char*)addr, addrlen));
|
||||
msgb_free(msg);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
317
src/hlr.c
317
src/hlr.c
@@ -23,6 +23,7 @@
|
||||
#include <getopt.h>
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/stats.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/gsm/gsup.h>
|
||||
@@ -32,6 +33,9 @@
|
||||
#include <osmocom/vty/ports.h>
|
||||
#include <osmocom/ctrl/control_vty.h>
|
||||
#include <osmocom/gsm/apn.h>
|
||||
#include <osmocom/gsm/gsm48_ie.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "hlr.h"
|
||||
@@ -45,6 +49,7 @@
|
||||
#include "hlr_ussd.h"
|
||||
|
||||
struct hlr *g_hlr;
|
||||
static void *hlr_ctx = NULL;
|
||||
static int quit = 0;
|
||||
|
||||
/* Trigger 'Insert Subscriber Data' messages to all connected GSUP clients.
|
||||
@@ -145,6 +150,78 @@ osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
|
||||
}
|
||||
}
|
||||
|
||||
static int generate_new_msisdn(char *msisdn, const char *imsi, unsigned int len)
|
||||
{
|
||||
int i, j, rc;
|
||||
uint8_t rand_buf[GSM23003_MSISDN_MAX_DIGITS];
|
||||
|
||||
OSMO_ASSERT(len <= sizeof(rand_buf));
|
||||
|
||||
/* Generate a random unique MSISDN (with retry) */
|
||||
for (i = 0; i < 10; i++) {
|
||||
/* Get a random number (with retry) */
|
||||
for (j = 0; j < 10; j++) {
|
||||
rc = osmo_get_rand_id(rand_buf, len);
|
||||
if (!rc)
|
||||
break;
|
||||
}
|
||||
if (rc) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "IMSI='%s': Failed to generate new MSISDN, random number generator"
|
||||
" failed (rc=%d)\n", imsi, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Shift 0x00 ... 0xff range to 30 ... 39 (ASCII numbers) */
|
||||
for (j = 0; j < len; j++)
|
||||
msisdn[j] = 48 + (rand_buf[j] % 10);
|
||||
msisdn[j] = '\0';
|
||||
|
||||
/* Ensure there is no subscriber with such MSISDN */
|
||||
if (db_subscr_exists_by_msisdn(g_hlr->dbc, msisdn) == -ENOENT)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Failure */
|
||||
LOGP(DMAIN, LOGL_ERROR, "IMSI='%s': Failed to generate a new MSISDN, consider increasing "
|
||||
"the length for the automatically assigned MSISDNs "
|
||||
"(see 'subscriber-create-on-demand' command)\n", imsi);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int subscr_create_on_demand(const char *imsi)
|
||||
{
|
||||
char msisdn[GSM23003_MSISDN_MAX_DIGITS + 1];
|
||||
int rc;
|
||||
unsigned int rand_msisdn_len = g_hlr->subscr_create_on_demand_rand_msisdn_len;
|
||||
|
||||
if (!g_hlr->subscr_create_on_demand)
|
||||
return -1;
|
||||
if (db_subscr_exists_by_imsi(g_hlr->dbc, imsi) == 0)
|
||||
return -1;
|
||||
if (rand_msisdn_len && generate_new_msisdn(msisdn, imsi, rand_msisdn_len) != 0)
|
||||
return -1;
|
||||
|
||||
LOGP(DMAIN, LOGL_INFO, "IMSI='%s': Creating subscriber on demand\n", imsi);
|
||||
rc = db_subscr_create(g_hlr->dbc, imsi, g_hlr->subscr_create_on_demand_flags);
|
||||
if (rc) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "Failed to create subscriber on demand (rc=%d): IMSI='%s'\n", rc, imsi);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!rand_msisdn_len)
|
||||
return 0;
|
||||
|
||||
/* Update MSISDN of the new (just allocated) subscriber */
|
||||
rc = db_subscr_update_msisdn_by_imsi(g_hlr->dbc, imsi, msisdn);
|
||||
if (rc) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "IMSI='%s': Failed to assign MSISDN='%s' (rc=%d)\n", imsi, msisdn, rc);
|
||||
return rc;
|
||||
}
|
||||
LOGP(DMAIN, LOGL_INFO, "IMSI='%s': Successfully assigned MSISDN='%s'\n", imsi, msisdn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Send Auth Info handling
|
||||
***********************************************************************/
|
||||
@@ -156,16 +233,22 @@ static int rx_send_auth_info(struct osmo_gsup_conn *conn,
|
||||
{
|
||||
struct osmo_gsup_message gsup_out;
|
||||
struct msgb *msg_out;
|
||||
bool separation_bit = false;
|
||||
int rc;
|
||||
|
||||
subscr_create_on_demand(gsup->imsi);
|
||||
|
||||
/* initialize return message structure */
|
||||
memset(&gsup_out, 0, sizeof(gsup_out));
|
||||
memcpy(&gsup_out.imsi, &gsup->imsi, sizeof(gsup_out.imsi));
|
||||
|
||||
if (gsup->rat_types_len >= 1 && gsup->rat_types[0] == OSMO_RAT_EUTRAN_SGS)
|
||||
separation_bit = true;
|
||||
|
||||
rc = db_get_auc(dbc, gsup->imsi, conn->auc_3g_ind,
|
||||
gsup_out.auth_vectors,
|
||||
ARRAY_SIZE(gsup_out.auth_vectors),
|
||||
gsup->rand, gsup->auts);
|
||||
gsup->rand, gsup->auts, separation_bit);
|
||||
if (rc <= 0) {
|
||||
gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR;
|
||||
switch (rc) {
|
||||
@@ -180,7 +263,7 @@ static int rx_send_auth_info(struct osmo_gsup_conn *conn,
|
||||
break;
|
||||
case -ENOENT:
|
||||
LOGP(DAUC, LOGL_NOTICE, "%s: IMSI not known\n", gsup->imsi);
|
||||
gsup_out.cause = GMM_CAUSE_IMSI_UNKNOWN;
|
||||
gsup_out.cause = GMM_CAUSE_ROAMING_NOTALLOWED;
|
||||
break;
|
||||
default:
|
||||
LOGP(DAUC, LOGL_ERROR, "%s: failure to look up IMSI in db\n", gsup->imsi);
|
||||
@@ -263,6 +346,9 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
|
||||
{
|
||||
struct hlr_subscriber *subscr;
|
||||
struct lu_operation *luop = lu_op_alloc_conn(conn);
|
||||
int i;
|
||||
bool allowed;
|
||||
|
||||
if (!luop) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "LU REQ from conn without addr?\n");
|
||||
return -EINVAL;
|
||||
@@ -288,13 +374,15 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
|
||||
}
|
||||
llist_add(&luop->list, &g_lu_ops);
|
||||
|
||||
subscr_create_on_demand(gsup->imsi);
|
||||
|
||||
/* Roughly follwing "Process Update_Location_HLR" of TS 09.02 */
|
||||
|
||||
/* check if subscriber is known at all */
|
||||
if (!lu_op_fill_subscr(luop, g_hlr->dbc, gsup->imsi)) {
|
||||
/* Send Error back: Subscriber Unknown in HLR */
|
||||
osmo_strlcpy(luop->subscr.imsi, gsup->imsi, sizeof(luop->subscr.imsi));
|
||||
lu_op_tx_error(luop, GMM_CAUSE_IMSI_UNKNOWN);
|
||||
lu_op_tx_error(luop, GMM_CAUSE_ROAMING_NOTALLOWED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -308,6 +396,34 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
allowed = false;
|
||||
LOGP(DAUC, LOGL_DEBUG, "LU: IMSI='%s' on %s sent RAT types: %zu\n", subscr->imsi,
|
||||
gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_CS ? "CS" : "PS", gsup->rat_types_len);
|
||||
for (i = 0; i < gsup->rat_types_len; i++) {
|
||||
enum osmo_rat_type rat = gsup->rat_types[i];
|
||||
if (rat <= 0 || rat >= OSMO_RAT_COUNT) {
|
||||
lu_op_tx_error(luop, GMM_CAUSE_COND_IE_ERR);
|
||||
return 0;
|
||||
}
|
||||
if (luop->subscr.rat_types[rat]) {
|
||||
allowed = true;
|
||||
LOGP(DAUC, LOGL_DEBUG, "LU: IMSI='%s' allowed on %s\n",
|
||||
subscr->imsi, osmo_rat_type_name(rat));
|
||||
} else {
|
||||
LOGP(DAUC, LOGL_DEBUG, "LU: IMSI='%s' not allowed on %s\n",
|
||||
subscr->imsi, osmo_rat_type_name(rat));
|
||||
}
|
||||
}
|
||||
if (!allowed && gsup->rat_types_len > 0) {
|
||||
LOGP(DAUC, LOGL_DEBUG, "ISMI='%s' not allowed on %s%s\n",
|
||||
subscr->imsi, osmo_rat_type_name(gsup->rat_types[0]),
|
||||
gsup->rat_types_len > 1 ? " (nor on the other available RAT types)" : "");
|
||||
lu_op_tx_error(luop, GMM_CAUSE_NO_SUIT_CELL_IN_LA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: Set subscriber tracing = deactive in VLR/SGSN */
|
||||
|
||||
#if 0
|
||||
@@ -325,17 +441,17 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
|
||||
LOGP(DAUC, LOGL_DEBUG, "IMSI='%s': storing %s = %s\n",
|
||||
subscr->imsi, luop->is_ps ? "SGSN number" : "VLR number",
|
||||
osmo_quote_str((const char*)luop->peer, -1));
|
||||
if (db_subscr_lu(g_hlr->dbc, subscr->id, (const char *)luop->peer, luop->is_ps))
|
||||
if (db_subscr_lu(g_hlr->dbc, subscr->id, (const char *)luop->peer, luop->is_ps,
|
||||
gsup->rat_types, gsup->rat_types_len))
|
||||
LOGP(DAUC, LOGL_ERROR, "IMSI='%s': Cannot update %s in the database\n",
|
||||
subscr->imsi, luop->is_ps ? "SGSN number" : "VLR number");
|
||||
|
||||
{
|
||||
/* TODO: Subscriber allowed to roam in PLMN? */
|
||||
/* TODO: Update RoutingInfo */
|
||||
/* TODO: Reset Flag MS Purged (cs/ps) */
|
||||
/* TODO: Control_Tracing_HLR / Control_Tracing_HLR_with_SGSN */
|
||||
lu_op_tx_insert_subscr_data(luop);
|
||||
}
|
||||
/* TODO: Subscriber allowed to roam in PLMN? */
|
||||
/* TODO: Update RoutingInfo */
|
||||
/* TODO: Reset Flag MS Purged (cs/ps) */
|
||||
/* TODO: Control_Tracing_HLR / Control_Tracing_HLR_with_SGSN */
|
||||
lu_op_tx_insert_subscr_data(luop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -379,16 +495,10 @@ static int rx_purge_ms_req(struct osmo_gsup_conn *conn,
|
||||
static int gsup_send_err_reply(struct osmo_gsup_conn *conn, const char *imsi,
|
||||
enum osmo_gsup_message_type type_in, uint8_t err_cause)
|
||||
{
|
||||
int type_err = osmo_gsup_get_err_msg_type(type_in);
|
||||
int type_err = OSMO_GSUP_TO_MSGT_ERROR(type_in);
|
||||
struct osmo_gsup_message gsup_reply = {0};
|
||||
struct msgb *msg_out;
|
||||
|
||||
if (type_err < 0) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "unable to determine error response for %s\n",
|
||||
osmo_gsup_message_type_name(type_in));
|
||||
return type_err;
|
||||
}
|
||||
|
||||
OSMO_STRLCPY_ARRAY(gsup_reply.imsi, imsi);
|
||||
gsup_reply.message_type = type_err;
|
||||
gsup_reply.cause = err_cause;
|
||||
@@ -399,21 +509,166 @@ static int gsup_send_err_reply(struct osmo_gsup_conn *conn, const char *imsi,
|
||||
return osmo_gsup_conn_send(conn, msg_out);
|
||||
}
|
||||
|
||||
static int rx_check_imei_req(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup)
|
||||
{
|
||||
struct osmo_gsup_message gsup_reply = {0};
|
||||
struct msgb *msg_out;
|
||||
char imei[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1] = {0};
|
||||
int rc;
|
||||
|
||||
/* Require IMEI */
|
||||
if (!gsup->imei_enc) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "%s: missing IMEI\n", gsup->imsi);
|
||||
gsup_send_err_reply(conn, gsup->imsi, gsup->message_type, GMM_CAUSE_INV_MAND_INFO);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Decode IMEI (fails if IMEI is too long) */
|
||||
rc = gsm48_decode_bcd_number2(imei, sizeof(imei), gsup->imei_enc, gsup->imei_enc_len, 0);
|
||||
if (rc < 0) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "%s: failed to decode IMEI (rc: %i)\n", gsup->imsi, rc);
|
||||
gsup_send_err_reply(conn, gsup->imsi, gsup->message_type, GMM_CAUSE_INV_MAND_INFO);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if IMEI is too short */
|
||||
if (strlen(imei) != GSM23003_IMEI_NUM_DIGITS_NO_CHK) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "%s: wrong encoded IMEI length (IMEI: '%s', %lu, %i)\n", gsup->imsi, imei,
|
||||
strlen(imei), GSM23003_IMEI_NUM_DIGITS_NO_CHK);
|
||||
gsup_send_err_reply(conn, gsup->imsi, gsup->message_type, GMM_CAUSE_INV_MAND_INFO);
|
||||
return -1;
|
||||
}
|
||||
|
||||
subscr_create_on_demand(gsup->imsi);
|
||||
|
||||
/* Save in DB if desired */
|
||||
if (g_hlr->store_imei) {
|
||||
LOGP(DAUC, LOGL_DEBUG, "IMSI='%s': storing IMEI = %s\n", gsup->imsi, imei);
|
||||
if (db_subscr_update_imei_by_imsi(g_hlr->dbc, gsup->imsi, imei) < 0) {
|
||||
gsup_send_err_reply(conn, gsup->imsi, gsup->message_type, GMM_CAUSE_INV_MAND_INFO);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* Check if subscriber exists and print IMEI */
|
||||
LOGP(DMAIN, LOGL_INFO, "IMSI='%s': has IMEI = %s (consider setting 'store-imei')\n", gsup->imsi, imei);
|
||||
struct hlr_subscriber subscr;
|
||||
if (db_subscr_get_by_imsi(g_hlr->dbc, gsup->imsi, &subscr) < 0) {
|
||||
gsup_send_err_reply(conn, gsup->imsi, gsup->message_type, GMM_CAUSE_INV_MAND_INFO);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Accept all IMEIs */
|
||||
gsup_reply.imei_result = OSMO_GSUP_IMEI_RESULT_ACK;
|
||||
gsup_reply.message_type = OSMO_GSUP_MSGT_CHECK_IMEI_RESULT;
|
||||
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP Check_IMEI response");
|
||||
memcpy(gsup_reply.imsi, gsup->imsi, sizeof(gsup_reply.imsi));
|
||||
osmo_gsup_encode(msg_out, &gsup_reply);
|
||||
return osmo_gsup_conn_send(conn, msg_out);
|
||||
}
|
||||
|
||||
static char namebuf[255];
|
||||
#define LOGP_GSUP_FWD(gsup, level, fmt, args ...) \
|
||||
LOGP(DMAIN, level, "Forward %s (class=%s, IMSI=%s, %s->%s): " fmt, \
|
||||
osmo_gsup_message_type_name(gsup->message_type), \
|
||||
osmo_gsup_message_class_name(gsup->message_class), \
|
||||
gsup->imsi, \
|
||||
osmo_quote_str((const char *)gsup->source_name, gsup->source_name_len), \
|
||||
osmo_quote_str_buf2(namebuf, sizeof(namebuf), (const char *)gsup->destination_name, gsup->destination_name_len), \
|
||||
## args)
|
||||
|
||||
static int read_cb_forward(struct osmo_gsup_conn *conn, struct msgb *msg, const struct osmo_gsup_message *gsup)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct osmo_gsup_message *gsup_err;
|
||||
|
||||
/* FIXME: it would be better if the msgb never were deallocated immediately by osmo_gsup_addr_send(), which a
|
||||
* select-loop volatile talloc context could facilitate. Then we would still be able to access gsup-> members
|
||||
* (pointing into the msgb) even after sending failed, and we wouldn't need to copy this data before sending: */
|
||||
/* Prepare error message (before IEs get deallocated) */
|
||||
gsup_err = talloc_zero(hlr_ctx, struct osmo_gsup_message);
|
||||
OSMO_STRLCPY_ARRAY(gsup_err->imsi, gsup->imsi);
|
||||
gsup_err->message_class = gsup->message_class;
|
||||
gsup_err->destination_name = talloc_memdup(gsup_err, gsup->destination_name, gsup->destination_name_len);
|
||||
gsup_err->destination_name_len = gsup->destination_name_len;
|
||||
gsup_err->message_type = gsup->message_type;
|
||||
gsup_err->session_state = gsup->session_state;
|
||||
gsup_err->session_id = gsup->session_id;
|
||||
gsup_err->source_name = talloc_memdup(gsup_err, gsup->source_name, gsup->source_name_len);
|
||||
gsup_err->source_name_len = gsup->source_name_len;
|
||||
|
||||
/* Check for routing IEs */
|
||||
if (!gsup->source_name || !gsup->source_name_len || !gsup->destination_name || !gsup->destination_name_len) {
|
||||
LOGP_GSUP_FWD(gsup, LOGL_ERROR, "missing routing IEs\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Verify source name (e.g. "MSC-00-00-00-00-00-00") */
|
||||
if (gsup_route_find(conn->server, gsup->source_name, gsup->source_name_len) != conn) {
|
||||
LOGP_GSUP_FWD(gsup, LOGL_ERROR, "mismatching source name\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Forward message without re-encoding (so we don't remove unknown IEs) */
|
||||
LOGP_GSUP_FWD(gsup, LOGL_INFO, "checks passed, forwarding\n");
|
||||
|
||||
/* Remove incoming IPA header to be able to prepend an outgoing IPA header */
|
||||
msgb_pull_to_l2(msg);
|
||||
ret = osmo_gsup_addr_send(g_hlr->gs, gsup->destination_name, gsup->destination_name_len, msg);
|
||||
/* AT THIS POINT, THE msg MAY BE DEALLOCATED and the data like gsup->imsi, gsup->source_name etc may all be
|
||||
* invalid and cause segfaults. */
|
||||
msg = NULL;
|
||||
gsup = NULL;
|
||||
if (ret == -ENODEV)
|
||||
LOGP_GSUP_FWD(gsup_err, LOGL_ERROR, "destination not connected\n");
|
||||
else if (ret)
|
||||
LOGP_GSUP_FWD(gsup_err, LOGL_ERROR, "unknown error %i\n", ret);
|
||||
|
||||
end:
|
||||
/* Send error back to source */
|
||||
if (ret) {
|
||||
struct msgb *msg_err = msgb_alloc_headroom(1024+16, 16, "GSUP forward ERR response");
|
||||
OSMO_ASSERT(msg_err);
|
||||
gsup_err->message_type = OSMO_GSUP_MSGT_E_ROUTING_ERROR;
|
||||
osmo_gsup_encode(msg_err, gsup_err);
|
||||
LOGP_GSUP_FWD(gsup_err, LOGL_NOTICE, "Tx %s\n", osmo_gsup_message_type_name(gsup_err->message_type));
|
||||
osmo_gsup_conn_send(conn, msg_err);
|
||||
}
|
||||
talloc_free(gsup_err);
|
||||
if (msg)
|
||||
msgb_free(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
|
||||
{
|
||||
static struct osmo_gsup_message gsup;
|
||||
int rc;
|
||||
|
||||
if (!msgb_l2(msg) || !msgb_l2len(msg)) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "missing or empty L2 data\n");
|
||||
msgb_free(msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup);
|
||||
if (rc < 0) {
|
||||
LOGP(DMAIN, LOGL_ERROR, "error in GSUP decode: %d\n", rc);
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 3GPP TS 23.003 Section 2.2 clearly states that an IMSI with less than 5
|
||||
* digits is impossible. Even 5 digits is a highly theoretical case */
|
||||
if (strlen(gsup.imsi) < 5)
|
||||
return gsup_send_err_reply(conn, gsup.imsi, gsup.message_type, GMM_CAUSE_INV_MAND_INFO);
|
||||
if (strlen(gsup.imsi) < 5) { /* TODO: move this check to libosmogsm/gsup.c? */
|
||||
LOGP(DMAIN, LOGL_ERROR, "IMSI too short: %s\n", osmo_quote_str(gsup.imsi, -1));
|
||||
gsup_send_err_reply(conn, gsup.imsi, gsup.message_type, GMM_CAUSE_INV_MAND_INFO);
|
||||
msgb_free(msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (gsup.destination_name_len)
|
||||
return read_cb_forward(conn, msg, &gsup);
|
||||
|
||||
switch (gsup.message_type) {
|
||||
/* requests sent to us */
|
||||
@@ -459,6 +714,9 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
|
||||
lu_op_rx_gsup(luop, &gsup);
|
||||
}
|
||||
break;
|
||||
case OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST:
|
||||
rx_check_imei_req(conn, &gsup);
|
||||
break;
|
||||
default:
|
||||
LOGP(DMAIN, LOGL_DEBUG, "Unhandled GSUP message type %s\n",
|
||||
osmo_gsup_message_type_name(gsup.message_type));
|
||||
@@ -494,7 +752,7 @@ static struct {
|
||||
bool db_upgrade;
|
||||
} cmdline_opts = {
|
||||
.config_file = "osmo-hlr.cfg",
|
||||
.db_file = "hlr.db",
|
||||
.db_file = NULL,
|
||||
.daemonize = false,
|
||||
.db_upgrade = false,
|
||||
};
|
||||
@@ -564,13 +822,12 @@ static void handle_options(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
static void *hlr_ctx = NULL;
|
||||
|
||||
static void signal_hdlr(int signal)
|
||||
{
|
||||
switch (signal) {
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
LOGP(DMAIN, LOGL_NOTICE, "Terminating due to SIGINT\n");
|
||||
LOGP(DMAIN, LOGL_NOTICE, "Terminating due to signal=%d\n", signal);
|
||||
quit++;
|
||||
break;
|
||||
case SIGUSR1:
|
||||
@@ -610,6 +867,7 @@ int main(int argc, char **argv)
|
||||
INIT_LLIST_HEAD(&g_hlr->iuse_list);
|
||||
INIT_LLIST_HEAD(&g_hlr->ss_sessions);
|
||||
INIT_LLIST_HEAD(&g_hlr->ussd_routes);
|
||||
g_hlr->db_file_path = talloc_strdup(g_hlr, HLR_DEFAULT_DB_FILE_PATH);
|
||||
|
||||
/* Init default (call independent) SS session guard timeout value */
|
||||
g_hlr->ncss_guard_timeout = NCSS_GUARD_TIMEOUT_DEFAULT;
|
||||
@@ -620,10 +878,11 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
osmo_stats_init(hlr_ctx);
|
||||
vty_init(&vty_info);
|
||||
ctrl_vty_init(hlr_ctx);
|
||||
handle_options(argc, argv);
|
||||
hlr_vty_init(&hlr_log_info);
|
||||
hlr_vty_init();
|
||||
|
||||
rc = vty_read_config_file(cmdline_opts.config_file, NULL);
|
||||
if (rc < 0) {
|
||||
@@ -647,9 +906,12 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
g_hlr->dbc = db_open(hlr_ctx, cmdline_opts.db_file, true, cmdline_opts.db_upgrade);
|
||||
if (cmdline_opts.db_file)
|
||||
osmo_talloc_replace_string(g_hlr, &g_hlr->db_file_path, cmdline_opts.db_file);
|
||||
|
||||
g_hlr->dbc = db_open(hlr_ctx, g_hlr->db_file_path, true, cmdline_opts.db_upgrade);
|
||||
if (!g_hlr->dbc) {
|
||||
LOGP(DMAIN, LOGL_FATAL, "Error opening database\n");
|
||||
LOGP(DMAIN, LOGL_FATAL, "Error opening database %s\n", osmo_quote_str(g_hlr->db_file_path, -1));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -665,6 +927,7 @@ int main(int argc, char **argv)
|
||||
|
||||
osmo_init_ignore_signals();
|
||||
signal(SIGINT, &signal_hdlr);
|
||||
signal(SIGTERM, &signal_hdlr);
|
||||
signal(SIGUSR1, &signal_hdlr);
|
||||
|
||||
if (cmdline_opts.daemonize) {
|
||||
|
||||
10
src/hlr.h
10
src/hlr.h
@@ -25,6 +25,8 @@
|
||||
#include <stdbool.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
|
||||
#define HLR_DEFAULT_DB_FILE_PATH "hlr.db"
|
||||
|
||||
struct hlr_euse;
|
||||
|
||||
struct hlr {
|
||||
@@ -32,6 +34,7 @@ struct hlr {
|
||||
struct osmo_gsup_server *gs;
|
||||
|
||||
/* DB context */
|
||||
char *db_file_path;
|
||||
struct db_context *dbc;
|
||||
|
||||
/* Control Interface */
|
||||
@@ -51,6 +54,13 @@ struct hlr {
|
||||
struct llist_head ussd_routes;
|
||||
|
||||
struct llist_head ss_sessions;
|
||||
|
||||
bool store_imei;
|
||||
|
||||
bool subscr_create_on_demand;
|
||||
/* Bitmask of DB_SUBSCR_FLAG_* */
|
||||
uint8_t subscr_create_on_demand_flags;
|
||||
unsigned int subscr_create_on_demand_rand_msisdn_len;
|
||||
};
|
||||
|
||||
extern struct hlr *g_hlr;
|
||||
|
||||
@@ -302,7 +302,7 @@ void import_nitb_subscr(sqlite3 *nitb_db, sqlite3_stmt *stmt)
|
||||
|
||||
snprintf(imsi_str, sizeof(imsi_str), "%" PRId64, imsi);
|
||||
|
||||
rc = db_subscr_create(dbc, imsi_str);
|
||||
rc = db_subscr_create(dbc, imsi_str, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS);
|
||||
if (rc < 0) {
|
||||
LOGP(DDB, LOGL_ERROR, "OsmoNITB DB import to %s: failed to create IMSI %s: %d: %s\n",
|
||||
dbc->fname,
|
||||
|
||||
251
src/hlr_ussd.c
251
src/hlr_ussd.c
@@ -34,6 +34,7 @@
|
||||
#include "gsup_server.h"
|
||||
#include "gsup_router.h"
|
||||
#include "logging.h"
|
||||
#include "db.h"
|
||||
|
||||
/***********************************************************************
|
||||
* core data structures expressing config from VTY
|
||||
@@ -149,7 +150,7 @@ struct ss_session {
|
||||
/* link us to hlr->ss_sessions */
|
||||
struct llist_head list;
|
||||
/* imsi of this session */
|
||||
char imsi[GSM23003_IMSI_MAX_DIGITS+2];
|
||||
char imsi[OSMO_IMSI_BUF_SIZE];
|
||||
/* ID of this session (unique per IMSI) */
|
||||
uint32_t session_id;
|
||||
/* state of the session */
|
||||
@@ -166,6 +167,12 @@ struct ss_session {
|
||||
const struct hlr_iuse *iuse;
|
||||
} u;
|
||||
|
||||
/* subscriber's vlr_number
|
||||
* MO USSD: originating MSC's vlr_number
|
||||
* MT USSD: looked up once per session and cached here */
|
||||
uint8_t *vlr_number;
|
||||
size_t vlr_number_len;
|
||||
|
||||
/* we don't keep a pointer to the osmo_gsup_{route,conn} towards the MSC/VLR here,
|
||||
* as this might change during inter-VLR hand-over, and we simply look-up the serving MSC/VLR
|
||||
* every time we receive an USSD component from the EUSE */
|
||||
@@ -222,6 +229,35 @@ struct ss_session *ss_session_alloc(struct hlr *hlr, const char *imsi, uint32_t
|
||||
* handling functions for encoding SS messages + wrapping them in GSUP
|
||||
***********************************************************************/
|
||||
|
||||
/* Resolve the target MSC by ss->imsi and send GSUP message. */
|
||||
static int ss_gsup_send(struct ss_session *ss, struct osmo_gsup_server *gs, struct msgb *msg)
|
||||
{
|
||||
struct hlr_subscriber subscr = {};
|
||||
int rc;
|
||||
|
||||
/* Use vlr_number as looked up by the caller, or look up now. */
|
||||
if (!ss->vlr_number) {
|
||||
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||
if (rc < 0) {
|
||||
LOGPSS(ss, LOGL_ERROR, "Cannot find subscriber, cannot route GSUP message\n");
|
||||
msgb_free(msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
ss->vlr_number = (uint8_t *)talloc_strdup(ss, subscr.vlr_number);
|
||||
ss->vlr_number_len = strlen(subscr.vlr_number) + 1;
|
||||
}
|
||||
|
||||
/* Check for empty string (all vlr_number strings end in "\0", because otherwise gsup_route_find() fails) */
|
||||
if (ss->vlr_number_len == 1) {
|
||||
LOGPSS(ss, LOGL_ERROR, "Cannot send GSUP message, no VLR number stored for subscriber\n");
|
||||
msgb_free(msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOGPSS(ss, LOGL_DEBUG, "Tx SS/USSD to VLR %s\n", osmo_quote_str((char *)ss->vlr_number, ss->vlr_number_len));
|
||||
return osmo_gsup_addr_send(gs, ss->vlr_number, ss->vlr_number_len, msg);
|
||||
}
|
||||
|
||||
static int ss_tx_to_ms(struct ss_session *ss, enum osmo_gsup_message_type gsup_msg_type,
|
||||
bool final, struct msgb *ss_msg)
|
||||
|
||||
@@ -241,13 +277,12 @@ static int ss_tx_to_ms(struct ss_session *ss, enum osmo_gsup_message_type gsup_m
|
||||
resp.ss_info_len = msgb_length(ss_msg);
|
||||
}
|
||||
|
||||
resp_msg = gsm0480_msgb_alloc_name(__func__);
|
||||
resp_msg = msgb_alloc_headroom(4000, 64, __func__);
|
||||
OSMO_ASSERT(resp_msg);
|
||||
osmo_gsup_encode(resp_msg, &resp);
|
||||
msgb_free(ss_msg);
|
||||
|
||||
/* FIXME: resolve this based on the database vlr_addr */
|
||||
return osmo_gsup_addr_send(g_hlr->gs, (uint8_t *)"MSC-00-00-00-00-00-00", 22, resp_msg);
|
||||
return ss_gsup_send(ss, g_hlr->gs, resp_msg);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -301,11 +336,11 @@ static int handle_ussd_own_msisdn(struct osmo_gsup_conn *conn, struct ss_session
|
||||
ss_tx_ussd_7bit(ss, true, req->invoke_id, buf);
|
||||
break;
|
||||
case -ENOENT:
|
||||
ss_tx_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||
ss_tx_error(ss, req->invoke_id, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||
break;
|
||||
case -EIO:
|
||||
default:
|
||||
ss_tx_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||
ss_tx_error(ss, req->invoke_id, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@@ -320,6 +355,150 @@ static int handle_ussd_own_imsi(struct osmo_gsup_conn *conn, struct ss_session *
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_ussd_get_ran(struct osmo_gsup_conn *conn, struct ss_session *ss,
|
||||
const struct osmo_gsup_message *gsup,
|
||||
const struct ss_request *req)
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
char response[512];
|
||||
int rc;
|
||||
const char *rat;
|
||||
|
||||
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
if (!*subscr.last_lu_rat)
|
||||
rat = "nothing, you don't exist";
|
||||
else if (!strcmp(subscr.last_lu_rat, "GERAN-A"))
|
||||
rat = "2G";
|
||||
else if (!strcmp(subscr.last_lu_rat, "UTRAN-Iu"))
|
||||
rat = "3G";
|
||||
else
|
||||
rat = subscr.last_lu_rat;
|
||||
|
||||
snprintf(response, sizeof(response),
|
||||
"Now on %s. Available:%s%s.",
|
||||
rat,
|
||||
subscr.rat_types[OSMO_RAT_GERAN_A]? " 2G" : "",
|
||||
subscr.rat_types[OSMO_RAT_UTRAN_IU]? " 3G" : "");
|
||||
|
||||
rc = ss_tx_ussd_7bit(ss, true, req->invoke_id, response);
|
||||
break;
|
||||
case -ENOENT:
|
||||
rc = ss_tx_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||
break;
|
||||
case -EIO:
|
||||
default:
|
||||
rc = ss_tx_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int handle_ussd_gsm_on(struct osmo_gsup_conn *conn, 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_ussd_7bit(ss, true, req->invoke_id,
|
||||
"Enabled GERAN-A (2G)");
|
||||
break;
|
||||
case -ENOENT:
|
||||
rc = ss_tx_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||
break;
|
||||
case -EIO:
|
||||
default:
|
||||
rc = ss_tx_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int handle_ussd_gsm_off(struct osmo_gsup_conn *conn, 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_ussd_7bit(ss, true, req->invoke_id,
|
||||
"Disabled GERAN-A (2G)");
|
||||
break;
|
||||
case -ENOENT:
|
||||
rc = ss_tx_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||
break;
|
||||
case -EIO:
|
||||
default:
|
||||
rc = ss_tx_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int handle_ussd_umts_on(struct osmo_gsup_conn *conn, 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_ussd_7bit(ss, true, req->invoke_id,
|
||||
"Enabled UTRAN-Iu (3G)");
|
||||
break;
|
||||
case -ENOENT:
|
||||
rc = ss_tx_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||
break;
|
||||
case -EIO:
|
||||
default:
|
||||
rc = ss_tx_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int handle_ussd_umts_off(struct osmo_gsup_conn *conn, 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_ussd_7bit(ss, true, req->invoke_id,
|
||||
"Disabled UTRAN-Iu (3G)");
|
||||
break;
|
||||
case -ENOENT:
|
||||
rc = ss_tx_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
|
||||
break;
|
||||
case -EIO:
|
||||
default:
|
||||
rc = ss_tx_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct hlr_iuse hlr_iuses[] = {
|
||||
{
|
||||
@@ -330,6 +509,26 @@ static const struct hlr_iuse hlr_iuses[] = {
|
||||
.name = "own-imsi",
|
||||
.handle_ussd = handle_ussd_own_imsi,
|
||||
},
|
||||
{
|
||||
.name = "get-ran",
|
||||
.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,
|
||||
},
|
||||
};
|
||||
|
||||
const struct hlr_iuse *iuse_find(const char *name)
|
||||
@@ -433,8 +632,7 @@ static int handle_ussd(struct osmo_gsup_conn *conn, struct ss_session *ss,
|
||||
OSMO_ASSERT(msg_out);
|
||||
/* Received from EUSE, Forward to VLR */
|
||||
osmo_gsup_encode(msg_out, gsup);
|
||||
/* FIXME: resolve this based on the database vlr_addr */
|
||||
osmo_gsup_addr_send(conn->server, (uint8_t *)"MSC-00-00-00-00-00-00", 22, msg_out);
|
||||
ss_gsup_send(ss, conn->server, msg_out);
|
||||
} else {
|
||||
/* Received from VLR (MS) */
|
||||
if (ss->is_external) {
|
||||
@@ -471,6 +669,7 @@ int rx_proc_ss_req(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *
|
||||
struct hlr *hlr = conn->server->priv;
|
||||
struct ss_session *ss;
|
||||
struct ss_request req = {0};
|
||||
struct gsup_route *gsup_rt;
|
||||
|
||||
LOGP(DSS, LOGL_DEBUG, "%s/0x%08x: Process SS (%s)\n", gsup->imsi, gsup->session_id,
|
||||
osmo_gsup_session_state_name(gsup->session_state));
|
||||
@@ -484,6 +683,11 @@ int rx_proc_ss_req(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *
|
||||
/* FIXME: Send a Reject component? */
|
||||
goto out_err;
|
||||
}
|
||||
} else if (gsup->session_state != OSMO_GSUP_SESSION_STATE_END) {
|
||||
LOGP(DSS, LOGL_ERROR, "%s/0x%082x: Missing SS payload for '%s'\n",
|
||||
gsup->imsi, gsup->session_id,
|
||||
osmo_gsup_session_state_name(gsup->session_state));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
switch (gsup->session_state) {
|
||||
@@ -500,6 +704,20 @@ int rx_proc_ss_req(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *
|
||||
gsup->imsi, gsup->session_id);
|
||||
goto out_err;
|
||||
}
|
||||
/* Get IPA name from VLR conn and save as ss->vlr_number */
|
||||
if (!conn_is_euse(conn)) {
|
||||
gsup_rt = gsup_route_find_by_conn(conn);
|
||||
if (gsup_rt) {
|
||||
ss->vlr_number = (uint8_t *)talloc_strdup(ss, (const char *)gsup_rt->addr);
|
||||
ss->vlr_number_len = strlen((const char *)gsup_rt->addr) + 1;
|
||||
LOGPSS(ss, LOGL_DEBUG, "Destination IPA name retrieved from GSUP route: %s\n",
|
||||
osmo_quote_str((const char *)ss->vlr_number, ss->vlr_number_len));
|
||||
} else {
|
||||
LOGPSS(ss, LOGL_NOTICE, "Could not find GSUP route, therefore can't set the destination"
|
||||
" IPA name. We'll try to look it up later, but this should not"
|
||||
" have happened.\n");
|
||||
}
|
||||
}
|
||||
if (ss_op_is_ussd(req.opcode)) {
|
||||
if (conn_is_euse(conn)) {
|
||||
/* EUSE->VLR: MT USSD. EUSE is known ('conn'), VLR is to be resolved */
|
||||
@@ -557,13 +775,18 @@ int rx_proc_ss_req(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *
|
||||
gsup->imsi, gsup->session_id);
|
||||
goto out_err;
|
||||
}
|
||||
if (ss_op_is_ussd(req.opcode)) {
|
||||
/* dispatch unstructured SS to routing */
|
||||
handle_ussd(conn, ss, gsup, &req);
|
||||
} else {
|
||||
/* dispatch non-call SS to internal code */
|
||||
handle_ss(ss, gsup, &req);
|
||||
|
||||
/* SS payload is optional for END */
|
||||
if (gsup->ss_info && gsup->ss_info_len) {
|
||||
if (ss_op_is_ussd(req.opcode)) {
|
||||
/* dispatch unstructured SS to routing */
|
||||
handle_ussd(conn, ss, gsup, &req);
|
||||
} else {
|
||||
/* dispatch non-call SS to internal code */
|
||||
handle_ss(ss, gsup, &req);
|
||||
}
|
||||
}
|
||||
|
||||
ss_session_free(ss);
|
||||
break;
|
||||
default:
|
||||
|
||||
103
src/hlr_vty.c
103
src/hlr_vty.c
@@ -27,11 +27,13 @@
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/vty/vty.h>
|
||||
#include <osmocom/vty/stats.h>
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/logging.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
#include <osmocom/abis/ipa.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "hlr.h"
|
||||
#include "hlr_vty.h"
|
||||
#include "hlr_vty_subscr.h"
|
||||
@@ -71,6 +73,27 @@ DEFUN(cfg_gsup,
|
||||
static int config_write_hlr(struct vty *vty)
|
||||
{
|
||||
vty_out(vty, "hlr%s", VTY_NEWLINE);
|
||||
if (g_hlr->store_imei)
|
||||
vty_out(vty, " store-imei%s", VTY_NEWLINE);
|
||||
if (g_hlr->db_file_path && strcmp(g_hlr->db_file_path, HLR_DEFAULT_DB_FILE_PATH))
|
||||
vty_out(vty, " database %s%s", g_hlr->db_file_path, VTY_NEWLINE);
|
||||
if (g_hlr->subscr_create_on_demand) {
|
||||
const char *flags_str = "none";
|
||||
uint8_t flags = g_hlr->subscr_create_on_demand_flags;
|
||||
unsigned int rand_msisdn_len = g_hlr->subscr_create_on_demand_rand_msisdn_len;
|
||||
|
||||
if ((flags & DB_SUBSCR_FLAG_NAM_CS) && (flags & DB_SUBSCR_FLAG_NAM_PS))
|
||||
flags_str = "cs+ps";
|
||||
else if (flags & DB_SUBSCR_FLAG_NAM_CS)
|
||||
flags_str = "cs";
|
||||
else if (flags & DB_SUBSCR_FLAG_NAM_PS)
|
||||
flags_str = "ps";
|
||||
|
||||
if (rand_msisdn_len)
|
||||
vty_out(vty, " subscriber-create-on-demand %i %s%s", rand_msisdn_len, flags_str, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " subscriber-create-on-demand no-msisdn %s%s", flags_str, VTY_NEWLINE);
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -133,10 +156,13 @@ DEFUN(cfg_hlr_gsup_bind_ip,
|
||||
#define UROUTE_STR "Routing Configuration\n"
|
||||
#define PREFIX_STR "Prefix-Matching Route\n" "USSD Prefix\n"
|
||||
|
||||
#define INT_CHOICE "(own-msisdn|own-imsi)"
|
||||
#define INT_CHOICE "(own-msisdn|own-imsi|get-ran|gsm-on|gsm-off|umts-on|umts-off)"
|
||||
#define INT_STR "Internal USSD Handler\n" \
|
||||
"Respond with subscribers' own MSISDN\n" \
|
||||
"Respond with subscribers' own IMSI\n"
|
||||
"Respond with subscribers' own IMSI\n" \
|
||||
"Respond with available RAN types\n" \
|
||||
"Enable UMTS service\n" \
|
||||
"Disable UMTS service\n"
|
||||
|
||||
#define EXT_STR "External USSD Handler\n" \
|
||||
"Name of External USSD Handler (IPA CCM ID)\n"
|
||||
@@ -221,6 +247,15 @@ DEFUN(cfg_ussd_no_defaultroute, cfg_ussd_no_defaultroute_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_database, cfg_database_cmd,
|
||||
"database PATH",
|
||||
"Set the path to the HLR database file\n"
|
||||
"Relative or absolute file system path to the database file (default is '" HLR_DEFAULT_DB_FILE_PATH "')\n")
|
||||
{
|
||||
osmo_talloc_replace_string(g_hlr, &g_hlr->db_file_path, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
struct cmd_node euse_node = {
|
||||
EUSE_NODE,
|
||||
"%s(config-hlr-euse)# ",
|
||||
@@ -305,6 +340,59 @@ DEFUN(cfg_ncss_guard_timeout, cfg_ncss_guard_timeout_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_store_imei, cfg_store_imei_cmd,
|
||||
"store-imei",
|
||||
"Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send"
|
||||
" Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').")
|
||||
{
|
||||
g_hlr->store_imei = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_store_imei, cfg_no_store_imei_cmd,
|
||||
"no store-imei",
|
||||
"Do not save the IMEI in the database, when receiving Check IMEI requests.")
|
||||
{
|
||||
g_hlr->store_imei = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_subscr_create_on_demand, cfg_subscr_create_on_demand_cmd,
|
||||
"subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)",
|
||||
"Make a new record when a subscriber is first seen.\n"
|
||||
"Do not automatically assign MSISDN.\n"
|
||||
"Length of an automatically assigned MSISDN.\n"
|
||||
"Do not allow any NAM (Network Access Mode) by default.\n"
|
||||
"Allow access to circuit switched NAM by default.\n"
|
||||
"Allow access to packet switched NAM by default.\n"
|
||||
"Allow access to circuit and packet switched NAM by default.\n")
|
||||
{
|
||||
unsigned int rand_msisdn_len = 0;
|
||||
uint8_t flags = 0x00;
|
||||
|
||||
if (strcmp(argv[0], "no-msisdn") != 0)
|
||||
rand_msisdn_len = atoi(argv[0]);
|
||||
|
||||
if (strstr(argv[1], "cs"))
|
||||
flags |= DB_SUBSCR_FLAG_NAM_CS;
|
||||
if (strstr(argv[1], "ps"))
|
||||
flags |= DB_SUBSCR_FLAG_NAM_PS;
|
||||
|
||||
g_hlr->subscr_create_on_demand = true;
|
||||
g_hlr->subscr_create_on_demand_rand_msisdn_len = rand_msisdn_len;
|
||||
g_hlr->subscr_create_on_demand_flags = flags;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_subscr_create_on_demand, cfg_no_subscr_create_on_demand_cmd,
|
||||
"no subscriber-create-on-demand",
|
||||
"Do not make a new record when a subscriber is first seen.\n")
|
||||
{
|
||||
g_hlr->subscr_create_on_demand = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Common Code
|
||||
***********************************************************************/
|
||||
@@ -344,10 +432,11 @@ int hlr_vty_is_config_node(struct vty *vty, int node)
|
||||
}
|
||||
}
|
||||
|
||||
void hlr_vty_init(const struct log_info *cat)
|
||||
void hlr_vty_init(void)
|
||||
{
|
||||
logging_vty_add_cmds(cat);
|
||||
logging_vty_add_cmds();
|
||||
osmo_talloc_vty_add_cmds();
|
||||
osmo_stats_vty_add_cmds();
|
||||
|
||||
install_element_ve(&show_gsup_conn_cmd);
|
||||
|
||||
@@ -359,6 +448,8 @@ void hlr_vty_init(const struct log_info *cat)
|
||||
|
||||
install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
|
||||
|
||||
install_element(HLR_NODE, &cfg_database_cmd);
|
||||
|
||||
install_element(HLR_NODE, &cfg_euse_cmd);
|
||||
install_element(HLR_NODE, &cfg_no_euse_cmd);
|
||||
install_node(&euse_node, config_write_euse);
|
||||
@@ -368,6 +459,10 @@ void hlr_vty_init(const struct log_info *cat)
|
||||
install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
|
||||
install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd);
|
||||
install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd);
|
||||
install_element(HLR_NODE, &cfg_store_imei_cmd);
|
||||
install_element(HLR_NODE, &cfg_no_store_imei_cmd);
|
||||
install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd);
|
||||
install_element(HLR_NODE, &cfg_no_subscr_create_on_demand_cmd);
|
||||
|
||||
hlr_vty_subscriber_init();
|
||||
}
|
||||
|
||||
@@ -35,4 +35,4 @@ enum hlr_vty_node {
|
||||
|
||||
int hlr_vty_is_config_node(struct vty *vty, int node);
|
||||
int hlr_vty_go_parent(struct vty *vty);
|
||||
void hlr_vty_init(const struct log_info *cat);
|
||||
void hlr_vty_init(void);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <osmocom/vty/vty.h>
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
|
||||
#include "hlr.h"
|
||||
#include "db.h"
|
||||
@@ -35,29 +36,37 @@ struct vty;
|
||||
|
||||
#define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
|
||||
|
||||
static char *
|
||||
get_datestr(const time_t *t, char *datebuf)
|
||||
static char *get_datestr(const time_t *t)
|
||||
{
|
||||
char *p, *s = ctime_r(t, datebuf);
|
||||
static char buf[32];
|
||||
struct tm tm;
|
||||
|
||||
/* Strip trailing newline. */
|
||||
p = strchr(s, '\n');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
return s;
|
||||
tm = *gmtime(t);
|
||||
|
||||
strftime(buf, sizeof(buf), "%FT%T+00:00", &tm);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
||||
{
|
||||
int rc;
|
||||
int i;
|
||||
struct osmo_sub_auth_data aud2g;
|
||||
struct osmo_sub_auth_data aud3g;
|
||||
char datebuf[26]; /* for ctime_r(3) */
|
||||
|
||||
vty_out(vty, " ID: %"PRIu64"%s", subscr->id, VTY_NEWLINE);
|
||||
|
||||
vty_out(vty, " IMSI: %s%s", *subscr->imsi ? subscr->imsi : "none", VTY_NEWLINE);
|
||||
vty_out(vty, " MSISDN: %s%s", *subscr->msisdn ? subscr->msisdn : "none", VTY_NEWLINE);
|
||||
|
||||
if (*subscr->imei) {
|
||||
char checksum = osmo_luhn(subscr->imei, 14);
|
||||
if (checksum == -EINVAL)
|
||||
vty_out(vty, " IMEI: %s (INVALID LENGTH!)%s", subscr->imei, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " IMEI: %s%c%s", subscr->imei, checksum, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
if (*subscr->vlr_number)
|
||||
vty_out(vty, " VLR number: %s%s", subscr->vlr_number, VTY_NEWLINE);
|
||||
if (*subscr->sgsn_number)
|
||||
@@ -79,7 +88,15 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
||||
if (subscr->ms_purged_ps)
|
||||
vty_out(vty, " PS purged%s", VTY_NEWLINE);
|
||||
if (subscr->last_lu_seen)
|
||||
vty_out(vty, " last LU seen: %s UTC%s", get_datestr(&subscr->last_lu_seen, datebuf), VTY_NEWLINE);
|
||||
vty_out(vty, " last LU seen: %s%s", get_datestr(&subscr->last_lu_seen), VTY_NEWLINE);
|
||||
if (subscr->last_lu_rat[0])
|
||||
vty_out(vty, " last LU RAT: %s%s", subscr->last_lu_rat, VTY_NEWLINE);
|
||||
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->ms_purged_cs)
|
||||
vty_out(vty, " CS purged%s", VTY_NEWLINE);
|
||||
|
||||
if (!*subscr->imsi)
|
||||
return;
|
||||
@@ -131,6 +148,7 @@ static void subscr_dump_full_vty(struct vty *vty, 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];
|
||||
int rc = -1;
|
||||
if (strcmp(type, "imsi") == 0)
|
||||
rc = db_subscr_get_by_imsi(g_hlr->dbc, id, subscr);
|
||||
@@ -138,6 +156,17 @@ static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id,
|
||||
rc = db_subscr_get_by_msisdn(g_hlr->dbc, id, subscr);
|
||||
else if (strcmp(type, "id") == 0)
|
||||
rc = db_subscr_get_by_id(g_hlr->dbc, atoll(id), subscr);
|
||||
else if (strcmp(type, "imei") == 0) {
|
||||
/* Verify IMEI with checksum digit */
|
||||
if (osmo_imei_str_valid(id, true)) {
|
||||
/* Cut the checksum off */
|
||||
osmo_strlcpy(imei_buf, id, sizeof(imei_buf));
|
||||
id = imei_buf;
|
||||
vty_out(vty, "%% Checksum validated and stripped for search: imei = '%s'%s", id,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
rc = db_subscr_get_by_imei(g_hlr->dbc, id, subscr);
|
||||
}
|
||||
if (rc)
|
||||
vty_out(vty, "%% No subscriber for %s = '%s'%s",
|
||||
type, id, VTY_NEWLINE);
|
||||
@@ -147,12 +176,13 @@ static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id,
|
||||
#define SUBSCR_CMD "subscriber "
|
||||
#define SUBSCR_CMD_HELP "Subscriber management commands\n"
|
||||
|
||||
#define SUBSCR_ID "(imsi|msisdn|id) IDENT"
|
||||
#define SUBSCR_ID "(imsi|msisdn|id|imei) IDENT"
|
||||
#define SUBSCR_ID_HELP \
|
||||
"Identify subscriber by IMSI\n" \
|
||||
"Identify subscriber by MSISDN (phone number)\n" \
|
||||
"Identify subscriber by database ID\n" \
|
||||
"IMSI/MSISDN/ID of the subscriber\n"
|
||||
"Identify subscriber by IMEI\n" \
|
||||
"IMSI/MSISDN/ID/IMEI of the subscriber\n"
|
||||
|
||||
#define SUBSCR SUBSCR_CMD SUBSCR_ID " "
|
||||
#define SUBSCR_HELP SUBSCR_CMD_HELP SUBSCR_ID_HELP
|
||||
@@ -198,7 +228,7 @@ DEFUN(subscriber_create,
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
rc = db_subscr_create(g_hlr->dbc, imsi);
|
||||
rc = db_subscr_create(g_hlr->dbc, imsi, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS);
|
||||
|
||||
if (rc) {
|
||||
if (rc == -EEXIST)
|
||||
@@ -508,6 +538,122 @@ DEFUN(subscriber_aud3g,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(subscriber_imei,
|
||||
subscriber_imei_cmd,
|
||||
SUBSCR_UPDATE "imei (none|IMEI)",
|
||||
SUBSCR_UPDATE_HELP
|
||||
"Set IMEI of the subscriber (normally populated from MSC, no need to set this manually)\n"
|
||||
"Forget IMEI\n"
|
||||
"Set IMEI (use for debug only!)\n")
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
const char *id_type = argv[0];
|
||||
const char *id = argv[1];
|
||||
const char *imei = argv[2];
|
||||
char imei_buf[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1];
|
||||
|
||||
if (strcmp(imei, "none") == 0)
|
||||
imei = NULL;
|
||||
else {
|
||||
/* Verify IMEI with checksum digit */
|
||||
if (osmo_imei_str_valid(imei, true)) {
|
||||
/* Cut the checksum off */
|
||||
osmo_strlcpy(imei_buf, imei, sizeof(imei_buf));
|
||||
imei = imei_buf;
|
||||
} else if (!osmo_imei_str_valid(imei, false)) {
|
||||
vty_out(vty, "%% IMEI invalid: '%s'%s", imei, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
if (get_subscr_by_argv(vty, id_type, id, &subscr))
|
||||
return CMD_WARNING;
|
||||
|
||||
if (db_subscr_update_imei_by_imsi(g_hlr->dbc, subscr.imsi, imei)) {
|
||||
vty_out(vty, "%% Error: cannot update IMEI for subscriber IMSI='%s'%s",
|
||||
subscr.imsi, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (imei)
|
||||
vty_out(vty, "%% Updated subscriber IMSI='%s' to IMEI='%s'%s",
|
||||
subscr.imsi, imei, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, "%% Updated subscriber IMSI='%s': removed IMEI%s",
|
||||
subscr.imsi, VTY_NEWLINE);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(subscriber_nam,
|
||||
subscriber_nam_cmd,
|
||||
SUBSCR_UPDATE "network-access-mode (none|cs|ps|cs+ps)",
|
||||
SUBSCR_UPDATE_HELP
|
||||
"Set Network Access Mode (NAM) of the subscriber\n"
|
||||
"Do not allow access to circuit switched or packet switched services\n"
|
||||
"Allow access to circuit switched services only\n"
|
||||
"Allow access to packet switched services only\n"
|
||||
"Allow access to both circuit and packet switched services\n")
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
const char *id_type = argv[0];
|
||||
const char *id = argv[1];
|
||||
bool nam_cs = strstr(argv[2], "cs");
|
||||
bool nam_ps = strstr(argv[2], "ps");
|
||||
|
||||
if (get_subscr_by_argv(vty, id_type, id, &subscr))
|
||||
return CMD_WARNING;
|
||||
|
||||
if (nam_cs != subscr.nam_cs)
|
||||
hlr_subscr_nam(g_hlr, &subscr, nam_cs, 0);
|
||||
if (nam_ps != subscr.nam_ps)
|
||||
hlr_subscr_nam(g_hlr, &subscr, nam_ps, 1);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DEFUN(subscriber_rat,
|
||||
subscriber_rat_cmd,
|
||||
SUBSCR_UPDATE "rat (geran-a|utran-iu) (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"
|
||||
"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") == 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)
|
||||
{
|
||||
install_element_ve(&subscriber_show_cmd);
|
||||
@@ -519,4 +665,7 @@ void hlr_vty_subscriber_init(void)
|
||||
install_element(ENABLE_NODE, &subscriber_aud2g_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_no_aud3g_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_aud3g_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_imei_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_nam_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_rat_cmd);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,9 @@ struct lu_operation {
|
||||
enum lu_state state;
|
||||
/*! CS (false) or PS (true) Location Update? */
|
||||
bool is_ps;
|
||||
/*! RAT type indicator: coming in on GERAN-A? UTRAN-Iu? */
|
||||
enum osmo_rat_type via_rat;
|
||||
|
||||
/*! currently running timer */
|
||||
struct osmo_timer_list timer;
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@ VTY_TEST_DB = hlr_vty_test.db
|
||||
# make vty-test U=-u
|
||||
vty-test:
|
||||
-rm -f $(VTY_TEST_DB)
|
||||
sqlite3 $(VTY_TEST_DB) < $(top_srcdir)/sql/hlr.sql
|
||||
sqlite3 $(VTY_TEST_DB) < $(srcdir)/test_subscriber.vty.sql
|
||||
osmo_verify_transcript_vty.py -v \
|
||||
-n OsmoHLR -p 4258 \
|
||||
-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l $(VTY_TEST_DB)" \
|
||||
|
||||
@@ -13,6 +13,7 @@ AM_CFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
-no-install \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
||||
@@ -10,6 +10,10 @@ AM_CFLAGS = \
|
||||
$(SQLITE3_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
-no-install \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
db_test.ok \
|
||||
db_test.err \
|
||||
@@ -22,16 +26,20 @@ db_test_SOURCES = \
|
||||
$(NULL)
|
||||
|
||||
db_test_LDADD = \
|
||||
$(top_srcdir)/src/db.c \
|
||||
$(top_srcdir)/src/db_hlr.c \
|
||||
$(top_srcdir)/src/db_auc.c \
|
||||
$(top_srcdir)/src/logging.c \
|
||||
$(top_builddir)/src/logging.o \
|
||||
$(top_builddir)/src/db_auc.o \
|
||||
$(top_builddir)/src/db_hlr.o \
|
||||
$(top_builddir)/src/db.o \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(SQLITE3_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
if DB_SQLITE_DEBUG
|
||||
db_test_LDADD += $(top_builddir)/src/db_debug.o
|
||||
endif
|
||||
|
||||
.PHONY: db_test.db update_exp manual manual-nonverbose manual-gdb
|
||||
db_test.db:
|
||||
rm -f db_test.db
|
||||
|
||||
@@ -51,7 +51,12 @@ static void _fill_invalid(void *dest, size_t size)
|
||||
* The return code is then available in g_rc. */
|
||||
#define ASSERT_RC(call, expect_rc) \
|
||||
do { \
|
||||
fprintf(stderr, #call " --> " #expect_rc "\n"); \
|
||||
if ((expect_rc) == -ENOKEY) \
|
||||
fprintf(stderr, #call " --> -ENOKEY\n"); \
|
||||
else if ((expect_rc) == -ENOTSUP) \
|
||||
fprintf(stderr, #call " --> -ENOTSUP\n"); \
|
||||
else \
|
||||
fprintf(stderr, #call " --> " #expect_rc "\n"); \
|
||||
g_rc = call; \
|
||||
if (g_rc != (expect_rc)) \
|
||||
fprintf(stderr, " MISMATCH: got rc = %d, expected: " \
|
||||
@@ -67,7 +72,12 @@ static void _fill_invalid(void *dest, size_t size)
|
||||
do { \
|
||||
int rc; \
|
||||
fill_invalid(g_subscr); \
|
||||
fprintf(stderr, "db_subscr_get_by_" #by "(dbc, " #val ", &g_subscr) --> " \
|
||||
if ((expect_rc) == -ENOKEY) \
|
||||
fprintf(stderr, "db_subscr_get_by_" #by "(dbc, " #val ", &g_subscr) --> -ENOKEY \n"); \
|
||||
else if ((expect_rc) == -ENOTSUP) \
|
||||
fprintf(stderr, "db_subscr_get_by_" #by "(dbc, " #val ", &g_subscr) --> -ENOTSUP \n"); \
|
||||
else \
|
||||
fprintf(stderr, "db_subscr_get_by_" #by "(dbc, " #val ", &g_subscr) --> " \
|
||||
#expect_rc "\n"); \
|
||||
rc = db_subscr_get_by_##by(dbc, val, &g_subscr); \
|
||||
if (rc != (expect_rc)) \
|
||||
@@ -148,6 +158,7 @@ void dump_subscr(struct hlr_subscriber *subscr)
|
||||
Pd(id);
|
||||
Ps(imsi);
|
||||
Ps(msisdn);
|
||||
Ps(imei);
|
||||
Ps(vlr_number);
|
||||
Ps(sgsn_number);
|
||||
Ps(sgsn_address);
|
||||
@@ -159,6 +170,7 @@ void dump_subscr(struct hlr_subscriber *subscr)
|
||||
Pfo(lmsi, "0x%x", subscr);
|
||||
Pb(true, ms_purged_cs);
|
||||
Pb(true, ms_purged_ps);
|
||||
Ps(last_lu_rat);
|
||||
fprintf(stderr, "}\n");
|
||||
#undef Ps
|
||||
#undef Pd
|
||||
@@ -207,11 +219,23 @@ void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
|
||||
#undef Phex
|
||||
}
|
||||
|
||||
void db_raw_sql(struct db_context *dbc, const char *sql)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
fprintf(stderr, "raw SQL: %s\n", sql);
|
||||
ASSERT_RC(sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL), SQLITE_OK);
|
||||
ASSERT_RC(sqlite3_step(stmt), SQLITE_DONE);
|
||||
db_remove_reset(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
static const char *imsi0 = "123456789000000";
|
||||
static const char *imsi1 = "123456789000001";
|
||||
static const char *imsi2 = "123456789000002";
|
||||
static const char *short_imsi = "123456";
|
||||
static const char *unknown_imsi = "999999999";
|
||||
static const enum osmo_rat_type rat_types[2] = { OSMO_RAT_GERAN_A, OSMO_RAT_UTRAN_IU, };
|
||||
|
||||
static void test_subscr_create_update_sel_delete()
|
||||
{
|
||||
@@ -220,40 +244,45 @@ static void test_subscr_create_update_sel_delete()
|
||||
|
||||
comment("Create with valid / invalid IMSI");
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0), 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||
ASSERT_SEL(imsi, imsi0, 0);
|
||||
id0 = g_subscr.id;
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1), 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||
ASSERT_SEL(imsi, imsi1, 0);
|
||||
id1 = g_subscr.id;
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2), 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||
ASSERT_SEL(imsi, imsi2, 0);
|
||||
id2 = g_subscr.id;
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||
ASSERT_SEL(imsi, imsi0, 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||
ASSERT_SEL(imsi, imsi1, 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EIO);
|
||||
ASSERT_SEL(imsi, imsi2, 0);
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, "123456789 000003"), -EINVAL);
|
||||
ASSERT_RC(db_subscr_create(dbc, "123456789 000003", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EINVAL);
|
||||
ASSERT_SEL(imsi, "123456789000003", -ENOENT);
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, "123456789000002123456"), -EINVAL);
|
||||
ASSERT_RC(db_subscr_create(dbc, "123456789000002123456", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS),
|
||||
-EINVAL);
|
||||
ASSERT_SEL(imsi, "123456789000002123456", -ENOENT);
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, "foobar123"), -EINVAL);
|
||||
ASSERT_RC(db_subscr_create(dbc, "foobar123", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EINVAL);
|
||||
ASSERT_SEL(imsi, "foobar123", -ENOENT);
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, "123"), -EINVAL);
|
||||
ASSERT_RC(db_subscr_create(dbc, "123", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), -EINVAL);
|
||||
ASSERT_SEL(imsi, "123", -ENOENT);
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, short_imsi), 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, short_imsi, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||
ASSERT_SEL(imsi, short_imsi, 0);
|
||||
id_short = g_subscr.id;
|
||||
|
||||
comment("Check if subscriber exists (by IMSI)");
|
||||
|
||||
ASSERT_RC(db_subscr_exists_by_imsi(dbc, imsi0), 0);
|
||||
ASSERT_RC(db_subscr_exists_by_imsi(dbc, unknown_imsi), -ENOENT);
|
||||
|
||||
comment("Set valid / invalid MSISDN");
|
||||
|
||||
@@ -288,6 +317,11 @@ static void test_subscr_create_update_sel_delete()
|
||||
ASSERT_SEL(imsi, imsi0, 0);
|
||||
ASSERT_SEL(msisdn, "5432101234567891", -ENOENT);
|
||||
|
||||
comment("Check if subscriber exists (by MSISDN)");
|
||||
|
||||
ASSERT_RC(db_subscr_exists_by_msisdn(dbc, "543210123456789"), 0);
|
||||
ASSERT_RC(db_subscr_exists_by_msisdn(dbc, "5432101234567891"), -ENOENT);
|
||||
|
||||
comment("Set MSISDN on non-existent / invalid IMSI");
|
||||
|
||||
ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, unknown_imsi, "99"), -ENOENT);
|
||||
@@ -296,6 +330,23 @@ static void test_subscr_create_update_sel_delete()
|
||||
ASSERT_RC(db_subscr_update_msisdn_by_imsi(dbc, "foobar", "99"), -ENOENT);
|
||||
ASSERT_SEL(msisdn, "99", -ENOENT);
|
||||
|
||||
comment("Set valid / invalid IMEI");
|
||||
|
||||
ASSERT_RC(db_subscr_update_imei_by_imsi(dbc, imsi0, "12345678901234"), 0);
|
||||
ASSERT_SEL(imei, "12345678901234", 0);
|
||||
|
||||
ASSERT_RC(db_subscr_update_imei_by_imsi(dbc, imsi0, "123456789012345"), -EINVAL); /* too long */
|
||||
ASSERT_SEL(imei, "12345678901234", 0);
|
||||
ASSERT_SEL(imei, "123456789012345", -ENOENT);
|
||||
|
||||
comment("Set the same IMEI again");
|
||||
ASSERT_RC(db_subscr_update_imei_by_imsi(dbc, imsi0, "12345678901234"), 0);
|
||||
ASSERT_SEL(imei, "12345678901234", 0);
|
||||
|
||||
comment("Remove IMEI");
|
||||
ASSERT_RC(db_subscr_update_imei_by_imsi(dbc, imsi0, NULL), 0);
|
||||
ASSERT_SEL(imei, "12345678901234", -ENOENT);
|
||||
|
||||
comment("Set / unset nam_cs and nam_ps");
|
||||
|
||||
/* nam_val, is_ps */
|
||||
@@ -337,39 +388,44 @@ static void test_subscr_create_update_sel_delete()
|
||||
|
||||
comment("Record LU for PS and CS (SGSN and VLR names)");
|
||||
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "5952", true), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "5952", true, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "712", false), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "712", false, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
|
||||
comment("Record LU for PS and CS (SGSN and VLR names) *again*");
|
||||
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "111", true), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "111", true, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "111", true), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "111", true, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "222", false), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "222", false, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "222", false), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "222", false, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "333", false, rat_types, 1), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "333", false, rat_types, 1), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
|
||||
comment("Unset LU info for PS and CS (SGSN and VLR names)");
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "", true), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "", true, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "", false), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "", false, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "111", true), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "222", false), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "111", true, NULL, 0), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, "222", false, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, NULL, true), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, NULL, true, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, NULL, false), 0);
|
||||
ASSERT_RC(db_subscr_lu(dbc, id0, NULL, false, NULL, 0), 0);
|
||||
ASSERT_SEL(id, id0, 0);
|
||||
|
||||
comment("Record LU for non-existent ID");
|
||||
ASSERT_RC(db_subscr_lu(dbc, 99999, "5952", true), -ENOENT);
|
||||
ASSERT_RC(db_subscr_lu(dbc, 99999, "712", false), -ENOENT);
|
||||
ASSERT_RC(db_subscr_lu(dbc, 99999, "5952", true, NULL, 0), -ENOENT);
|
||||
ASSERT_RC(db_subscr_lu(dbc, 99999, "712", false, NULL, 0), -ENOENT);
|
||||
ASSERT_SEL(id, 99999, -ENOENT);
|
||||
|
||||
comment("Purge and un-purge PS and CS");
|
||||
@@ -434,6 +490,22 @@ static void test_subscr_create_update_sel_delete()
|
||||
ASSERT_RC(db_subscr_delete_by_id(dbc, id_short), 0);
|
||||
ASSERT_SEL(imsi, short_imsi, -ENOENT);
|
||||
|
||||
comment("Create and delete subscribers with non-default nam_cs and nam_ps");
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0, 0x00), 0);
|
||||
ASSERT_SEL(imsi, imsi0, 0);
|
||||
id0 = g_subscr.id;
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS), 0);
|
||||
ASSERT_SEL(imsi, imsi1, 0);
|
||||
id1 = g_subscr.id;
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||
ASSERT_SEL(imsi, imsi2, 0);
|
||||
id2 = g_subscr.id;
|
||||
|
||||
ASSERT_RC(db_subscr_delete_by_id(dbc, id0), 0);
|
||||
ASSERT_RC(db_subscr_delete_by_id(dbc, id1), 0);
|
||||
ASSERT_RC(db_subscr_delete_by_id(dbc, id2), 0);
|
||||
|
||||
comment_end();
|
||||
}
|
||||
|
||||
@@ -477,7 +549,7 @@ static void test_subscr_aud()
|
||||
|
||||
comment("Create subscriber");
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0), 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||
ASSERT_SEL(imsi, imsi0, 0);
|
||||
|
||||
id = g_subscr.id;
|
||||
@@ -689,7 +761,7 @@ static void test_subscr_aud()
|
||||
|
||||
comment("Re-add subscriber and verify auth data didn't come back");
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0), 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||
ASSERT_SEL(imsi, imsi0, 0);
|
||||
|
||||
/* For this test to work, we want to get the same subscriber ID back,
|
||||
@@ -705,6 +777,70 @@ static void test_subscr_aud()
|
||||
comment_end();
|
||||
}
|
||||
|
||||
/* Make each key too short in this test. Note that we can't set them longer than the allowed size without changing the
|
||||
* table structure. */
|
||||
static void test_subscr_aud_invalid_len()
|
||||
{
|
||||
int64_t id;
|
||||
|
||||
comment_start();
|
||||
comment("Create subscriber");
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||
ASSERT_SEL(imsi, imsi0, 0);
|
||||
id = g_subscr.id;
|
||||
|
||||
|
||||
/* Invalid Ki length */
|
||||
comment("Set auth data, 2G only, with invalid Ki length");
|
||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||
mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "0123456789abcdef0123456789abcdef")),
|
||||
0);
|
||||
/* Use raw SQL to avoid length check in db_subscr_update_aud_by_id(). This changes all rows in the table, which
|
||||
* is fine for this test (implicit WHERE 1). */
|
||||
db_raw_sql(dbc, "UPDATE auc_2g SET ki = '0123456789abcdef0123456789abcde'");
|
||||
ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
|
||||
|
||||
comment("Remove 2G auth data");
|
||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||
mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)),
|
||||
0);
|
||||
|
||||
/* Invalid K length */
|
||||
comment("Set auth data, 3G only, with invalid K length");
|
||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||
mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
|
||||
"BeefedCafeFaceAcedAddedDecadeFee", true,
|
||||
"C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)),
|
||||
0);
|
||||
db_raw_sql(dbc, "UPDATE auc_3g SET k = 'C01ffedC1cadaeAc1d1f1edAcac1aB0'");
|
||||
ASSERT_SEL_AUD(imsi0, -EIO, id);
|
||||
|
||||
/* Invalid OP length */
|
||||
comment("Set auth data, 3G only, with invalid OP length");
|
||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||
mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
|
||||
"BeefedCafeFaceAcedAddedDecadeFee", true,
|
||||
"C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)),
|
||||
0);
|
||||
db_raw_sql(dbc, "UPDATE auc_3g SET op = 'BeefedCafeFaceAcedAddedDecadeFe'");
|
||||
ASSERT_SEL_AUD(imsi0, -EIO, id);
|
||||
|
||||
/* Invalid OPC length */
|
||||
comment("Set auth data, 3G only, with invalid OPC length");
|
||||
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
|
||||
mk_aud_3g(OSMO_AUTH_ALG_MILENAGE,
|
||||
"BeefedCafeFaceAcedAddedDecadeFee", false,
|
||||
"C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)),
|
||||
0);
|
||||
db_raw_sql(dbc, "UPDATE auc_3g SET opc = 'BeefedCafeFaceAcedAddedDecadeFe'");
|
||||
ASSERT_SEL_AUD(imsi0, -EIO, id);
|
||||
|
||||
|
||||
comment("Delete subscriber");
|
||||
ASSERT_RC(db_subscr_delete_by_id(dbc, id), 0);
|
||||
comment_end();
|
||||
}
|
||||
|
||||
static void test_subscr_sqn()
|
||||
{
|
||||
int64_t id;
|
||||
@@ -721,7 +857,7 @@ static void test_subscr_sqn()
|
||||
|
||||
comment("Create subscriber");
|
||||
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0), 0);
|
||||
ASSERT_RC(db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS), 0);
|
||||
ASSERT_SEL(imsi, imsi0, 0);
|
||||
|
||||
id = g_subscr.id;
|
||||
@@ -856,9 +992,11 @@ int main(int argc, char **argv)
|
||||
|
||||
test_subscr_create_update_sel_delete();
|
||||
test_subscr_aud();
|
||||
test_subscr_aud_invalid_len();
|
||||
test_subscr_sqn();
|
||||
|
||||
printf("Done\n");
|
||||
db_close(dbc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
--- Create with valid / invalid IMSI
|
||||
|
||||
db_subscr_create(dbc, imsi0) --> 0
|
||||
db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -11,7 +11,7 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000000',
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, imsi1) --> 0
|
||||
db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi1, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -19,7 +19,7 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000001',
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, imsi2) --> 0
|
||||
db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi2, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -27,7 +27,7 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000002',
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, imsi0) --> -EIO
|
||||
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
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
||||
@@ -36,10 +36,10 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000000',
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, imsi1) --> -EIO
|
||||
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
|
||||
|
||||
db_subscr_create(dbc, imsi1) --> -EIO
|
||||
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
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi1, &g_subscr) --> 0
|
||||
@@ -48,10 +48,10 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000001',
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, imsi2) --> -EIO
|
||||
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
|
||||
|
||||
db_subscr_create(dbc, imsi2) --> -EIO
|
||||
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
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi2, &g_subscr) --> 0
|
||||
@@ -60,31 +60,31 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000002',
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, "123456789 000003") --> -EINVAL
|
||||
db_subscr_create(dbc, "123456789 000003", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EINVAL
|
||||
DAUC Cannot create subscriber: invalid IMSI: '123456789 000003'
|
||||
|
||||
db_subscr_get_by_imsi(dbc, "123456789000003", &g_subscr) --> -ENOENT
|
||||
DAUC Cannot read subscriber from db: IMSI='123456789000003': No such subscriber
|
||||
|
||||
db_subscr_create(dbc, "123456789000002123456") --> -EINVAL
|
||||
db_subscr_create(dbc, "123456789000002123456", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EINVAL
|
||||
DAUC Cannot create subscriber: invalid IMSI: '123456789000002123456'
|
||||
|
||||
db_subscr_get_by_imsi(dbc, "123456789000002123456", &g_subscr) --> -ENOENT
|
||||
DAUC Cannot read subscriber from db: IMSI='123456789000002123456': No such subscriber
|
||||
|
||||
db_subscr_create(dbc, "foobar123") --> -EINVAL
|
||||
db_subscr_create(dbc, "foobar123", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EINVAL
|
||||
DAUC Cannot create subscriber: invalid IMSI: 'foobar123'
|
||||
|
||||
db_subscr_get_by_imsi(dbc, "foobar123", &g_subscr) --> -ENOENT
|
||||
DAUC Cannot read subscriber from db: IMSI='foobar123': No such subscriber
|
||||
|
||||
db_subscr_create(dbc, "123") --> -EINVAL
|
||||
db_subscr_create(dbc, "123", DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> -EINVAL
|
||||
DAUC Cannot create subscriber: invalid IMSI: '123'
|
||||
|
||||
db_subscr_get_by_imsi(dbc, "123", &g_subscr) --> -ENOENT
|
||||
DAUC Cannot read subscriber from db: IMSI='123': No such subscriber
|
||||
|
||||
db_subscr_create(dbc, short_imsi) --> 0
|
||||
db_subscr_create(dbc, short_imsi, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, short_imsi, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -93,6 +93,13 @@ struct hlr_subscriber {
|
||||
}
|
||||
|
||||
|
||||
--- Check if subscriber exists (by IMSI)
|
||||
|
||||
db_subscr_exists_by_imsi(dbc, imsi0) --> 0
|
||||
|
||||
db_subscr_exists_by_imsi(dbc, unknown_imsi) --> -ENOENT
|
||||
|
||||
|
||||
--- Set valid / invalid MSISDN
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
||||
@@ -212,6 +219,13 @@ db_subscr_get_by_msisdn(dbc, "5432101234567891", &g_subscr) --> -ENOENT
|
||||
DAUC Cannot read subscriber from db: MSISDN='5432101234567891': No such subscriber
|
||||
|
||||
|
||||
--- Check if subscriber exists (by MSISDN)
|
||||
|
||||
db_subscr_exists_by_msisdn(dbc, "543210123456789") --> 0
|
||||
|
||||
db_subscr_exists_by_msisdn(dbc, "5432101234567891") --> -ENOENT
|
||||
|
||||
|
||||
--- Set MSISDN on non-existent / invalid IMSI
|
||||
|
||||
db_subscr_update_msisdn_by_imsi(dbc, unknown_imsi, "99") --> -ENOENT
|
||||
@@ -227,6 +241,54 @@ db_subscr_get_by_msisdn(dbc, "99", &g_subscr) --> -ENOENT
|
||||
DAUC Cannot read subscriber from db: MSISDN='99': No such subscriber
|
||||
|
||||
|
||||
--- Set valid / invalid IMEI
|
||||
|
||||
db_subscr_update_imei_by_imsi(dbc, imsi0, "12345678901234") --> 0
|
||||
|
||||
db_subscr_get_by_imei(dbc, "12345678901234", &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
.id = 1,
|
||||
.imsi = '123456789000000',
|
||||
.msisdn = '543210123456789',
|
||||
.imei = '12345678901234',
|
||||
}
|
||||
|
||||
db_subscr_update_imei_by_imsi(dbc, imsi0, "123456789012345") --> -EINVAL
|
||||
DAUC Cannot update subscriber IMSI='123456789000000': invalid IMEI: '123456789012345'
|
||||
|
||||
db_subscr_get_by_imei(dbc, "12345678901234", &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
.id = 1,
|
||||
.imsi = '123456789000000',
|
||||
.msisdn = '543210123456789',
|
||||
.imei = '12345678901234',
|
||||
}
|
||||
|
||||
db_subscr_get_by_imei(dbc, "123456789012345", &g_subscr) --> -ENOENT
|
||||
DAUC Cannot read subscriber from db: IMEI=123456789012345: No such subscriber
|
||||
|
||||
|
||||
--- Set the same IMEI again
|
||||
|
||||
db_subscr_update_imei_by_imsi(dbc, imsi0, "12345678901234") --> 0
|
||||
|
||||
db_subscr_get_by_imei(dbc, "12345678901234", &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
.id = 1,
|
||||
.imsi = '123456789000000',
|
||||
.msisdn = '543210123456789',
|
||||
.imei = '12345678901234',
|
||||
}
|
||||
|
||||
|
||||
--- Remove IMEI
|
||||
|
||||
db_subscr_update_imei_by_imsi(dbc, imsi0, NULL) --> 0
|
||||
|
||||
db_subscr_get_by_imei(dbc, "12345678901234", &g_subscr) --> -ENOENT
|
||||
DAUC Cannot read subscriber from db: IMEI=12345678901234: No such subscriber
|
||||
|
||||
|
||||
--- Set / unset nam_cs and nam_ps
|
||||
|
||||
db_subscr_nam(dbc, imsi0, false, true) --> 0
|
||||
@@ -373,7 +435,7 @@ DAUC Cannot disable CS: no such subscriber: IMSI='foobar'
|
||||
|
||||
--- Record LU for PS and CS (SGSN and VLR names)
|
||||
|
||||
db_subscr_lu(dbc, id0, "5952", true) --> 0
|
||||
db_subscr_lu(dbc, id0, "5952", true, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -383,7 +445,7 @@ struct hlr_subscriber {
|
||||
.sgsn_number = '5952',
|
||||
}
|
||||
|
||||
db_subscr_lu(dbc, id0, "712", false) --> 0
|
||||
db_subscr_lu(dbc, id0, "712", false, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -397,7 +459,7 @@ struct hlr_subscriber {
|
||||
|
||||
--- Record LU for PS and CS (SGSN and VLR names) *again*
|
||||
|
||||
db_subscr_lu(dbc, id0, "111", true) --> 0
|
||||
db_subscr_lu(dbc, id0, "111", true, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -408,7 +470,7 @@ struct hlr_subscriber {
|
||||
.sgsn_number = '111',
|
||||
}
|
||||
|
||||
db_subscr_lu(dbc, id0, "111", true) --> 0
|
||||
db_subscr_lu(dbc, id0, "111", true, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -419,7 +481,7 @@ struct hlr_subscriber {
|
||||
.sgsn_number = '111',
|
||||
}
|
||||
|
||||
db_subscr_lu(dbc, id0, "222", false) --> 0
|
||||
db_subscr_lu(dbc, id0, "222", false, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -430,7 +492,7 @@ struct hlr_subscriber {
|
||||
.sgsn_number = '111',
|
||||
}
|
||||
|
||||
db_subscr_lu(dbc, id0, "222", false) --> 0
|
||||
db_subscr_lu(dbc, id0, "222", false, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -441,20 +503,44 @@ struct hlr_subscriber {
|
||||
.sgsn_number = '111',
|
||||
}
|
||||
|
||||
db_subscr_lu(dbc, id0, "333", false, rat_types, 1) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
.id = 1,
|
||||
.imsi = '123456789000000',
|
||||
.msisdn = '543210123456789',
|
||||
.vlr_number = '333',
|
||||
.sgsn_number = '111',
|
||||
.last_lu_rat = 'GERAN-A',
|
||||
}
|
||||
|
||||
db_subscr_lu(dbc, id0, "333", false, rat_types, 1) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
.id = 1,
|
||||
.imsi = '123456789000000',
|
||||
.msisdn = '543210123456789',
|
||||
.vlr_number = '333',
|
||||
.sgsn_number = '111',
|
||||
.last_lu_rat = 'GERAN-A',
|
||||
}
|
||||
|
||||
|
||||
--- Unset LU info for PS and CS (SGSN and VLR names)
|
||||
|
||||
db_subscr_lu(dbc, id0, "", true) --> 0
|
||||
db_subscr_lu(dbc, id0, "", true, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
.id = 1,
|
||||
.imsi = '123456789000000',
|
||||
.msisdn = '543210123456789',
|
||||
.vlr_number = '222',
|
||||
.vlr_number = '333',
|
||||
}
|
||||
|
||||
db_subscr_lu(dbc, id0, "", false) --> 0
|
||||
db_subscr_lu(dbc, id0, "", false, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -463,9 +549,9 @@ struct hlr_subscriber {
|
||||
.msisdn = '543210123456789',
|
||||
}
|
||||
|
||||
db_subscr_lu(dbc, id0, "111", true) --> 0
|
||||
db_subscr_lu(dbc, id0, "111", true, NULL, 0) --> 0
|
||||
|
||||
db_subscr_lu(dbc, id0, "222", false) --> 0
|
||||
db_subscr_lu(dbc, id0, "222", false, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -476,7 +562,7 @@ struct hlr_subscriber {
|
||||
.sgsn_number = '111',
|
||||
}
|
||||
|
||||
db_subscr_lu(dbc, id0, NULL, true) --> 0
|
||||
db_subscr_lu(dbc, id0, NULL, true, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -486,7 +572,7 @@ struct hlr_subscriber {
|
||||
.vlr_number = '222',
|
||||
}
|
||||
|
||||
db_subscr_lu(dbc, id0, NULL, false) --> 0
|
||||
db_subscr_lu(dbc, id0, NULL, false, NULL, 0) --> 0
|
||||
|
||||
db_subscr_get_by_id(dbc, id0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -498,10 +584,10 @@ struct hlr_subscriber {
|
||||
|
||||
--- Record LU for non-existent ID
|
||||
|
||||
db_subscr_lu(dbc, 99999, "5952", true) --> -ENOENT
|
||||
db_subscr_lu(dbc, 99999, "5952", true, NULL, 0) --> -ENOENT
|
||||
DAUC Cannot update SGSN number for subscriber ID=99999: no such subscriber
|
||||
|
||||
db_subscr_lu(dbc, 99999, "712", false) --> -ENOENT
|
||||
db_subscr_lu(dbc, 99999, "712", false, NULL, 0) --> -ENOENT
|
||||
DAUC Cannot update VLR number for subscriber ID=99999: no such subscriber
|
||||
|
||||
db_subscr_get_by_id(dbc, 99999, &g_subscr) --> -ENOENT
|
||||
@@ -704,6 +790,43 @@ db_subscr_delete_by_id(dbc, id_short) --> 0
|
||||
db_subscr_get_by_imsi(dbc, short_imsi, &g_subscr) --> -ENOENT
|
||||
DAUC Cannot read subscriber from db: IMSI='123456': No such subscriber
|
||||
|
||||
|
||||
--- Create and delete subscribers with non-default nam_cs and nam_ps
|
||||
|
||||
db_subscr_create(dbc, imsi0, 0x00) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
.id = 1,
|
||||
.imsi = '123456789000000',
|
||||
.nam_cs = false,
|
||||
.nam_ps = false,
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, imsi1, DB_SUBSCR_FLAG_NAM_CS) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi1, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
.id = 2,
|
||||
.imsi = '123456789000001',
|
||||
.nam_ps = false,
|
||||
}
|
||||
|
||||
db_subscr_create(dbc, imsi2, DB_SUBSCR_FLAG_NAM_PS) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi2, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
.id = 3,
|
||||
.imsi = '123456789000002',
|
||||
.nam_cs = false,
|
||||
}
|
||||
|
||||
db_subscr_delete_by_id(dbc, id0) --> 0
|
||||
|
||||
db_subscr_delete_by_id(dbc, id1) --> 0
|
||||
|
||||
db_subscr_delete_by_id(dbc, id2) --> 0
|
||||
|
||||
===== test_subscr_create_update_sel_delete: SUCCESS
|
||||
|
||||
|
||||
@@ -721,7 +844,7 @@ DAUC IMSI='123456789000000': No such subscriber
|
||||
|
||||
--- Create subscriber
|
||||
|
||||
db_subscr_create(dbc, imsi0) --> 0
|
||||
db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -729,12 +852,12 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000000',
|
||||
}
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
@@ -811,12 +934,12 @@ DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> 0
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
@@ -836,12 +959,12 @@ DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, "f000000000000f00000000000f000000")) --> 0
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
@@ -938,12 +1061,12 @@ DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_NONE, NULL, false, NULL, 0)) --> 0
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
@@ -973,12 +1096,12 @@ DAUC IMSI='123456789000000': Updating SQN=0 in DB
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_NONE, "asdfasdfasd", false, "asdfasdfasdf", 99999)) --> 0
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
@@ -1211,7 +1334,7 @@ DAUC Cannot read subscriber from db: IMSI='123456789000000': No such subscriber
|
||||
|
||||
--- Re-add subscriber and verify auth data didn't come back
|
||||
|
||||
db_subscr_create(dbc, imsi0) --> 0
|
||||
db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -1219,12 +1342,12 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000000',
|
||||
}
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
|
||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
@@ -1239,6 +1362,91 @@ DAUC IMSI='123456789000000': No such subscriber
|
||||
===== test_subscr_aud: SUCCESS
|
||||
|
||||
|
||||
===== test_subscr_aud_invalid_len
|
||||
|
||||
--- Create subscriber
|
||||
|
||||
db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
.id = 1,
|
||||
.imsi = '123456789000000',
|
||||
}
|
||||
|
||||
|
||||
--- Set auth data, 2G only, with invalid Ki length
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "0123456789abcdef0123456789abcdef")) --> 0
|
||||
|
||||
raw SQL: UPDATE auc_2g SET ki = '0123456789abcdef0123456789abcde'
|
||||
sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
|
||||
|
||||
sqlite3_step(stmt) --> SQLITE_DONE
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': Error reading Ki, expected length 16 but has length 15
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
|
||||
|
||||
--- Remove 2G auth data
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> 0
|
||||
|
||||
|
||||
--- Set auth data, 3G only, with invalid K length
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", true, "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)) --> 0
|
||||
|
||||
raw SQL: UPDATE auc_3g SET k = 'C01ffedC1cadaeAc1d1f1edAcac1aB0'
|
||||
sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
|
||||
|
||||
sqlite3_step(stmt) --> SQLITE_DONE
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': Error reading K, expected length 16 but has length 15
|
||||
|
||||
|
||||
|
||||
--- Set auth data, 3G only, with invalid OP length
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", true, "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)) --> 0
|
||||
|
||||
raw SQL: UPDATE auc_3g SET op = 'BeefedCafeFaceAcedAddedDecadeFe'
|
||||
sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
|
||||
|
||||
sqlite3_step(stmt) --> SQLITE_DONE
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': Error reading OP, expected length 16 but has length 15
|
||||
|
||||
|
||||
|
||||
--- Set auth data, 3G only, with invalid OPC length
|
||||
|
||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", false, "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)) --> 0
|
||||
|
||||
raw SQL: UPDATE auc_3g SET opc = 'BeefedCafeFaceAcedAddedDecadeFe'
|
||||
sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
|
||||
|
||||
sqlite3_step(stmt) --> SQLITE_DONE
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': Error reading OPC, expected length 16 but has length 15
|
||||
|
||||
|
||||
|
||||
--- Delete subscriber
|
||||
|
||||
db_subscr_delete_by_id(dbc, id) --> 0
|
||||
|
||||
===== test_subscr_aud_invalid_len: SUCCESS
|
||||
|
||||
|
||||
===== test_subscr_sqn
|
||||
|
||||
--- Set SQN for unknown subscriber
|
||||
@@ -1258,7 +1466,7 @@ DAUC Cannot read subscriber from db: ID=9999: No such subscriber
|
||||
|
||||
--- Create subscriber
|
||||
|
||||
db_subscr_create(dbc, imsi0) --> 0
|
||||
db_subscr_create(dbc, imsi0, DB_SUBSCR_FLAG_NAM_CS | DB_SUBSCR_FLAG_NAM_PS) --> 0
|
||||
|
||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
|
||||
struct hlr_subscriber {
|
||||
@@ -1266,7 +1474,7 @@ struct hlr_subscriber {
|
||||
.imsi = '123456789000000',
|
||||
}
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
@@ -1277,7 +1485,7 @@ DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
db_update_sqn(dbc, id, 123) --> -ENOENT
|
||||
DAUC Cannot update SQN for subscriber ID=1: no auc_3g entry for such subscriber
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
@@ -1285,7 +1493,7 @@ DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
db_update_sqn(dbc, id, 543) --> -ENOENT
|
||||
DAUC Cannot update SQN for subscriber ID=1: no auc_3g entry for such subscriber
|
||||
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
|
||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
|
||||
DAUC IMSI='123456789000000': No 2G Auth Data
|
||||
DAUC IMSI='123456789000000': No 3G Auth Data
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ AM_CFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
-no-install \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
||||
@@ -12,6 +12,7 @@ AM_CFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
-no-install \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
||||
@@ -16,9 +16,13 @@ OsmoHLR> list
|
||||
show talloc-context (application|all) (full|brief|DEPTH)
|
||||
show talloc-context (application|all) (full|brief|DEPTH) tree ADDRESS
|
||||
show talloc-context (application|all) (full|brief|DEPTH) filter REGEXP
|
||||
show stats
|
||||
show stats level (global|peer|subscriber)
|
||||
show asciidoc counters
|
||||
show rate-counters
|
||||
show gsup-connections
|
||||
subscriber (imsi|msisdn|id) IDENT show
|
||||
show subscriber (imsi|msisdn|id) IDENT
|
||||
subscriber (imsi|msisdn|id|imei) IDENT show
|
||||
show subscriber (imsi|msisdn|id|imei) IDENT
|
||||
|
||||
OsmoHLR> enable
|
||||
OsmoHLR# list
|
||||
@@ -71,6 +75,7 @@ OsmoHLR(config-hlr)# list
|
||||
exit
|
||||
end
|
||||
gsup
|
||||
database PATH
|
||||
euse NAME
|
||||
no euse NAME
|
||||
ussd route prefix PREFIX internal (own-msisdn|own-imsi)
|
||||
@@ -79,6 +84,10 @@ OsmoHLR(config-hlr)# list
|
||||
ussd default-route external EUSE
|
||||
no ussd default-route
|
||||
ncss-guard-timeout <0-255>
|
||||
store-imei
|
||||
no store-imei
|
||||
subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)
|
||||
no subscriber-create-on-demand
|
||||
|
||||
OsmoHLR(config-hlr)# gsup
|
||||
OsmoHLR(config-hlr-gsup)# list
|
||||
@@ -98,6 +107,7 @@ OsmoHLR(config-hlr)# exit
|
||||
OsmoHLR(config)# exit
|
||||
OsmoHLR# configure terminal
|
||||
OsmoHLR(config)# hlr
|
||||
OsmoHLR(config-hlr)# store-imei
|
||||
OsmoHLR(config-hlr)# gsup
|
||||
OsmoHLR(config-hlr-gsup)# end
|
||||
OsmoHLR# disable
|
||||
@@ -116,6 +126,8 @@ log stderr
|
||||
logging level ss info
|
||||
...
|
||||
hlr
|
||||
store-imei
|
||||
database hlr_vty_test.db
|
||||
gsup
|
||||
bind ip 127.0.0.1
|
||||
ussd route prefix *#100# internal own-msisdn
|
||||
|
||||
43
tests/test_subscr_create_on_demand.vty
Normal file
43
tests/test_subscr_create_on_demand.vty
Normal file
@@ -0,0 +1,43 @@
|
||||
OsmoHLR> enable
|
||||
OsmoHLR# configure terminal
|
||||
OsmoHLR(config)# hlr
|
||||
|
||||
OsmoHLR(config-hlr)# subscriber-create-on-demand no-msisdn none
|
||||
OsmoHLR(config-hlr)# show running-config
|
||||
...
|
||||
hlr
|
||||
...
|
||||
subscriber-create-on-demand no-msisdn none
|
||||
...
|
||||
|
||||
OsmoHLR(config-hlr)# subscriber-create-on-demand 3 none
|
||||
OsmoHLR(config-hlr)# show running-config
|
||||
...
|
||||
hlr
|
||||
...
|
||||
subscriber-create-on-demand 3 none
|
||||
...
|
||||
|
||||
OsmoHLR(config-hlr)# subscriber-create-on-demand 4 cs
|
||||
OsmoHLR(config-hlr)# show running-config
|
||||
...
|
||||
hlr
|
||||
...
|
||||
subscriber-create-on-demand 4 cs
|
||||
...
|
||||
|
||||
OsmoHLR(config-hlr)# subscriber-create-on-demand 5 ps
|
||||
OsmoHLR(config-hlr)# show running-config
|
||||
...
|
||||
hlr
|
||||
...
|
||||
subscriber-create-on-demand 5 ps
|
||||
...
|
||||
|
||||
OsmoHLR(config-hlr)# subscriber-create-on-demand 6 cs+ps
|
||||
OsmoHLR(config-hlr)# show running-config
|
||||
...
|
||||
hlr
|
||||
...
|
||||
subscriber-create-on-demand 6 cs+ps
|
||||
...
|
||||
@@ -2,15 +2,17 @@ OsmoHLR> enable
|
||||
|
||||
OsmoHLR# list
|
||||
...
|
||||
subscriber (imsi|msisdn|id) IDENT show
|
||||
show subscriber (imsi|msisdn|id) IDENT
|
||||
subscriber (imsi|msisdn|id|imei) IDENT show
|
||||
show subscriber (imsi|msisdn|id|imei) IDENT
|
||||
subscriber imsi IDENT create
|
||||
subscriber (imsi|msisdn|id) IDENT delete
|
||||
subscriber (imsi|msisdn|id) IDENT update msisdn (none|MSISDN)
|
||||
subscriber (imsi|msisdn|id) IDENT update aud2g none
|
||||
subscriber (imsi|msisdn|id) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor) ki KI
|
||||
subscriber (imsi|msisdn|id) IDENT update aud3g none
|
||||
subscriber (imsi|msisdn|id) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>]
|
||||
subscriber (imsi|msisdn|id|imei) IDENT delete
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update msisdn (none|MSISDN)
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update aud2g none
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor) ki KI
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update aud3g none
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>]
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update imei (none|IMEI)
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update network-access-mode (none|cs|ps|cs+ps)
|
||||
|
||||
OsmoHLR# subscriber?
|
||||
subscriber Subscriber management commands
|
||||
@@ -19,27 +21,36 @@ OsmoHLR# subscriber ?
|
||||
imsi Identify subscriber by IMSI
|
||||
msisdn Identify subscriber by MSISDN (phone number)
|
||||
id Identify subscriber by database ID
|
||||
imei Identify subscriber by IMEI
|
||||
|
||||
OsmoHLR# subscriber imsi ?
|
||||
IDENT IMSI/MSISDN/ID of the subscriber
|
||||
IDENT IMSI/MSISDN/ID/IMEI of the subscriber
|
||||
OsmoHLR# subscriber msisdn ?
|
||||
IDENT IMSI/MSISDN/ID of the subscriber
|
||||
IDENT IMSI/MSISDN/ID/IMEI of the subscriber
|
||||
OsmoHLR# subscriber id ?
|
||||
IDENT IMSI/MSISDN/ID of the subscriber
|
||||
IDENT IMSI/MSISDN/ID/IMEI of the subscriber
|
||||
OsmoHLR# subscriber imei ?
|
||||
IDENT IMSI/MSISDN/ID/IMEI of the subscriber
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
% No subscriber for imsi = '123456789023000'
|
||||
OsmoHLR# subscriber id 1 show
|
||||
% No subscriber for id = '1'
|
||||
OsmoHLR# subscriber id 101 show
|
||||
% No subscriber for id = '101'
|
||||
OsmoHLR# subscriber msisdn 12345 show
|
||||
% No subscriber for msisdn = '12345'
|
||||
OsmoHLR# subscriber imei 357613004448485 show
|
||||
% Checksum validated and stripped for search: imei = '35761300444848'
|
||||
% No subscriber for imei = '35761300444848'
|
||||
|
||||
OsmoHLR# show subscriber imsi 123456789023000
|
||||
% No subscriber for imsi = '123456789023000'
|
||||
OsmoHLR# show subscriber id 1
|
||||
% No subscriber for id = '1'
|
||||
OsmoHLR# show subscriber id 101
|
||||
% No subscriber for id = '101'
|
||||
OsmoHLR# show subscriber msisdn 12345
|
||||
% No subscriber for msisdn = '12345'
|
||||
OsmoHLR# show subscriber imei 357613004448485
|
||||
% Checksum validated and stripped for search: imei = '35761300444848'
|
||||
% No subscriber for imei = '35761300444848'
|
||||
|
||||
OsmoHLR# subscriber imsi 1234567890230001 create
|
||||
% Not a valid IMSI: 1234567890230001
|
||||
@@ -50,16 +61,16 @@ OsmoHLR# subscriber imsi 12345 create
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 create
|
||||
% Created subscriber 123456789023000
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
OsmoHLR# subscriber msisdn 12345 show
|
||||
@@ -69,15 +80,15 @@ OsmoHLR# subscriber imsi 123456789023000 update msisdn 12345
|
||||
% Updated subscriber IMSI='123456789023000' to MSISDN='12345'
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 12345
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 12345
|
||||
OsmoHLR# subscriber msisdn 12345 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 12345
|
||||
|
||||
@@ -91,33 +102,35 @@ OsmoHLR# subscriber msisdn 423 update msisdn none
|
||||
OsmoHLR# subscriber msisdn 423 show
|
||||
% No subscriber for msisdn = '423'
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
OsmoHLR# subscriber imsi 123456789023000 update msisdn 423
|
||||
% Updated subscriber IMSI='123456789023000' to MSISDN='423'
|
||||
OsmoHLR# subscriber msisdn 423 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
OsmoHLR# subscriber msisdn 423 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update ?
|
||||
msisdn Set MSISDN (phone number) of the subscriber
|
||||
aud2g Set 2G authentication data
|
||||
aud3g Set UMTS authentication data (3G, and 2G with UMTS AKA)
|
||||
msisdn Set MSISDN (phone number) of the subscriber
|
||||
aud2g Set 2G authentication data
|
||||
aud3g Set UMTS authentication data (3G, and 2G with UMTS AKA)
|
||||
imei Set IMEI of the subscriber (normally populated from MSC, no need to set this manually)
|
||||
network-access-mode Set Network Access Mode (NAM) of the subscriber
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update msisdn ?
|
||||
none Remove MSISDN (phone number)
|
||||
@@ -141,7 +154,7 @@ OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ki val ?
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud2g xor ki Deaf0ff1ceD0d0DabbedD1ced1ceF00d
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: XOR
|
||||
@@ -149,39 +162,39 @@ OsmoHLR# subscriber imsi 123456789023000 show
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ki BeefedCafeFaceAcedAddedDecadeFee
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v1
|
||||
KI=beefedcafefaceacedaddeddecadefee
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v1
|
||||
KI=beefedcafefaceacedaddeddecadefee
|
||||
OsmoHLR# subscriber msisdn 423 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v1
|
||||
KI=beefedcafefaceacedaddeddecadefee
|
||||
|
||||
OsmoHLR# subscriber id 1 update aud2g comp128v2 ki CededEffacedAceFacedBadFadedBeef
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 update aud2g comp128v2 ki CededEffacedAceFacedBadFadedBeef
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v2
|
||||
KI=cededeffacedacefacedbadfadedbeef
|
||||
OsmoHLR# subscriber msisdn 423 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v2
|
||||
KI=cededeffacedacefacedbadfadedbeef
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v2
|
||||
@@ -189,63 +202,63 @@ OsmoHLR# subscriber imsi 123456789023000 show
|
||||
|
||||
OsmoHLR# subscriber msisdn 423 update aud2g comp128v3 ki C01ffedC1cadaeAc1d1f1edAcac1aB0a
|
||||
OsmoHLR# subscriber msisdn 423 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v3
|
||||
KI=c01ffedc1cadaeac1d1f1edacac1ab0a
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v3
|
||||
KI=c01ffedc1cadaeac1d1f1edacac1ab0a
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v3
|
||||
KI=c01ffedc1cadaeac1d1f1edacac1ab0a
|
||||
|
||||
OsmoHLR# subscriber id 1 update aud2g nonsense ki BeefedCafeFaceAcedAddedDecadeFee
|
||||
OsmoHLR# subscriber id 101 update aud2g nonsense ki BeefedCafeFaceAcedAddedDecadeFee
|
||||
% Unknown command.
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v3
|
||||
KI=c01ffedc1cadaeac1d1f1edacac1ab0a
|
||||
|
||||
OsmoHLR# subscriber id 1 update aud2g milenage ki BeefedCafeFaceAcedAddedDecadeFee
|
||||
OsmoHLR# subscriber id 101 update aud2g milenage ki BeefedCafeFaceAcedAddedDecadeFee
|
||||
% Unknown command.
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v3
|
||||
KI=c01ffedc1cadaeac1d1f1edacac1ab0a
|
||||
|
||||
OsmoHLR# subscriber id 1 update aud2g xor ki CoiffedCicadaeAcidifiedAcaciaBoa
|
||||
OsmoHLR# subscriber id 101 update aud2g xor ki CoiffedCicadaeAcidifiedAcaciaBoa
|
||||
% Invalid value for KI: 'CoiffedCicadaeAcidifiedAcaciaBoa'
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v3
|
||||
KI=c01ffedc1cadaeac1d1f1edacac1ab0a
|
||||
|
||||
OsmoHLR# subscriber id 1 update aud2g xor ki C01ffedC1cadaeAc1d1f1edAcac1aB0aX
|
||||
OsmoHLR# subscriber id 101 update aud2g xor ki C01ffedC1cadaeAc1d1f1edAcac1aB0aX
|
||||
% Invalid value for KI: 'C01ffedC1cadaeAc1d1f1edAcac1aB0aX'
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v3
|
||||
KI=c01ffedc1cadaeac1d1f1edacac1ab0a
|
||||
|
||||
OsmoHLR# subscriber id 1 update aud2g none
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 update aud2g none
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
|
||||
@@ -275,7 +288,7 @@ OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0D
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc CededEffacedAceFacedBadFadedBeef
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
3G auth: MILENAGE
|
||||
@@ -286,7 +299,7 @@ OsmoHLR# subscriber imsi 123456789023000 show
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d op DeafBeddedBabeAcceededFadedDecaf
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
3G auth: MILENAGE
|
||||
@@ -296,13 +309,13 @@ OsmoHLR# subscriber imsi 123456789023000 show
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g none
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc CededEffacedAceFacedBadFadedBeef ind-bitlen 23
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
3G auth: MILENAGE
|
||||
@@ -313,7 +326,7 @@ OsmoHLR# subscriber imsi 123456789023000 show
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k CoiffedCicadaeAcidifiedAcaciaBoa opc CededEffacedAceFacedBadFadedBeef
|
||||
% Invalid value for K: 'CoiffedCicadaeAcidifiedAcaciaBoa'
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
3G auth: MILENAGE
|
||||
@@ -324,7 +337,7 @@ OsmoHLR# subscriber imsi 123456789023000 show
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc CoiffedCicadaeAcidifiedAcaciaBoa
|
||||
% Invalid value for OPC: 'CoiffedCicadaeAcidifiedAcaciaBoa'
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
3G auth: MILENAGE
|
||||
@@ -336,7 +349,7 @@ OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0D
|
||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d op CoiffedCicadaeAcidifiedAcaciaBoa
|
||||
% Invalid value for OP: 'CoiffedCicadaeAcidifiedAcaciaBoa'
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
3G auth: MILENAGE
|
||||
@@ -344,9 +357,9 @@ OsmoHLR# subscriber imsi 123456789023000 show
|
||||
OP=c01ffedc1cadaeac1d1f1edacac1ab0a
|
||||
IND-bitlen=5
|
||||
|
||||
OsmoHLR# subscriber id 1 update aud2g comp128v2 ki CededEffacedAceFacedBadFadedBeef
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
OsmoHLR# subscriber id 101 update aud2g comp128v2 ki CededEffacedAceFacedBadFadedBeef
|
||||
OsmoHLR# subscriber id 101 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: 423
|
||||
2G auth: COMP128v2
|
||||
@@ -361,16 +374,100 @@ OsmoHLR# subscriber imsi 123456789023000 delete
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
% No subscriber for imsi = '123456789023000'
|
||||
OsmoHLR# subscriber id 1 show
|
||||
% No subscriber for id = '1'
|
||||
OsmoHLR# subscriber id 101 show
|
||||
% No subscriber for id = '101'
|
||||
OsmoHLR# subscriber msisdn 423 show
|
||||
% No subscriber for msisdn = '423'
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 create
|
||||
% Created subscriber 123456789023000
|
||||
ID: 1
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 delete
|
||||
% Deleted subscriber for IMSI '123456789023000'
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 create
|
||||
% Created subscriber 123456789023000
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update imei ?
|
||||
none Forget IMEI
|
||||
IMEI Set IMEI (use for debug only!)
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update imei 35761300444848
|
||||
% Updated subscriber IMSI='123456789023000' to IMEI='35761300444848'
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update imei 357613004448484
|
||||
% IMEI invalid: '357613004448484'
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update imei 357613004448485
|
||||
% Updated subscriber IMSI='123456789023000' to IMEI='35761300444848'
|
||||
|
||||
OsmoHLR# show subscriber imei 35761300444848
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
IMEI: 357613004448485
|
||||
|
||||
OsmoHLR# show subscriber imei 357613004448485
|
||||
% Checksum validated and stripped for search: imei = '35761300444848'
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
IMEI: 357613004448485
|
||||
|
||||
OsmoHLR# show subscriber imei 357613004448484
|
||||
% No subscriber for imei = '357613004448484'
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update imei none
|
||||
% Updated subscriber IMSI='123456789023000': removed IMEI
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 delete
|
||||
% Deleted subscriber for IMSI '123456789023000'
|
||||
|
||||
OsmoHLR# show subscriber id 99
|
||||
ID: 99
|
||||
IMSI: 000000000000099
|
||||
MSISDN: none
|
||||
IMEI: 12345 (INVALID LENGTH!)
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 create
|
||||
% Created subscriber 123456789023000
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
OsmoHLR# subscriber imsi 123456789023000 update network-access-mode none
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
CS disabled
|
||||
PS disabled
|
||||
OsmoHLR# subscriber imsi 123456789023000 update network-access-mode cs
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
PS disabled
|
||||
OsmoHLR# subscriber imsi 123456789023000 update network-access-mode ps
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
CS disabled
|
||||
OsmoHLR# subscriber imsi 123456789023000 update network-access-mode cs+ps
|
||||
OsmoHLR# subscriber imsi 123456789023000 show
|
||||
ID: 101
|
||||
IMSI: 123456789023000
|
||||
MSISDN: none
|
||||
OsmoHLR# subscriber imsi 123456789023000 delete
|
||||
% Deleted subscriber for IMSI '123456789023000'
|
||||
|
||||
6
tests/test_subscriber.vty.sql
Normal file
6
tests/test_subscriber.vty.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
-- Subscriber with invalid IMEI length
|
||||
INSERT INTO subscriber (id, imsi, imei) VALUES(99, '000000000000099', '12345');
|
||||
|
||||
-- Dummy entry with ID=100 gives all subscribers created in the VTY test an
|
||||
-- ID > 100, so we can pre-fill the database with IDs < 100.
|
||||
INSERT INTO subscriber (id, imsi) VALUES(100, '000000000000100');
|
||||
Reference in New Issue
Block a user