aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2018-12-26 01:49:53 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2019-12-25 19:09:45 +0100
commitce172efc0bfe25f6e0d473100bc8d4f68de6db42 (patch)
tree4700925aa5c47266beba17610e990828787deafe
parent2f1049827b6f562155de140c8da16d8f286fa78d (diff)
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
-rw-r--r--include/osmocom/hlr/db.h12
-rw-r--r--sql/hlr.sql12
-rw-r--r--sql/upgrade_v2_to_v3.sql8
-rw-r--r--src/db.c37
-rw-r--r--src/db_hlr.c121
-rw-r--r--src/hlr_vty_subscr.c46
-rw-r--r--src/lu_fsm.c24
-rw-r--r--tests/db_upgrade/create_subscribers.vty18
-rw-r--r--tests/db_upgrade/db_upgrade_test.ok11
9 files changed, 283 insertions, 6 deletions
diff --git a/include/osmocom/hlr/db.h b/include/osmocom/hlr/db.h
index 1f1bacb..5fbc846 100644
--- a/include/osmocom/hlr/db.h
+++ b/include/osmocom/hlr/db.h
@@ -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
};
@@ -107,8 +110,13 @@ struct hlr_subscriber {
/* 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(). */
@@ -170,6 +178,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*.
diff --git a/sql/hlr.sql b/sql/hlr.sql
index e855a6c..fd71aef 100644
--- a/sql/hlr.sql
+++ b/sql/hlr.sql
@@ -87,8 +87,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')) 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 = 7;
diff --git a/sql/upgrade_v2_to_v3.sql b/sql/upgrade_v2_to_v3.sql
new file mode 100644
index 0000000..7d475c1
--- /dev/null
+++ b/sql/upgrade_v2_to_v3.sql
@@ -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;
diff --git a/src/db.c b/src/db.c
index c265ffa..fa868ea 100644
--- a/src/db.c
+++ b/src/db.c
@@ -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 7
#define SEL_COLUMNS \
"id," \
@@ -90,6 +90,12 @@ static const char *stmt_sql[] = {
[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)
@@ -507,6 +513,30 @@ 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;
+}
+
typedef int (*db_upgrade_func_t)(struct db_context *dbc);
static db_upgrade_func_t db_upgrade_path[] = {
db_upgrade_v1,
@@ -515,6 +545,7 @@ static db_upgrade_func_t db_upgrade_path[] = {
db_upgrade_v4,
db_upgrade_v5,
db_upgrade_v6,
+ db_upgrade_v7,
};
static int db_get_user_version(struct db_context *dbc)
@@ -643,9 +674,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);
diff --git a/src/db_hlr.c b/src/db_hlr.c
index b13763a..ee53a39 100644
--- a/src/db_hlr.c
+++ b/src/db_hlr.c
@@ -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);
@@ -511,6 +511,9 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
out:
db_remove_reset(stmt);
+ if (ret == 0)
+ db_subscr_get_rat_types(dbc, subscr);
+
switch (ret) {
case 0:
*err = NULL;
@@ -987,3 +990,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;
+}
diff --git a/src/hlr_vty_subscr.c b/src/hlr_vty_subscr.c
index dfbf72f..15e26ad 100644
--- a/src/hlr_vty_subscr.c
+++ b/src/hlr_vty_subscr.c
@@ -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>
@@ -76,6 +77,7 @@ static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t
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;
@@ -114,6 +116,10 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
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);
+ 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 +636,45 @@ DEFUN(subscriber_nam,
}
+DEFUN(subscriber_rat,
+ subscriber_rat_cmd,
+ SUBSCR_UPDATE "rat (geran-a|utran-iu) (allowed|forbidden)",
+ SUBSCR_UPDATE_HELP
+ "Allow or forbid specific Radio Access Types\n"
+ "Set access to GERAN-A\n"
+ "Set access to UTRAN-Iu\n"
+ "Allow access\n"
+ "Forbid access\n")
+{
+ struct hlr_subscriber subscr;
+ const char *id_type = argv[0];
+ const char *id = argv[1];
+ const char *rat_str = argv[2];
+ const char *allowed_forbidden = argv[3];
+ enum osmo_rat_type rat;
+ 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;
+
+ 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 +688,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);
}
diff --git a/src/lu_fsm.c b/src/lu_fsm.c
index af3bed3..f5154c2 100644
--- a/src/lu_fsm.c
+++ b/src/lu_fsm.c
@@ -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);
@@ -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
diff --git a/tests/db_upgrade/create_subscribers.vty b/tests/db_upgrade/create_subscribers.vty
index 30eeba6..0edd22e 100644
--- a/tests/db_upgrade/create_subscribers.vty
+++ b/tests/db_upgrade/create_subscribers.vty
@@ -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
diff --git a/tests/db_upgrade/db_upgrade_test.ok b/tests/db_upgrade/db_upgrade_test.ok
index 0a45f7c..a366b3d 100644
--- a/tests/db_upgrade/db_upgrade_test.ok
+++ b/tests/db_upgrade/db_upgrade_test.ok
@@ -86,6 +86,7 @@ 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
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
Resulting db:
@@ -174,10 +175,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 7
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.