Compare commits

..

16 Commits

Author SHA1 Message Date
Neels Hofmeyr
1f8f1b9777 cosmetic comment tweak
Change-Id: I0482d663e6c9042545677f9280c751323d332439
2019-12-25 19:09:45 +01:00
Piotr Krysik
a5ed663dea 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-12-25 19:09:45 +01:00
Harald Welte
15031855bf AUC: Add support for setting the AMF separation bit to '1' for EUTRAN
Change-Id: Ic766bc40f6126bb479bd0a05b0e96bec3e240008
2019-12-25 19:09:45 +01:00
Neels Hofmeyr
83b909e4f3 Revert "mention *#201#, *#301# in USSD get_ran (HACK)"
This reverts commit 05e888ed7c.
2019-12-25 19:09:45 +01:00
Neels Hofmeyr
fde8f64d1d mention *#201#, *#301# in USSD get_ran (HACK)
Change-Id: Idbedbc679868a88dae1c85f82527f3f20067b879
2019-12-25 19:09:45 +01:00
gsmevent admin
d8e8a8425a send GMM_CAUSE_ROAMING_NOTALLOWED instead of GMM_CAUSE_IMSI_UNKNOWN HARDCODED 2019-12-25 19:09:45 +01:00
Neels Hofmeyr
c1d56fd2e9 add USSD handlers to enable/disable 2G access
Change-Id: Ib266bf6ebc7692362a443efbf9b4ae69aee671d6
2019-12-25 19:09:45 +01:00
Neels Hofmeyr
6ac66ac3ad for ussd_get_ran, show current RAT
Change-Id: I81adb1785c1a46e9153a6914ef2c699e9c90b731
2019-12-25 19:09:45 +01:00
Neels Hofmeyr
769a7f46f4 auto upgrade hlr.db in the service file
Change-Id: Icd3af5160e6d8f31fed5e84055fbb09322c54c2b
2019-12-25 19:09:45 +01:00
Neels Hofmeyr
5bc457e19a add column 'last_lu_rat', show last RAN type
Change-Id: I5d73b1d928b61175d3198326706b7f49ba50e16f
2019-12-25 19:09:45 +01:00
Vadim Yanitskiy
e3c788d9a8 SS/USSD: update configuretion example
Change-Id: I3801968d29bae917bf8669bb4ac03a9c4f3cb96c
2019-12-25 19:09:45 +01:00
Vadim Yanitskiy
e6751dd207 SS/USSD: add IUSEs to enable / disable UMTS
Change-Id: Icf85ec8dd71813a9bbf359b9011456844f398337
2019-12-25 19:09:45 +01:00
Vadim Yanitskiy
e8b7b8634b SS/USSD: implement an IUSE for getting RAN type(s)
Change-Id: I8d95413784b039df50a4cdcac49289060f0414c6
2019-12-25 19:09:45 +01:00
Neels Hofmeyr
ce172efc0b 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-12-25 19:09:45 +01:00
Neels Hofmeyr
2f1049827b trial: SMS-over-GSUP 2019-12-23 16:52:24 +01:00
Neels Hofmeyr
92d1c4a0de db v6: determine 3G AUC IND from VLR name
Each VLR requesting auth tuples should use a distinct IND pool for 3G auth.  So
far we tied the IND to the GSUP peer connection; MSC and SGSN were always
distinct GSUP peers, they ended up using distinct INDs.

However, we have implemented a GSUP proxy, so that, in a distributed setup, a
remotely roaming subscriber has only one direct GSUP peer proxying for both
remote MSC and SGSN. That means as soon as a subscriber roams to a different
site, we would use the GSUP proxy name to determine the IND instead of the
separate MSC and SGSN. The site's MSC and SGSN appear as the same client, get
the same IND bucket, waste SQNs rapidly and cause auth tuple generation load.

So instead of using the local client as IND, persistently keep a list of VLR
names and assign a different IND to each. Use the gsup_req->source_name as
indicator, which reflects the actual remote VLR's name (remote MSC or SGSN).

Persist the site <-> IND assignments in the database.

Add an IND test to db_test.c

