Compare commits

..

15 Commits

Author SHA1 Message Date
Piotr Krysik
0b49796412 Enabling/disabling 4G RAN for given subscriber
The change adds support for enabling and disabling connection
through 4G RAN by a subscriber with use of USSD codes.

Change-Id: Idf964d9c770a0a1cb5c486eb2a7592d6bf44171c
2019-08-22 14:30:22 +02:00
gsmevent admin
a1e7759bc1 AUCH test fixes by Lynxis 2019-08-22 13:52:24 +02:00
Harald Welte
15f88107c7 AUC: Add support for setting the AMF separation bit to '1' for EUTRAN
Change-Id: Ic766bc40f6126bb479bd0a05b0e96bec3e240008
2019-08-22 12:47:41 +02:00
Neels Hofmeyr
94c38a9e03 Revert "mention *#201#, *#301# in USSD get_ran (HACK)"
This reverts commit 05e888ed7c.
2019-08-20 04:45:25 +02:00
Neels Hofmeyr
05e888ed7c mention *#201#, *#301# in USSD get_ran (HACK)
Change-Id: Idbedbc679868a88dae1c85f82527f3f20067b879
2019-08-20 04:45:19 +02:00
gsmevent admin
9eb10efb23 send GMM_CAUSE_ROAMING_NOTALLOWED instead of GMM_CAUSE_IMSI_UNKNOWN HARDCODED 2019-08-20 04:45:19 +02:00
Neels Hofmeyr
63450d990b add USSD handlers to enable/disable 2G access
Change-Id: Ib266bf6ebc7692362a443efbf9b4ae69aee671d6
2019-08-20 04:42:48 +02:00
Neels Hofmeyr
d2d9f35835 for ussd_get_ran, show current RAT
Change-Id: I81adb1785c1a46e9153a6914ef2c699e9c90b731
2019-08-20 04:42:46 +02:00
Neels Hofmeyr
80b7fe759f auto upgrade hlr.db in the service file
Change-Id: Icd3af5160e6d8f31fed5e84055fbb09322c54c2b
2019-08-20 04:41:06 +02:00
Neels Hofmeyr
b984a6c995 add column 'last_lu_rat', show last RAN type
Change-Id: I5d73b1d928b61175d3198326706b7f49ba50e16f
2019-08-20 04:41:06 +02:00
Vadim Yanitskiy
3896888468 SS/USSD: update configuretion example
Change-Id: I3801968d29bae917bf8669bb4ac03a9c4f3cb96c
2019-08-20 04:40:09 +02:00
Vadim Yanitskiy
e9dd9c6282 SS/USSD: add IUSEs to enable / disable UMTS
Change-Id: Icf85ec8dd71813a9bbf359b9011456844f398337
2019-08-20 04:40:09 +02:00
Vadim Yanitskiy
277b2d642a SS/USSD: implement an IUSE for getting RAN type(s)
Change-Id: I8d95413784b039df50a4cdcac49289060f0414c6
2019-08-20 04:40:09 +02:00
Neels Hofmeyr
f1949f7b99 Add DB storage for enabling / disabling arbitrary RAT types.
So far we have only GERAN-A and UTRAN-Iu, but to be future compatible,
implement an arbitrary length list of RAT types: add DB table subscriber_rat.

Backwards compatibility: if there is no entry in subscriber_rat, all RAT types
shall be allowed. As soon as there is an entry, it can either be false to
forbid a RAT or true to still allow a RAT type.

Depends: I93850710ab55a605bf61b95063a69682a2899bb1 (libosmocore)
Change-Id: I3e399ca8a85421f77a9a15e608413d1507722955
2019-08-20 04:40:07 +02:00
Neels Hofmeyr
f302de93dd change format of 'last LU seen'
So far, the time string format comes from ctime_r, and we manually add "UTC" to it.

The ctime_r format is wildly chaotic IMHO, mixing weekday, day-of-month and
hour and year in very unsorted ways.

Adding "UTC" to it is non-standard.

Instead use an ISO-8601 standardized time string via strftime().

Change-Id: I6731968f05050399f4dd43b241290186e0c59e1a
2019-08-19 02:24:05 +02:00
67 changed files with 1077 additions and 943 deletions

1
.gitignore vendored
View File

