bts_shutdown_fsm: fix spurious RAMP_COMPL events in WAIT_TRX_CLOSED
With multiple TRXes ramping down in lockstep, both their final ramp-timer callbacks fire back-to-back in the same event loop pass, setting p_total_cur_mdBm to the target value for both before any async hardware acknowledgement arrives. When the first SETPOWER ack returns and fires ramp_down_compl_cb() for TRX0, the remaining-TRX check in st_wait_ramp_down_compl() inspects p_total_cur_mdBm for TRX1 and finds it already at the target - concluding that all TRXes are done. The FSM then transitions to WAIT_TRX_CLOSED, and the second ack (for TRX1) fires ramp_down_compl_cb() into the wrong state, producing:
BTS_SHUTDOWN(...){WAIT_TRX_CLOSED}: Event BTS_SHUTDOWN_EV_TRX_RAMP_COMPL not permitted
The root cause is that p_total_cur_mdBm is a *requested* value set in the timer callback, not a confirmed one. The hardware confirmation arrives asynchronously via power_trx_change_compl() -> power_ramp_do_step(), which is also where compl_cb() is invoked.
Fix by adding a 'complete' flag to trx_power_params.ramp that is:
* cleared when _power_ramp_start() begins a new ramp, and * set just before compl_cb() is called in power_ramp_do_step()
The shutdown FSM remaining-TRX count then checks !ramp.complete instead of comparing p_total_cur_mdBm against the target, correctly reflecting which TRXes have actually received hardware confirmation of ramp completion.
Condition `synch_seq != RACH_SYNCH_SEQ_TS0` is unlikely to be true, given that no other synch. sequences are defined by 3GPP TS 45.002. Even if this happens for whatever reason (e.g. a bug), assigning `synch_seq` to `RACH_SYNCH_SEQ_TS0` is not needed, as `synch_seq` is never read after the switch statement. The logging message is not useful either, since we already print the synch. seq. above.
osmo-bts-trx: check sscanf() result in NOMTXPOWER/SETPOWER handlers
Both trx_ctrl_rx_rsp_nomtxpower() and trx_ctrl_rx_rsp_setpower() were calling sscanf() without checking its return value. On a parse failure the local variable remained uninitialized and was passed directly to the callback, resulting in a garbage power level.
The function accesses msg->data[0..4] without first verifying that the message is at least 5 bytes long, which would cause a buffer over-read on a malformed (too short) LAPDm frame.
The function is declared `bool` but returns `-EINVAL` on an error path. `-EINVAL` is `-22`, which in C implicitly converts to `bool true`. Returning `false` makes more sense when we don't know the MF layout.
osmo-bts-trx: check sscanf() result in NOMTXPOWER/SETPOWER handlers
Both trx_ctrl_rx_rsp_nomtxpower() and trx_ctrl_rx_rsp_setpower() were calling sscanf() without checking its return value. On a parse failure the local variable remained uninitialized and was passed directly to the callback, resulting in a garbage power level.
measurement: is_meas_complete(): fix fn_mod variable type
`fn_mod` was declared as 'unsigned int' but initialized to -1, which yields `UINT_MAX` via implicit conversion. Use 'int' instead to make the sentinel value unambiguous and match the `%d` format used in the debug log.
tx_power: get_pa_drive_level_mdBm(): assert on out-of-range ARFCN
The function previously returned `INT_MIN` as an error sentinel when the ARFCN exceeded the calibration table size (1024 entries, covering all valid GSM ARFCNs 0..1023). None of the callers checked for this value, so it would silently propagate through power calculations and eventually be passed to `bts_model_change_power()`.
An out-of-range ARFCN indicates a serious misconfiguration; replace the range check and `return INT_MIN` with an `OSMO_ASSERT`.
Both functions were writing into the same static buffer, so any caller holding a pointer returned by one and then invoking the other would silently end up with a stale/overwritten string. Move name_buf into each function as a local static, so the two buffers are independent.