tbf: Store the timing advance (TA) value in the GprsMs object

The TA value rather relates to an MS and not to a single TBF. So all
TBFs share the same TA value. Currently the TA value is stored per
TBF and eventually copied from an old TBF to a new one. It is in
general only passed with an RACH request when the TLLI and thus the
MS is not yet known.

This commit adds a TA member to the GprsMs class and uses that one
when the TBF is associated to an MS object. Since the TBF is not
always associated with an MS object (after RACH or when it has been
replaced by another TBF), the TA value is still stored in each TBF
and that value is used as long as no MS object is being associated.

Sponsored-by: On-Waves ehf
diff --git a/src/bts.cpp b/src/bts.cpp
index 6bcfea0..010b8e8 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -438,7 +438,7 @@
 			/* FIXME: send reject */
 			return -EBUSY;
 		}
-		tbf->ta = qta >> 2;
+		tbf->set_ta(qta >> 2);
 		tbf->set_state(GPRS_RLCMAC_FLOW);
 		tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
 		tbf_timer_start(tbf, 3169, m_bts.t3169, 0);
@@ -461,7 +461,7 @@
 			m_bts.alpha, m_bts.gamma, -1);
 	else
 		plen = Encoding::write_immediate_assignment(&m_bts, immediate_assignment, 0, ra,
-			Fn, tbf->ta, tbf->trx->arfcn, tbf->first_ts, tbf->tsc(),
+			Fn, tbf->ta(), tbf->trx->arfcn, tbf->first_ts, tbf->tsc(),
 			tbf->tfi(), tbf->m_usf[tbf->first_ts], 0, 0, 0, 0,
 			m_bts.alpha, m_bts.gamma, -1);
 	pcu_l1if_tx_agch(immediate_assignment, plen);
@@ -486,8 +486,6 @@
 
 		old_tbf->was_releasing = old_tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE);
 
-		/* use TA from old TBF */
-		dl_tbf->ta = old_tbf->ta;
 		/* change state */
 		dl_tbf->set_state(GPRS_RLCMAC_ASSIGN);
 		dl_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