@@ -50,7 +50,6 @@ tests/gsup_server/gsup_server_test
tests/gsup/gsup_test
tests/db/db_test
tests/hlr_vty_test.db*
tests/db_upgrade/*.dump
# manuals
doc/manuals/*.html

View File

@@ -34,10 +34,10 @@ PKG_PROG_PKG_CONFIG([0.20])
PKG_CHECK_MODULES(TALLOC, [talloc >= 2.0.1])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.3.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.3.0)
PKG_CHECK_MODULES(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)
@@ -175,8 +175,6 @@ AC_OUTPUT(
src/Makefile
src/gsupclient/Makefile
include/Makefile
include/osmocom/Makefile
include/osmocom/hlr/Makefile
libosmo-gsup-client.pc
sql/Makefile
doc/manuals/Makefile
@@ -186,6 +184,6 @@ AC_OUTPUT(
tests/auc/Makefile
tests/auc/gen_ts_55_205_test_sets/Makefile
tests/gsup_server/Makefile
tests/gsup/Makefile
tests/db/Makefile
tests/db_upgrade/Makefile
)

View File

@@ -5,7 +5,7 @@ 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]

42
debian/changelog vendored
View File

@@ -1,45 +1,3 @@
osmo-hlr (1.2.0) unstable; urgency=medium
[ Ruben Undheim ]
* Fix test for return codes on mipsel and alpha archs
[ Thorsten Alteholz ]
* fix spelling errors detected by lintian
[ Pau Espin Pedrol ]
* tests: Fix db_test err file to expect error code name instead of value
[ Oliver Smith ]
* tests/test_nodes.vty: check less libosmocore cmds
* tests/db_upgrade: disable for old sqlite versions
* gitignore: add tests/db_upgrade/*.dump
* gsup_client.h: fix license header: GPLv2+
* tests/auc: change back to python3
[ Neels Hofmeyr ]
* fix double free in osmo_gsup_client_enc_send()
* db upgrade to v2: log version 2, not 1
* fix upgrade to version 2: imei column default value
* add --db-check option
* hlr.sql: move comment
* add db_upgrade test
* hlr db schema 3: hlr_number -> msc_number
* db.c: code dup: add db_run_statements() for arrays of statements
* move headers to include/osmocom/hlr
* fix upgrade test in presence of ~/.sqliterc
* db upgrade: remove some code dup
* add osmo_gsup_msgb_alloc()
* Makefile convenience: add VTY_TEST var to run only one test
* remove gsup_test
* test_nodes.vty: tweak: add some '?' checks
* db v4: add column last_lu_seen_ps
[ Harald Welte ]
* AUC: Add support for setting the AMF separation bit to '1' for EUTRAN
* hlr: exit(2) on unsupported positional arguments on command line
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 03 Jan 2020 12:37:35 +0100
osmo-hlr (1.1.0) unstable; urgency=medium
[ Oliver Smith ]

2
debian/control vendored
View File

@@ -7,7 +7,7 @@ Build-Depends: debhelper (>= 9),
dh-autoreconf,
dh-systemd (>= 1.5),
autotools-dev,
python3-minimal,
python-minimal,
libosmocore-dev,
libosmo-abis-dev,
libosmo-netif-dev,

View File

@@ -24,3 +24,10 @@ 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
ussd route prefix *#400# internal lte-off
ussd route prefix *#401# internal lte-on

View File

@@ -52,7 +52,7 @@ transceiving only RAND and SRES, may be applicable. (See 3GPP TS 33.102, chapter
|aud3g.ind_bitlen|5|Nr of index bits at lower SQN end
|apn||
|vlr_number||3GPP TS 23.008 chapter 2.4.5
|msc_number||3GPP TS 23.008 chapter 2.4.6
|hlr_number||3GPP TS 23.008 chapter 2.4.6
|sgsn_number||3GPP TS 23.008 chapter 2.4.8.1
|sgsn_address||3GPP TS 23.008 chapter 2.13.10
|ggsn_number||3GPP TS 23.008 chapter 2.4.8.2

View File

@@ -1,3 +1,2 @@
SUBDIRS = osmocom
nobase_include_HEADERS = osmocom/gsupclient/gsup_client.h

View File

@@ -1,3 +0,0 @@
SUBDIRS = \
hlr \
$(NULL)

View File

@@ -6,17 +6,18 @@
* Author: Jacob Erlbeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 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/>.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once

View File

@@ -1,14 +0,0 @@
noinst_HEADERS = \
auc.h \
ctrl.h \
db.h \
gsup_router.h \
gsup_server.h \
hlr.h \
hlr_ussd.h \
hlr_vty.h \
hlr_vty_subscr.h \
logging.h \
luop.h \
rand.h \
$(NULL)

View File

@@ -12,7 +12,7 @@ CREATE TABLE subscriber (
-- Chapter 2.4.5
vlr_number VARCHAR(15),
-- Chapter 2.4.6
msc_number VARCHAR(15),
hlr_number VARCHAR(15),
-- Chapter 2.4.8.1
sgsn_number VARCHAR(15),
-- Chapter 2.13.10
@@ -43,7 +43,11 @@ 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_ps TIMESTAMP default NULL
-- Last Radio Access Type list as sent during Location Updating Request.
-- This is usually just one RAT name, but can be a comma separated list of strings
-- of all the RAT types sent during Location Updating Request.
last_lu_rat TEXT default NULL
);
CREATE TABLE subscriber_apn (
@@ -70,11 +74,19 @@ CREATE TABLE auc_3g (
op VARCHAR(32), -- hex string: operator's secret key (128bit)
opc VARCHAR(32), -- hex string: derived from OP and K (128bit)
sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage
-- nr of index bits at lower SQN end
ind_bitlen INTEGER NOT NULL DEFAULT 5
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','EUTRAN-SGs')) 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!

8
sql/upgrade_v2_to_v3.sql Normal file
View 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;

View File

@@ -11,7 +11,6 @@ AM_CFLAGS = \
$(NULL)
AM_CPPFLAGS = -I$(top_srcdir)/include \
-I$(top_builddir)/include \
$(NULL)
EXTRA_DIST = \
@@ -25,6 +24,18 @@ BUILT_SOURCES = \
CLEANFILES = $(BUILT_SOURCES)
noinst_HEADERS = \
auc.h \
db.h \
hlr.h \
luop.h \
gsup_router.h \
gsup_server.h \
logging.h \
rand.h \
ctrl.h \
hlr_vty.h \
hlr_vty_subscr.h \
hlr_ussd.h \
db_bootstrap.h \
$(NULL)

View File

@@ -23,8 +23,8 @@
#include <osmocom/core/utils.h>
#include <osmocom/crypt/auth.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/rand.h>
#include "logging.h"
#include "rand.h"
#define hexb(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
#define hex(buf,sz) osmo_hexdump_nospc((void*)buf, sz)

View File

@@ -28,9 +28,9 @@
#include <osmocom/gsm/gsm23003.h>
#include <osmocom/ctrl/ports.h>
#include <osmocom/hlr/hlr.h>
#include <osmocom/hlr/ctrl.h>
#include <osmocom/hlr/db.h>
#include "hlr.h"
#include "ctrl.h"
#include "db.h"
#define SEL_BY "by-"
#define SEL_BY_IMSI SEL_BY "imsi-"

357
src/db.c
View File

@@ -23,8 +23,8 @@
#include <sqlite3.h>
#include <string.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/db.h>
#include "logging.h"
#include "db.h"
#include "db_bootstrap.h"
/* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */
@@ -46,7 +46,7 @@
"ms_purged_cs," \
"ms_purged_ps," \
"last_lu_seen," \
"last_lu_seen_ps" \
"last_lu_rat"
static const char *stmt_sql[] = {
[DB_STMT_SEL_BY_IMSI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imsi = ?",
@@ -79,10 +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_PS] = "UPDATE subscriber SET last_lu_seen_ps = 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)
@@ -203,38 +209,28 @@ void db_close(struct db_context *dbc)
talloc_free(dbc);
}
static int db_run_statements(struct db_context *dbc, const char **statements, size_t statements_count)
static int db_bootstrap(struct db_context *dbc)
{
int rc;
int i;
for (i = 0; i < statements_count; i++) {
const char *stmt_str = statements[i];
for (i = 0; i < ARRAY_SIZE(stmt_bootstrap_sql); i++) {
int rc;
sqlite3_stmt *stmt;
rc = sqlite3_prepare_v2(dbc->db, stmt_str, -1, &stmt, NULL);
rc = sqlite3_prepare_v2(dbc->db, stmt_bootstrap_sql[i], -1, &stmt, NULL);
if (rc != SQLITE_OK) {
LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", stmt_str);
LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n", stmt_bootstrap_sql[i]);
return rc;
}
rc = sqlite3_step(stmt);
db_remove_reset(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "SQL error: (%d) %s, during stmt '%s'",
rc, sqlite3_errmsg(dbc->db), stmt_str);
LOGP(DDB, LOGL_ERROR, "Cannot bootstrap database: SQL error: (%d) %s,"
" during stmt '%s'",
rc, sqlite3_errmsg(dbc->db), stmt_bootstrap_sql[i]);
return rc;
}
}
return rc;
}
static int db_bootstrap(struct db_context *dbc)
{
int rc = db_run_statements(dbc, stmt_bootstrap_sql, ARRAY_SIZE(stmt_bootstrap_sql));
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "Cannot bootstrap database\n");
return rc;
}
return SQLITE_OK;
}
@@ -275,180 +271,151 @@ static bool db_is_bootstrapped_v0(struct db_context *dbc)
static int
db_upgrade_v1(struct db_context *dbc)
{
sqlite3_stmt *stmt;
int rc;
const char *statements[] = {
"ALTER TABLE subscriber ADD COLUMN last_lu_seen TIMESTAMP default NULL",
"PRAGMA user_version = 1",
};
const char *update_stmt_sql = "ALTER TABLE subscriber ADD COLUMN last_lu_seen TIMESTAMP default NULL";
const char *set_schema_version_sql = "PRAGMA user_version = 1";
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 1\n");
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_v2(struct db_context *dbc)
{
sqlite3_stmt *stmt;
int rc;
const char *statements[] = {
"ALTER TABLE subscriber ADD COLUMN imei VARCHAR(14)",
"PRAGMA user_version = 2",
};
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 = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 2\n");
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 rc;
/* A newer SQLite version would allow simply 'ATLER TABLE subscriber RENAME COLUMN hlr_number TO msc_number'.
* This is a really expensive workaround for that in order to cover earlier SQLite versions as well:
* Create a new table with the new column name and copy the data over (https://www.sqlite.org/faq.html#q11).
*/
#define SUBSCR_V3_CREATE \
"(\n" \
"-- OsmoHLR's DB scheme is modelled roughly after TS 23.008 version 13.3.0\n" \
" id INTEGER PRIMARY KEY,\n" \
" -- Chapter 2.1.1.1\n" \
" imsi VARCHAR(15) UNIQUE NOT NULL,\n" \
" -- Chapter 2.1.2\n" \
" msisdn VARCHAR(15) UNIQUE,\n" \
" -- Chapter 2.2.3: Most recent / current IMEISV\n" \
" imeisv VARCHAR,\n" \
" -- Chapter 2.1.9: Most recent / current IMEI\n" \
" imei VARCHAR(14),\n" \
" -- Chapter 2.4.5\n" \
" vlr_number VARCHAR(15),\n" \
" -- Chapter 2.4.6\n" \
" msc_number VARCHAR(15),\n" \
" -- Chapter 2.4.8.1\n" \
" sgsn_number VARCHAR(15),\n" \
" -- Chapter 2.13.10\n" \
" sgsn_address VARCHAR,\n" \
" -- Chapter 2.4.8.2\n" \
" ggsn_number VARCHAR(15),\n" \
" -- Chapter 2.4.9.2\n" \
" gmlc_number VARCHAR(15),\n" \
" -- Chapter 2.4.23\n" \
" smsc_number VARCHAR(15),\n" \
" -- Chapter 2.4.24\n" \
" periodic_lu_tmr INTEGER,\n" \
" -- Chapter 2.13.115\n" \
" periodic_rau_tau_tmr INTEGER,\n" \
" -- Chapter 2.1.1.2: network access mode\n" \
" nam_cs BOOLEAN NOT NULL DEFAULT 1,\n" \
" nam_ps BOOLEAN NOT NULL DEFAULT 1,\n" \
" -- Chapter 2.1.8\n" \
" lmsi INTEGER,\n" \
\
" -- The below purged flags might not even be stored non-volatile,\n" \
" -- refer to TS 23.012 Chapter 3.6.1.4\n" \
" -- Chapter 2.7.5\n" \
" ms_purged_cs BOOLEAN NOT NULL DEFAULT 0,\n" \
" -- Chapter 2.7.6\n" \
" ms_purged_ps BOOLEAN NOT NULL DEFAULT 0,\n" \
\
" -- Timestamp of last location update seen from subscriber\n" \
" -- The value is a string which encodes a UTC timestamp in granularity of seconds.\n" \
" last_lu_seen TIMESTAMP default NULL\n" \
")\n"
#define SUBSCR_V2_COLUMN_NAMES \
"id," \
"imsi," \
"msisdn," \
"imeisv," \
"imei," \
"vlr_number," \
"hlr_number," \
"sgsn_number," \
"sgsn_address," \
"ggsn_number," \
"gmlc_number," \
"smsc_number," \
"periodic_lu_tmr," \
"periodic_rau_tau_tmr," \
"nam_cs," \
"nam_ps," \
"lmsi," \
"ms_purged_cs," \
"ms_purged_ps," \
"last_lu_seen"
#define SUBSCR_V3_COLUMN_NAMES \
"id," \
"imsi," \
"msisdn," \
"imeisv," \
"imei," \
"vlr_number," \
"msc_number," \
"sgsn_number," \
"sgsn_address," \
"ggsn_number," \
"gmlc_number," \
"smsc_number," \
"periodic_lu_tmr," \
"periodic_rau_tau_tmr," \
"nam_cs," \
"nam_ps," \
"lmsi," \
"ms_purged_cs," \
"ms_purged_ps," \
"last_lu_seen"
const char *statements[] = {
"BEGIN TRANSACTION",
"CREATE TEMPORARY TABLE subscriber_backup" SUBSCR_V3_CREATE,
"INSERT INTO subscriber_backup SELECT " SUBSCR_V2_COLUMN_NAMES " FROM subscriber",
"DROP TABLE subscriber",
"CREATE TABLE subscriber" SUBSCR_V3_CREATE,
"INSERT INTO subscriber SELECT " SUBSCR_V3_COLUMN_NAMES " FROM subscriber_backup",
"DROP TABLE subscriber_backup",
"COMMIT",
"PRAGMA user_version = 3",
int i;
const char *stmts[] = {
"CREATE TABLE subscriber_rat",
"CREATE UNIQUE INDEX idx_subscr_rat_flag",
NULL
};
sqlite3_stmt *stmt = NULL;
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 3\n");
return rc;
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 rc;
return SQLITE_DONE;
}
static int db_upgrade_v4(struct db_context *dbc)
{
sqlite3_stmt *stmt;
int rc;
const char *statements[] = {
"ALTER TABLE subscriber ADD COLUMN last_lu_seen_ps TIMESTAMP default NULL",
"PRAGMA user_version = 4",
};
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 = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 4\n");
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;
}
typedef int (*db_upgrade_func_t)(struct db_context *dbc);
static db_upgrade_func_t db_upgrade_path[] = {
db_upgrade_v1,
db_upgrade_v2,
db_upgrade_v3,
db_upgrade_v4,
};
static int db_get_user_version(struct db_context *dbc)
{
const char *user_version_sql = "PRAGMA user_version";
@@ -559,25 +526,61 @@ 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);
for (; allow_upgrade && (version < ARRAY_SIZE(db_upgrade_path)); version++) {
db_upgrade_func_t upgrade_func = db_upgrade_path[version];
rc = upgrade_func(dbc);
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "Failed to upgrade HLR DB schema to version %d: (rc=%d) %s\n",
version+1, rc, sqlite3_errmsg(dbc->db));
goto out_free;
if (version < CURRENT_SCHEMA_VERSION && allow_upgrade) {
int orig_version = version;
switch (version) {
case 0:
rc = db_upgrade_v1(dbc);
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "Failed to upgrade HLR DB schema to version 1: (rc=%d) %s\n",
rc, sqlite3_errmsg(dbc->db));
goto out_free;
}
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+1);
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);

