move to hex TMSI representation

Submitted by axilirator@gmail.com on March 31, 2016, 7:23 a.m.

Details

Message ID 1459409036-15607-1-git-send-email-axilirator@gmail.com
State New
Series "move to hex TMSI representation"
Headers show

Commit Message

axilirator@gmail.com March 31, 2016, 7:23 a.m.
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(-)

Patch hide | download patch | download mbox

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);