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.orgHarald 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>