diff options
author | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2020-07-08 19:11:58 +0700 |
---|---|---|
committer | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2020-07-12 21:43:46 +0700 |
commit | d39b8410590f7183c78acb6ded8f6e7257257681 (patch) | |
tree | a3d2514f0da233d89ec557e917a3103be6dbaa4b | |
parent | bb0609ed484977ff60faf3ac8256ce97f5f7c0a0 (diff) |
trxcon/scheduler: check TDMA frame order, drop out of order bursts
When running together with fake_trx.py (mostly used back-end), it
is currently possible that Downlink bursts are received in a wrong
order if more than one transceiver is configured (multi-trx mode).
This is how it looks like:
DTRXD DEBUG trx_if.c:612 RX burst tn=3 fn=629 rssi=-86 toa=0
DSCHD DEBUG sched_lchan_tchf.c:60 Traffic received on TCH/F: fn=629 ts=3 bid=1
DTRXD DEBUG trx_if.c:612 RX burst tn=3 fn=630 rssi=-86 toa=0
DSCHD DEBUG sched_lchan_tchf.c:60 Traffic received on TCH/F: fn=630 ts=3 bid=2
DTRXD DEBUG trx_if.c:612 RX burst tn=3 fn=631 rssi=-86 toa=0
DSCHD DEBUG sched_lchan_tchf.c:60 Traffic received on TCH/F: fn=631 ts=3 bid=3
DTRXD DEBUG trx_if.c:612 RX burst tn=3 fn=633 (!) rssi=-86 toa=0
DSCHD NOTICE sched_trx.c:663 Substituting (!) lost TDMA frame 632 on TCH/F
DSCHD DEBUG sched_lchan_tchf.c:60 Traffic received on TCH/F: fn=632 ts=3 bid=0
DSCHD DEBUG sched_lchan_tchf.c:60 Traffic received on TCH/F: fn=633 ts=3 bid=1
DTRXD DEBUG trx_if.c:612 RX burst tn=3 fn=632 (!) rssi=-86 toa=0
DTRXD NOTICE sched_trx.c:640 Too many (>104) contiguous TDMA frames elapsed (2715647)
since the last processed fn=633 (current fn=632)
so here a burst with TDMA fn=633 was received earlier than a burst
with TDMA fn=632. The burst loss detection logic considered the
latter one as lost, and substituted it with a dummy burst. When
finally the out-of-order burst with TDMA fn=632 was received, we
got the large number of allegedly elapsed frames:
((632 + 2715648) - 633) % 2715648 == 2715647
Given that late bursts get substituted, the best thing we can do
is to reject them and log an error. Passing them to the logical
channel handler (again) might lead to undefined behaviour.
Change-Id: I873c8555ea2ca190b1689227bb0fdcba87188772
Related: OS#4658, OS#4546
-rw-r--r-- | src/host/trxcon/sched_trx.c | 31 |
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) |