Change in osmocom-bb[master]: trxcon/scheduler: fix Measurement Reporting on SACCH

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Fri Sep 28 23:15:58 UTC 2018


Harald Welte has submitted this change and it was merged. ( https://gerrit.osmocom.org/11138 )

Change subject: trxcon/scheduler: fix Measurement Reporting on SACCH
......................................................................

trxcon/scheduler: fix Measurement Reporting on SACCH

According to 3GPP TS 04.08, section 3.4.1, SACCH logical channel
accompanies either a traffic or a signaling channel. It has the
particularity that continuous transmission must occur in both
directions, so on the Uplink direction measurement result messages
are sent at each possible occasion when nothing else has to be sent.
The LAPDm fill frames (0x01, 0x03, 0x01, 0x2b, ...) are not
applicable on SACCH channels!

Unfortunately, 3GPP TS 04.08 doesn't clearly state which "else
messages" besides Measurement Reports can be send by the MS on
SACCH channels. However, in sub-clause 3.4.1 it's stated that
the interval between two successive measurement result messages
shall not exceed one L2 frame.

This change introduces a separate handler for SACCH primitives,
which dequeues a SACCH primitive from transmit queue, if present.
Otherwise it dequeues a cached Measurement Report (the last
received one). Finally, if the cache is empty, a "dummy"
measurement report is used. When it's possible,
a non-MR primitive is prioritized.

Change-Id: If1b8dc74ced746d6270676fdde75fcda32f91a3d
Related: OS#2988
---
M src/host/trxcon/sched_prim.c
M src/host/trxcon/sched_trx.c
M src/host/trxcon/sched_trx.h
3 files changed, 211 insertions(+), 14 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/src/host/trxcon/sched_prim.c b/src/host/trxcon/sched_prim.c
index 2067900..275a050 100644
--- a/src/host/trxcon/sched_prim.c
+++ b/src/host/trxcon/sched_prim.c
@@ -122,6 +122,194 @@
 	return 0;
 }
 
