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(-)
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index 7d6c776..785dc36 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -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
diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c index 0935fc5..04aee79 100644 --- a/openbsc/src/libmsc/db.c +++ b/openbsc/src/libmsc/db.c @@ -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); } diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index f49c53a..9879a53 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -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));
diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c index 781ef61..8ed57ca 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.c +++ b/openbsc/tests/gsm0408/gsm0408_test.c @@ -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);