There was an earlier patch version that separated the IND pools by cn_domain,
but it turned out to add complex semantics, while only solving one aspect of
the "adjacent VLR" problem. We need a solution not only for CS vs PS, but also
for 2,3G vs 4G, and for sites that are physically adjacent to each other. This
patch version does not offer any automatic solution for that -- as soon as more
than 2^IND_bitlen (usually 32) VLRs show up, it is the responsibility of the
admin to ensure the 'ind' table in the hlr.db does not have unfortunate IND
assignments. So far no VTY commands exist for that, they may be added in the
future.

Related: OS#4319
Change-Id: I6f0a6bbef3a27507605c3b4a0e1a89bdfd468374
2019-12-23 16:52:08 +01:00
16 changed files with 620 additions and 38 deletions

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]

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

@@ -5,6 +5,7 @@
#include <osmocom/gsupclient/gsup_peer_id.h>
#include <osmocom/gsm/gsup.h>
#include <osmocom/gsm/gsm_utils.h>
struct hlr;
@@ -37,6 +38,8 @@ enum stmt_idx {
DB_STMT_IND_ADD,
DB_STMT_IND_SELECT,
DB_STMT_IND_DEL,
DB_STMT_UPD_RAT_FLAG,
DB_STMT_RAT_BY_ID,
_NUM_DB_STMT
};
@@ -104,11 +107,18 @@ struct hlr_subscriber {
bool ms_purged_ps;
time_t last_lu_seen;
time_t last_lu_seen_ps;
char last_lu_rat_cs[128];
char last_lu_rat_ps[128];
/* talloc'd IPA unit name */
struct osmo_ipa_name vlr_via_proxy;
struct osmo_ipa_name sgsn_via_proxy;
bool rat_types[OSMO_RAT_COUNT];
};
static const struct hlr_subscriber hlr_subscriber_empty = {
.rat_types = { true, true, true },
};
/* A format string for use with strptime(3). This format string is
* used to parse the last_lu_seen column stored in the HLR database.
* See https://sqlite.org/lang_datefunc.html, function datetime(). */
@@ -162,7 +172,8 @@ int db_subscr_get_by_imei(struct db_context *dbc, const char *imei, struct hlr_s
int db_subscr_nam(struct db_context *dbc, const char *imsi, bool nam_val, bool is_ps);
int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
const struct osmo_ipa_name *vlr_name, bool is_ps,
const struct osmo_ipa_name *via_proxy);
const struct osmo_ipa_name *via_proxy,
const enum osmo_rat_type rat_types[], size_t rat_types_len);
int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
bool purge_val, bool is_ps);
@@ -170,6 +181,10 @@ int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
int db_ind(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr, unsigned int *ind);
int db_ind_del(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr);
int db_subscr_set_rat_type_flag(struct db_context *dbc, int64_t subscr_id, enum osmo_rat_type rat, bool allowed);
int db_subscr_get_rat_types(struct db_context *dbc, struct hlr_subscriber *subscr);
int hlr_subscr_rat_flag(struct hlr *hlr, struct hlr_subscriber *subscr, enum osmo_rat_type rat, bool allowed);
/*! Call sqlite3_column_text() and copy result to a char[].
* \param[out] buf A char[] used as sizeof() arg(!) and osmo_strlcpy() target.
* \param[in] stmt An sqlite3_stmt*.

View File

@@ -45,6 +45,12 @@ CREATE TABLE subscriber (
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_cs TEXT default NULL,
last_lu_rat_ps TEXT default NULL,
-- When a LU was received via a proxy, that proxy's hlr_number is stored here,
-- while vlr_number reflects the MSC on the far side of that proxy.
vlr_via_proxy VARCHAR,
@@ -87,8 +93,18 @@ CREATE TABLE ind (
UNIQUE (vlr)
);
-- Optional: add subscriber entries to allow or disallow specific RATs (2G or 3G or ...).
-- If a subscriber has no entry, that means that all RATs are allowed (backwards compat).
CREATE TABLE subscriber_rat (
subscriber_id INTEGER, -- subscriber.id
rat TEXT CHECK(rat in ('GERAN-A', 'UTRAN-Iu','EUTRAN-SGs')) NOT NULL, -- Radio Access Technology, see enum ran_type
allowed BOOLEAN CHECK(allowed in (0, 1)) NOT NULL DEFAULT 0,
UNIQUE (subscriber_id, rat)
);
CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi);
CREATE UNIQUE INDEX idx_subscr_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 = 6;
PRAGMA user_version = 8;

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

@@ -30,7 +30,7 @@
#include "db_bootstrap.h"
/* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */
#define CURRENT_SCHEMA_VERSION 6
#define CURRENT_SCHEMA_VERSION 8
#define SEL_COLUMNS \
"id," \
@@ -49,6 +49,8 @@
"ms_purged_ps," \
"last_lu_seen," \
"last_lu_seen_ps," \
"last_lu_rat_cs," \
"last_lu_rat_ps," \
"vlr_via_proxy," \
"sgsn_via_proxy"
@@ -83,13 +85,23 @@ 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_cs = $rat"
" WHERE id = $subscriber_id",
[DB_STMT_SET_LAST_LU_SEEN_PS] = "UPDATE subscriber SET last_lu_seen_ps = datetime($val, 'unixepoch'),"
" last_lu_rat_ps = $rat"
" WHERE id = $subscriber_id",
[DB_STMT_EXISTS_BY_IMSI] = "SELECT 1 FROM subscriber WHERE imsi = $imsi",
[DB_STMT_EXISTS_BY_MSISDN] = "SELECT 1 FROM subscriber WHERE msisdn = $msisdn",
[DB_STMT_IND_ADD] = "INSERT INTO ind (vlr) VALUES ($vlr)",
[DB_STMT_IND_SELECT] = "SELECT ind FROM ind WHERE vlr = $vlr",
[DB_STMT_IND_DEL] = "DELETE FROM ind WHERE vlr = $vlr",
[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)
@@ -335,7 +347,7 @@ 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'.
/* A newer SQLite version would allow simply 'ALTER TABLE subscriber RENAME COLUMN hlr_number TO msc_number'.
* This is a really expensive workaround for that in order to cover earlier SQLite versions as well:
* Create a new table with the new column name and copy the data over (https://www.sqlite.org/faq.html#q11).
*/
@@ -489,12 +501,11 @@ static int db_upgrade_v6(struct db_context *dbc)
int rc;
const char *statements[] = {
"CREATE TABLE ind (\n"
" cn_domain INTEGER NOT NULL,\n"
" -- 3G auth IND bucket to be used for this VLR, where IND = (idx << 1) + cn_domain -1\n"
" -- 3G auth IND pool to be used for this VLR\n"
" ind INTEGER PRIMARY KEY,\n"
" -- VLR identification, usually the GSUP source_name\n"
" vlr TEXT NOT NULL,\n"
" UNIQUE (cn_domain, vlr)\n"
" UNIQUE (vlr)\n"
")"
,
"PRAGMA user_version = 6",
@@ -508,6 +519,47 @@ static int db_upgrade_v6(struct db_context *dbc)
return rc;
}
static int db_upgrade_v7(struct db_context *dbc)
{
int rc;
const char *statements[] = {
"-- Optional: add subscriber entries to allow or disallow specific RATs (2G or 3G or ...).\n"
"-- If a subscriber has no entry, that means that all RATs are allowed (backwards compat).\n"
"CREATE TABLE subscriber_rat (\n"
" subscriber_id INTEGER, -- subscriber.id\n"
" rat TEXT CHECK(rat in ('GERAN-A', 'UTRAN-Iu')) NOT NULL, -- Radio Access Technology, see enum ran_type\n"
" allowed BOOLEAN CHECK(allowed in (0, 1)) NOT NULL DEFAULT 0,\n"
" UNIQUE (subscriber_id, rat)\n"
")",
"CREATE UNIQUE INDEX idx_subscr_rat_flag ON subscriber_rat (subscriber_id, rat)",
"PRAGMA user_version = 7",
};
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 7\n");
return rc;
}
return rc;
}
static int db_upgrade_v8(struct db_context *dbc)
{
int rc;
const char *statements[] = {
"ALTER TABLE subscriber ADD COLUMN last_lu_rat_cs TEXT default NULL",
"ALTER TABLE subscriber ADD COLUMN last_lu_rat_ps TEXT default NULL",
"PRAGMA user_version = 8",
};
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 7\n");
return rc;
}
return rc;
}
typedef int (*db_upgrade_func_t)(struct db_context *dbc);
static db_upgrade_func_t db_upgrade_path[] = {
db_upgrade_v1,
@@ -516,6 +568,8 @@ static db_upgrade_func_t db_upgrade_path[] = {
db_upgrade_v4,
db_upgrade_v5,
db_upgrade_v6,
db_upgrade_v7,
db_upgrade_v8,
};
static int db_get_user_version(struct db_context *dbc)
@@ -644,9 +698,9 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logg
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

@@ -483,7 +483,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);
@@ -505,12 +505,17 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
subscr->imsi, "CS");
parse_last_lu_seen(&subscr->last_lu_seen_ps, (const char *)sqlite3_column_text(stmt, 15),
subscr->imsi, "PS");
copy_sqlite3_text_to_ipa_name(&subscr->vlr_via_proxy, stmt, 16);
copy_sqlite3_text_to_ipa_name(&subscr->sgsn_via_proxy, stmt, 17);
copy_sqlite3_text_to_buf(subscr->last_lu_rat_cs, stmt, 16);
copy_sqlite3_text_to_buf(subscr->last_lu_rat_ps, stmt, 17);
copy_sqlite3_text_to_ipa_name(&subscr->vlr_via_proxy, stmt, 18);
copy_sqlite3_text_to_ipa_name(&subscr->sgsn_via_proxy, stmt, 19);
out:
db_remove_reset(stmt);
if (ret == 0)
db_subscr_get_rat_types(dbc, subscr);
switch (ret) {
case 0:
*err = NULL;
@@ -737,11 +742,14 @@ out:
*/
int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
const struct osmo_ipa_name *vlr_name, bool is_ps,
const struct osmo_ipa_name *via_proxy)
const struct osmo_ipa_name *via_proxy,
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];
@@ -803,6 +811,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,
@@ -987,3 +1010,119 @@ int db_ind_del(struct db_context *dbc, const struct osmo_gsup_peer_id *vlr)
{
return _db_ind(dbc, vlr, NULL, true);
}
int db_subscr_set_rat_type_flag(struct db_context *dbc, int64_t subscr_id, enum osmo_rat_type rat, bool allowed)
{
int rc;
int ret = 0;
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_UPD_RAT_FLAG];
if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
return -EIO;
OSMO_ASSERT(rat >= 0 && rat < OSMO_RAT_COUNT);
if (!db_bind_text(stmt, "$rat", osmo_rat_type_name(rat)))
return -EIO;
if (!db_bind_int(stmt, "$allowed", allowed ? 1 : 0))
return -EIO;
/* execute the statement */
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "%s %s: SQL error: %s\n",
allowed ? "enable" : "disable", osmo_rat_type_name(rat),
sqlite3_errmsg(dbc->db));
ret = -EIO;
goto out;
}
/* verify execution result */
rc = sqlite3_changes(dbc->db);
if (!rc) {
LOGP(DDB, LOGL_ERROR, "Cannot %s %s: no such subscriber: ID=%" PRIu64 "\n",
allowed ? "enable" : "disable", osmo_rat_type_name(rat),
subscr_id);
ret = -ENOENT;
goto out;
} else if (rc != 1) {
LOGP(DDB, LOGL_ERROR, "%s %s: SQL modified %d rows (expected 1)\n",
allowed ? "enable" : "disable", osmo_rat_type_name(rat),
rc);
ret = -EIO;
}
out:
db_remove_reset(stmt);
return ret;
}
int db_subscr_get_rat_types(struct db_context *dbc, struct hlr_subscriber *subscr)
{
int rc;
int ret = 0;
int i;
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_RAT_BY_ID];
if (!db_bind_int64(stmt, "$subscriber_id", subscr->id))
return -EIO;
for (i = 0; i < OSMO_RAT_COUNT; i++)
subscr->rat_types[i] = true;
/* execute the statement */
while (1) {
enum osmo_rat_type rat;
bool allowed;
rc = sqlite3_step(stmt);
if (rc == SQLITE_DONE)
break;
if (rc != SQLITE_ROW)
return -rc;
rc = get_string_value(osmo_rat_type_names, (const char*)sqlite3_column_text(stmt, 0));
if (rc == -EINVAL) {
ret = -EINVAL;
goto out;
}
if (rc <= 0 || rc >= OSMO_RAT_COUNT) {
ret = -EINVAL;
goto out;
}
rat = rc;
allowed = sqlite3_column_int(stmt, 1);
subscr->rat_types[rat] = allowed;
LOGP(DAUC, LOGL_DEBUG, "db: imsi='%s' %s %s\n",
subscr->imsi, osmo_rat_type_name(rat), allowed ? "allowed" : "forbidden");
}
out:
db_remove_reset(stmt);
return ret;
}
int hlr_subscr_rat_flag(struct hlr *hlr, struct hlr_subscriber *subscr, enum osmo_rat_type rat, bool allowed)
{
int rc;
OSMO_ASSERT(rat >= 0 && rat < OSMO_RAT_COUNT);
db_subscr_get_rat_types(hlr->dbc, subscr);
if (subscr->rat_types[rat] == allowed) {
LOGHLR(subscr->imsi, LOGL_DEBUG, "Already has the requested value when asked to %s %s\n",
allowed ? "enable" : "disable", osmo_rat_type_name(rat));
return -ENOEXEC;
}
rc = db_subscr_set_rat_type_flag(hlr->dbc, subscr->id, rat, allowed);
if (rc)
return rc > 0? -rc : rc;
/* FIXME: If we're disabling, send message to VLR to detach subscriber */
return 0;
}

