lchan activation: indicate whether TA is known

On lchan activation, we already know the Timing Advance in most
situations: from the Channel Request RACH, or from a previous lchan in
the same cell. Place this information in lchan->activate.info.ta.

So far, the lchan->last_ta (until recently called rqd_ta) was used to
store the initial TA for channel activation -- move the initial TA to
lchan->activate.info.ta, for proper scoping.

Only an inter-cell handover does not yet know a Timing Advance (until
the Handover Detection RACH is received), so indicate
activate.info.ta_known = false for that case.

If ta_known is false, do not include an Access Delay IE in the Channel
Activation message, ensuring that the BTS does not use an arbitrary TA
that is likely inaccurate.

The effect for OsmoBTS is that we will *not* start the downlink SACCH on
channel activation for inter-cell handover, but will wait for a HO RACH
first, and then use the correct TA when enabling downlink SACCH.

Related: OS#4008 SYS#5192
Change-Id: I986bf93e8acd6aef7eaf63ac962480b680aa894f
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 6cb3cf0..edfae26 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -571,6 +571,8 @@
 	/* During intra-BSC handover, we keep the MGW endpoint intact and just re-route to the new lchan. This
 	 * activate_info is for the new lchan, the re_use_mgw_endpoint_from_lchan points at the old lchan. */
 	struct gsm_lchan *re_use_mgw_endpoint_from_lchan;
+	bool ta_known;
+	uint8_t ta;
 };
 
 struct gsm_lchan {
diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c
index edffd35..67e7d27 100644
--- a/src/osmo-bsc/abis_rsl.c
+++ b/src/osmo-bsc/abis_rsl.c
@@ -521,7 +521,6 @@
 	struct msgb *msg;
 	int rc;
 	uint8_t *len;
-	uint8_t ta;
 
 	struct rsl_ie_chan_mode cm;
 	struct gsm48_chan_desc cd;
@@ -541,12 +540,6 @@
 		return rc;
 	}
 
-	ta = lchan->last_ta;
-
-	/* BS11 requires TA shifted by 2 bits */
-	if (bts->type == GSM_BTS_TYPE_BS11)
-		ta <<= 2;
-
 	memset(&cd, 0, sizeof(cd));
 	gsm48_lchan2chan_desc(&cd, lchan);
 
@@ -601,7 +594,13 @@
 	if (bts->ms_power_ctrl.mode != GSM_PWR_CTRL_MODE_NONE)
 		msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
 
-	msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
+	if (lchan->activate.info.ta_known) {
+		uint8_t ta = lchan->activate.info.ta;
+		/* BS11 requires TA shifted by 2 bits */
+		if (bts->type == GSM_BTS_TYPE_BS11)
+			ta <<= 2;
+		msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
+	}
 
 	/* BS/MS Power Control Parameters (if supported by BTS model) */
 	add_power_control_params(msg, RSL_IE_BS_POWER_PARAM, lchan);
@@ -1756,13 +1755,14 @@
 	OSMO_ASSERT(lchan->rqd_ref);
 
 	*(lchan->rqd_ref) = rqd->ref;
-	lchan->last_ta = rqd->ta;
 
 	LOG_LCHAN(lchan, LOGL_DEBUG, "MS: Channel Request: reason=%s ra=0x%02x ta=%d\n",
 		  gsm_chreq_name(rqd->reason), rqd->ref.ra, rqd->ta);
 	info = (struct lchan_activate_info){
 		.activ_for = FOR_MS_CHANNEL_REQUEST,
 		.chan_mode = GSM48_CMODE_SIGN,
+		.ta = rqd->ta,
+		.ta_known = true,
 	};
 
 	lchan_activate(lchan, &info);
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index a8b6439..39219a4 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -487,6 +487,8 @@
 			.requires_voice_stream = conn->assignment.requires_voice_stream,
 			.msc_assigned_cic = req->msc_assigned_cic,
 			.re_use_mgw_endpoint_from_lchan = conn->lchan,
+			.ta = conn->lchan->last_ta,
+			.ta_known = true,
 		};
 
 		osmo_fsm_inst_dispatch(conn->lchan->fi, LCHAN_EV_REQUEST_MODE_MODIFY, &info);
@@ -562,6 +564,8 @@
 		.requires_voice_stream = conn->assignment.requires_voice_stream,
 		.msc_assigned_cic = req->msc_assigned_cic,
 		.re_use_mgw_endpoint_from_lchan = conn->lchan,
+		.ta = conn->lchan->last_ta,
+		.ta_known = true,
 	};
 	lchan_activate(conn->assignment.new_lchan, &info);
 }
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c
index b9caf04..87359dc 100644
--- a/src/osmo-bsc/handover_fsm.c
+++ b/src/osmo-bsc/handover_fsm.c
@@ -408,6 +408,13 @@
 		.s15_s0 = conn->lchan->activate.info.s15_s0,
 	};
 
+	/* For intra-cell handover, we know the accurate Timing Advance from the previous lchan. For inter-cell
+	 * handover, no Timing Advance for the new cell is known, so leave it unset. */
+	if (ho->new_bts == bts) {
+		info.ta = conn->lchan->last_ta;
+		info.ta_known = true;
+	}
+
 	lchan_activate(ho->new_lchan, &info);
 }
 
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index 7a75c0b..9c7ecaf 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -580,7 +580,6 @@
 		ms_power_dbm = ms_pwr_dbm(bts->band, old_lchan->ms_power);
 		lchan_update_ms_power_ctrl_level(lchan, ms_power_dbm >= 0 ? ms_power_dbm : bts->ms_max_power);
 		lchan->bs_power = old_lchan->bs_power;
-		lchan->last_ta = old_lchan->last_ta;
 	} else {
 		lchan_update_ms_power_ctrl_level(lchan, bts->ms_max_power);
 		/* Upon last entering the UNUSED state, from lchan_reset():
@@ -702,8 +701,13 @@
 	lchan->encr = lchan->activate.info.encr;
 
 	rc = rsl_tx_chan_activ(lchan, act_type, ho_ref);
-	if (rc)
+	if (rc) {
 		lchan_fail_to(LCHAN_ST_UNUSED, "Tx Chan Activ failed: %s (%d)", strerror(-rc), rc);
+		return;
+	}
+
+	if (lchan->activate.info.ta_known)
+		lchan->last_ta = lchan->activate.info.ta;
 }
 
 static void lchan_fsm_post_activ_ack(struct osmo_fsm_inst *fi);