ms: Support new and old TLLIs

According to the specification (GSM 04.08/24.008, 4.7.1.5) after a
new P-TMSI has been assigned, the old P-TMSI must be kept basically
until it has been used by both sides. Since the TLLI will be derived
from the P-TMSI, the old TLLI must also be kept until the new TLLI
has been used by both MS and SGSN.

This commit modifies the TLLI handling of GprsMs accordingly.
set_tlli() is only used with TLLIs derived from MS messages,
confirm_tlli() is used with TLLIs derived from messages received from
the SGSN. tlli() returns the value set by the MS. check_tlli()
matches each of the TLLI used by either MS or SGSN as well as the old
TLLI until it has been confirmed.

Sponsored-by: On-Waves ehf
diff --git a/tests/ms/MsTest.cpp b/tests/ms/MsTest.cpp
index 0895e4d..01f2642 100644
--- a/tests/ms/MsTest.cpp
+++ b/tests/ms/MsTest.cpp
@@ -232,6 +232,99 @@
 	printf("=== end %s ===\n", __func__);
 }
 
+static void test_ms_change_tlli()
+{
+	uint32_t start_tlli = 0xaa000000;
+	uint32_t new_ms_tlli = 0xff001111;
+	uint32_t other_sgsn_tlli = 0xff00eeee;
+	GprsMs *ms;
+
+	printf("=== start %s ===\n", __func__);
+
+	ms = new GprsMs(start_tlli);
+
+	OSMO_ASSERT(ms->is_idle());
+
+	/* MS announces TLLI, SGSN uses it immediately */
+	ms->set_tlli(new_ms_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(ms->check_tlli(start_tlli));
+
+	ms->confirm_tlli(new_ms_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(!ms->check_tlli(start_tlli));
+
+	/* MS announces TLLI, SGSN uses it later */
+	ms->set_tlli(start_tlli);
+	ms->confirm_tlli(start_tlli);
+
+	ms->set_tlli(new_ms_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(ms->check_tlli(start_tlli));
+
+	ms->confirm_tlli(start_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(ms->check_tlli(start_tlli));
+
+	ms->set_tlli(new_ms_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(ms->check_tlli(start_tlli));
+
+	ms->confirm_tlli(new_ms_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(!ms->check_tlli(start_tlli));
+
+	/* MS announces TLLI, SGSN uses it later after another new TLLI */
+	ms->set_tlli(start_tlli);
+	ms->confirm_tlli(start_tlli);
+
+	ms->set_tlli(new_ms_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(ms->check_tlli(start_tlli));
+
+	ms->confirm_tlli(other_sgsn_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(ms->check_tlli(other_sgsn_tlli));
+
+	ms->set_tlli(new_ms_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(ms->check_tlli(other_sgsn_tlli));
+
+	ms->confirm_tlli(new_ms_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(!ms->check_tlli(start_tlli));
+	OSMO_ASSERT(!ms->check_tlli(other_sgsn_tlli));
+
+	/* SGSN uses the new TLLI before it is announced by the MS (shouldn't
+	 * happen in normal use) */
+	ms->set_tlli(start_tlli);
+	ms->confirm_tlli(start_tlli);
+
+	ms->confirm_tlli(new_ms_tlli);
+	OSMO_ASSERT(ms->tlli() == start_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(ms->check_tlli(start_tlli));
+
+	ms->set_tlli(new_ms_tlli);
+	OSMO_ASSERT(ms->tlli() == new_ms_tlli);
+	OSMO_ASSERT(ms->check_tlli(new_ms_tlli));
+	OSMO_ASSERT(!ms->check_tlli(start_tlli));
+
+	delete ms;
+
+	printf("=== end %s ===\n", __func__);
+}
+
 static void test_ms_storage()
 {
 	uint32_t tlli = 0xffeeddbb;
@@ -320,6 +413,7 @@
 	test_ms_state();
 	test_ms_callback();
 	test_ms_replace_tbf();
+	test_ms_change_tlli();
 	test_ms_storage();
 
 	if (getenv("TALLOC_REPORT_FULL"))