View File

@@ -320,7 +320,7 @@ static int rx_send_auth_info(struct osmo_gsup_req *req)
" Returning slightly inaccurate cause 'IMSI Unknown' via GSUP");
return rc;
case -ENOENT:
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "IMSI unknown");
osmo_gsup_req_respond_err(req, GMM_CAUSE_ROAMING_NOTALLOWED, "IMSI unknown");
return rc;
default:
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "failure to look up IMSI in db");
@@ -372,7 +372,7 @@ static int rx_purge_ms_req(struct osmo_gsup_req *req)
if (rc == 0)
osmo_gsup_req_respond_msgt(req, OSMO_GSUP_MSGT_PURGE_MS_RESULT, true);
else if (rc == -ENOENT)
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "IMSI unknown");
osmo_gsup_req_respond_err(req, GMM_CAUSE_ROAMING_NOTALLOWED, "IMSI unknown");
else
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "db error");
return rc;

View File

@@ -373,6 +373,206 @@ static int handle_ussd_own_imsi(struct ss_session *ss,
return 0;
}
static int handle_ussd_get_ran(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_cs)
rat = "nothing, you don't exist";
else if (!strcmp(subscr.last_lu_rat_cs, "GERAN-A"))
rat = "2G";
else if (!strcmp(subscr.last_lu_rat_cs, "UTRAN-Iu"))
rat = "3G";
else if (!strcmp(subscr.last_lu_rat_cs, "EUTRAN-SGs"))
rat = "4G";
else
rat = subscr.last_lu_rat_cs;
snprintf(response, sizeof(response),
"Now on %s. Available:%s%s%s.",
rat,
subscr.rat_types[OSMO_RAT_GERAN_A]? " 2G" : "",
subscr.rat_types[OSMO_RAT_UTRAN_IU]? " 3G" : "",
subscr.rat_types[OSMO_RAT_EUTRAN_SGS]? " 4G" : "");
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id, response);
break;
case -ENOENT:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
break;
case -EIO:
default:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
break;
}
return rc;
}
static int handle_ussd_gsm_on(struct ss_session *ss,
const struct osmo_gsup_message *gsup,
const struct ss_request *req)
{
struct hlr_subscriber subscr;
int rc;
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
switch (rc) {
case 0:
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_GERAN_A, true);
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
"Enabled GERAN-A (2G)");
break;
case -ENOENT:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
break;
case -EIO:
default:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
break;
}
return rc;
}
static int handle_ussd_gsm_off(struct ss_session *ss,
const struct osmo_gsup_message *gsup,
const struct ss_request *req)
{
struct hlr_subscriber subscr;
int rc;
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
switch (rc) {
case 0:
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_GERAN_A, false);
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
"Disabled GERAN-A (2G)");
break;
case -ENOENT:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
break;
case -EIO:
default:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
break;
}
return rc;
}
static int handle_ussd_umts_on(struct ss_session *ss,
const struct osmo_gsup_message *gsup,
const struct ss_request *req)
{
struct hlr_subscriber subscr;
int rc;
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
switch (rc) {
case 0:
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_UTRAN_IU, true);
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
"Enabled UTRAN-Iu (3G)");
break;
case -ENOENT:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
break;
case -EIO:
default:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
break;
}
return rc;
}
static int handle_ussd_umts_off(struct ss_session *ss,
const struct osmo_gsup_message *gsup,
const struct ss_request *req)
{
struct hlr_subscriber subscr;
int rc;
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
switch (rc) {
case 0:
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_UTRAN_IU, false);
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
"Disabled UTRAN-Iu (3G)");
break;
case -ENOENT:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
break;
case -EIO:
default:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
break;
}
return rc;
}
static int handle_ussd_lte_on(struct ss_session *ss,
const struct osmo_gsup_message *gsup,
const struct ss_request *req)
{
struct hlr_subscriber subscr;
int rc;
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
switch (rc) {
case 0:
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_EUTRAN_SGS, true);
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
"Enabled EUTRAN-SGs (4G)");
break;
case -ENOENT:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
break;
case -EIO:
default:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
break;
}
return rc;
}
static int handle_ussd_lte_off(struct ss_session *ss,
const struct osmo_gsup_message *gsup,
const struct ss_request *req)
{
struct hlr_subscriber subscr;
int rc;
rc = db_subscr_get_by_imsi(g_hlr->dbc, ss->imsi, &subscr);
switch (rc) {
case 0:
hlr_subscr_rat_flag(g_hlr, &subscr, OSMO_RAT_EUTRAN_SGS, false);
rc = ss_tx_to_ms_ussd_7bit(ss, true, req->invoke_id,
"Disabled EUTRAN-SGs (4G)");
break;
case -ENOENT:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER);
break;
case -EIO:
default:
rc = ss_tx_to_ms_error(ss, true, GSM0480_ERR_CODE_SYSTEM_FAILURE);
break;
}
return rc;
}
static const struct hlr_iuse hlr_iuses[] = {
{
@@ -383,6 +583,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)

View File

@@ -174,10 +174,17 @@ DEFUN(cfg_hlr_gsup_ipa_name,
#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

@@ -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 <osmocom/hlr/hlr.h>
#include <osmocom/hlr/db.h>
@@ -48,7 +49,7 @@ static char *get_datestr(const time_t *t, char *buf, size_t bufsize)
return buf;
}
static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t last_lu_seen)
static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t last_lu_seen, const char *last_lu_rat)
{
uint32_t age;
char datebuf[32];
@@ -56,7 +57,7 @@ static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t
return;
vty_out(vty, " last LU seen on %s: %s", domain_label, get_datestr(&last_lu_seen, datebuf, sizeof(datebuf)));
if (!timestamp_age(&last_lu_seen, &age))
vty_out(vty, " (invalid timestamp)%s", VTY_NEWLINE);
vty_out(vty, " (invalid timestamp)");
else {
vty_out(vty, " (");
#define UNIT_AGO(UNITNAME, UNITVAL) \
@@ -68,14 +69,18 @@ static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t
UNIT_AGO("h", 60*60);
UNIT_AGO("m", 60);
UNIT_AGO("s", 1);
vty_out(vty, " ago)%s", VTY_NEWLINE);
vty_out(vty, " ago)");
#undef UNIT_AGO
}
if (last_lu_rat && *last_lu_rat != '\0')
vty_out(vty, " on %s", last_lu_rat);
vty_out(vty, "%s", VTY_NEWLINE);
}
static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
{
int rc;
int i;
struct osmo_sub_auth_data aud2g;
struct osmo_sub_auth_data aud3g;
@@ -112,8 +117,12 @@ 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);
dump_last_lu_seen(vty, "CS", subscr->last_lu_seen, subscr->last_lu_rat_cs);
dump_last_lu_seen(vty, "PS", subscr->last_lu_seen_ps, subscr->last_lu_rat_ps);
for (i = OSMO_RAT_UNKNOWN + 1; i < ARRAY_SIZE(subscr->rat_types); i++) {
vty_out(vty, " %s: %s%s", osmo_rat_type_name(i), subscr->rat_types[i] ? "allowed" : "forbidden",
VTY_NEWLINE);
}
if (!*subscr->imsi)
return;
@@ -630,6 +639,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);
@@ -643,4 +694,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