View File

@@ -3,6 +3,8 @@
#include <stdbool.h>
#include <sqlite3.h>
#include <osmocom/gsm/gsm_utils.h>
struct hlr;
enum stmt_idx {
@@ -28,9 +30,10 @@ enum stmt_idx {
DB_STMT_AUC_3G_INSERT,
DB_STMT_AUC_3G_DELETE,
DB_STMT_SET_LAST_LU_SEEN,
DB_STMT_SET_LAST_LU_SEEN_PS,
DB_STMT_EXISTS_BY_IMSI,
DB_STMT_EXISTS_BY_MSISDN,
DB_STMT_UPD_RAT_FLAG,
DB_STMT_RAT_BY_ID,
_NUM_DB_STMT
};
@@ -96,9 +99,14 @@ struct hlr_subscriber {
bool ms_purged_cs;
bool ms_purged_ps;
time_t last_lu_seen;
time_t last_lu_seen_ps;
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(). */
@@ -151,13 +159,18 @@ int db_subscr_get_by_id(struct db_context *dbc, int64_t id,
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*.

View File

@@ -26,10 +26,10 @@
#include <sqlite3.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/db.h>
#include <osmocom/hlr/auc.h>
#include <osmocom/hlr/rand.h>
#include "logging.h"
#include "db.h"
#include "auc.h"
#include "rand.h"
#define LOGAUC(imsi, level, fmt, args ...) LOGP(DAUC, level, "IMSI='%s': " fmt, imsi, ## args)

View File

@@ -33,11 +33,11 @@
#include <sqlite3.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/hlr.h>
#include <osmocom/hlr/db.h>
#include <osmocom/hlr/gsup_server.h>
#include <osmocom/hlr/luop.h>
#include "logging.h"
#include "hlr.h"
#include "db.h"
#include "gsup_server.h"
#include "luop.h"
#define LOGHLR(imsi, level, fmt, args ...) LOGP(DAUC, level, "IMSI='%s': " fmt, imsi, ## args)
@@ -438,36 +438,14 @@ out:
return ret;
}
static void parse_last_lu_seen(time_t *dst, const char *last_lu_seen_str, const char *imsi, const char *label)
{
struct tm tm = {0};
time_t val;
if (!last_lu_seen_str || last_lu_seen_str[0] == '\0')
return;
if (strptime(last_lu_seen_str, DB_LAST_LU_SEEN_FMT, &tm) == NULL) {
LOGP(DAUC, LOGL_ERROR, "IMSI-%s: Last LU Seen %s: Cannot parse timestamp '%s'\n",
imsi, label, last_lu_seen_str);
return;
}
errno = 0;
val = mktime(&tm);
if (val == -1) {
LOGP(DAUC, LOGL_ERROR, "IMSI-%s: Last LU Seen %s: Cannot convert timestamp '%s' to time_t: %s\n",
imsi, label, last_lu_seen_str, strerror(errno));
val = 0;
}
*dst = val;
}
/* 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)
{
int rc;
int ret = 0;
const char *last_lu_seen_str;
struct tm tm = {0};
/* execute the statement */
rc = sqlite3_step(stmt);
@@ -483,7 +461,7 @@ 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);
@@ -501,14 +479,28 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
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);
parse_last_lu_seen(&subscr->last_lu_seen, (const char *)sqlite3_column_text(stmt, 14),
subscr->imsi, "CS");
parse_last_lu_seen(&subscr->last_lu_seen_ps, (const char *)sqlite3_column_text(stmt, 15),
subscr->imsi, "PS");
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",
last_lu_seen_str, subscr->imsi, strerror(errno));
} else {
subscr->last_lu_seen = mktime(&tm);
if (subscr->last_lu_seen == -1) {
LOGP(DAUC, LOGL_ERROR, "Cannot convert LU timestamp '%s' to time_t: %s\n",
last_lu_seen_str, strerror(errno));
subscr->last_lu_seen = 0;
}
}
}
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;
@@ -734,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];
@@ -782,7 +777,7 @@ int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
goto out;
}
stmt = dbc->stmt[is_ps? DB_STMT_SET_LAST_LU_SEEN_PS : DB_STMT_SET_LAST_LU_SEEN];
stmt = dbc->stmt[DB_STMT_SET_LAST_LU_SEEN];
if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
return -EIO;
@@ -792,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,
@@ -921,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;
}

View File

