Move first_common_ts from gprs_rlcmac_tbf to GprsMs

The field contains a common value between the 2 active TBFs of the MS,
so it makes no sense to have them duplicated on each TBF. It can be
sanely stored in the MS object.

Change-Id: I8df01a99ccbfaf7a442ade5000ee282bd638fbba
diff --git a/src/gprs_ms.c b/src/gprs_ms.c
index 933953e..c9eaf97 100644
--- a/src/gprs_ms.c
+++ b/src/gprs_ms.c
@@ -120,6 +120,7 @@
 	ms->current_cs_ul = UNKNOWN;
 	ms->current_cs_dl = UNKNOWN;
 	ms->is_idle = true;
+	ms->first_common_ts = TBF_TS_UNSET;
 	INIT_LLIST_HEAD(&ms->list);
 	INIT_LLIST_HEAD(&ms->old_tbfs);
 
@@ -383,6 +384,7 @@
 
 	if (!ms->dl_tbf && !ms->ul_tbf) {
 		ms_set_reserved_slots(ms, NULL, 0, 0);
+		ms->first_common_ts = TBF_TS_UNSET;
 
 		if (ms_tlli(ms) != 0)
 			ms_release_timer_start(ms);
@@ -918,15 +920,15 @@
 	return cs;
 }
 
-int ms_first_common_ts(const struct GprsMs *ms)
+int8_t ms_first_common_ts(const struct GprsMs *ms)
 {
-	if (ms->dl_tbf)
-		return tbf_first_common_ts(dl_tbf_as_tbf(ms->dl_tbf));
+	return ms->first_common_ts;
+}
 
-	if (ms->ul_tbf)
-		return tbf_first_common_ts(ul_tbf_as_tbf(ms->ul_tbf));
-
-	return -1;
+void ms_set_first_common_ts(struct GprsMs *ms, uint8_t first_common_ts)
+{
+	OSMO_ASSERT(first_common_ts < 8);
+	ms->first_common_ts = first_common_ts;
 }
 
 uint8_t ms_dl_slots(const struct GprsMs *ms)
diff --git a/src/gprs_ms.h b/src/gprs_ms.h
index 4ff261c..716ad74 100644
--- a/src/gprs_ms.h
+++ b/src/gprs_ms.h
@@ -64,6 +64,8 @@
 	struct gprs_rlcmac_ul_tbf *ul_tbf;
 	struct gprs_rlcmac_dl_tbf *dl_tbf;
 	struct llist_head old_tbfs; /* list of gprs_rlcmac_tbf */
+	/* First common timeslot number used both in UL and DL, 0..7 or TBF_TS_UNSET (-1): */
+	int8_t first_common_ts;
 
 	uint32_t tlli;
 	uint32_t new_ul_tlli;
@@ -101,7 +103,8 @@
 
 struct GprsMs *ms_alloc(struct gprs_rlcmac_bts *bts, uint32_t tlli);
 
-int ms_first_common_ts(const struct GprsMs *ms);
+int8_t ms_first_common_ts(const struct GprsMs *ms);
+void ms_set_first_common_ts(struct GprsMs *ms, uint8_t first_common_ts);
 void ms_set_reserved_slots(struct GprsMs *ms, struct gprs_rlcmac_trx *trx,
 			   uint8_t ul_slots, uint8_t dl_slots);
 struct GprsMs *ms_ref(struct GprsMs *ms);
diff --git a/src/gprs_rlcmac_ts_alloc.cpp b/src/gprs_rlcmac_ts_alloc.cpp
index b5757a7..026ad6e 100644
--- a/src/gprs_rlcmac_ts_alloc.cpp
+++ b/src/gprs_rlcmac_ts_alloc.cpp
@@ -411,8 +411,9 @@
 
 	tbf->trx = trx;
 	/* the only one TS is the common TS */
-	tbf->first_ts = tbf->first_common_ts = ts;
+	tbf->first_ts = ts;
 	ms_set_reserved_slots(ms, trx, 1 << ts, 1 << ts);
+	ms_set_first_common_ts(ms, ts);
 
 	tbf->upgrade_to_multislot = false;
 	bts_do_rate_ctr_inc(bts, CTR_TBF_ALLOC_ALGO_A);
@@ -945,9 +946,8 @@
 	/* Step 4: Update MS and TBF and really allocate the resources */
 
 	update_ms_reserved_slots(trx, ms, reserved_ul_slots, reserved_dl_slots, ul_slots, dl_slots);
-
+	ms_set_first_common_ts(ms, first_common_ts);
 	tbf->trx = trx;
