WCN3620 only registers a 2.4 GHz band, but its firmware can report scan results with rf_band values that select the 5 GHz channel mapping. The resulting receive status references an unsupported band. On a WCN3620 tablet, this caused a NULL dereference in the survey update called by wcn36xx_rx_skb(), with a reported frequency of 5280 MHz. Only use the 5 GHz mapping when that band is registered. Otherwise interpret the descriptor's channel as a 2.4 GHz channel. Reject scan frequencies absent from the registered channel tables before updating survey data or delivering the frame to mac80211. Ordinary receive and valid dual-band scan mappings are unchanged. This follows Stephan Gerhold's WCN3620 workaround in the msm8916 integration tree, using registered band support instead of a radio-ID check. AI tools assisted with crash analysis, adaptation of the workaround, testing and preparation and review of this submission. Link: https://github.com/msm8916-mainline/linux/commit/0be2d63a476e83c757d9caafc22eae00bcfd1df8 Fixes: 8a27ca394782 ("wcn36xx: Correct band/freq reporting on RX") Assisted-by: LLM Signed-off-by: Alexander Vernel --- The original crash was on 7.3.0-rc6-tb-x103f-mdp3-r28, based on 6c377d19d4a51 with board/display bring-up patches. The affected txrx.c matches that mainline base. Firmware reported API 1.5.1.2 and CRM 67946-1. Selected UART lines (other lines omitted): PC is at wcn36xx_rx_skb+0x160/0x74c [wcn36xx] LR is at wcn36xx_rx_skb+0x378/0x74c [wcn36xx] r3 : 00000000 r2 : c1cec260 r1 : 000014a0 r0 : ffffffc4 wcn36xx_rx_skb [wcn36xx] from wcn36xx_rx_handle_packets+0x140/0x218 [wcn36xx] wcn36xx_rx_handle_packets [wcn36xx] from wcn36xx_dxe_rx_frame+0x70/0xd0 [wcn36xx] Kernel panic - not syncing: Fatal exception in interrupt Decoding the exact module locates the fault in wcn36xx_update_survey(), inlined into wcn36xx_rx_skb(). The frequency is 0x14a0 = 5280 MHz and the supported-band pointer is NULL. The raw descriptor was not captured; neither its exact rf_band value nor the actual receive channel is known. The fallback follows the earlier workaround. Channel-table membership checks that the decoded frequency is supported, not that it is the frequency on which this particular frame was received. Tested on a Lenovo TB-X103F with WCN3620 using a mainline-based board bring-up kernel, 7.3.0-rc6-tb-x103f-mdp3-r29. The 20-minute UART capture showed no kernel alerts. Twelve normal scan requests were accepted; 4 MiB was uploaded and 48 MiB downloaded with SHA256 verification. This does not establish that the malformed descriptor occurred again. No dual-band hardware testing was performed. An extracted-function host harness passes 261 RX cases covering band and channel decoding, missing channels, ordinary RX and queue purge. The original code traps at the unsupported-band survey access. With only the band guard removed, the synthetic WCN3620 channel-6 case is dropped instead of delivered as 2437 MHz. With only the channel guard removed, invalid-frequency cases are not dropped. These are separate expectations; the mutation tests do not show that both guards are individually needed to prevent the reported panic. These tests use shims and do not simulate firmware, concurrency or full A-MSDU handling. An ARMv7 W=1 kernel/modules/DTB build completed without warnings. drivers/net/wireless/ath/wcn36xx/txrx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 882699879..c12d4a503 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -367,7 +367,9 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) */ u8 hwch = (bd->reserved0 << 4) + bd->rx_ch; - if (bd->rf_band != 1 && hwch <= sizeof(ab_rx_ch_map) && hwch >= 1) { + /* WCN3620 can report a 5 GHz band for 2.4 GHz scan results. */ + if (wcn->hw->wiphy->bands[NL80211_BAND_5GHZ] && + bd->rf_band != 1 && hwch <= sizeof(ab_rx_ch_map) && hwch >= 1) { status.band = NL80211_BAND_5GHZ; status.freq = ieee80211_channel_to_frequency(ab_rx_ch_map[hwch - 1], status.band); @@ -375,6 +377,9 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) status.band = NL80211_BAND_2GHZ; status.freq = ieee80211_channel_to_frequency(hwch, status.band); } + + if (!ieee80211_get_channel(wcn->hw->wiphy, status.freq)) + goto drop; } else { status.band = WCN36XX_BAND(wcn); status.freq = WCN36XX_CENTER_FREQ(wcn);