tbf: Use TLLI as ID if TFI not yet assigned

Currently the old TFI is always used as ID when a
PACKET DOWNLINK ASSIGNMENT is generated. This fails
if the old TBF has not been fully assigned yet. The
MS will then ignore the PDA.

This commit changes write_packet_downlink_assignment to accept
an additional parameter old_tfi_is_valid and uses the new TBF's
TLLI instead of the olf TFI if that parameter is set to false.

Sponsored-by: On-Waves ehf
diff --git a/src/encoding.cpp b/src/encoding.cpp
index a5e5064..9471fff 100644
--- a/src/encoding.cpp
+++ b/src/encoding.cpp
@@ -274,8 +274,9 @@
 
 /* generate downlink assignment */
 void Encoding::write_packet_downlink_assignment(RlcMacDownlink_t * block,
-	uint8_t old_tfi, uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf,
-	uint8_t poll, uint8_t rrbp, uint8_t alpha, uint8_t gamma, int8_t ta_idx,
+	bool old_tfi_is_valid, uint8_t old_tfi, uint8_t old_downlink,
+	struct gprs_rlcmac_tbf *tbf, uint8_t poll, uint8_t rrbp,
+	uint8_t alpha, uint8_t gamma, int8_t ta_idx,
 	uint8_t ta_ts, bool use_egprs)
 {
 	// Packet downlink assignment TS 44.060 11.2.7
@@ -295,9 +296,14 @@
 
 	block->u.Packet_Downlink_Assignment.Exist_PERSISTENCE_LEVEL      = 0x0;          // PERSISTENCE_LEVEL: off
 
-	block->u.Packet_Downlink_Assignment.ID.UnionType                 = 0x0;          // TFI = on
-	block->u.Packet_Downlink_Assignment.ID.u.Global_TFI.UnionType    = old_downlink; // 0=UPLINK TFI, 1=DL TFI
-	block->u.Packet_Downlink_Assignment.ID.u.Global_TFI.u.UPLINK_TFI = old_tfi;      // TFI
+	if (old_tfi_is_valid) {
+		block->u.Packet_Downlink_Assignment.ID.UnionType                 = 0x0;          // TFI = on
+		block->u.Packet_Downlink_Assignment.ID.u.Global_TFI.UnionType    = old_downlink; // 0=UPLINK TFI, 1=DL TFI
+		block->u.Packet_Downlink_Assignment.ID.u.Global_TFI.u.UPLINK_TFI = old_tfi;      // TFI
+	} else {
+		block->u.Packet_Downlink_Assignment.ID.UnionType                 = 0x1;          // TLLI
+		block->u.Packet_Downlink_Assignment.ID.u.TLLI                    = tbf->tlli();
+	}
 
 	block->u.Packet_Downlink_Assignment.MAC_MODE            = 0x0;          // Dynamic Allocation
 	block->u.Packet_Downlink_Assignment.RLC_MODE            = 0x0;          // RLC acknowledged mode
diff --git a/src/encoding.h b/src/encoding.h
index 6ee30ac..1248725 100644
--- a/src/encoding.h
+++ b/src/encoding.h
@@ -55,7 +55,7 @@
 			int8_t use_egprs);
 
 	static void write_packet_downlink_assignment(RlcMacDownlink_t * block,
-			uint8_t old_tfi, uint8_t old_downlink,
+			bool old_tfi_is_valid, uint8_t old_tfi, uint8_t old_downlink,
 			struct gprs_rlcmac_tbf *tbf, uint8_t poll, uint8_t rrbp,
 			uint8_t alpha, uint8_t gamma,
 			int8_t ta_idx, uint8_t ta_ts, bool use_egprs);
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 1694bbb..04c7272 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -907,6 +907,7 @@
 	unsigned int rrbp = 0;
 	uint32_t new_poll_fn = 0;
 	int rc;
