wifi: ath11k: Ignore frags from uninitialized peer in dp.
authorHarshitha Prem <quic_hprem@quicinc.com>
Mon, 3 Apr 2023 18:41:54 +0000 (00:11 +0530)
committerKalle Valo <quic_kvalo@quicinc.com>
Mon, 17 Apr 2023 10:28:30 +0000 (13:28 +0300)
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 this certain 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 uninitialised and when we walk in
ath11k_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:
  ath11k_dp_process_rx_err+0x550/0x1084 [ath11k]
  ath11k_dp_service_srng+0x70/0x370 [ath11k]
  0xffffffc009693a04
  __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
  start_kernel+0x480/0x4b8
  Code: f9400281 f94066a2 91405021 b94a0023 (f9406401)

Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1

Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
Signed-off-by: Nagarajan Maran <quic_nmaran@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20230403184155.8670-2-quic_nmaran@quicinc.com
drivers/net/wireless/ath/ath11k/dp.c
drivers/net/wireless/ath/ath11k/dp_rx.c
drivers/net/wireless/ath/ath11k/peer.h

index f5156a7..d070bcb 100644 (file)
@@ -36,6 +36,7 @@ void ath11k_dp_peer_cleanup(struct ath11k *ar, int vdev_id, const u8 *addr)
        }
 
        ath11k_peer_rx_tid_cleanup(ar, peer);
+       peer->dp_setup_done = false;
        crypto_free_shash(peer->tfm_mmic);
        spin_unlock_bh(&ab->base_lock);
 }
@@ -72,7 +73,8 @@ int ath11k_dp_peer_setup(struct ath11k *ar, int vdev_id, const u8 *addr)
        ret = ath11k_peer_rx_frag_setup(ar, addr, vdev_id);
        if (ret) {
                ath11k_warn(ab, "failed to setup rx defrag context\n");
-               return ret;
+               tid--;
+               goto peer_clean;
        }
 
        /* TODO: Setup other peer specific resource used in data path */
index d22e534..ab6b18d 100644 (file)
@@ -3130,6 +3130,7 @@ int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id
        }
 
        peer->tfm_mmic = tfm;
+       peer->dp_setup_done = true;
        spin_unlock_bh(&ab->base_lock);
 
        return 0;
@@ -3575,6 +3576,13 @@ static int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar,
                ret = -ENOENT;
                goto out_unlock;
        }
+       if (!peer->dp_setup_done) {
+               ath11k_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 6dd17ba..9bd385d 100644 (file)
@@ -35,6 +35,7 @@ struct ath11k_peer {
        u16 sec_type;
        u16 sec_type_grp;
        bool is_authorized;
+       bool dp_setup_done;
 };
 
 void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id);