+/**
+ * Composes a new primitive using either cached (if populated),
+ * or "dummy" Measurement Report message.
+ *
+ * @param  lchan lchan to assign a primitive
+ * @return       SACCH primitive to be transmitted
+ */
+static struct trx_ts_prim *prim_compose_mr(struct trx_lchan_state *lchan)
+{
+	struct trx_ts_prim *prim;
+	uint8_t *mr_src_ptr;
+	bool cached;
+	int rc;
+
+	/* "Dummy" Measurement Report */
+	static const uint8_t meas_rep_dummy[] = {
+		/* L1 SACCH pseudo-header */
+		0x0f, 0x00,
+
+		/* LAPDm header */
+		0x01, 0x03, 0x49,
+
+		/* Measurement report */
+		0x06, 0x15, 0x36, 0x36, 0x01, 0xC0,
+
+		/* TODO: Padding? Randomize if so */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	};
+
+	/* Allocate a new primitive */
+	rc = sched_prim_init(lchan, &prim, GSM_MACBLOCK_LEN,
+		trx_lchan_desc[lchan->type].chan_nr, TRX_CH_LID_SACCH);
+	OSMO_ASSERT(rc == 0);
+
+	/* Check if the MR cache is populated (verify LAPDm header) */
+	cached = (lchan->sacch.mr_cache[2] != 0x00
+		&& lchan->sacch.mr_cache[3] != 0x00
+		&& lchan->sacch.mr_cache[4] != 0x00);
+	if (cached) { /* Use the cached one */
+		mr_src_ptr = lchan->sacch.mr_cache;
+		lchan->sacch.mr_cache_usage++;
+	} else { /* Use "dummy" one */
+		mr_src_ptr = (uint8_t *) meas_rep_dummy;
+	}
+
+	/* Compose a new Measurement Report primitive */
+	memcpy(prim->payload, mr_src_ptr, GSM_MACBLOCK_LEN);
+
+#if 0
+	/**
+	 * Update the L1 SACCH pseudo-header (only for cached MRs)
+	 *
+	 * FIXME: this would require having access to the trx_instance,
+	 * what can be achieved either by chain-passing the pointer
+	 * through sched_prim_dequeue(), or by adding some
+	 * back-pointers to the logical channel state.
+	 *
+	 * TODO: filling of the actual values into cached Measurement
+	 * Reports would break the distance spoofing feature. If it
+	 * were known whether the spoofing is enabled or not, we could
+	 * decide whether to update the cached L1 SACCH header here.
+	 */
+	if (!cached) {
+		prim->payload[0] = trx->tx_power;
+		prim->payload[1] = trx->ta;
+	}
+#endif
+
+	/* Inform about the cache usage count */
+	if (cached && lchan->sacch.mr_cache_usage > 5) {
+		LOGP(DSCHD, LOGL_NOTICE, "SACCH MR cache usage count=%u > 5 "
+			"on lchan=%s => ancient measurements, please fix!\n",
+			lchan->sacch.mr_cache_usage,
+			trx_lchan_desc[lchan->type].name);
+	}
+
+	LOGP(DSCHD, LOGL_NOTICE, "Using a %s Measurement Report "
+		"on lchan=%s\n", (cached ? "cached" : "dummy"),
+		trx_lchan_desc[lchan->type].name);
+
+	return prim;
+}
+
+/**
+ * Dequeues a SACCH primitive from transmit queue, if present.
+ * Otherwise dequeues a cached Measurement Report (the last
+ * received one). Finally, if the cache is empty, a "dummy"
+ * measurement report is used.
+ *
+ * According to 3GPP TS 04.08, section 3.4.1, SACCH channel
+ * accompanies either a traffic or a signaling channel. It
+ * has the particularity that continuous transmission must
+ * occur in both directions, so on the Uplink direction
+ * measurement result messages are sent at each possible
+ * occasion when nothing else has to be sent. The LAPDm
+ * fill frames (0x01, 0x03, 0x01, 0x2b, ...) are not
+ * applicable on SACCH channels!
+ *
+ * Unfortunately, 3GPP TS 04.08 doesn't clearly state
+ * which "else messages" besides Measurement Reports
+ * can be send by the MS on SACCH channels. However,
+ * in sub-clause 3.4.1 it's stated that the interval
+ * between two successive measurement result messages
+ * shall not exceed one L2 frame.
+ *
+ * @param  queue transmit queue to take a prim from
+ * @param  lchan lchan to assign a primitive
+ * @return       SACCH primitive to be transmitted
+ */
+static struct trx_ts_prim *prim_dequeue_sacch(struct llist_head *queue,
+	struct trx_lchan_state *lchan)
+{
+	struct trx_ts_prim *prim_nmr = NULL;
+	struct trx_ts_prim *prim_mr = NULL;
+	struct trx_ts_prim *prim;
+	bool mr_now;
+
+	/* Shall we transmit MR now? */
+	mr_now = !lchan->sacch.mr_tx_last;
+
+#define PRIM_IS_MR(prim) \
+	(prim->payload[5] == GSM48_PDISC_RR \
+		&& prim->payload[6] == GSM48_MT_RR_MEAS_REP)
+
+	/* Iterate over all primitives in the queue */
+	llist_for_each_entry(prim, queue, list) {
+		/* We are looking for particular channel */
+		if (prim->chan != lchan->type)
+			continue;
+
+		/* Just to be sure... */
+		if (prim->payload_len != GSM_MACBLOCK_LEN)
+			continue;
+
+		/* Look for a Measurement Report */
+		if (!prim_mr && PRIM_IS_MR(prim))
+			prim_mr = prim;
+
+		/* Look for anything else */
+		if (!prim_nmr && !PRIM_IS_MR(prim))
+			prim_nmr = prim;
+
+		/* Should we look further? */
+		if (mr_now && prim_mr)
+			break; /* MR was found */
+		else if (!mr_now && prim_nmr)
+			break; /* something else was found */
+	}
+
+	LOGP(DSCHD, LOGL_DEBUG, "SACCH MR selection on lchan=%s: "
+		"mr_tx_last=%d prim_mr=%p prim_nmr=%p\n",
+		trx_lchan_desc[lchan->type].name,
+		lchan->sacch.mr_tx_last,
+		prim_mr, prim_nmr);
+
+	/* Prioritize non-MR prim if possible */
+	if (mr_now && prim_mr)
+		prim = prim_mr;
+	else if (!mr_now && prim_nmr)
+		prim = prim_nmr;
+	else if (!mr_now && prim_mr)
+		prim = prim_mr;
+	else /* Nothing was found */
+		prim = NULL;
+
+	/* Have we found what we were looking for? */
+	if (prim) /* Dequeue if so */
+		llist_del(&prim->list);
+	else /* Otherwise compose a new MR */
+		prim = prim_compose_mr(lchan);
+
+	/* Update the cached report */
+	if (prim == prim_mr) {
+		memcpy(lchan->sacch.mr_cache,
+			prim->payload, GSM_MACBLOCK_LEN);
+		lchan->sacch.mr_cache_usage = 0;
+
+		LOGP(DSCHD, LOGL_DEBUG, "SACCH MR cache has been updated "
+			"for lchan=%s\n", trx_lchan_desc[lchan->type].name);
+	}
+
+	/* Update the MR transmission state */
+	lchan->sacch.mr_tx_last = PRIM_IS_MR(prim);
+
+	return prim;
+}
+
 /* Dequeues a primitive of a given channel type */
 static struct trx_ts_prim *prim_dequeue_one(struct llist_head *queue,
 	enum trx_lchan_type lchan_type)
