Changes
#1269 (Jun 30, 2026, 4:41:04 PM)
common: reset lchan meas state in gsm_lchan_release()
lchan->meas (including interf_meas_num and num_ul_meas) is normally
only reset by lchan_meas_reset() called from rsl_tx_chan_act_ack() on
RSL CHANNEL ACTIVATION. Idle logical channels are never RSL-activated,
so their measurement state is never reset via that path.
On an OML link re-establishment, osmo-bts does not exit: abis.c tears
down the signalling links, the bts_shutdown FSM powers down all TRXs,
and then waits for reconnect. The gsm_bts/trx/ts/lchan structures
remain in memory, so stale interf_meas_num survives the reconnect.
This is why we're seeing these ERRORs while running ttcn3-bts-test:
(bts=0,trx=2,ts=4,ss=6) Not enough room to store interference report (0dBm)
Add a lchan_meas_reset() call to gsm_lchan_release(), which is called
from gsm_ts_release() when the nm_channel_fsm enters state
NM_CHAN_ST_OP_DISABLED_NOTINSTALLED. This is exactly the right
moment: the radio is fully stopped, so no new samples arrive.
Change-Id: I18dc9d30417b0c5b2e579660d4a087d93445f956
AI-Assisted: yes (Claude)
lchan->meas (including interf_meas_num and num_ul_meas) is normally
only reset by lchan_meas_reset() called from rsl_tx_chan_act_ack() on
RSL CHANNEL ACTIVATION. Idle logical channels are never RSL-activated,
so their measurement state is never reset via that path.
On an OML link re-establishment, osmo-bts does not exit: abis.c tears
down the signalling links, the bts_shutdown FSM powers down all TRXs,
and then waits for reconnect. The gsm_bts/trx/ts/lchan structures
remain in memory, so stale interf_meas_num survives the reconnect.
This is why we're seeing these ERRORs while running ttcn3-bts-test:
(bts=0,trx=2,ts=4,ss=6) Not enough room to store interference report (0dBm)
Add a lchan_meas_reset() call to gsm_lchan_release(), which is called
from gsm_ts_release() when the nm_channel_fsm enters state
NM_CHAN_ST_OP_DISABLED_NOTINSTALLED. This is exactly the right
moment: the radio is fully stopped, so no new samples arrive.
Change-Id: I18dc9d30417b0c5b2e579660d4a087d93445f956
AI-Assisted: yes (Claude)
#1268 (Jun 30, 2026, 4:31:47 PM)
common: stop buffering UL measurements when SACCH is deactivated
When the BSC sends RSL DEACT SACCH, the per-SACCH UL measurement drain
stops (it runs on SACCH timing), but the producer in lchan_new_ul_meas()
keeps appending the measurement contributions from every received
TCH/SDCCH burst. After one SACCH period (104 frames) the 104-slot
uplink measurement buffer fills up, yielding a flood of:
NOTICE measurement.c:336 no space for uplink measurement, num_ul_meas=104
Add a bool sacch_active flag to gsm_lchan, set to true in the common
l1sap_chan_act() and clear in l1sap_chan_deact_sacch(). Guard
lchan_new_ul_meas() with this flag so that measurements are silently
discarded while SACCH is inactive - there is nothing to drain the
buffer and no SACCH channel on which to report the results to the BSC.
Change-Id: I3943c788cab5d2411b06ac681d4d412852bac0a7
AI-Assisted: yes (Claude)
When the BSC sends RSL DEACT SACCH, the per-SACCH UL measurement drain
stops (it runs on SACCH timing), but the producer in lchan_new_ul_meas()
keeps appending the measurement contributions from every received
TCH/SDCCH burst. After one SACCH period (104 frames) the 104-slot
uplink measurement buffer fills up, yielding a flood of:
NOTICE measurement.c:336 no space for uplink measurement, num_ul_meas=104
Add a bool sacch_active flag to gsm_lchan, set to true in the common
l1sap_chan_act() and clear in l1sap_chan_deact_sacch(). Guard
lchan_new_ul_meas() with this flag so that measurements are silently
discarded while SACCH is inactive - there is nothing to drain the
buffer and no SACCH channel on which to report the results to the BSC.
Change-Id: I3943c788cab5d2411b06ac681d4d412852bac0a7
AI-Assisted: yes (Claude)
#1267 (Jun 30, 2026, 4:22:27 PM)
common: flush paging queue in nm_bts_fsm's NOTINSTALLED on_enter
paging_reset() exists to flush stale paging records from the queue,
but was never called anywhere. Stale paging records can accumulate
when the OML link goes down: osmo-bts does not exit, so the paging
queue survives into the next BSC session.
Call it alongside bts_cbch_reset() and bts_asci_notification_reset()
in st_op_disabled_notinstalled_on_enter(), which fires after all TRXs
are confirmed closed and before a new OML connection is accepted.
Change-Id: I109ab282986b68b68ba5c11859c44b771c0416fd
AI-Assisted: yes (Claude)
paging_reset() exists to flush stale paging records from the queue,
but was never called anywhere. Stale paging records can accumulate
when the OML link goes down: osmo-bts does not exit, so the paging
queue survives into the next BSC session.
Call it alongside bts_cbch_reset() and bts_asci_notification_reset()
in st_op_disabled_notinstalled_on_enter(), which fires after all TRXs
are confirmed closed and before a new OML connection is accepted.
Change-Id: I109ab282986b68b68ba5c11859c44b771c0416fd
AI-Assisted: yes (Claude)
#1266 (Jun 29, 2026, 2:54:11 PM)
common: stop buffering UL measurements when SACCH is deactivated
When the BSC sends RSL DEACT SACCH, the per-SACCH UL measurement drain
stops (it runs on SACCH timing), but the producer in lchan_new_ul_meas()
keeps appending the measurement contributions from every received
TCH/SDCCH burst. After one SACCH period (104 frames) the 104-slot
uplink measurement buffer fills up, yielding a flood of:
NOTICE measurement.c:336 no space for uplink measurement, num_ul_meas=104
Add a bool sacch_active flag to gsm_lchan, set to true in the common
l1sap_chan_act() and clear in l1sap_chan_deact_sacch(). Guard
lchan_new_ul_meas() with this flag so that measurements are silently
discarded while SACCH is inactive - there is nothing to drain the
buffer and no SACCH channel on which to report the results to the BSC.
Change-Id: I3943c788cab5d2411b06ac681d4d412852bac0a7
AI-Assisted: yes (Claude)
When the BSC sends RSL DEACT SACCH, the per-SACCH UL measurement drain
stops (it runs on SACCH timing), but the producer in lchan_new_ul_meas()
keeps appending the measurement contributions from every received
TCH/SDCCH burst. After one SACCH period (104 frames) the 104-slot
uplink measurement buffer fills up, yielding a flood of:
NOTICE measurement.c:336 no space for uplink measurement, num_ul_meas=104
Add a bool sacch_active flag to gsm_lchan, set to true in the common
l1sap_chan_act() and clear in l1sap_chan_deact_sacch(). Guard
lchan_new_ul_meas() with this flag so that measurements are silently
discarded while SACCH is inactive - there is nothing to drain the
buffer and no SACCH channel on which to report the results to the BSC.
Change-Id: I3943c788cab5d2411b06ac681d4d412852bac0a7
AI-Assisted: yes (Claude)
#1265 (Jun 29, 2026, 2:25:40 PM)
l1sap: fix duplicate RF RESOURCE INDICATION on clock bootstrap
The TTCN-3 test suite (ttcn3-bts-test) expects to receive exactly one
RF RESOURCE INDICATION message from each TRX during the bootstrap stage,
while waiting for all TRX to come up and be configured by the BSC.
l1sap_interf_meas_report() fires whenever bts->gsm_time.fn % period is
0, where period = intave * 104 (typically 624 frames). Since CLCK.ind
with FN=0 satisfies this condition, a report is sent at the very
beginning of each clock epoch.
This was not a problem before commit fcfc4e83, because the first
CLCK.ind from the transciever was effectively a no-op: with
last_fn_timer.fn zero-initialised, the first indication at FN=0 yielded
elapsed_fn=0 (not > MAX_FN_SKEW), and the catch-up loop (while fn !=
last_fn_timer.fn) would not execute either. Downlink scheduling only
started on the second CLCK.ind (at FN=102, which is > MAX_FN_SKEW),
and 102 % 624 != 0, so no RF RESOURCE INDICATION was triggered.
fcfc4e83 changed the logic so that Downlink scheduling now begins
immediately on the first CLCK.ind, via an unconditional call to
trx_setup_clock() -> bts_sched_fn(fn). When fake_trx starts its frame
counter from FN=0, this immediately triggers l1sap_interf_meas_report()
because 0 % 624 == 0. A second report follows ~2.88s later when the
periodic timer reaches FN=624, making the bootstrap logic
in ttcn3-bts-test unhappy.
Fix by shifting the trigger to (fn + 1) % period == 0, i.e. the report
fires at the last frame of each period rather than the first. FN=0 now
yields (0+1) % 624 = 1 != 0, suppressing the spurious bootstrap report.
The periodic behaviour and report cadence are otherwise unchanged.
Change-Id: I6550178427b08e67c9763f0f37efff5b88960b1f
Related: fcfc4e83 ("osmo-bts-trx: fix spurious shutdown on first CLCK.ind from osmo-trx")
AI-Assisted: yes (Claude)
The TTCN-3 test suite (ttcn3-bts-test) expects to receive exactly one
RF RESOURCE INDICATION message from each TRX during the bootstrap stage,
while waiting for all TRX to come up and be configured by the BSC.
l1sap_interf_meas_report() fires whenever bts->gsm_time.fn % period is
0, where period = intave * 104 (typically 624 frames). Since CLCK.ind
with FN=0 satisfies this condition, a report is sent at the very
beginning of each clock epoch.
This was not a problem before commit fcfc4e83, because the first
CLCK.ind from the transciever was effectively a no-op: with
last_fn_timer.fn zero-initialised, the first indication at FN=0 yielded
elapsed_fn=0 (not > MAX_FN_SKEW), and the catch-up loop (while fn !=
last_fn_timer.fn) would not execute either. Downlink scheduling only
started on the second CLCK.ind (at FN=102, which is > MAX_FN_SKEW),
and 102 % 624 != 0, so no RF RESOURCE INDICATION was triggered.
fcfc4e83 changed the logic so that Downlink scheduling now begins
immediately on the first CLCK.ind, via an unconditional call to
trx_setup_clock() -> bts_sched_fn(fn). When fake_trx starts its frame
counter from FN=0, this immediately triggers l1sap_interf_meas_report()
because 0 % 624 == 0. A second report follows ~2.88s later when the
periodic timer reaches FN=624, making the bootstrap logic
in ttcn3-bts-test unhappy.
Fix by shifting the trigger to (fn + 1) % period == 0, i.e. the report
fires at the last frame of each period rather than the first. FN=0 now
yields (0+1) % 624 = 1 != 0, suppressing the spurious bootstrap report.
The periodic behaviour and report cadence are otherwise unchanged.
Change-Id: I6550178427b08e67c9763f0f37efff5b88960b1f
Related: fcfc4e83 ("osmo-bts-trx: fix spurious shutdown on first CLCK.ind from osmo-trx")
AI-Assisted: yes (Claude)
#1264 (Jun 29, 2026, 2:16:14 PM)
common: reset lchan meas state in gsm_ts_release()
lchan->meas (including interf_meas_num and num_ul_meas) is normally
only reset by lchan_meas_reset() called from rsl_tx_chan_act_ack() on
RSL CHANNEL ACTIVATION. Idle logical channels are never RSL-activated,
so their measurement state is never reset via that path.
On an OML link re-establishment, osmo-bts does not exit: abis.c tears
down the signalling links, the bts_shutdown FSM powers down all TRXs,
and then waits for reconnect. The gsm_bts/trx/ts/lchan structures
remain in memory, so stale interf_meas_num survives the reconnect.
This is why we're seeing these ERRORs while running ttcn3-bts-test:
(bts=0,trx=2,ts=4,ss=6) Not enough room to store interference report (0dBm)
Add a lchan_meas_reset() call to gsm_ts_release(), which is called
from nm_channel_fsm's NOTINSTALLED on_enter after the TRX is confirmed
closed. This is exactly the right moment: the radio is fully stopped,
so no new samples arrive.
Change-Id: I18dc9d30417b0c5b2e579660d4a087d93445f956
AI-Assisted: yes (Claude)
lchan->meas (including interf_meas_num and num_ul_meas) is normally
only reset by lchan_meas_reset() called from rsl_tx_chan_act_ack() on
RSL CHANNEL ACTIVATION. Idle logical channels are never RSL-activated,
so their measurement state is never reset via that path.
On an OML link re-establishment, osmo-bts does not exit: abis.c tears
down the signalling links, the bts_shutdown FSM powers down all TRXs,
and then waits for reconnect. The gsm_bts/trx/ts/lchan structures
remain in memory, so stale interf_meas_num survives the reconnect.
This is why we're seeing these ERRORs while running ttcn3-bts-test:
(bts=0,trx=2,ts=4,ss=6) Not enough room to store interference report (0dBm)
Add a lchan_meas_reset() call to gsm_ts_release(), which is called
from nm_channel_fsm's NOTINSTALLED on_enter after the TRX is confirmed
closed. This is exactly the right moment: the radio is fully stopped,
so no new samples arrive.
Change-Id: I18dc9d30417b0c5b2e579660d4a087d93445f956
AI-Assisted: yes (Claude)
#1263 (Jun 29, 2026, 2:07:05 PM)
common: flush paging queue in nm_bts_fsm's NOTINSTALLED on_enter
paging_reset() exists to flush stale paging records from the queue,
but was never called anywhere. Stale paging records can accumulate
when the OML link goes down: osmo-bts does not exit, so the paging
queue survives into the next BSC session.
Call it alongside bts_cbch_reset() and bts_asci_notification_reset()
in st_op_disabled_notinstalled_on_enter(), which fires after all TRXs
are confirmed closed and before a new OML connection is accepted.
Change-Id: I109ab282986b68b68ba5c11859c44b771c0416fd
AI-Assisted: yes (Claude)
paging_reset() exists to flush stale paging records from the queue,
but was never called anywhere. Stale paging records can accumulate
when the OML link goes down: osmo-bts does not exit, so the paging
queue survives into the next BSC session.
Call it alongside bts_cbch_reset() and bts_asci_notification_reset()
in st_op_disabled_notinstalled_on_enter(), which fires after all TRXs
are confirmed closed and before a new OML connection is accepted.
Change-Id: I109ab282986b68b68ba5c11859c44b771c0416fd
AI-Assisted: yes (Claude)
#1262 (Jun 29, 2026, 1:59:57 PM)
common: stop buffering UL measurements when SACCH is deactivated
When the BSC sends RSL DEACT SACCH, the per-SACCH UL measurement drain
stops (it runs on SACCH timing), but the producer in lchan_new_ul_meas()
keeps appending the measurement contributions from every received
TCH/SDCCH burst. After one SACCH period (104 frames) the 104-slot
uplink measurement buffer fills up, yielding a flood of:
NOTICE measurement.c:336 no space for uplink measurement, num_ul_meas=104
Add a bool sacch_active flag to gsm_lchan, set to true in the common
l1sap_chan_act() and clear in l1sap_chan_deact_sacch(). Guard
lchan_new_ul_meas() with this flag so that measurements are silently
discarded while SACCH is inactive - there is nothing to drain the
buffer and no SACCH channel on which to report the results to the BSC.
Change-Id: I3943c788cab5d2411b06ac681d4d412852bac0a7
AI-Assisted: yes (Claude)
When the BSC sends RSL DEACT SACCH, the per-SACCH UL measurement drain
stops (it runs on SACCH timing), but the producer in lchan_new_ul_meas()
keeps appending the measurement contributions from every received
TCH/SDCCH burst. After one SACCH period (104 frames) the 104-slot
uplink measurement buffer fills up, yielding a flood of:
NOTICE measurement.c:336 no space for uplink measurement, num_ul_meas=104
Add a bool sacch_active flag to gsm_lchan, set to true in the common
l1sap_chan_act() and clear in l1sap_chan_deact_sacch(). Guard
lchan_new_ul_meas() with this flag so that measurements are silently
discarded while SACCH is inactive - there is nothing to drain the
buffer and no SACCH channel on which to report the results to the BSC.
Change-Id: I3943c788cab5d2411b06ac681d4d412852bac0a7
AI-Assisted: yes (Claude)
#1261 (Jun 29, 2026, 1:50:36 PM)
oml: validate Intave Parameter range in SET BTS ATTR
3GPP TS 52.021 §9.4.24 defines valid range for the Intave Parameter
as 1..31, matching the fixed size of the per-lchan interference sample
buffer (interf_meas_dbm[31] in lchan.h). Previously any uint8_t value
was accepted without validation, meaning a buggy BSC could send
intave=0 (silently disabling interference reporting) or intave>31
(causing a buffer overflow in gsm_lchan_interf_meas_push()).
Let's guard against that by NACKing the SET BTS ATTR message with
cause=NM_NACK_PARAM_RANGE if the value is outside the valid range.
Change-Id: Id4d3353d4397aaa2517091b020d38ee15e084e2c
AI-Assisted: yes (Claude)
3GPP TS 52.021 §9.4.24 defines valid range for the Intave Parameter
as 1..31, matching the fixed size of the per-lchan interference sample
buffer (interf_meas_dbm[31] in lchan.h). Previously any uint8_t value
was accepted without validation, meaning a buggy BSC could send
intave=0 (silently disabling interference reporting) or intave>31
(causing a buffer overflow in gsm_lchan_interf_meas_push()).
Let's guard against that by NACKing the SET BTS ATTR message with
cause=NM_NACK_PARAM_RANGE if the value is outside the valid range.
Change-Id: Id4d3353d4397aaa2517091b020d38ee15e084e2c
AI-Assisted: yes (Claude)
#1260 (Jun 23, 2026, 7:51:25 PM)
osmo-bts-trx: fix spurious clock skew shutdown after self-compensation
When the BTS runs ahead of the transceiver (elapsed_fn < 0),
trx_sched_clock() reschedules the timerfd to deliberately delay the
next FN. osmo_timerfd_schedule() resets the timerfd and discards any
accumulated expirations, but last_fn_timer.tv was left pointing at
the previous callback. The next trx_fn_timer_cb() then measures
elapsed_us all the way back to that previous callback - spanning the
deliberate delay (or any OS stall that preceded us) - and falsely
trips the "PC clock skew too high" check, shutting the BTS down
for no good reason.
Advance last_fn_timer.tv to the projected firing time of the
rescheduled timer so that the next callback measures roughly
one FN interval, as expected.
Change-Id: Icdb7db8abe70258ae008d9514b6608bd74bb2881
AI-Assisted: yes (Claude)
Related: OS#6794
When the BTS runs ahead of the transceiver (elapsed_fn < 0),
trx_sched_clock() reschedules the timerfd to deliberately delay the
next FN. osmo_timerfd_schedule() resets the timerfd and discards any
accumulated expirations, but last_fn_timer.tv was left pointing at
the previous callback. The next trx_fn_timer_cb() then measures
elapsed_us all the way back to that previous callback - spanning the
deliberate delay (or any OS stall that preceded us) - and falsely
trips the "PC clock skew too high" check, shutting the BTS down
for no good reason.
Advance last_fn_timer.tv to the projected firing time of the
rescheduled timer so that the next callback measures roughly
one FN interval, as expected.
Change-Id: Icdb7db8abe70258ae008d9514b6608bd74bb2881
AI-Assisted: yes (Claude)
Related: OS#6794
#1259 (Jun 23, 2026, 7:41:57 PM)
osmo-bts-trx: fix spurious shutdown on first CLCK.ind from osmo-trx
osmo-trx starts its frame counter from a random value rather than 0.
When the first CLCK.ind arrives, last_fn_timer and last_clk_ind are
still zero-initialised (set by trx_sched_clock_started()), so:
* compute_elapsed_fn(0, fn) wraps to a large negative for any fn
greater than hyperframe/2 (1357824), satisfying elapsed_fn < 0;
* compute_elapsed_us({0,0}, &tv_now) returns the full CLOCK_MONOTONIC
uptime (potentially days), satisfying the error_us threshold.
Together these trip the stale-clock shutdown introduced in the previous
commit (0199c108), even though the transceiver is perfectly healthy:
DL1C NOTICE scheduler_trx.c:490 GSM clock started, waiting for clock indications
DL1C FATAL scheduler_trx.c:589 Stale CLCK.ind: fn=1456348 is 250957770198 us behind
DOML NOTICE bts_shutdown_fsm.c:268 BTS_SHUTDOWN(bts0){NONE}: Shutting down BTS, exit 1, reason: TRX clock skew too high
Fix by adding clk_ind_received to osmo_trx_clock_state. On the first
CLCK.ind after a (re)start, skip all elapsed-time checks and directly
bootstrap the scheduler from the reported FN. The stale-clock
detection remains fully active for every subsequent indication,
where last_clk_ind holds a real baseline.
Change-Id: I25e76e02d29fd8f88130d15d0adfe8d90a017924
Fixes: 0199c108 ("osmo-bts-trx: shut down on stale clock indication from transceiver")
Related: OS#7021
osmo-trx starts its frame counter from a random value rather than 0.
When the first CLCK.ind arrives, last_fn_timer and last_clk_ind are
still zero-initialised (set by trx_sched_clock_started()), so:
* compute_elapsed_fn(0, fn) wraps to a large negative for any fn
greater than hyperframe/2 (1357824), satisfying elapsed_fn < 0;
* compute_elapsed_us({0,0}, &tv_now) returns the full CLOCK_MONOTONIC
uptime (potentially days), satisfying the error_us threshold.
Together these trip the stale-clock shutdown introduced in the previous
commit (0199c108), even though the transceiver is perfectly healthy:
DL1C NOTICE scheduler_trx.c:490 GSM clock started, waiting for clock indications
DL1C FATAL scheduler_trx.c:589 Stale CLCK.ind: fn=1456348 is 250957770198 us behind
DOML NOTICE bts_shutdown_fsm.c:268 BTS_SHUTDOWN(bts0){NONE}: Shutting down BTS, exit 1, reason: TRX clock skew too high
Fix by adding clk_ind_received to osmo_trx_clock_state. On the first
CLCK.ind after a (re)start, skip all elapsed-time checks and directly
bootstrap the scheduler from the reported FN. The stale-clock
detection remains fully active for every subsequent indication,
where last_clk_ind holds a real baseline.
Change-Id: I25e76e02d29fd8f88130d15d0adfe8d90a017924
Fixes: 0199c108 ("osmo-bts-trx: shut down on stale clock indication from transceiver")
Related: OS#7021
#1258 (Jun 20, 2026, 7:46:07 AM)
struct gsm_bts: drop unused ms_max_power
Change-Id: I0b02015db8b8e670eaff40c578f0474d9be9bb45
Change-Id: I0b02015db8b8e670eaff40c578f0474d9be9bb45
#1257 (Jun 20, 2026, 7:36:48 AM)
osmo-bts-trx: fix spurious clock skew shutdown after self-compensation
When the BTS runs ahead of the transceiver (elapsed_fn < 0),
trx_sched_clock() reschedules the timerfd to deliberately delay the
next FN. osmo_timerfd_schedule() resets the timerfd and discards any
accumulated expirations, but last_fn_timer.tv was left pointing at
the previous callback. The next trx_fn_timer_cb() then measures
elapsed_us all the way back to that previous callback - spanning the
deliberate delay (or any OS stall that preceded us) - and falsely
trips the "PC clock skew too high" check, shutting the BTS down
for no good reason.
Advance last_fn_timer.tv to the projected firing time of the
rescheduled timer so that the next callback measures roughly
one FN interval, as expected.
Change-Id: Icdb7db8abe70258ae008d9514b6608bd74bb2881
AI-Assisted: yes (Claude)
Related: OS#6794
When the BTS runs ahead of the transceiver (elapsed_fn < 0),
trx_sched_clock() reschedules the timerfd to deliberately delay the
next FN. osmo_timerfd_schedule() resets the timerfd and discards any
accumulated expirations, but last_fn_timer.tv was left pointing at
the previous callback. The next trx_fn_timer_cb() then measures
elapsed_us all the way back to that previous callback - spanning the
deliberate delay (or any OS stall that preceded us) - and falsely
trips the "PC clock skew too high" check, shutting the BTS down
for no good reason.
Advance last_fn_timer.tv to the projected firing time of the
rescheduled timer so that the next callback measures roughly
one FN interval, as expected.
Change-Id: Icdb7db8abe70258ae008d9514b6608bd74bb2881
AI-Assisted: yes (Claude)
Related: OS#6794
#1256 (Jun 20, 2026, 7:27:31 AM)
common: track whether gsm_time has been initialized
l1sap_info_time_ind() used 'bts->gsm_time.fn != 0' as a proxy for
"we have a previous frame number to diff against". This is unreliable:
Fn=0 is a _valid_ frame number, recurring on every hyperframe wrap.
If gsm_time.fn happened to be 0 and the next time indication jumped
forward by more than one frame, the real gap was silently swallowed.
It also gave no clean way to suppress the bogus "Invalid condition
detected: Frame difference is ..." message that appears when the PHY
(re)starts its TDMA frame number (e.g. from 0) on bring-up.
Introduce an explicit 'bts->gsm_time_valid' flag instead:
* l1sap_info_time_ind() treats the first indication of an epoch as
having no gap (frames_expired = 0): no warning, no RACH-slot
accounting;
* the flag is cleared in st_op_disabled_notinstalled_on_enter(), so
each BTS bring-up starts a fresh clock epoch regardless of which
FN the PHY reports first.
Change-Id: I7022b0ad084a0c224f7e8c04aca0648915b1a1c6
AI-Assisted: yes (Claude)
Related: OS#7020
l1sap_info_time_ind() used 'bts->gsm_time.fn != 0' as a proxy for
"we have a previous frame number to diff against". This is unreliable:
Fn=0 is a _valid_ frame number, recurring on every hyperframe wrap.
If gsm_time.fn happened to be 0 and the next time indication jumped
forward by more than one frame, the real gap was silently swallowed.
It also gave no clean way to suppress the bogus "Invalid condition
detected: Frame difference is ..." message that appears when the PHY
(re)starts its TDMA frame number (e.g. from 0) on bring-up.
Introduce an explicit 'bts->gsm_time_valid' flag instead:
* l1sap_info_time_ind() treats the first indication of an epoch as
having no gap (frames_expired = 0): no warning, no RACH-slot
accounting;
* the flag is cleared in st_op_disabled_notinstalled_on_enter(), so
each BTS bring-up starts a fresh clock epoch regardless of which
FN the PHY reports first.
Change-Id: I7022b0ad084a0c224f7e8c04aca0648915b1a1c6
AI-Assisted: yes (Claude)
Related: OS#7020
#1255 (Jun 20, 2026, 7:17:21 AM)
tests/meas: remove unused 'delta'
gcc 16.1.1 emits a -Wunused-but-set-variable warning.
Change-Id: I2540d701743caefb4bf54bb5b4ebe683d3257071
gcc 16.1.1 emits a -Wunused-but-set-variable warning.
Change-Id: I2540d701743caefb4bf54bb5b4ebe683d3257071
#1254 (Jun 20, 2026, 7:07:16 AM)
osmo-bts-trx: shut down on stale clock indication from transceiver
We expect the transceiver to be a reliable, monotonic clock source.
If it reports an FN far behind our local timer (elapsed_fn < 0) while
far more wall-clock time elapsed than its FN advance accounts for,
its clock has likely stalled and the indication carries a stale frame
number. Acting on it drags the scheduler backwards and re-transmits
already-sent TDMA frames, corrupting lchan-internal state(s).
Detect this and shut down the process, same rationale as the existing
"PC clock skew too high" check in trx_fn_timer_cb().
Change-Id: If787ab7ed70aa2dcb0389ceb58620c2302c3431a
AI-Assisted: yes (Claude)
Related: OS#7020, OS#6794
We expect the transceiver to be a reliable, monotonic clock source.
If it reports an FN far behind our local timer (elapsed_fn < 0) while
far more wall-clock time elapsed than its FN advance accounts for,
its clock has likely stalled and the indication carries a stale frame
number. Acting on it drags the scheduler backwards and re-transmits
already-sent TDMA frames, corrupting lchan-internal state(s).
Detect this and shut down the process, same rationale as the existing
"PC clock skew too high" check in trx_fn_timer_cb().
Change-Id: If787ab7ed70aa2dcb0389ceb58620c2302c3431a
AI-Assisted: yes (Claude)
Related: OS#7020, OS#6794
#1253 (Jun 17, 2026, 11:50:19 PM)
osmo-bts-trx: shut down on stale clock indication from transceiver
We expect the transceiver to be a reliable, monotonic clock source.
If it reports an FN far behind our local timer (elapsed_fn < 0) while
far more wall-clock time elapsed than its FN advance accounts for,
its clock has likely stalled and the indication carries a stale frame
number. Acting on it drags the scheduler backwards and re-transmits
already-sent TDMA frames, corrupting lchan-internal state(s).
Detect this and shut down the process, same rationale as the existing
"PC clock skew too high" check in trx_fn_timer_cb().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: If787ab7ed70aa2dcb0389ceb58620c2302c3431a
Related: OS#7020, OS#6794
We expect the transceiver to be a reliable, monotonic clock source.
If it reports an FN far behind our local timer (elapsed_fn < 0) while
far more wall-clock time elapsed than its FN advance accounts for,
its clock has likely stalled and the indication carries a stale frame
number. Acting on it drags the scheduler backwards and re-transmits
already-sent TDMA frames, corrupting lchan-internal state(s).
Detect this and shut down the process, same rationale as the existing
"PC clock skew too high" check in trx_fn_timer_cb().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: If787ab7ed70aa2dcb0389ceb58620c2302c3431a
Related: OS#7020, OS#6794
#1252 (Jun 17, 2026, 10:28:23 PM)
osmo-bts-trx: reset BTS GSM time on clock (re)start
trx_sched_clock_started() is called when the transceiver is powered
on, e.g. after an A-bis link re-establishment, which in ttcn3-bts-test
happens once per testcase. The transceiver restarts its TDMA frame
number from ~0, but we only reset the per-TRX clock state (tcs),
leaving bts->gsm_time.fn at the previous epoch's value.
As a result the first (low) FN reported by the transceiver is mistaken
for a huge backwards jump, e.g.:
l1sap.c:628 Invalid condition detected: Frame difference is 102-10386=2705364 > 1!
Reset bts->gsm_time to FN 0 here so each clock epoch starts clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: Id8da126e460d3846a3be5bdb271553457fdd0590
trx_sched_clock_started() is called when the transceiver is powered
on, e.g. after an A-bis link re-establishment, which in ttcn3-bts-test
happens once per testcase. The transceiver restarts its TDMA frame
number from ~0, but we only reset the per-TRX clock state (tcs),
leaving bts->gsm_time.fn at the previous epoch's value.
As a result the first (low) FN reported by the transceiver is mistaken
for a huge backwards jump, e.g.:
l1sap.c:628 Invalid condition detected: Frame difference is 102-10386=2705364 > 1!
Reset bts->gsm_time to FN 0 here so each clock epoch starts clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: Id8da126e460d3846a3be5bdb271553457fdd0590