+	bool old_tfi_is_valid = is_tfi_assigned();
 
 	if (direction == GPRS_RLCMAC_DL_TBF && !is_control_ts(ts)) {
 		LOGP(DRLCMAC, LOGL_NOTICE, "Cannot poll for downlink "
@@ -954,6 +955,19 @@
 		return NULL;
 	}
 
+	if (new_dl_tbf == as_dl_tbf(this))
+		LOGP(DRLCMAC, LOGL_DEBUG,
+			"New and old TBF are the same %s\n", name());
+
+	if (old_tfi_is_valid && !new_dl_tbf->is_tlli_valid()) {
+		LOGP(DRLCMACDL, LOGL_ERROR,
+			"The old TFI is not assigned and there is no "
+			"TLLI. Old TBF %s, new TBF %s\n",
+			name(), new_dl_tbf->name());
+		dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
+		return NULL;
+	}
+
 	new_dl_tbf->was_releasing = was_releasing;
 	msg = msgb_alloc(23, "rlcmac_dl_ass");
 	if (!msg)
@@ -967,9 +981,10 @@
 		"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
 	LOGP(DRLCMAC, LOGL_INFO, "%s  start Packet Downlink Assignment (PACCH)\n", tbf_name(new_dl_tbf));
 	RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
-	Encoding::write_packet_downlink_assignment(mac_control_block, m_tfi,
-		(direction == GPRS_RLCMAC_DL_TBF), new_dl_tbf,
-		poll_ass_dl, rrbp, bts_data()->alpha, bts_data()->gamma, -1, 0,
+	Encoding::write_packet_downlink_assignment(mac_control_block,
+		old_tfi_is_valid, m_tfi, (direction == GPRS_RLCMAC_DL_TBF),
+		new_dl_tbf, poll_ass_dl, rrbp,
+		bts_data()->alpha, bts_data()->gamma, -1, 0,
 		is_egprs_enabled());
 	LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n");
 	encode_gsm_rlcmac_downlink(ass_vec, mac_control_block);
diff --git a/src/tbf.h b/src/tbf.h
index edb8280..d1b286c 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -132,6 +132,7 @@
 	void update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction);
 
 	uint8_t tfi() const;
+	bool is_tfi_assigned() const;
 
 	const char *imsi() const;
 	void assign_imsi(const char *imsi);
@@ -310,6 +311,16 @@
 	return tlli() != 0;
 }
 
+inline bool gprs_rlcmac_tbf::is_tfi_assigned() const
+{
+	/* The TBF is established or has been assigned by a IMM.ASS for
+	 * download */
+	return state > GPRS_RLCMAC_ASSIGN ||
+		(direction == GPRS_RLCMAC_DL_TBF &&
+		 state == GPRS_RLCMAC_ASSIGN &&
+		 (state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)));
+}
+
 inline uint8_t gprs_rlcmac_tbf::tfi() const
 {
 	return m_tfi;
diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err
index 177a5b5..02b6a3d 100644
--- a/tests/tbf/TbfTest.err
+++ b/tests/tbf/TbfTest.err
@@ -58,6 +58,7 @@
 The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed
 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) append
 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) append
+New and old TBF are the same TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)
 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)  start Packet Downlink Assignment (PACCH)
 +++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++
 ------------------------- TX : Packet Downlink Assignment -------------------------
@@ -140,6 +141,7 @@
 The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed
 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) append
 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) append
+New and old TBF are the same TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)
 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)  start Packet Downlink Assignment (PACCH)
 +++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++
 ------------------------- TX : Packet Downlink Assignment -------------------------
@@ -222,6 +224,7 @@
 The MS object cannot fully confirm an unexpected TLLI: 0xffeeddcc, partly confirmed
 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) append
 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW) append
+New and old TBF are the same TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)
 TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=FLOW)  start Packet Downlink Assignment (PACCH)
 +++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++
 ------------------------- TX : Packet Downlink Assignment -------------------------