-	tbf->first_common_ts = first_common_ts;
 	tbf->first_ts = first_ts;
 
 	if (tbf->direction == GPRS_RLCMAC_DL_TBF)
diff --git a/src/pcu_vty_functions.cpp b/src/pcu_vty_functions.cpp
index 76baffe..e35e817 100644
--- a/src/pcu_vty_functions.cpp
+++ b/src/pcu_vty_functions.cpp
@@ -54,21 +54,22 @@
 	gprs_rlcmac_ul_tbf *ul_tbf = tbf_as_ul_tbf(tbf);
 	gprs_rlcmac_dl_tbf *dl_tbf = tbf_as_dl_tbf(tbf);
 	uint32_t state_flags = tbf_state_flags(tbf);
+	struct GprsMs *ms = tbf_ms(tbf);
 
 	vty_out(vty, "TBF: TFI=%d TLLI=0x%08x (%s) TA=%u DIR=%s IMSI=%s%s", tbf->tfi(),
 		tbf->tlli(), tbf->is_tlli_valid() ? "valid" : "invalid",
 		tbf->ta(),
 		tbf->direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
 		tbf->imsi(), VTY_NEWLINE);
-	vty_out(vty, " created=%lu state=%s flags=%08x [CCCH:%u, PACCH:%u] 1st_TS=%d 1st_cTS=%d ctrl_TS=%d MS_CLASS=%d/%d%s",
+	vty_out(vty, " created=%lu state=%s flags=%08x [CCCH:%u, PACCH:%u] 1st_TS=%d 1st_cTS=%" PRId8 " ctrl_TS=%d MS_CLASS=%d/%d%s",
 		tbf->created_ts(), tbf->state_name(),
 		state_flags,
 		state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH),
 		state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH),
 		tbf->first_ts,
-		tbf->first_common_ts, tbf->control_ts,
+		ms_first_common_ts(ms), tbf->control_ts,
 		tbf->ms_class(),
-		ms_egprs_ms_class(tbf->ms()),
+		ms_egprs_ms_class(ms),
 		VTY_NEWLINE);
 	vty_out(vty, " TS_alloc=");
 	for (int i = 0; i < 8; i++) {
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 3d9d453..7483d49 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -91,7 +91,6 @@
 	direction(dir),
 	trx(NULL),
 	first_ts(TBF_TS_UNSET),
-	first_common_ts(TBF_TS_UNSET),
 	control_ts(TBF_TS_UNSET),
 	fT(0),
 	num_fT_exp(0),
@@ -308,13 +307,14 @@
 
 void tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf)
 {
+	int8_t first_common_ts = ms_first_common_ts(tbf_ms(tbf));
 	if (tbf->control_ts == TBF_TS_UNSET)
 		LOGPTBF(tbf, LOGL_INFO, "Setting Control TS %d\n",
-			tbf->first_common_ts);
-	else if (tbf->control_ts != tbf->first_common_ts)
+			first_common_ts);
+	else if (tbf->control_ts != first_common_ts)
 		LOGPTBF(tbf, LOGL_INFO, "Changing Control TS %d -> %d\n",
-			tbf->control_ts, tbf->first_common_ts);
-	tbf->control_ts = tbf->first_common_ts;
+			tbf->control_ts, first_common_ts);
+	tbf->control_ts = first_common_ts;
 }
 
 void gprs_rlcmac_tbf::n_reset(enum tbf_counters n)
@@ -738,7 +738,8 @@
 	if (direction == GPRS_RLCMAC_DL_TBF) {
 		if (control_ts < 8)
 			slots |= 1 << control_ts;
-		if (first_common_ts < 8)
+		int8_t first_common_ts = ms_first_common_ts(tbf_ms(this));
+		if (first_common_ts != TBF_TS_UNSET)
 			slots |= 1 << first_common_ts;
 
 		return slots;
@@ -825,11 +826,6 @@
 	return &tbf->m_llc;
 }
 
