lchan_fsm: don't mark lchan as BORKEN on unsupported mode NACK
When the BTS NACKs a Channel Activation with RSL_ERR_SERV_OPT_UNAVAIL or RSL_ERR_SERV_OPT_UNIMPL, it means the requested service or channel mode is not supported - not that the hardware is broken. In this case the lchan should transition to LCHAN_ST_WAIT_AFTER_ERROR rather than LCHAN_ST_BORKEN, which is reserved for genuine hardware failures.
Also add LCHAN_EV_RTP_ERROR to LCHAN_ST_WAIT_AFTER_ERROR's in_event_mask so that a late LCHAN_EV_RTP_ERROR (e.g. MGCP CRCX timeout arriving after the NACK was already handled) is silently absorbed rather than triggering an unexpected-event warning.
assignment_fsm: pass lchan to lchan_type_compat_with_mode()
The lchan pointer is needed by the next patch, which will check the BTS ipaccess supported-features flags to reject channel modes that the BTS has reported as unsupported before attempting to activate the lchan.
ipaccess: fix buffer overread in ipacc_parse_supp_flags()
The loop used OSMO_MAX(e->len, 4), which iterates at least 4 times even when the IE is shorter than 4 bytes, causing a buffer overread. Replace with OSMO_MIN(e->len, sizeof(u32)) to cap the iteration both at the actual IE length and at the uint32_t accumulator size.
assignment_fsm: check ipaccess channel mode support
Add ipacc_chan_mode_supported(), which checks the NM_IPAC_F_CHANM_* flags stored in the Baseband Transceiver's MO state (populated during OML bring-up) to decide whether the BTS can handle a requested channel mode. If the IE containing supported channel modes was never received, the function returns true as if the given mode was supported.
Without this change, requesting a channel mode not supported by the BTS results in a NACK to the RSL Channel Activation, which causes the lchan to be marked as BROKEN and thus unavailable.
The lchan_rtp_fsm is a child FSM that manages the MGW/RTP endpoint. When the parent lchan_fsm transitions away before the child has finished its work (e.g. a CRCX timeout or a DLCX completing after the lchan is already idle), the child can still deliver LCHAN_EV_RTP_RELEASED or LCHAN_EV_RTP_ERROR to the parent.
Currently these late events are not in the in_event_mask of every state that can be reached with the child still running:
* LCHAN_ST_UNUSED: entered from WAIT_AFTER_ERROR after the error timer fires, while a DLCX triggered at error time may still be in flight. * LCHAN_ST_WAIT_AFTER_ERROR: already handles LCHAN_EV_RTP_RELEASED but misses LCHAN_EV_RTP_ERROR (e.g. CRCX timeout arriving after the NACK was handled).
Add the missing events to both states' in_event_mask and provide a no-op handler in lchan_fsm_unused() so that the assert is not hit.
handover_fsm: fix send_handover_performed() using wrong lchan
send_handover_performed() is called from handover_end() before gscon_change_primary_lchan() updates conn->lchan to the new lchan. As a result, the Cell Identifier, Chosen Channel, Chosen Encryption Algorithm, and Speech Version/Codec IEs were all populated from the source (old) lchan rather than the target (new) lchan.
As per 3GPP TS 48.008 §3.2.1.25, HANDOVER PERFORMED must report the target cell and channel. For intra-BSC handover to a different BTS this caused the MSC to receive the wrong Cell Identifier.
Fix by initialising lchan from ho->new_lchan instead of conn->lchan, and deriving the BTS via lchan->ts->trx->bts.
Change-Id: I4111351dc38fc2dbe844c2bd07b3ecfaaadd864e Related: osmo-ttcn3-hacks.git I82aadcc3a80c183cb93522b829071294b156a218 Found-By: Claude Sonnet 4.6