@@ -23,9 +23,9 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/gsup_server.h>
#include <osmocom/hlr/gsup_router.h>
#include "logging.h"
#include "gsup_server.h"
#include "gsup_router.h"
/*! Find a route for the given address.
* \param[in] gs gsup server

View File

@@ -1,7 +1,7 @@
#pragma once
#include <stdint.h>
#include <osmocom/hlr/gsup_server.h>
#include "gsup_server.h"
struct gsup_route {
struct llist_head list;

View File

@@ -21,8 +21,8 @@
#include <errno.h>
#include <osmocom/hlr/gsup_server.h>
#include <osmocom/hlr/gsup_router.h>
#include "gsup_server.h"
#include "gsup_router.h"
#include <osmocom/core/logging.h>

View File

@@ -27,15 +27,8 @@
#include <osmocom/gsm/gsm48_ie.h>
#include <osmocom/gsm/apn.h>
#include <osmocom/hlr/gsup_server.h>
#include <osmocom/hlr/gsup_router.h>
struct msgb *osmo_gsup_msgb_alloc(const char *label)
{
struct msgb *msg = msgb_alloc_headroom(1024+16, 16, label);
OSMO_ASSERT(msg);
return msg;
}
#include "gsup_server.h"
#include "gsup_router.h"
static void osmo_gsup_server_send(struct osmo_gsup_conn *conn,
int proto_ext, struct msgb *msg_tx)

View File

@@ -47,7 +47,6 @@ struct osmo_gsup_conn {
bool supports_ps; /* client supports OSMO_GSUP_CN_DOMAIN_PS */
};
struct msgb *osmo_gsup_msgb_alloc(const char *label);
int osmo_gsup_conn_send(struct osmo_gsup_conn *conn, struct msgb *msg);
int osmo_gsup_conn_ccm_get(const struct osmo_gsup_conn *clnt, uint8_t **addr,

View File

@@ -386,8 +386,7 @@ int osmo_gsup_client_enc_send(struct osmo_gsup_client *gsupc,
rc = osmo_gsup_client_send(gsupc, gsup_msgb);
if (rc) {
LOGP(DLGSUP, LOGL_ERROR, "Couldn't send GSUP message\n");
/* Do not free, osmo_gsup_client_send() already has. */
return rc;
goto error;
}
return 0;

108
src/hlr.c
View File

@@ -37,16 +37,16 @@
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/hlr/db.h>
#include <osmocom/hlr/hlr.h>
#include <osmocom/hlr/ctrl.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/gsup_server.h>
#include <osmocom/hlr/gsup_router.h>
#include <osmocom/hlr/rand.h>
#include <osmocom/hlr/luop.h>
#include <osmocom/hlr/hlr_vty.h>
#include <osmocom/hlr/hlr_ussd.h>
#include "db.h"
#include "hlr.h"
#include "ctrl.h"
#include "logging.h"
#include "gsup_server.h"
#include "gsup_router.h"
#include "rand.h"
#include "luop.h"
#include "hlr_vty.h"
#include "hlr_ussd.h"
struct hlr *g_hlr;
static void *hlr_ctx = NULL;
@@ -128,7 +128,7 @@ osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
}
/* Send ISD to MSC/SGSN */
msg_out = osmo_gsup_msgb_alloc("GSUP ISD UPDATE");
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP ISD UPDATE");
if (msg_out == NULL) {
LOGP(DLGSUP, LOGL_ERROR,
"IMSI='%s': Cannot notify GSUP client; could not allocate msg buffer "
@@ -242,7 +242,7 @@ static int rx_send_auth_info(struct osmo_gsup_conn *conn,
memset(&gsup_out, 0, sizeof(gsup_out));
memcpy(&gsup_out.imsi, &gsup->imsi, sizeof(gsup_out.imsi));
if (gsup->current_rat_type == OSMO_RAT_EUTRAN_SGS)
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,
@@ -263,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);
@@ -275,7 +275,7 @@ static int rx_send_auth_info(struct osmo_gsup_conn *conn,
gsup_out.num_auth_vectors = rc;
}
msg_out = osmo_gsup_msgb_alloc("GSUP AUC response");
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP AUC response");
osmo_gsup_encode(msg_out, &gsup_out);
return osmo_gsup_conn_send(conn, msg_out);
}
@@ -346,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;
@@ -379,7 +382,7 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
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;
}
@@ -393,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
@@ -410,7 +441,8 @@ 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");
@@ -455,7 +487,7 @@ static int rx_purge_ms_req(struct osmo_gsup_conn *conn,
gsup_reply.cause = GMM_CAUSE_NET_FAIL;
}
msg_out = osmo_gsup_msgb_alloc("GSUP AUC response");
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP AUC response");
osmo_gsup_encode(msg_out, &gsup_reply);
return osmo_gsup_conn_send(conn, msg_out);
}
@@ -470,7 +502,8 @@ static int gsup_send_err_reply(struct osmo_gsup_conn *conn, const char *imsi,
OSMO_STRLCPY_ARRAY(gsup_reply.imsi, imsi);
gsup_reply.message_type = type_err;
gsup_reply.cause = err_cause;
msg_out = osmo_gsup_msgb_alloc("GSUP ERR response");
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP ERR response");
OSMO_ASSERT(msg_out);
osmo_gsup_encode(msg_out, &gsup_reply);
LOGP(DMAIN, LOGL_NOTICE, "Tx %s\n", osmo_gsup_message_type_name(type_err));
return osmo_gsup_conn_send(conn, msg_out);
@@ -528,7 +561,7 @@ static int rx_check_imei_req(struct osmo_gsup_conn *conn, const struct osmo_gsup
/* Accept all IMEIs */
gsup_reply.imei_result = OSMO_GSUP_IMEI_RESULT_ACK;
gsup_reply.message_type = OSMO_GSUP_MSGT_CHECK_IMEI_RESULT;
msg_out = osmo_gsup_msgb_alloc("GSUP Check_IMEI response");
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);
@@ -594,7 +627,8 @@ static int read_cb_forward(struct osmo_gsup_conn *conn, struct msgb *msg, const
end:
/* Send error back to source */
if (ret) {
struct msgb *msg_err = osmo_gsup_msgb_alloc("GSUP forward ERR response");
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));
@@ -708,7 +742,6 @@ static void print_help()
printf(" -T --timestamp Prefix every log line with a timestamp.\n");
printf(" -e --log-level number Set a global loglevel.\n");
printf(" -U --db-upgrade Allow HLR database schema upgrades.\n");
printf(" -C --db-check Quit after opening (and upgrading) the database.\n");
printf(" -V --version Print the version of OsmoHLR.\n");
}
@@ -717,7 +750,6 @@ static struct {
const char *db_file;
bool daemonize;
bool db_upgrade;
bool db_check;
} cmdline_opts = {
.config_file = "osmo-hlr.cfg",
.db_file = NULL,
@@ -739,7 +771,6 @@ static void handle_options(int argc, char **argv)
{"log-level", 1, 0, 'e'},
{"timestamp", 0, 0, 'T'},
{"db-upgrade", 0, 0, 'U' },
{"db-check", 0, 0, 'C' },
{"version", 0, 0, 'V' },
{0, 0, 0, 0}
};
@@ -778,9 +809,6 @@ static void handle_options(int argc, char **argv)
case 'U':
cmdline_opts.db_upgrade = true;
break;
case 'C':
cmdline_opts.db_check = true;
break;
case 'V':
print_version(1);
exit(0);
@@ -792,11 +820,6 @@ static void handle_options(int argc, char **argv)
break;
}
}
if (argc > optind) {
fprintf(stderr, "Unsupported positional arguments on command line\n");
exit(2);
}
}
static void signal_hdlr(int signal)
@@ -869,6 +892,12 @@ int main(int argc, char **argv)
return rc;
}
/* start telnet after reading config for vty_get_bind_addr() */
rc = telnet_init_dynif(hlr_ctx, NULL, vty_get_bind_addr(),
OSMO_VTY_PORT_HLR);
if (rc < 0)
return rc;
LOGP(DMAIN, LOGL_NOTICE, "hlr starting\n");
rc = rand_init();
@@ -886,23 +915,6 @@ int main(int argc, char **argv)
exit(1);
}
if (cmdline_opts.db_check) {
LOGP(DMAIN, LOGL_NOTICE, "Cmdline option --db-check: Database was opened successfully, quitting.\n");
db_close(g_hlr->dbc);
log_fini();
talloc_free(hlr_ctx);
talloc_free(tall_vty_ctx);
talloc_disable_null_tracking();
exit(0);
}
/* start telnet after reading config for vty_get_bind_addr() */
rc = telnet_init_dynif(hlr_ctx, NULL, vty_get_bind_addr(),
OSMO_VTY_PORT_HLR);
if (rc < 0)
return rc;
g_hlr->gs = osmo_gsup_server_create(hlr_ctx, g_hlr->gsup_bind_addr, OSMO_GSUP_PORT,
read_cb, &g_lu_ops, g_hlr);
if (!g_hlr->gs) {

View File

@@ -29,9 +29,9 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/application.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/db.h>
#include <osmocom/hlr/rand.h>
#include "logging.h"
#include "db.h"
#include "rand.h"
struct hlr_db_tool_ctx {
/* DB context */

View File

@@ -29,12 +29,12 @@
#include <string.h>
#include <errno.h>
#include <osmocom/hlr/hlr.h>
#include <osmocom/hlr/hlr_ussd.h>
#include <osmocom/hlr/gsup_server.h>
#include <osmocom/hlr/gsup_router.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/db.h>
#include "hlr.h"
#include "hlr_ussd.h"
#include "gsup_server.h"
#include "gsup_router.h"
#include "logging.h"
#include "db.h"
/***********************************************************************
* core data structures expressing config from VTY
@@ -317,7 +317,7 @@ static int ss_tx_ussd_7bit(struct ss_session *ss, bool final, uint8_t invoke_id,
* Internal USSD Handlers
***********************************************************************/
#include <osmocom/hlr/db.h>
#include "db.h"
static int handle_ussd_own_msisdn(struct osmo_gsup_conn *conn, struct ss_session *ss,
const struct osmo_gsup_message *gsup, const struct ss_request *req)
@@ -355,6 +355,206 @@ 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 if (!strcmp(subscr.last_lu_rat, "EUTRAN-SGs"))
rat = "4G";
else
rat = subscr.last_lu_rat;
snprintf(response, sizeof(response),
"Now on %s. Available:%s%s%s.",
rat,
subscr.rat_types[OSMO_RAT_GERAN_A]? " 2G" : "",
subscr.rat_types[OSMO_RAT_UTRAN_IU]? " 3G" : "",
subscr.rat_types[OSMO_RAT_EUTRAN_SGS]? " 4G" : "");
rc = ss_tx_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 int handle_ussd_lte_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_EUTRAN_SGS, true);
rc = ss_tx_ussd_7bit(ss, true, req->invoke_id,
"Enabled EUTRAN-SGs (4G)");
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_lte_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_EUTRAN_SGS, false);
rc = ss_tx_ussd_7bit(ss, true, req->invoke_id,
"Disabled EUTRAN-SGs (4G)");
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[] = {
{
@@ -365,6 +565,34 @@ 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,
},
{
.name = "lte-on",
.handle_ussd = handle_ussd_lte_on,
},
{
.name = "lte-off",
.handle_ussd = handle_ussd_lte_off,
},
};
const struct hlr_iuse *iuse_find(const char *name)
@@ -464,7 +692,8 @@ static int handle_ussd(struct osmo_gsup_conn *conn, struct ss_session *ss,
}
if (is_euse_originated) {
msg_out = osmo_gsup_msgb_alloc("GSUP USSD FW");
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP USSD FW");
OSMO_ASSERT(msg_out);
/* Received from EUSE, Forward to VLR */
osmo_gsup_encode(msg_out, gsup);
ss_gsup_send(ss, conn->server, msg_out);
@@ -480,7 +709,8 @@ static int handle_ussd(struct osmo_gsup_conn *conn, struct ss_session *ss,
LOGPSS(ss, LOGL_ERROR, "Cannot find conn for EUSE %s\n", addr);
ss_tx_error(ss, req->invoke_id, GSM0480_ERR_CODE_SYSTEM_FAILURE);
} else {
msg_out = osmo_gsup_msgb_alloc("GSUP USSD FW");
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP USSD FW");
OSMO_ASSERT(msg_out);
osmo_gsup_encode(msg_out, gsup);
osmo_gsup_conn_send(conn, msg_out);
}

View File

@@ -5,7 +5,7 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/gsup.h>
#include <osmocom/hlr/gsup_server.h>
#include "gsup_server.h"
#define NCSS_GUARD_TIMEOUT_DEFAULT 30

View File

@@ -33,12 +33,12 @@
#include <osmocom/vty/misc.h>
#include <osmocom/abis/ipa.h>
#include <osmocom/hlr/db.h>
#include <osmocom/hlr/hlr.h>
#include <osmocom/hlr/hlr_vty.h>
#include <osmocom/hlr/hlr_vty_subscr.h>
#include <osmocom/hlr/hlr_ussd.h>
#include <osmocom/hlr/gsup_server.h>
#include "db.h"
#include "hlr.h"
#include "hlr_vty.h"
#include "hlr_vty_subscr.h"
#include "hlr_ussd.h"
#include "gsup_server.h"
struct cmd_node hlr_node = {
HLR_NODE,
@@ -150,16 +150,23 @@ DEFUN(cfg_hlr_gsup_bind_ip,
* USSD Entity
***********************************************************************/
#include <osmocom/hlr/hlr_ussd.h>
#include "hlr_ussd.h"
#define USSD_STR "USSD Configuration\n"
#define UROUTE_STR "Routing Configuration\n"
#define PREFIX_STR "Prefix-Matching Route\n" "USSD Prefix\n"
#define INT_CHOICE "(own-msisdn|own-imsi)"
#define INT_CHOICE "(own-msisdn|own-imsi|get-ran|gsm-on|gsm-off|umts-on|umts-off|lte-on|lte-off)"
#define INT_STR "Internal USSD Handler\n" \
"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 GSM service\n" \
"Disable GSM service\n" \
"Enable UMTS service\n" \
"Disable UMTS service\n" \
"Enable LTE service\n" \
"Disable LTE service\n"
#define EXT_STR "External USSD Handler\n" \
"Name of External USSD Handler (IPA CCM ID)\n"

View File

@@ -25,7 +25,7 @@
#include <osmocom/core/logging.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/command.h>
#include <osmocom/hlr/hlr.h>
#include "hlr.h"
enum hlr_vty_node {
HLR_NODE = _LAST_OSMOVTY_NODE + 1,

View File

@@ -27,38 +27,30 @@
#include <osmocom/vty/vty.h>
#include <osmocom/vty/command.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/hlr/hlr.h>
#include <osmocom/hlr/db.h>
#include "hlr.h"
#include "db.h"
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);
static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t last_lu_seen)
{
char datebuf[26]; /* for ctime_r(3) */
if (!last_lu_seen)
return;
vty_out(vty, " last LU seen on %s: %s UTC%s", domain_label, get_datestr(&last_lu_seen, datebuf),
VTY_NEWLINE);
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;
@@ -95,8 +87,16 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
vty_out(vty, " PS disabled%s", VTY_NEWLINE);
if (subscr->ms_purged_ps)
vty_out(vty, " PS purged%s", VTY_NEWLINE);
dump_last_lu_seen(vty, "CS", subscr->last_lu_seen);
dump_last_lu_seen(vty, "PS", subscr->last_lu_seen_ps);
if (subscr->last_lu_seen)
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;
@@ -613,6 +613,48 @@ DEFUN(subscriber_nam,
}
DEFUN(subscriber_rat,
subscriber_rat_cmd,
SUBSCR_UPDATE "rat (geran-a|utran-iu|eutran-sgs) (allowed|forbidden)",
SUBSCR_UPDATE_HELP
"Allow or forbid specific Radio Access Types\n"
"Set access to GERAN-A\n"
"Set access to UTRAN-Iu\n"
"Set access to EUTRAN-SGs\n"
"Allow access\n"
"Forbid access\n")
{
struct hlr_subscriber subscr;
const char *id_type = argv[0];
const char *id = argv[1];
const char *rat_str = argv[2];
const char *allowed_forbidden = argv[3];
enum osmo_rat_type rat = OSMO_RAT_UNKNOWN;
bool allowed;
int rc;
if (strcmp(rat_str, "geran-a") == 0)
rat = OSMO_RAT_GERAN_A;
else if (strcmp(rat_str, "utran-iu") == 0)
rat = OSMO_RAT_UTRAN_IU;
else if (strcmp(rat_str, "eutran-sgs") == 0)
rat = OSMO_RAT_EUTRAN_SGS;
allowed = (strcmp(allowed_forbidden, "allowed") == 0);
if (get_subscr_by_argv(vty, id_type, id, &subscr))
return CMD_WARNING;
rc = hlr_subscr_rat_flag(g_hlr, &subscr, rat, allowed);
if (rc && rc != -ENOEXEC) {
vty_out(vty, "%% Error: cannot set %s to %s%s",
osmo_rat_type_name(rat), allowed ? "allowed" : "forbidden", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
void hlr_vty_subscriber_init(void)
{
install_element_ve(&subscriber_show_cmd);
@@ -626,4 +668,5 @@ void hlr_vty_subscriber_init(void)
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);
}

View File

@@ -1,5 +1,5 @@
#include <osmocom/core/utils.h>
#include <osmocom/hlr/logging.h>
#include "logging.h"
const struct log_info_cat hlr_log_info_cat[] = {
[DMAIN] = {

View File

@@ -28,10 +28,10 @@
#include <osmocom/gsm/gsup.h>
#include <osmocom/gsm/apn.h>
#include <osmocom/hlr/gsup_server.h>
#include <osmocom/hlr/gsup_router.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/luop.h>
#include "gsup_server.h"
#include "gsup_router.h"
#include "logging.h"
#include "luop.h"
const struct value_string lu_state_names[] = {
{ LU_S_NULL, "NULL" },
@@ -50,7 +50,8 @@ static void _luop_tx_gsup(struct lu_operation *luop,
{
struct msgb *msg_out;
msg_out = osmo_gsup_msgb_alloc("GSUP LUOP");
msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP LUOP");
OSMO_ASSERT(msg_out);
osmo_gsup_encode(msg_out, gsup);
osmo_gsup_addr_send(luop->gsup_server, luop->peer,

View File

@@ -27,8 +27,8 @@
#include <osmocom/core/timer.h>
#include <osmocom/gsm/gsup.h>
#include <osmocom/hlr/db.h>
#include <osmocom/hlr/gsup_server.h>
#include "db.h"
#include "gsup_server.h"
#define CANCEL_TIMEOUT_SECS 30
#define ISD_TIMEOUT_SECS 30
@@ -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? E-UTRAN?*/
enum osmo_rat_type via_rat;
/*! currently running timer */
struct osmo_timer_list timer;

View File

@@ -44,7 +44,7 @@
#include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/hlr/logging.h>
#include "logging.h"
static struct osmo_gsup_client *g_gc;

View File

@@ -2,7 +2,7 @@ SUBDIRS = \
auc \
gsup_server \
db \
db_upgrade \
gsup \
$(NULL)
# The `:;' works around a Bash 3.2 bug when the output is not writeable.
@@ -44,14 +44,12 @@ python-tests:
# don't run vty and ctrl tests concurrently so that the ports don't conflict
$(MAKE) vty-test
$(MAKE) ctrl-test
$(MAKE) db-upgrade-equivalence-test
else
python-tests:
echo "Not running python-based external tests (determined at configure-time)"
endif
VTY_TEST_DB = hlr_vty_test.db
VTY_TEST ?= *.vty
# To update the VTY script from current application behavior,
# pass -u to vty_script_runner.py by doing:
@@ -63,8 +61,9 @@ vty-test:
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)" \
$(U) $(srcdir)/$(VTY_TEST)
-rm -f $(VTY_TEST_DB) $(VTY_TEST_DB)-*
$(U) $(srcdir)/*.vty
-rm -f $(VTY_TEST_DB)
-rm $(VTY_TEST_DB)-*
CTRL_TEST_DB = hlr_ctrl_test.db
@@ -82,9 +81,6 @@ ctrl-test:
-rm -f $(CTRL_TEST_DB)
-rm $(CTRL_TEST_DB)-*
db-upgrade-equivalence-test:
$(MAKE) -C db_upgrade upgrade-equivalence-test
check-local: atconfig $(TESTSUITE)
$(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS)
$(MAKE) $(AM_MAKEFLAGS) python-tests

View File

@@ -2,12 +2,12 @@ SUBDIRS = gen_ts_55_205_test_sets
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/src \
$(NULL)
AM_CFLAGS = \
-Wall \
-ggdb3 \
-I$(top_srcdir)/include \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(NULL)

View File

@@ -29,8 +29,8 @@
#include <osmocom/crypt/auth.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/auc.h>
#include "logging.h"
#include "auc.h"
#define comment_start() fprintf(stderr, "\n===== %s\n", __func__);
#define comment_end() fprintf(stderr, "===== %s: SUCCESS\n\n", __func__);

View File

@@ -33,8 +33,8 @@
#include <osmocom/crypt/auth.h>
#include <osmocom/hlr/logging.h>
#include <osmocom/hlr/auc.h>
#include "logging.h"
#include "auc.h"
#define comment_start() fprintf(stderr, "\n===== %s\n", __func__);
#define comment_end() fprintf(stderr, "===== %s: SUCCESS\n\n", __func__);

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python3
#!/usr/bin/env python
# FIXME: use python3 once buildslaves are updated.
# Convert test sets pasted from 3GPP TS 55.205 to C code.
# (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>

View File

@@ -1,7 +1,7 @@
AM_CFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
-I$(top_builddir)/include \
-I$(top_srcdir)/src \
-I$(top_builddir)/src \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \

View File

@@ -27,8 +27,8 @@
#include <osmocom/core/utils.h>
#include <osmocom/core/logging.h>
#include <osmocom/hlr/db.h>
#include <osmocom/hlr/logging.h>
#include "db.h"
#include "logging.h"
#define comment_start() fprintf(stderr, "\n===== %s\n", __func__);
#define comment(fmt, args...) fprintf(stderr, "\n--- " fmt "\n\n", ## args);
@@ -170,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
@@ -234,6 +235,7 @@ 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()
{
@@ -386,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");

View File

@@ -435,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 {
@@ -445,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 {
@@ -459,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 {
@@ -470,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 {
@@ -481,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 {
@@ -492,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 {
@@ -503,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 {
@@ -525,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 {
@@ -538,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 {
@@ -548,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 {
@@ -560,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

View File

@@ -1,14 +0,0 @@
EXTRA_DIST = \
db_upgrade_test.sh \
db_upgrade_test.err \
db_upgrade_test.ok \
hlr_db_v0.sql \
osmo-hlr.cfg \
create_subscribers.vty \
$(NULL)
update_exp:
$(srcdir)/db_upgrade_test.sh $(srcdir) $(builddir) >"$(srcdir)/db_upgrade_test.ok" 2>"$(srcdir)/db_upgrade_test.err"
upgrade-equivalence-test:
$(srcdir)/db_upgrade_test.sh $(srcdir) $(builddir) do-equivalence-test

View File

@@ -1,47 +0,0 @@
OsmoHLR> enable
OsmoHLR# subscriber imsi 123456789012345 create
% Created subscriber 123456789012345
ID: 1
IMSI: 123456789012345
MSISDN: none
OsmoHLR# subscriber imsi 123456789012345 update msisdn 098765432109876
% Updated subscriber IMSI='123456789012345' to MSISDN='098765432109876'
OsmoHLR# subscriber imsi 123456789012345 update aud2g comp128v1 ki BeefedCafeFaceAcedAddedDecadeFee
OsmoHLR# subscriber imsi 123456789012345 update aud3g milenage k C01ffedC1cadaeAc1d1f1edAcac1aB0a opc CededEffacedAceFacedBadFadedBeef
OsmoHLR# subscriber imsi 111111111 create
% Created subscriber 111111111
ID: 2
IMSI: 111111111
MSISDN: none
OsmoHLR# subscriber imsi 222222222 create
% Created subscriber 222222222
ID: 3
IMSI: 222222222
MSISDN: none
OsmoHLR# subscriber imsi 222222222 update msisdn 22222
% Updated subscriber IMSI='222222222' to MSISDN='22222'
OsmoHLR# subscriber imsi 333333 create
% Created subscriber 333333
ID: 4
IMSI: 333333
MSISDN: none
OsmoHLR# subscriber imsi 333333 update msisdn 3
% Updated subscriber IMSI='333333' to MSISDN='3'
OsmoHLR# subscriber imsi 333333 update aud2g comp128v2 ki 33333333333333333333333333333333
OsmoHLR# subscriber imsi 444444444444444 create
% Created subscriber 444444444444444
ID: 5
IMSI: 444444444444444
MSISDN: none
OsmoHLR# subscriber imsi 444444444444444 update msisdn 4444
% Updated subscriber IMSI='444444444444444' to MSISDN='4444'
OsmoHLR# subscriber imsi 444444444444444 update aud3g milenage k 44444444444444444444444444444444 op 44444444444444444444444444444444
OsmoHLR# subscriber imsi 5555555 create
% Created subscriber 5555555
ID: 6
IMSI: 5555555
MSISDN: none
OsmoHLR# subscriber imsi 5555555 update msisdn 55555555555555
% Updated subscriber IMSI='5555555' to MSISDN='55555555555555'
OsmoHLR# subscriber imsi 5555555 update aud2g xor ki 55555555555555555555555555555555
OsmoHLR# subscriber imsi 5555555 update aud3g milenage k 55555555555555555555555555555555 opc 55555555555555555555555555555555

View File

@@ -1,6 +0,0 @@
update subscriber set vlr_number = 'MSC-1' where id = 1;
update subscriber set ms_purged_cs = 1 where id = 2;
update subscriber set ms_purged_ps = 1 where id = 3;
update subscriber set nam_cs = 0 where id = 4;
update subscriber set nam_ps = 0 where id = 5;
update subscriber set nam_cs = 0, nam_ps = 0 where id = 6;

View File

@@ -1,172 +0,0 @@
Creating db in schema version 0
Version 0 db:
Table: auc_2g
name|type|notnull|dflt_value|pk
algo_id_2g|INTEGER|1||0
ki|VARCHAR(32)|1||0
subscriber_id|INTEGER|0||1
Table auc_2g contents:
algo_id_2g|ki|subscriber_id
1|BeefedCafeFaceAcedAddedDecadeFee|1
2|33333333333333333333333333333333|4
4|55555555555555555555555555555555|6
Table: auc_3g
name|type|notnull|dflt_value|pk
algo_id_3g|INTEGER|1||0
ind_bitlen|INTEGER|1|5|0
k|VARCHAR(32)|1||0
op|VARCHAR(32)|0||0
opc|VARCHAR(32)|0||0
sqn|INTEGER|1|0|0
subscriber_id|INTEGER|0||1
Table auc_3g contents:
algo_id_3g|ind_bitlen|k|op|opc|sqn|subscriber_id
5|5|C01ffedC1cadaeAc1d1f1edAcac1aB0a||CededEffacedAceFacedBadFadedBeef|0|1
5|5|44444444444444444444444444444444|44444444444444444444444444444444||0|5
5|5|55555555555555555555555555555555||55555555555555555555555555555555|0|6
Table: subscriber
name|type|notnull|dflt_value|pk
ggsn_number|VARCHAR(15)|0||0
gmlc_number|VARCHAR(15)|0||0
hlr_number|VARCHAR(15)|0||0
id|INTEGER|0||1
imeisv|VARCHAR|0||0
imsi|VARCHAR(15)|1||0
lmsi|INTEGER|0||0
ms_purged_cs|BOOLEAN|1|0|0
ms_purged_ps|BOOLEAN|1|0|0
msisdn|VARCHAR(15)|0||0
nam_cs|BOOLEAN|1|1|0
nam_ps|BOOLEAN|1|1|0
periodic_lu_tmr|INTEGER|0||0
periodic_rau_tau_tmr|INTEGER|0||0
sgsn_address|VARCHAR|0||0
sgsn_number|VARCHAR(15)|0||0
smsc_number|VARCHAR(15)|0||0
vlr_number|VARCHAR(15)|0||0
Table subscriber contents:
ggsn_number|gmlc_number|hlr_number|id|imeisv|imsi|lmsi|ms_purged_cs|ms_purged_ps|msisdn|nam_cs|nam_ps|periodic_lu_tmr|periodic_rau_tau_tmr|sgsn_address|sgsn_number|smsc_number|vlr_number
|||1||123456789012345||0|0|098765432109876|1|1||||||MSC-1
|||2||111111111||1|0||1|1||||||
|||3||222222222||0|1|22222|1|1||||||
|||4||333333||0|0|3|0|1||||||
|||5||444444444444444||0|0|4444|1|0||||||
|||6||5555555||0|0|55555555555555|0|0||||||
Table: subscriber_apn
name|type|notnull|dflt_value|pk
apn|VARCHAR(256)|1||0
subscriber_id|INTEGER|0||0
Table subscriber_apn contents:
Table: subscriber_multi_msisdn
name|type|notnull|dflt_value|pk
msisdn|VARCHAR(15)|1||0
subscriber_id|INTEGER|0||0
Table subscriber_multi_msisdn contents:
Launching osmo-hlr to upgrade db:
osmo-hlr --database $db --db-upgrade --db-check --config-file $srcdir/osmo-hlr.cfg
rc = 0
DMAIN hlr starting
DDB using database: <PATH>test.db
DDB Database <PATH>test.db' has HLR DB schema version 0
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 1
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 2
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 3
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 4
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
Resulting db:
Table: auc_2g
name|type|notnull|dflt_value|pk
algo_id_2g|INTEGER|1||0
ki|VARCHAR(32)|1||0
subscriber_id|INTEGER|0||1
Table auc_2g contents:
algo_id_2g|ki|subscriber_id
1|BeefedCafeFaceAcedAddedDecadeFee|1
2|33333333333333333333333333333333|4
4|55555555555555555555555555555555|6
Table: auc_3g
name|type|notnull|dflt_value|pk
algo_id_3g|INTEGER|1||0
ind_bitlen|INTEGER|1|5|0
k|VARCHAR(32)|1||0
op|VARCHAR(32)|0||0
opc|VARCHAR(32)|0||0
sqn|INTEGER|1|0|0
subscriber_id|INTEGER|0||1
Table auc_3g contents:
algo_id_3g|ind_bitlen|k|op|opc|sqn|subscriber_id
5|5|C01ffedC1cadaeAc1d1f1edAcac1aB0a||CededEffacedAceFacedBadFadedBeef|0|1
5|5|44444444444444444444444444444444|44444444444444444444444444444444||0|5
5|5|55555555555555555555555555555555||55555555555555555555555555555555|0|6
Table: subscriber
name|type|notnull|dflt_value|pk
ggsn_number|VARCHAR(15)|0||0
gmlc_number|VARCHAR(15)|0||0
id|INTEGER|0||1
imei|VARCHAR(14)|0||0
imeisv|VARCHAR|0||0
imsi|VARCHAR(15)|1||0
last_lu_seen|TIMESTAMP|0|NULL|0
last_lu_seen_ps|TIMESTAMP|0|NULL|0
lmsi|INTEGER|0||0
ms_purged_cs|BOOLEAN|1|0|0
ms_purged_ps|BOOLEAN|1|0|0
msc_number|VARCHAR(15)|0||0
msisdn|VARCHAR(15)|0||0
nam_cs|BOOLEAN|1|1|0
nam_ps|BOOLEAN|1|1|0
periodic_lu_tmr|INTEGER|0||0
periodic_rau_tau_tmr|INTEGER|0||0
sgsn_address|VARCHAR|0||0
sgsn_number|VARCHAR(15)|0||0
smsc_number|VARCHAR(15)|0||0
vlr_number|VARCHAR(15)|0||0
Table subscriber contents:
ggsn_number|gmlc_number|id|imei|imeisv|imsi|last_lu_seen|last_lu_seen_ps|lmsi|ms_purged_cs|ms_purged_ps|msc_number|msisdn|nam_cs|nam_ps|periodic_lu_tmr|periodic_rau_tau_tmr|sgsn_address|sgsn_number|smsc_number|vlr_number
||1|||123456789012345||||0|0||098765432109876|1|1||||||MSC-1
||2|||111111111||||1|0|||1|1||||||
||3|||222222222||||0|1||22222|1|1||||||
||4|||333333||||0|0||3|0|1||||||
||5|||444444444444444||||0|0||4444|1|0||||||
||6|||5555555||||0|0||55555555555555|0|0||||||
Table: subscriber_apn
name|type|notnull|dflt_value|pk
apn|VARCHAR(256)|1||0
subscriber_id|INTEGER|0||0
Table subscriber_apn contents:
Table: subscriber_multi_msisdn
name|type|notnull|dflt_value|pk
msisdn|VARCHAR(15)|1||0
subscriber_id|INTEGER|0||0
Table subscriber_multi_msisdn contents:
Verify that osmo-hlr can open it:
osmo-hlr --database $db --db-check --config-file $srcdir/osmo-hlr.cfg
rc = 0
DMAIN hlr starting
DDB using database: <PATH>test.db
DDB Database <PATH>test.db' has HLR DB schema version 4
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.

View File

@@ -1,83 +0,0 @@
#!/bin/sh
srcdir="${1:-.}"
builddir="${2:-.}"
do_equivalence_test="$3"
set -e
db="$builddir/test.db"
osmo_hlr="$builddir/../../src/osmo-hlr"
cfg="$srcdir/osmo-hlr.cfg"
dump_sorted_schema(){
db_file="$1"
tables="$(sqlite3 -batch -noheader "$db_file" "SELECT name FROM sqlite_master WHERE type = 'table' order by name")"
for table in $tables; do
echo
echo "Table: $table"
sqlite3 -batch -header "$db_file" "SELECT name,type,\"notnull\",dflt_value,pk FROM PRAGMA_TABLE_INFO('$table') order by name;"
echo
echo "Table $table contents:"
columns="$(sqlite3 -batch -noheader "$db_file" "SELECT name FROM PRAGMA_TABLE_INFO('$table') order by name;")"
sqlite3 -batch -header "$db_file" "SELECT $(echo $columns | sed 's/ /,/g') from $table;"
done
}
rm -f "$db"
echo "Creating db in schema version 0"
sqlite3 -batch "$db" < "$srcdir/hlr_db_v0.sql"
echo
echo "Version 0 db:"
dump_sorted_schema "$db"
set +e
echo
echo "Launching osmo-hlr to upgrade db:"
echo osmo-hlr --database '$db' --db-upgrade --db-check --config-file '$srcdir/osmo-hlr.cfg'
"$osmo_hlr" --database "$db" --db-upgrade --db-check --config-file "$cfg" >log 2>&1
echo "rc = $?"
cat log | sed 's@[^ "]*/@<PATH>@g'
echo
echo "Resulting db:"
dump_sorted_schema "$db"
echo
echo "Verify that osmo-hlr can open it:"
echo osmo-hlr --database '$db' --db-check --config-file '$srcdir/osmo-hlr.cfg'
"$osmo_hlr" --database "$db" --db-check --config-file "$cfg" >log 2>&1
echo "rc = $?"
cat log | sed 's@[^ "]*/@<PATH>@g'
if [ -n "$do_equivalence_test" ]; then
# this part requires osmo_interact_vty.py, so this test is not part of the normal run
set -e -x
mint_db="$builddir/mint.db"
rm -f "$mint_db"
osmo_verify_transcript_vty.py -v \
-n OsmoHLR -p 4258 \
-r "$osmo_hlr -c $cfg -l $mint_db" \
"$srcdir/create_subscribers.vty"
sqlite3 -batch "$mint_db" < "$srcdir/create_subscribers_step2.sql"
set +x
test_dump="$builddir/test.dump"
mint_dump="$builddir/mint.dump"
dump_sorted_schema "$db" > "$test_dump"
dump_sorted_schema "$mint_db" > "$mint_dump"
echo
echo "Newly created sorted schema is:"
cat "$mint_dump"
echo
echo "Diff to upgraded schema:"
diff -u "$mint_dump" "$test_dump"
echo "rc=$?"
fi
rm -f log
rm -f "$db"

View File

@@ -1,80 +0,0 @@
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE subscriber (
-- OsmoHLR's DB scheme is modelled roughly after TS 23.008 version 13.3.0
id INTEGER PRIMARY KEY,
-- Chapter 2.1.1.1
imsi VARCHAR(15) UNIQUE NOT NULL,
-- Chapter 2.1.2
msisdn VARCHAR(15) UNIQUE,
-- Chapter 2.2.3: Most recent / current IMEI
imeisv VARCHAR,
-- Chapter 2.4.5
vlr_number VARCHAR(15),
-- Chapter 2.4.6
hlr_number VARCHAR(15),
-- Chapter 2.4.8.1
sgsn_number VARCHAR(15),
-- Chapter 2.13.10
sgsn_address VARCHAR,
-- Chapter 2.4.8.2
ggsn_number VARCHAR(15),
-- Chapter 2.4.9.2
gmlc_number VARCHAR(15),
-- Chapter 2.4.23
smsc_number VARCHAR(15),
-- Chapter 2.4.24
periodic_lu_tmr INTEGER,
-- Chapter 2.13.115
periodic_rau_tau_tmr INTEGER,
-- Chapter 2.1.1.2: network access mode
nam_cs BOOLEAN NOT NULL DEFAULT 1,
nam_ps BOOLEAN NOT NULL DEFAULT 1,
-- Chapter 2.1.8
lmsi INTEGER,
-- The below purged flags might not even be stored non-volatile,
-- refer to TS 23.012 Chapter 3.6.1.4
-- Chapter 2.7.5
ms_purged_cs BOOLEAN NOT NULL DEFAULT 0,
-- Chapter 2.7.6
ms_purged_ps BOOLEAN NOT NULL DEFAULT 0
);
INSERT INTO subscriber VALUES(1,'123456789012345','098765432109876',NULL,'MSC-1',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,1,NULL,0,0);
INSERT INTO subscriber VALUES(2,'111111111',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,1,NULL,1,0);
INSERT INTO subscriber VALUES(3,'222222222','22222',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,1,NULL,0,1);
INSERT INTO subscriber VALUES(4,'333333','3',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,1,NULL,0,0);
INSERT INTO subscriber VALUES(5,'444444444444444','4444',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,0,NULL,0,0);
INSERT INTO subscriber VALUES(6,'5555555','55555555555555',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,0,NULL,0,0);
CREATE TABLE subscriber_apn (
subscriber_id INTEGER, -- subscriber.id
apn VARCHAR(256) NOT NULL
);
CREATE TABLE subscriber_multi_msisdn (
-- Chapter 2.1.3
subscriber_id INTEGER, -- subscriber.id
msisdn VARCHAR(15) NOT NULL
);
CREATE TABLE auc_2g (
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
algo_id_2g INTEGER NOT NULL, -- enum osmo_auth_algo value
ki VARCHAR(32) NOT NULL -- hex string: subscriber's secret key (128bit)
);
INSERT INTO auc_2g VALUES(1,1,'BeefedCafeFaceAcedAddedDecadeFee');
INSERT INTO auc_2g VALUES(4,2,'33333333333333333333333333333333');
INSERT INTO auc_2g VALUES(6,4,'55555555555555555555555555555555');
CREATE TABLE auc_3g (
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value
k VARCHAR(32) NOT NULL, -- hex string: subscriber's secret key (128bit)
op VARCHAR(32), -- hex string: operator's secret key (128bit)
opc VARCHAR(32), -- hex string: derived from OP and K (128bit)
sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage
-- nr of index bits at lower SQN end
ind_bitlen INTEGER NOT NULL DEFAULT 5
);
INSERT INTO auc_3g VALUES(1,5,'C01ffedC1cadaeAc1d1f1edAcac1aB0a',NULL,'CededEffacedAceFacedBadFadedBeef',0,5);
INSERT INTO auc_3g VALUES(5,5,'44444444444444444444444444444444','44444444444444444444444444444444',NULL,0,5);
INSERT INTO auc_3g VALUES(6,5,'55555555555555555555555555555555',NULL,'55555555555555555555555555555555',0,5);
CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi)
;
COMMIT;

View File

@@ -1,6 +0,0 @@
log stderr
logging level db notice
logging print category-hex 0
logging print file 0
logging print category 1
logging color 0

42
tests/gsup/Makefile.am Normal file
View File

@@ -0,0 +1,42 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/src \
$(NULL)
AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
-no-install \
$(NULL)
EXTRA_DIST = \
gsup_test.ok \
gsup_test.err \
$(NULL)
noinst_PROGRAMS = \
gsup_test \
$(NULL)
gsup_test_SOURCES = \
gsup_test.c \
$(NULL)
gsup_test_LDADD = \
$(top_srcdir)/src/luop.c \
$(top_srcdir)/src/gsup_server.c \
$(top_srcdir)/src/gsup_router.c \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOABIS_LIBS) \
$(NULL)
.PHONY: update_exp
update_exp:
$(builddir)/gsup_test >"$(srcdir)/gsup_test.ok" 2>"$(srcdir)/gsup_test.err"

91
tests/gsup/gsup_test.c Normal file
View File

@@ -0,0 +1,91 @@
/* (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* 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 <string.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/application.h>
#include <osmocom/gsm/gsup.h>
#include "logging.h"
#include "luop.h"
struct osmo_gsup_server;
/* override osmo_gsup_addr_send() to not actually send anything. */
int osmo_gsup_addr_send(struct osmo_gsup_server *gs,
const uint8_t *addr, size_t addrlen,
struct msgb *msg)
{
LOGP(DMAIN, LOGL_DEBUG, "%s\n", msgb_hexdump(msg));
msgb_free(msg);
return 0;
}
int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
struct hlr_subscriber *subscr)
{
return 0;
}
/* Verify that the internally allocated msgb is large enough */
void test_gsup_tx_insert_subscr_data()
{
struct lu_operation luop = {
.state = LU_S_LU_RECEIVED,
.subscr = {
.imsi = "123456789012345",
.msisdn = "987654321098765",
.nam_cs = true,
.nam_ps = true,
},
.is_ps = true,
};
lu_op_tx_insert_subscr_data(&luop);
}
const struct log_info_cat default_categories[] = {
[DMAIN] = {
.name = "DMAIN",
.description = "Main Program",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
};
static struct log_info info = {
.cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories),
};
int main(int argc, char **argv)
{
void *ctx = talloc_named_const(NULL, 0, "gsup_test");
osmo_init_logging2(ctx, &info);
log_set_print_filename(osmo_stderr_target, 0);
log_set_print_timestamp(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 0);
log_set_print_category(osmo_stderr_target, 1);
test_gsup_tx_insert_subscr_data();
printf("Done.\n");
return EXIT_SUCCESS;
}

2
tests/gsup/gsup_test.err Normal file
View File

@@ -0,0 +1,2 @@
DMAIN 10 01 08 21 43 65 87 09 21 43 f5 08 09 08 89 67 45 23 01 89 67 f5 05 07 10 01 01 12 02 01 2a 28 01 01
DMAIN LU OP state change: LU RECEIVED -> ISD SENT

1
tests/gsup/gsup_test.ok Normal file
View File

@@ -0,0 +1 @@
Done.

View File

@@ -1,11 +1,11 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/src \
$(NULL)
AM_CFLAGS = \
-Wall \
-ggdb3 \
-I$(top_srcdir)/include \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \

View File

@@ -20,7 +20,7 @@
#include <stdio.h>
#include <osmocom/core/utils.h>
#include <osmocom/hlr/gsup_server.h>
#include "gsup_server.h"
#define comment_start() printf("\n===== %s\n", __func__)
#define comment_end() printf("===== %s: SUCCESS\n\n", __func__)

View File

@@ -1,15 +1,3 @@
OsmoHLR> ?
show Show running system information
list Print command list
exit Exit current mode and down to previous mode
help Description of the interactive help system
enable Turn on privileged mode command
terminal Set terminal line parameters
who Display who is on vty
logging Configure logging
no Negate a command or set its defaults
logp Print a message on all log outputs; useful for placing markers in test logs
subscriber Subscriber management commands
OsmoHLR> list
show version
show online-help
@@ -37,24 +25,14 @@ OsmoHLR> list
show subscriber (imsi|msisdn|id|imei) IDENT
OsmoHLR> enable
OsmoHLR# ?
help Description of the interactive help system
list Print command list
write Write running configuration to memory, network, or terminal
show Show running system information
exit Exit current mode and down to previous mode
disable Turn off privileged mode command
configure Configuration from vty interface
copy Copy configuration
terminal Set terminal line parameters
who Display who is on vty
logging Configure logging
no Negate a command or set its defaults
logp Print a message on all log outputs; useful for placing markers in test logs
subscriber Subscriber management commands
OsmoHLR# list
help
...
list
write terminal
write file
write memory
write
show running-config
exit
disable
configure terminal
@@ -72,35 +50,28 @@ OsmoHLR# list
...
OsmoHLR# configure terminal
OsmoHLR(config)# ?
...
banner Set banner string
service Set up miscellaneous service
line Configure a terminal line
ctrl Configure the Control Interface
log Configure logging sub-system
stats Configure stats sub-system
hlr Configure the HLR
OsmoHLR(config)# list
help
...
list
write terminal
write file
write memory
write
show running-config
exit
end
...
hlr
OsmoHLR(config)# hlr
OsmoHLR(config-hlr)# ?
...
euse Configure a particular External USSD Entity
no Negate a command or set its defaults
ussd USSD Configuration
ncss-guard-timeout Set guard timer for NCSS (call independent SS) session activity
store-imei Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').
subscriber-create-on-demand Make a new record when a subscriber is first seen.
OsmoHLR(config-hlr)# list
help
...
list
write terminal
write file
write memory
write
show running-config
exit
end
gsup
@@ -119,11 +90,16 @@ OsmoHLR(config-hlr)# list
no subscriber-create-on-demand
OsmoHLR(config-hlr)# gsup
OsmoHLR(config-hlr-gsup)# ?
...
bind Listen/Bind related socket option
OsmoHLR(config-hlr-gsup)# list
...
help
list
write terminal
write file
write memory
write
show running-config
exit
end
bind ip A.B.C.D
OsmoHLR(config-hlr-gsup)# exit

View File

@@ -15,6 +15,13 @@ cat $abs_srcdir/auc/auc_ts_55_205_test_sets.err > experr
AT_CHECK([$abs_top_builddir/tests/auc/auc_ts_55_205_test_sets], [], [expout], [experr])
AT_CLEANUP
AT_SETUP([gsup])
AT_KEYWORDS([gsup])
cat $abs_srcdir/gsup/gsup_test.ok > expout
cat $abs_srcdir/gsup/gsup_test.err > experr
AT_CHECK([$abs_top_builddir/tests/gsup/gsup_test], [], [expout], [experr])
AT_CLEANUP
AT_SETUP([gsup_server])
AT_KEYWORDS([gsup_server])
cat $abs_srcdir/gsup_server/gsup_server_test.ok > expout
@@ -29,13 +36,3 @@ cat $abs_srcdir/db/db_test.err > experr
sqlite3 db_test.db < $abs_top_srcdir/sql/hlr.sql
AT_CHECK([$abs_top_builddir/tests/db/db_test], [], [expout], [experr])
AT_CLEANUP
# AT_SKIP_IF: disable for old sqlite versions, because the way we dump tables in the test doesn't work with it.
# https://lists.osmocom.org/pipermail/openbsc/2019-November/013063.html
AT_SETUP([db_upgrade])
AT_SKIP_IF([ ! pkg-config sqlite3 --exists --atleast-version=3.16.2 ])
AT_KEYWORDS([db_upgrade])
cat $abs_srcdir/db_upgrade/db_upgrade_test.ok > expout
cat $abs_srcdir/db_upgrade/db_upgrade_test.err > experr
AT_CHECK([$abs_srcdir/db_upgrade/db_upgrade_test.sh $abs_srcdir/db_upgrade $abs_builddir/db_upgrade], [], [expout], [experr])
AT_CLEANUP