wifi: ath12k: Ignore fragments from uninitialized peer in dp
authorHarshitha Prem <quic_hprem@quicinc.com>
Sat, 26 Aug 2023 05:42:43 +0000 (08:42 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Nov 2023 17:19:36 +0000 (17:19 +0000)
[ Upstream commit bbc86757ca62423c3b6bd8f7176da1ff43450769 ]

When max virtual ap interfaces are configured in all the bands with
ACS and hostapd restart is done every 60s, a crash is observed at
random times.

In the above scenario, a fragmented packet is received for self peer,
for which rx_tid and rx_frags are not initialized in datapath.
While handling this fragment, crash is observed as the rx_frag list
is uninitialized and when we walk in ath12k_dp_rx_h_sort_frags,
skb null leads to exception.

To address this, before processing received fragments we check
dp_setup_done flag is set to ensure that peer has completed its
dp peer setup for fragment queue, else ignore processing the
fragments.

Call trace:
    PC points to "ath12k_dp_process_rx_err+0x4e8/0xfcc [ath12k]"
    LR points to "ath12k_dp_process_rx_err+0x480/0xfcc [ath12k]".
    The Backtrace obtained is as follows:
    ath12k_dp_process_rx_err+0x4e8/0xfcc [ath12k]
    ath12k_dp_service_srng+0x78/0x260 [ath12k]
    ath12k_pci_write32+0x990/0xb0c [ath12k]
    __napi_poll+0x30/0xa4
    net_rx_action+0x118/0x270
    __do_softirq+0x10c/0x244
    irq_exit+0x64/0xb4
    __handle_domain_irq+0x88/0xac
    gic_handle_irq+0x74/0xbc
    el1_irq+0xf0/0x1c0
    arch_cpu_idle+0x10/0x18
    do_idle+0x104/0x248
    cpu_startup_entry+0x20/0x64
    rest_init+0xd0/0xdc
    arch_call_rest_init+0xc/0x14

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20230821130343.29495-2-quic_hprem@quicinc.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/wireless/ath/ath12k/dp.c
drivers/net/wireless/ath/ath12k/dp_rx.c
drivers/net/wireless/ath/ath12k/peer.h

index f933896..6893466 100644 (file)
@@ -38,6 +38,7 @@ void ath12k_dp_peer_cleanup(struct ath12k *ar, int vdev_id, const u8 *addr)
 
        ath12k_dp_rx_peer_tid_cleanup(ar, peer);
        crypto_free_shash(peer->tfm_mmic);
+       peer->dp_setup_done = false;
        spin_unlock_bh(&ab->base_lock);
 }
 
index 17da39b..690a010 100644 (file)
@@ -2748,6 +2748,7 @@ int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev
        }
 
        peer->tfm_mmic = tfm;
+       peer->dp_setup_done = true;
        spin_unlock_bh(&ab->base_lock);
 
        return 0;
@@ -3214,6 +3215,14 @@ static int ath12k_dp_rx_frag_h_mpdu(struct ath12k *ar,
                ret = -ENOENT;
                goto out_unlock;
        }
+
+       if (!peer->dp_setup_done) {
+               ath12k_warn(ab, "The peer %pM [%d] has uninitialized datapath\n",
+                           peer->addr, peer_id);
+               ret = -ENOENT;
+               goto out_unlock;
+       }
+
        rx_tid = &peer->rx_tid[tid];
 
        if ((!skb_queue_empty(&rx_tid->rx_frags) && seqno != rx_tid->cur_sn) ||
index b296dc0..c6edb24 100644 (file)
@@ -44,6 +44,9 @@ struct ath12k_peer {
        struct ppdu_user_delayba ppdu_stats_delayba;
        bool delayba_flag;
        bool is_authorized;
+
+       /* protected by ab->data_lock */
+       bool dp_setup_done;
 };
 
 void ath12k_peer_unmap_event(struct ath12k_base *ab, u16 peer_id);