@@ -108,6 +108,8 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
{
struct osmo_fsm_inst *fi;
struct lu *lu;
bool any_rat_allowed;
int i;
OSMO_ASSERT(update_location_req);
OSMO_ASSERT(update_location_req->gsup.message_type == OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST);
@@ -136,7 +138,7 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
}
if (db_subscr_get_by_imsi(g_hlr->dbc, update_location_req->gsup.imsi, &lu->subscr) < 0) {
lu_failure(lu, GMM_CAUSE_IMSI_UNKNOWN, "Subscriber does not exist");
lu_failure(lu, GMM_CAUSE_ROAMING_NOTALLOWED, "Subscriber does not exist");
return;
}
@@ -151,6 +153,28 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
return;
}
/* Check if any available RAT type is allowed. See 3GPP TS 29.010 3.2 'Routeing area updating' and 3.8 'Location
* update' for the "No Suitable cells in location area" error code. */
any_rat_allowed = false;
for (i = 0; i < update_location_req->gsup.supported_rat_types_len; i++) {
enum osmo_rat_type rat = update_location_req->gsup.supported_rat_types[i];
if (rat <= 0 || rat >= OSMO_RAT_COUNT) {
lu_failure(lu, GMM_CAUSE_COND_IE_ERR, "Invalid RAT type in GSUP request: %s",
osmo_rat_type_name(rat));
return;
}
if (lu->subscr.rat_types[rat]) {
any_rat_allowed = true;
LOG_LU(lu, LOGL_DEBUG, "subscriber allowed on %s\n", osmo_rat_type_name(rat));
} else {
LOG_LU(lu, LOGL_DEBUG, "subscriber not allowed on %s\n", osmo_rat_type_name(rat));
}
}
if (!any_rat_allowed && update_location_req->gsup.supported_rat_types_len > 0) {
lu_failure(lu, GMM_CAUSE_NO_SUIT_CELL_IN_LA, "subscriber not allowed on any available RAT type");
return;
}
/* TODO: Set subscriber tracing = deactive in VLR/SGSN */
#if 0
@@ -186,7 +210,8 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
return;
}
if (db_subscr_lu(g_hlr->dbc, lu->subscr.id, &lu->vlr_name.ipa_name, lu->is_ps,
osmo_gsup_peer_id_is_empty(&lu->via_proxy)? NULL : &lu->via_proxy.ipa_name)) {
osmo_gsup_peer_id_is_empty(&lu->via_proxy)? NULL : &lu->via_proxy.ipa_name,
update_location_req->gsup.supported_rat_types, update_location_req->gsup.supported_rat_types_len)) {
lu_failure(lu, GMM_CAUSE_NET_FAIL, "Cannot update %s in the database",
lu->is_ps ? "SGSN number" : "VLR number");
return;

View File

@@ -80,7 +80,7 @@ static void proxy_deferred_gsup_req_add(struct proxy *proxy, struct osmo_gsup_re
static void proxy_pending_req_remote_hlr_connect_result(struct osmo_gsup_req *req, struct remote_hlr *remote_hlr)
{
if (!remote_hlr || !remote_hlr_is_up(remote_hlr)) {
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "Proxy: Failed to connect to home HLR");
osmo_gsup_req_respond_err(req, GMM_CAUSE_ROAMING_NOTALLOWED, "Proxy: Failed to connect to home HLR");
return;
}

View File

@@ -173,6 +173,8 @@ 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_cs);
Ps(last_lu_rat_ps);
fprintf(stderr, "}\n");
#undef Ps
#undef Pd
@@ -243,7 +245,7 @@ static int db_subscr_lu_str(struct db_context *dbc, int64_t subscr_id,
{
struct osmo_ipa_name vlr_nr;
osmo_ipa_name_set_str(&vlr_nr, vlr_or_sgsn_number);
return db_subscr_lu(dbc, subscr_id, &vlr_nr, is_ps, NULL);
return db_subscr_lu(dbc, subscr_id, &vlr_nr, is_ps, NULL, NULL, 0);
}
static void test_subscr_create_update_sel_delete()

View File

@@ -4,6 +4,9 @@ OsmoHLR# subscriber imsi 123456789012345 create
ID: 1
IMSI: 123456789012345
MSISDN: none
GERAN-A: allowed
UTRAN-Iu: allowed
EUTRAN-SGs: allowed
OsmoHLR# subscriber imsi 123456789012345 update msisdn 098765432109876
% Updated subscriber IMSI='123456789012345' to MSISDN='098765432109876'
OsmoHLR# subscriber imsi 123456789012345 update aud2g comp128v1 ki BeefedCafeFaceAcedAddedDecadeFee
@@ -13,11 +16,17 @@ OsmoHLR# subscriber imsi 111111111 create
ID: 2
IMSI: 111111111
MSISDN: none
GERAN-A: allowed
UTRAN-Iu: allowed
EUTRAN-SGs: allowed
OsmoHLR# subscriber imsi 222222222 create
% Created subscriber 222222222
ID: 3
IMSI: 222222222
MSISDN: none
GERAN-A: allowed
UTRAN-Iu: allowed
EUTRAN-SGs: allowed
OsmoHLR# subscriber imsi 222222222 update msisdn 22222
% Updated subscriber IMSI='222222222' to MSISDN='22222'
OsmoHLR# subscriber imsi 333333 create
@@ -25,6 +34,9 @@ OsmoHLR# subscriber imsi 333333 create
ID: 4
IMSI: 333333
MSISDN: none
GERAN-A: allowed
UTRAN-Iu: allowed
EUTRAN-SGs: allowed
OsmoHLR# subscriber imsi 333333 update msisdn 3
% Updated subscriber IMSI='333333' to MSISDN='3'
OsmoHLR# subscriber imsi 333333 update aud2g comp128v2 ki 33333333333333333333333333333333
@@ -33,6 +45,9 @@ OsmoHLR# subscriber imsi 444444444444444 create
ID: 5
IMSI: 444444444444444
MSISDN: none
GERAN-A: allowed
UTRAN-Iu: allowed
EUTRAN-SGs: allowed
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
@@ -41,6 +56,9 @@ OsmoHLR# subscriber imsi 5555555 create
ID: 6
IMSI: 5555555
MSISDN: none
GERAN-A: allowed
UTRAN-Iu: allowed
EUTRAN-SGs: allowed
OsmoHLR# subscriber imsi 5555555 update msisdn 55555555555555
% Updated subscriber IMSI='5555555' to MSISDN='55555555555555'
OsmoHLR# subscriber imsi 5555555 update aud2g xor ki 55555555555555555555555555555555

View File

@@ -86,6 +86,8 @@ DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 3
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 4
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 5
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 6
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 7
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 8
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
Resulting db:
@@ -120,7 +122,6 @@ algo_id_3g|ind_bitlen|k|op|opc|sqn|subscriber_id
Table: ind
name|type|notnull|dflt_value|pk
cn_domain|INTEGER|1||0
ind|INTEGER|0||1
vlr|TEXT|1||0
@@ -134,6 +135,8 @@ id|INTEGER|0||1
imei|VARCHAR(14)|0||0
imeisv|VARCHAR|0||0
imsi|VARCHAR(15)|1||0
last_lu_rat_cs|TEXT|0|NULL|0
last_lu_rat_ps|TEXT|0|NULL|0
last_lu_seen|TIMESTAMP|0|NULL|0
last_lu_seen_ps|TIMESTAMP|0|NULL|0
lmsi|INTEGER|0||0
@@ -153,13 +156,13 @@ vlr_number|VARCHAR(15)|0||0
vlr_via_proxy|VARCHAR|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|sgsn_via_proxy|smsc_number|vlr_number|vlr_via_proxy
||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||||||||
ggsn_number|gmlc_number|id|imei|imeisv|imsi|last_lu_rat_cs|last_lu_rat_ps|last_lu_seen|last_lu_seen_ps|lmsi|ms_purged_cs|ms_purged_ps|msc_number|msisdn|nam_cs|nam_ps|periodic_lu_tmr|periodic_rau_tau_tmr|sgsn_address|sgsn_number|sgsn_via_proxy|smsc_number|vlr_number|vlr_via_proxy
||1|||123456789012345||||||0|0||098765432109876|1|1|||||||MSC-1|
||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
@@ -175,10 +178,18 @@ subscriber_id|INTEGER|0||0
Table subscriber_multi_msisdn contents:
Table: subscriber_rat
name|type|notnull|dflt_value|pk
allowed|BOOLEAN|1|0|0
rat|TEXT|1||0
subscriber_id|INTEGER|0||0
Table subscriber_rat contents:
Verify that osmo-hlr can open it:
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 6
DDB Database <PATH>test.db' has HLR DB schema version 8
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.