summaryrefslogtreecommitdiffstats
path: root/src/host/trxcon/sched_trx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/host/trxcon/sched_trx.c')
-rw-r--r--src/host/trxcon/sched_trx.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/src/host/trxcon/sched_trx.c b/src/host/trxcon/sched_trx.c
index 9195b336..0025e0cc 100644
--- a/src/host/trxcon/sched_trx.c
+++ b/src/host/trxcon/sched_trx.c
@@ -625,7 +625,7 @@ static int subst_frame_loss(struct trx_lchan_state *lchan,
{
const struct trx_multiframe *mf;
const struct trx_frame *fp;
- unsigned int elapsed, i;
+ int elapsed, i;
/* Wait until at least one TDMA frame is processed */
if (lchan->tdma.num_proc == 0)
@@ -634,10 +634,28 @@ static int subst_frame_loss(struct trx_lchan_state *lchan,
/* Short alias for the current multiframe */
mf = lchan->ts->mf_layout;
- /* How many frames elapsed since the last one? */
- elapsed = GSM_TDMA_FN_SUB(fn, lchan->tdma.last_proc);
+ /* Calculate how many frames elapsed since the last received one.
+ * The algorithm is based on GSM::FNDelta() from osmo-trx. */
+ elapsed = fn - lchan->tdma.last_proc;
+ if (elapsed >= GSM_TDMA_HYPERFRAME / 2)
+ elapsed -= GSM_TDMA_HYPERFRAME;
+ else if (elapsed < -GSM_TDMA_HYPERFRAME / 2)
+ elapsed += GSM_TDMA_HYPERFRAME;
+
+ /* Check TDMA frame order (wrong order is possible with fake_trx.py, see OS#4658) */
+ if (elapsed < 0) {
+ /* This burst has already been substituted by a dummy burst (all bits set to zero),
+ * so better drop it. Otherwise we risk to get undefined behavior in handler(). */
+ LOGP(DSCHD, LOGL_ERROR, "(%s) Rx burst with fn=%u older than the last "
+ "processed fn=%u (see OS#4658) => dropping\n",
+ trx_lchan_desc[lchan->type].name,
+ fn, lchan->tdma.last_proc);
+ return -EALREADY;
+ }
+
+ /* Check how many frames we (potentially) need to compensate */
if (elapsed > mf->period) {
- LOGP(DSCHD, LOGL_NOTICE, "Too many (>%u) contiguous TDMA frames elapsed (%u) "
+ LOGP(DSCHD, LOGL_NOTICE, "Too many (>%u) contiguous TDMA frames elapsed (%d) "
"since the last processed fn=%u (current %u)\n",
mf->period, elapsed, lchan->tdma.last_proc, fn);
return -EIO;
@@ -687,6 +705,7 @@ int sched_trx_handle_rx_burst(struct trx_instance *trx, uint8_t tn,
trx_lchan_rx_func *handler;
enum trx_lchan_type chan;
uint8_t offset, bid;
+ int rc;
/* Check whether required timeslot is allocated and configured */
ts = trx->ts_list[tn];
@@ -720,7 +739,9 @@ int sched_trx_handle_rx_burst(struct trx_instance *trx, uint8_t tn,
return 0;
/* Compensate lost TDMA frames (if any) */
- subst_frame_loss(lchan, handler, fn);
+ rc = subst_frame_loss(lchan, handler, fn);
+ if (rc == -EALREADY)
+ return rc;
/* Perform A5/X decryption if required */
if (lchan->a5.algo)