@@ -515,7 +513,7 @@
 	/* use request reference that has maximum distance to current time,
 	 * so the assignment will not conflict with possible RACH requests. */
 	plen = Encoding::write_immediate_assignment(&m_bts, immediate_assignment, 1, 125,
-		(tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta,
+		(tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta(),
 		tbf->trx->arfcn, tbf->first_ts, tbf->tsc(), tbf->tfi(), 0, tbf->tlli(), poll,
 		tbf->poll_fn, 0, m_bts.alpha, m_bts.gamma, -1);
 	pcu_l1if_tx_pch(immediate_assignment, plen, imsi);
@@ -836,7 +834,7 @@
 
 		/* This call will register the new TBF with the MS on success */
 		tbf_alloc_ul(bts_data(), tbf->trx->trx_no, tbf->ms_class,
-			tbf->tlli(), tbf->ta, tbf);
+			tbf->tlli(), tbf->ta(), tbf);
 
 		/* schedule uplink assignment */
 		tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
@@ -846,14 +844,13 @@
 void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, uint32_t fn)
 {
 	struct gprs_rlcmac_sba *sba;
-	int rc;
 
 	if (request->ID.UnionType) {
 		struct gprs_rlcmac_ul_tbf *ul_tbf = NULL;
 		struct gprs_rlcmac_dl_tbf *dl_tbf = NULL;
 		uint32_t tlli = request->ID.u.TLLI;
 		uint8_t ms_class = 0;
-		uint8_t ta;
+		uint8_t ta = 0;
 
 		GprsMs *ms = bts()->ms_by_tlli(tlli);
 		/* Keep the ms, even if it gets idle temporarily */
@@ -862,6 +859,7 @@
 		if (ms) {
 			ul_tbf = ms->ul_tbf();
 			dl_tbf = ms->dl_tbf();
+			ta = ms->ta();
 		}
 
 		if (ul_tbf) {
@@ -890,14 +888,8 @@
 				"in packet resource request of single "
 				"block, but there is no resource request "
 				"scheduled!\n");
-			rc = bts()->timing_advance()->recall(tlli);
-			if (rc >= 0)
-				ta = rc;
-			else
-				ta = 0;
 		} else {
 			ta = sba->ta;
-			bts()->timing_advance()->remember(tlli, ta);
 			bts()->sba()->free_sba(sba);
 		}
 		if (request->Exist_MS_Radio_Access_capability)
diff --git a/src/encoding.cpp b/src/encoding.cpp
index ffd6108..167bfd4 100644
--- a/src/encoding.cpp
+++ b/src/encoding.cpp
@@ -195,7 +195,7 @@
 	bitvec_write_field(dest, wp,bts->initial_cs_ul-1, 2); // CHANNEL_CODING_COMMAND 
 	bitvec_write_field(dest, wp,0x1,1); // TLLI_BLOCK_CHANNEL_CODING 
 	bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_VALUE = on
-	bitvec_write_field(dest, wp,tbf->ta,6); // TIMING_ADVANCE_VALUE
+	bitvec_write_field(dest, wp,tbf->ta(),6); // TIMING_ADVANCE_VALUE
 	if (ta_idx < 0) {
 		bitvec_write_field(dest, wp,0x0,1);   // switch TIMING_ADVANCE_INDEX = off
 	} else {
@@ -275,7 +275,7 @@
 	}
 
 	block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.Exist_TIMING_ADVANCE_VALUE = 0x1; // TIMING_ADVANCE_VALUE = on
-	block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.TIMING_ADVANCE_VALUE       = tbf->ta;  // TIMING_ADVANCE_VALUE
+	block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.TIMING_ADVANCE_VALUE       = tbf->ta();  // TIMING_ADVANCE_VALUE
 	if (ta_idx < 0) {
 		block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.Exist_IndexAndtimeSlot     = 0x0; // TIMING_ADVANCE_INDEX = off
 	} else {
diff --git a/src/gprs_ms.cpp b/src/gprs_ms.cpp
index c2320a2..d6520c3 100644
--- a/src/gprs_ms.cpp
+++ b/src/gprs_ms.cpp
@@ -60,6 +60,7 @@
 	m_tlli(tlli),
 	m_new_ul_tlli(0),
 	m_new_dl_tlli(0),
+	m_ta(0),
 	m_is_idle(true),
 	m_ref(0),
 	m_list(this)
@@ -263,3 +264,15 @@
 	m_imsi[sizeof(m_imsi) - 1] = '\0';
 }
 
+void GprsMs::set_ta(uint8_t ta_)
+{
+	if (ta_ == m_ta)
+		return;
+
+	LOGP(DRLCMAC, LOGL_INFO,
+		"Modifying MS object, TLLI = 0x%08x, TA %d -> %d\n",
+		tlli(), m_ta, ta_);
+
+	m_ta = ta_;
+}
+
diff --git a/src/gprs_ms.h b/src/gprs_ms.h
index 7f8af41..9c3acb4 100644
--- a/src/gprs_ms.h
+++ b/src/gprs_ms.h
@@ -59,6 +59,9 @@
 	const char *imsi() const;
 	void set_imsi(const char *imsi);
 
+	uint8_t ta() const;
+	void set_ta(uint8_t ta);
+
 	void attach_tbf(gprs_rlcmac_tbf *tbf);
 	void attach_ul_tbf(gprs_rlcmac_ul_tbf *tbf);
 	void attach_dl_tbf(gprs_rlcmac_dl_tbf *tbf);
@@ -88,6 +91,7 @@
 
 	/* store IMSI for look-up and PCH retransmission */
 	char m_imsi[16];
+	uint8_t m_ta;
 
 	bool m_is_idle;
 	int m_ref;
@@ -111,3 +115,8 @@
 {
 	return m_imsi;
 }
+
+inline uint8_t GprsMs::ta() const
+{
+	return m_ta;
+}
diff --git a/src/tbf.cpp b/src/tbf.cpp
index ac0cdf3..53f1ae1 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -89,13 +89,32 @@
 	m_ms->set_imsi(imsi_);
 }
 
+uint8_t gprs_rlcmac_tbf::ta() const
+{
+	return m_ms ? m_ms->ta() : m_ta;
+}
+
+void gprs_rlcmac_tbf::set_ta(uint8_t ta)
+{
+	if (ms())
+		ms()->set_ta(ta);
+
+	m_ta = ta;
+}
+
 void gprs_rlcmac_tbf::set_ms(GprsMs *ms)
 {
 	if (m_ms == ms)
 		return;
 
-	if (m_ms)
+	if (m_ms) {
+		/* Save the TA locally. This will also be called, if the MS
+		 * object detaches itself from the TBF, for instance if
+		 * attach_tbf() is called */
+		m_ta = m_ms->ta();
+
 		m_ms->detach_tbf(this);
+	}
 
 	m_ms = ms;
 
@@ -110,6 +129,9 @@
 		if (!new_ms)
 			new_ms = bts->ms_store().create_ms(tlli, dir);
 
+		if (dir == GPRS_RLCMAC_UL_TBF)
+			new_ms->set_ta(m_ta);
+
 		set_ms(new_ms);
 		return;
 	}