-uint8_t tbf_first_common_ts(const struct gprs_rlcmac_tbf *tbf)
-{
-	return tbf->first_common_ts;
-}
-
 uint8_t tbf_dl_slots(const struct gprs_rlcmac_tbf *tbf)
 {
 	return tbf->dl_slots();
diff --git a/src/tbf.h b/src/tbf.h
index 211b8a7..d4d52f9 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -134,7 +134,6 @@
 bool tbf_timers_pending(struct gprs_rlcmac_tbf *tbf, enum tbf_timers t);
 void tbf_free(struct gprs_rlcmac_tbf *tbf);
 struct gprs_llc *tbf_llc(struct gprs_rlcmac_tbf *tbf);
-uint8_t tbf_first_common_ts(const struct gprs_rlcmac_tbf *tbf);
 uint8_t tbf_dl_slots(const struct gprs_rlcmac_tbf *tbf);
 uint8_t tbf_ul_slots(const struct gprs_rlcmac_tbf *tbf);
 bool tbf_is_tfi_assigned(const struct gprs_rlcmac_tbf *tbf);
@@ -220,8 +219,6 @@
 	enum gprs_rlcmac_tbf_direction direction;
 	struct gprs_rlcmac_trx *trx;
 	uint8_t first_ts; /* first TS used by TBF */
-	uint8_t first_common_ts; /* first TS where the phone can send and
-		receive simultaniously */
 	uint8_t control_ts; /* timeslot control messages and polling */
 	struct gprs_rlcmac_pdch *pdch[8]; /* list of PDCHs allocated to TBF */
 
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index 43cd4f6..e4e4f79 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -167,7 +167,7 @@
 	ul_tbf->trx = trx;
 	/* The only one TS is the common, control TS */
 	ul_tbf->first_ts = ts;
-	ul_tbf->first_common_ts = ts;
+	ms_set_first_common_ts(ms, ts);
 	tbf_assign_control_ts(ul_tbf);
 	ul_tbf->m_ctrs = rate_ctr_group_alloc(ul_tbf, &tbf_ctrg_desc, next_tbf_ctr_group_id++);
 	ul_tbf->m_ul_egprs_ctrs = rate_ctr_group_alloc(ul_tbf,
diff --git a/tests/alloc/AllocTest.cpp b/tests/alloc/AllocTest.cpp
index 379e69a..3316702 100644
--- a/tests/alloc/AllocTest.cpp
+++ b/tests/alloc/AllocTest.cpp
@@ -176,12 +176,13 @@
 {
 	if (!verbose)
 		return;
+	const struct GprsMs *ms = tbf_ms(tbf);
 
 	for (size_t i = 0; i < ARRAY_SIZE(tbf->pdch); ++i)
 		if (tbf->pdch[i])
 			printf("PDCH[%zu] is used for %s\n", i, dir);
 	printf("PDCH[%d] is control_ts for %s\n", tbf->control_ts, dir);
-	printf("PDCH[%d] is first common for %s\n", tbf->first_common_ts, dir);
+	printf("PDCH[%d] is first common for %s\n", ms_first_common_ts(ms), dir);
 }
 
 #define ENABLE_PDCH(ts_no, enable_flag, trx)	\
@@ -237,8 +238,6 @@
 
 	dump_assignment(dl_tbf, "DL", verbose);
 
-	OSMO_ASSERT(dl_tbf->first_common_ts == ul_tbf->first_common_ts);
-
 	check_tfi_usage(bts);
 
 	tbf_free(dl_tbf);
@@ -284,12 +283,9 @@
 
 	dump_assignment(ul_tbf, "UL", verbose);
 
-	OSMO_ASSERT(dl_tbf->first_common_ts == ul_tbf->first_common_ts);
-
 	/* now update the dl_tbf */
 	dl_tbf->update();
 	dump_assignment(dl_tbf, "DL", verbose);
-	OSMO_ASSERT(dl_tbf->first_common_ts == ul_tbf->first_common_ts);
 
 	check_tfi_usage(bts);
 
@@ -334,8 +330,6 @@
 
 	dump_assignment(dl_tbf, "DL", true);
 
-	OSMO_ASSERT(dl_tbf->first_common_ts == ul_tbf->first_common_ts);
-
 	check_tfi_usage(bts);
 
 	tbf_free(dl_tbf);
@@ -575,13 +569,13 @@
 		trx = ms_current_trx(ms);
 
 		OSMO_ASSERT(ul_tbf || dl_tbf);
-
+		OSMO_ASSERT(ms_first_common_ts(ms) != TBF_TS_UNSET);
 		if (ul_tbf) {
-			ul_slots = 1 << ul_tbf->first_common_ts;
+			ul_slots = 1 << (uint8_t)ms_first_common_ts(ms);
 			tfi = ul_tbf->tfi();
 			dir = GPRS_RLCMAC_UL_TBF;
 		} else {
-			ul_slots = 1 << dl_tbf->first_common_ts;
+			ul_slots = 1 << (uint8_t)ms_first_common_ts(ms);
 			tfi = dl_tbf->tfi();
 			dir = GPRS_RLCMAC_DL_TBF;
 		}