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/src/gprs_ms.cpp b/src/gprs_ms.cpp
index af9e834..4c2f7cc 100644
--- a/src/gprs_ms.cpp
+++ b/src/gprs_ms.cpp
@@ -58,6 +58,8 @@
 	m_ul_tbf(NULL),
 	m_dl_tbf(NULL),
 	m_tlli(tlli),
+	m_new_ul_tlli(0),
+	m_new_dl_tlli(0),
 	m_is_idle(true),
 	m_ref(0),
 	m_list(this)
@@ -185,12 +187,52 @@
 
 void GprsMs::set_tlli(uint32_t tlli)
 {
-	if (tlli == m_tlli)
+	if (tlli == m_tlli || tlli == m_new_ul_tlli)
 		return;
 
+	if (tlli != m_new_dl_tlli) {
+		LOGP(DRLCMAC, LOGL_INFO,
+			"Modifying MS object, UL TLLI: 0x%08x -> 0x%08x, "
+			"not yet confirmed\n",
+			this->tlli(), tlli);
+		m_new_ul_tlli = tlli;
+		return;
+	}
+
 	LOGP(DRLCMAC, LOGL_INFO,
-		"Modifying MS object, TLLI: 0x%08x -> 0x%08x\n",
+		"Modifying MS object, TLLI: 0x%08x -> 0x%08x, "
+		"already confirmed partly\n",
 		m_tlli, tlli);
 
 	m_tlli = tlli;
+	m_new_dl_tlli = 0;
+	m_new_ul_tlli = 0;
+}
+
+bool GprsMs::confirm_tlli(uint32_t tlli)
+{
+	if (tlli == m_tlli || tlli == m_new_dl_tlli)
+		return false;
+
+	if (tlli != m_new_ul_tlli) {
+		/* The MS has not sent a message with the new TLLI, which may
+		 * happen according to the spec [TODO: add reference]. */
+
+		LOGP(DRLCMAC, LOGL_INFO,
+			"The MS object cannot fully confirm an unexpected TLLI: 0x%08x, "
+			"partly confirmed\n", tlli);
+		/* Use the network's idea of TLLI as candidate, this does not
+		 * change the result value of tlli() */
+		m_new_dl_tlli = tlli;
+		return false;
+	}
+
+	LOGP(DRLCMAC, LOGL_INFO,
+		"Modifying MS object, TLLI: 0x%08x confirmed\n", tlli);
+
+	m_tlli = tlli;
+	m_new_dl_tlli = 0;
+	m_new_ul_tlli = 0;
+
+	return true;
 }