@@ -144,11 +166,13 @@
 		return NULL;
 	}
 	tbf->m_contention_resolution_done = 1;
-	tbf->ta = ta; /* use current TA */
 	tbf->set_state(GPRS_RLCMAC_ASSIGN);
 	tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
 	tbf_timer_start(tbf, 3169, bts->t3169, 0);
 	tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF);
+	OSMO_ASSERT(tbf->ms());
+
+	tbf->ms()->set_ta(ta);
 
 	return tbf;
 }
@@ -786,8 +810,6 @@
 
 void gprs_rlcmac_tbf::update_tlli(uint32_t tlli)
 {
-	/* update the timing advance for the new tlli */
-	bts->timing_advance()->update(0, tlli, ta);
 }
 
 int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
@@ -843,8 +865,6 @@
 		tbf_free(ul_tbf);
 		ul_tbf = NULL;
 	}
-	/* store current timing advance */
-	bts->timing_advance()->remember(tlli(), ta);
 	return 1;
 }
 
diff --git a/src/tbf.h b/src/tbf.h
index 5ea6d4e..d288669 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -149,6 +149,8 @@
 
 	const char *imsi() const;
 	void assign_imsi(const char *imsi);
+	uint8_t ta() const;
+	void set_ta(uint8_t);
 
 	time_t created_ts() const;
 
@@ -165,7 +167,6 @@
 	uint8_t control_ts; /* timeslot control messages and polling */
 	uint8_t ms_class;
 	struct gprs_rlcmac_pdch *pdch[8]; /* list of PDCHs allocated to TBF */
-	uint16_t ta;
 
 	gprs_llc m_llc;
 
@@ -225,6 +226,9 @@
 	static const char *tbf_state_name[6];
 
 	class GprsMs *m_ms;
+
+	/* Field to take the TA value if no MS is associated */
+	uint8_t m_ta;
 private:
 	mutable char m_name_buf[60];
 };
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index edaf298..2289e3f 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -151,42 +151,30 @@
 				const uint8_t ms_class,
 				const uint8_t *data, const uint16_t len)
 {
-	uint8_t trx, ta, ss;
+	uint8_t trx, ss;
 	int8_t use_trx;
+	uint16_t ta = 0;
 	struct gprs_rlcmac_ul_tbf *ul_tbf = NULL, *old_ul_tbf;
 	struct gprs_rlcmac_dl_tbf *dl_tbf = NULL;
 	int8_t tfi; /* must be signed */
-	int rc;
 	GprsMs *ms;
 
 	/* check for uplink data, so we copy our informations */
 #warning "Do the same look up for IMSI, TLLI and OLD_TLLI"
 #warning "Refactor the below lines... into a new method"
 	ms = bts->bts->ms_store().get_ms(tlli, tlli_old, imsi);
-	if (ms)
+	if (ms) {
 		ul_tbf = ms->ul_tbf();
+		ta = ms->ta();
+	}
 
 	if (ul_tbf && ul_tbf->m_contention_resolution_done
 	 && !ul_tbf->m_final_ack_sent) {
 		use_trx = ul_tbf->trx->trx_no;
-		ta = ul_tbf->ta;
 		ss = 0;
 		old_ul_tbf = ul_tbf;
 	} else {
 		use_trx = -1;
-		/* we already have an uplink TBF, so we use that TA */
-		if (ul_tbf)
-			ta = ul_tbf->ta;
-		else {
-			/* recall TA */
-			rc = bts->bts->timing_advance()->recall(tlli);
-			if (rc < 0) {
-				LOGP(DRLCMAC, LOGL_NOTICE, "TA unknown"
-					", assuming 0\n");
-				ta = 0;
-			} else
-				ta = rc;
-		}
 		ss = 1; /* PCH assignment only allows one timeslot */
 		old_ul_tbf = NULL;
 	}
@@ -205,8 +193,8 @@
 		bts->bts->llc_dropped_frame();
 		return -EBUSY;
 	}
-	dl_tbf->ta = ta;
 	dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
+	dl_tbf->ms()->set_ta(ta);
 
 	LOGP(DRLCMAC, LOGL_DEBUG, "%s [DOWNLINK] START\n", tbf_name(dl_tbf));
 
@@ -801,7 +789,6 @@
 	}
 
 	new_tbf->set_ms(ms());
-	new_tbf->ta = ta;
 
 	/* Copy over all data to the new TBF */
 	new_tbf->m_llc.put_frame(data, len);