@@ -14,7 +14,7 @@
#define GSM_SUBSCRIBER_FIRST_CONTACT 0x00000001
/* gprs_sgsn.h defines additional flags including and above bit 16 (0x10000) */
-#define tmsi_from_string(str) strtoul(str, NULL, 10)
+#define tmsi_from_string(str) strtoul(str + 2, NULL, 16)
#define GSM_SUBSCRIBER_NO_EXPIRATION 0x0
@@ -47,7 +47,7 @@ static char *db_basename = NULL;
static char *db_dirname = NULL;
static dbi_conn conn;
-#define SCHEMA_REVISION "4"
+#define SCHEMA_REVISION "5"
enum {
SCHEMA_META,
@@ -83,7 +83,7 @@ static const char *create_stmts[] = {
"name TEXT, "
"extension TEXT UNIQUE, "
"authorized INTEGER NOT NULL DEFAULT 0, "
- "tmsi TEXT UNIQUE, "
+ "tmsi INTEGER UNIQUE, "
"lac INTEGER NOT NULL DEFAULT 0, "
"expire_lu TIMESTAMP DEFAULT NULL"
")",
@@ -212,6 +212,7 @@ static int update_db_revision_2(void)
}
dbi_result_free(result);
+ LOGP(DDB, LOGL_NOTICE, "Migration complete.\n");
return 0;
}
@@ -357,6 +358,7 @@ static int update_db_revision_3(void)
else
dbi_result_free(result);
+ LOGP(DDB, LOGL_NOTICE, "Migration complete.\n");
return 0;
rollback:
@@ -369,6 +371,108 @@ rollback:
return -EINVAL;
}
+static int update_db_revision_4(void)
+{
+ dbi_result result;
+
+ LOGP(DDB, LOGL_NOTICE, "Going to migrate from revision 4\n");
+
+ result = dbi_conn_query(conn, "BEGIN EXCLUSIVE TRANSACTION");
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR,
+ "Failed to begin transaction "
+ "(upgrade from rev 4)\n");
+ return -EINVAL;
+ }
+ dbi_result_free(result);
+
+ /* Rename old Subscriber table to be able create a new one */
+ result = dbi_conn_query(conn,
+ "ALTER TABLE Subscriber RENAME TO Subscriber_4");
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR,
+ "Failed to rename the old Subscriber table "
+ "(upgrade from rev 4).\n");
+ goto rollback;
+ }
+ dbi_result_free(result);
+
+ /* Create new Subscriber table */
+ result = dbi_conn_query(conn, create_stmts[SCHEMA_SUBSCRIBER]);
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR,
+ "Failed to create a new Subscriber table "
+ "(upgrade from rev 4).\n");
+ goto rollback;
+ }
+ dbi_result_free(result);
+
+ /* Copy subscriber data into the new table */
+ result = dbi_conn_query(conn,
+ "INSERT INTO Subscriber "
+ "SELECT * FROM Subscriber_4");
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR,
+ "Failed to copy subscriber data into the new table "
+ "(upgrade from rev 4).\n");
+ goto rollback;
+ }
+ dbi_result_free(result);
+
+ /* Remove the temporary table */
+ result = dbi_conn_query(conn, "DROP TABLE Subscriber_4");
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR,
+ "Failed to drop the old Subscriber table "
+ "(upgrade from rev 4).\n");
+ goto rollback;
+ }
+ dbi_result_free(result);
+
+ /* We're done. Bump DB Meta revision to 5 */
+ result = dbi_conn_query(conn,
+ "UPDATE Meta "
+ "SET value = '5' "
+ "WHERE key = 'revision'");
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR,
+ "Failed to update DB schema revision "
+ "(upgrade from rev 4).\n");
+ goto rollback;
+ }
+ dbi_result_free(result);
+
+ result = dbi_conn_query(conn, "COMMIT TRANSACTION");
+ if (!result) {
+ LOGP(DDB, LOGL_ERROR,
+ "Failed to commit the transaction "
+ "(upgrade from rev 4)\n");
+ return -EINVAL;
+ }
+
+ /* Shrink DB file size by actually wiping out Subscriber_4 table data */
+ result = dbi_conn_query(conn, "VACUUM");
+ if (!result)
+ LOGP(DDB, LOGL_ERROR,
+ "VACUUM failed. Ignoring it "
+ "(upgrade from rev 4).\n");
+ else
+ dbi_result_free(result);
+
+ LOGP(DDB, LOGL_NOTICE, "Migration complete.\n");
+ return 0;
+
+rollback:
+ result = dbi_conn_query(conn, "ROLLBACK TRANSACTION");
+ if (!result)
+ LOGP(DDB, LOGL_ERROR,
+ "Rollback failed "
+ "(upgrade from rev 4).\n");
+ else
+ dbi_result_free(result);
+ return -EINVAL;
+}
+
static int check_db_revision(void)
{
dbi_result result;
@@ -388,20 +492,18 @@ static int check_db_revision(void)
dbi_result_free(result);
return -EINVAL;
}
- if (!strcmp(rev_s, "2")) {
- if (update_db_revision_2()) {
- LOGP(DDB, LOGL_FATAL, "Failed to update database from schema revision '%s'.\n", rev_s);
- dbi_result_free(result);
- return -EINVAL;
- }
- } else if (!strcmp(rev_s, "3")) {
- if (update_db_revision_3()) {
- LOGP(DDB, LOGL_FATAL, "Failed to update database from schema revision '%s'.\n", rev_s);
- dbi_result_free(result);
- return -EINVAL;
- }
- } else if (!strcmp(rev_s, SCHEMA_REVISION)) {
+
+ if (!strcmp(rev_s, SCHEMA_REVISION)) {
/* everything is fine */
+ } else if (!strcmp(rev_s, "2")) {
+ if (update_db_revision_2())
+ goto error;
+ } else if (!strcmp(rev_s, "3")) {
+ if (update_db_revision_3())
+ goto error;
+ } else if (!strcmp(rev_s, "4")) {
+ if (update_db_revision_4())
+ goto error;
} else {
LOGP(DDB, LOGL_FATAL, "Invalid database schema revision '%s'.\n", rev_s);
dbi_result_free(result);
@@ -410,6 +512,11 @@ static int check_db_revision(void)
dbi_result_free(result);
return 0;
+
+error:
+ LOGP(DDB, LOGL_FATAL, "Failed to update database from schema revision '%s'.\n", rev_s);
+ dbi_result_free(result);
+ return -EINVAL;
}
static int db_configure(void)
@@ -808,10 +915,6 @@ static void db_set_from_query(struct gsm_subscriber *subscr, dbi_conn result)
if (string)
strncpy(subscr->imsi, string, GSM_IMSI_LENGTH-1);
- string = dbi_result_get_string(result, "tmsi");
- if (string)
- subscr->tmsi = tmsi_from_string(string);
-
string = dbi_result_get_string(result, "name");
if (string)
strncpy(subscr->name, string, GSM_NAME_LENGTH);
@@ -820,7 +923,8 @@ static void db_set_from_query(struct gsm_subscriber *subscr, dbi_conn result)
if (string)
strncpy(subscr->extension, string, GSM_EXTENSION_LENGTH);
- subscr->lac = dbi_result_get_ulonglong(result, "lac");
+ subscr->tmsi = dbi_result_get_ulonglong(result, "tmsi");
+ subscr->lac = dbi_result_get_ulonglong(result, "lac");
if (!dbi_result_field_is_null(result, "expire_lu"))
subscr->expire_lu = dbi_result_get_datetime(result, "expire_lu");
@@ -828,7 +932,6 @@ static void db_set_from_query(struct gsm_subscriber *subscr, dbi_conn result)
subscr->expire_lu = GSM_SUBSCRIBER_NO_EXPIRATION;
subscr->authorized = dbi_result_get_ulonglong(result, "authorized");
-
}
#define BASE_QUERY "SELECT * FROM Subscriber "
@@ -893,9 +996,10 @@ struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field,
subscr->id = dbi_result_get_ulonglong(result, "id");
db_set_from_query(subscr, result);
- DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %u, EXTEN '%s', LAC %hu, AUTH %u\n",
- subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension,
- subscr->lac, subscr->authorized);
+ DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', "
+ "TMSI 0x%08x, EXTEN '%s', LAC %hu, AUTH %u\n",
+ subscr->id, subscr->imsi, subscr->name, subscr->tmsi,
+ subscr->extension, subscr->lac, subscr->authorized);
dbi_result_free(result);
get_equipment_by_subscr(subscr);
@@ -998,7 +1102,6 @@ int db_sync_subscriber(struct gsm_subscriber *subscriber)
}
dbi_result_free(result);
-
return 0;
}
@@ -1225,7 +1328,7 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber)
}
if (!dbi_result_next_row(result)) {
dbi_result_free(result);
- DEBUGP(DDB, "Allocated TMSI %u for IMSI %s.\n",
+ DEBUGP(DDB, "Allocated TMSI 0x%08x for IMSI %s.\n",
subscriber->tmsi, subscriber->imsi);
return db_sync_subscriber(subscriber);
}
@@ -189,7 +189,8 @@ static struct gsm_subscriber *get_subscr_by_argv(struct gsm_network *gsmnet,
else if (!strcmp(type, "imsi"))
return subscr_get_by_imsi(gsmnet->subscr_group, id);
else if (!strcmp(type, "tmsi"))
- return subscr_get_by_tmsi(gsmnet->subscr_group, atoi(id));
+ return subscr_get_by_tmsi(gsmnet->subscr_group,
+ tmsi_from_string(id));
else if (!strcmp(type, "id"))
return subscr_get_by_id(gsmnet->subscr_group, atoi(id));
@@ -93,7 +93,7 @@ static void test_mi_functionality(void)
/* tmsi code */
mi_len = gsm48_generate_mid_from_tmsi(mi, tmsi);
gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len - 2);
- COMPARE((uint32_t)strtoul(mi_parsed, NULL, 10), ==, tmsi);
+ COMPARE((uint32_t)tmsi_from_string(mi_parsed), ==, tmsi);
/* imsi code */
mi_len = gsm48_generate_mid_from_imsi(mi, imsi_odd);
In OpenBSC, we traditionally displayed a TMSI in its integer representation, which is quite unusual in the telecom world. A TMSI is normally printed as a series of 8 hex digits. This patch aligns OpenBSC with the telecom industry standard and should be applied with corresponding patch for libosmocore. - Use hex representation in VTY - Increased DB SCHEMA_REVISION - Implemented DB migration code db_test is temporary broken because incremental migration isn't implemented yet (WIP). Signed-off-by: Vadim Yanitskiy <axilirator@gmail.com> --- openbsc/include/openbsc/gsm_subscriber.h | 2 +- openbsc/src/libmsc/db.c | 155 +++++++++++++++++++++++++----- openbsc/src/libmsc/vty_interface_layer3.c | 3 +- openbsc/tests/gsm0408/gsm0408_test.c | 2 +- 4 files changed, 133 insertions(+), 29 deletions(-)