@@ -285,6 +473,10 @@
 struct trx_ts_prim *sched_prim_dequeue(struct llist_head *queue,
 	uint32_t fn, struct trx_lchan_state *lchan)
 {
+	/* SACCH is unorthodox, see 3GPP TS 04.08, section 3.4.1 */
+	if (CHAN_IS_SACCH(lchan->type))
+		return prim_dequeue_sacch(queue, lchan);
+
 	/* There is nothing to dequeue */
 	if (llist_empty(queue))
 		return NULL;
@@ -346,6 +538,8 @@
 
 	/* Make sure that there is no existing primitive */
 	OSMO_ASSERT(lchan->prim == NULL);
+	/* Not applicable for SACCH! */
+	OSMO_ASSERT(!CHAN_IS_SACCH(lchan->type));
 
 	/**
 	 * Determine what actually should be generated:
@@ -360,18 +554,8 @@
 		/* FIXME: should we do anything for CSD? */
 		return 0;
 	} else {
-		uint8_t *cur = prim_buffer;
-
-		if (CHAN_IS_SACCH(chan)) {
-			/* Add 2-byte SACCH header */
-			/* FIXME: How to get TA and MS Tx Power from l1l->trx->tx_power + l1l->trx->ta? */
-			cur[0] = cur[1] = 0x00;
-			cur += 2;
-		}
-
-		/* Copy a fill frame payload */
-		memcpy(cur, lapdm_fill_frame, sizeof(lapdm_fill_frame));
-		cur += sizeof(lapdm_fill_frame);
+		/* Copy LAPDm fill frame's header */
+		memcpy(prim_buffer, lapdm_fill_frame, sizeof(lapdm_fill_frame));
 
 		/**
 		 * TS 144.006, section 5.2 "Frame delimitation and fill bits"
@@ -379,7 +563,7 @@
 		 * be set to the binary value "00101011", each fill bit should
 		 * be set to a random value when sent by the network.
 		 */
-		for (i = cur - prim_buffer; i < GSM_MACBLOCK_LEN; i++)
+		for (i = sizeof(lapdm_fill_frame); i < GSM_MACBLOCK_LEN; i++)
 			prim_buffer[i] = (uint8_t) rand();
 
 		/* Define a prim length */
diff --git a/src/host/trxcon/sched_trx.c b/src/host/trxcon/sched_trx.c
index fc29998..0b83af3 100644
--- a/src/host/trxcon/sched_trx.c
+++ b/src/host/trxcon/sched_trx.c
@@ -460,7 +460,7 @@
 	/* Forget the current prim */
 	sched_prim_drop(lchan);
 
-	/* TCH specific variables */
+	/* Channel specific stuff */
 	if (CHAN_IS_TCH(lchan->type)) {
 		lchan->dl_ongoing_facch = 0;
 		lchan->ul_facch_blocks = 0;
@@ -469,6 +469,9 @@
 
 		/* Reset AMR state */
 		memset(&lchan->amr, 0x00, sizeof(lchan->amr));
+	} else if (CHAN_IS_SACCH(lchan->type)) {
+		/* Reset SACCH state */
+		memset(&lchan->sacch, 0x00, sizeof(lchan->sacch));
 	}
 
 	/* Reset ciphering state */
diff --git a/src/host/trxcon/sched_trx.h b/src/host/trxcon/sched_trx.h
index 818c95a..10ae256 100644
--- a/src/host/trxcon/sched_trx.h
+++ b/src/host/trxcon/sched_trx.h
@@ -186,6 +186,16 @@
 		int32_t toa256_sum;
 	} meas;
 
+	/*! \brief SACCH state */
+	struct {
+		/*! \brief Cached measurement report (last received) */
+		uint8_t mr_cache[GSM_MACBLOCK_LEN];
+		/*! \brief Cache usage counter */
+		uint8_t mr_cache_usage;
+		/*! \brief Was a MR transmitted last time? */
+		bool mr_tx_last;
+	} sacch;
+
 	/* AMR specific */
 	struct {
 		/*! \brief 4 possible codecs for AMR */

-- 
To view, visit https://gerrit.osmocom.org/11138
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: If1b8dc74ced746d6270676fdde75fcda32f91a3d
Gerrit-Change-Number: 11138
Gerrit-PatchSet: 5
Gerrit-Owner: Vadim Yanitskiy <axilirator at gmail.com>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder (1000002)
Gerrit-Reviewer: Pau Espin Pedrol <pespin at sysmocom.de>
Gerrit-Reviewer: Vadim Yanitskiy <axilirator at gmail.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20180928/af88bdc8/attachment.htm>


More information about the gerrit-log mailing list