5bbf9e04a4db7fd75577934ad38fac6627b50596
[librecmc/librecmc.git] /
1 From a06bfb3c9f69f303692cdae87bc0899d2ae8b2a6 Mon Sep 17 00:00:00 2001
2 From: Harshitha Prem <quic_hprem@quicinc.com>
3 Date: Tue, 4 Apr 2023 00:11:54 +0530
4 Subject: [PATCH] wifi: ath11k: Ignore frags from uninitialized peer in dp.
5
6 When max virtual ap interfaces are configured in all the bands with
7 ACS and hostapd restart is done every 60s, a crash is observed at
8 random times.
9 In this certain scenario, a fragmented packet is received for
10 self peer, for which rx_tid and rx_frags are not initialized in
11 datapath. While handling this fragment, crash is observed as the
12 rx_frag list is uninitialised and when we walk in
13 ath11k_dp_rx_h_sort_frags, skb null leads to exception.
14
15 To address this, before processing received fragments we check
16 dp_setup_done flag is set to ensure that peer has completed its
17 dp peer setup for fragment queue, else ignore processing the
18 fragments.
19
20 Call trace:
21   ath11k_dp_process_rx_err+0x550/0x1084 [ath11k]
22   ath11k_dp_service_srng+0x70/0x370 [ath11k]
23   0xffffffc009693a04
24   __napi_poll+0x30/0xa4
25   net_rx_action+0x118/0x270
26   __do_softirq+0x10c/0x244
27   irq_exit+0x64/0xb4
28   __handle_domain_irq+0x88/0xac
29   gic_handle_irq+0x74/0xbc
30   el1_irq+0xf0/0x1c0
31   arch_cpu_idle+0x10/0x18
32   do_idle+0x104/0x248
33   cpu_startup_entry+0x20/0x64
34   rest_init+0xd0/0xdc
35   arch_call_rest_init+0xc/0x14
36   start_kernel+0x480/0x4b8
37   Code: f9400281 f94066a2 91405021 b94a0023 (f9406401)
38
39 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
40
41 Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
42 Signed-off-by: Nagarajan Maran <quic_nmaran@quicinc.com>
43 Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
44 Link: https://lore.kernel.org/r/20230403184155.8670-2-quic_nmaran@quicinc.com
45 ---
46  drivers/net/wireless/ath/ath11k/dp.c    | 4 +++-
47  drivers/net/wireless/ath/ath11k/dp_rx.c | 8 ++++++++
48  drivers/net/wireless/ath/ath11k/peer.h  | 1 +
49  3 files changed, 12 insertions(+), 1 deletion(-)
50
51 --- a/drivers/net/wireless/ath/ath11k/dp.c
52 +++ b/drivers/net/wireless/ath/ath11k/dp.c
53 @@ -36,6 +36,7 @@ void ath11k_dp_peer_cleanup(struct ath11
54         }
55  
56         ath11k_peer_rx_tid_cleanup(ar, peer);
57 +       peer->dp_setup_done = false;
58         crypto_free_shash(peer->tfm_mmic);
59         spin_unlock_bh(&ab->base_lock);
60  }
61 @@ -72,7 +73,8 @@ int ath11k_dp_peer_setup(struct ath11k *
62         ret = ath11k_peer_rx_frag_setup(ar, addr, vdev_id);
63         if (ret) {
64                 ath11k_warn(ab, "failed to setup rx defrag context\n");
65 -               return ret;
66 +               tid--;
67 +               goto peer_clean;
68         }
69  
70         /* TODO: Setup other peer specific resource used in data path */
71 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c
72 +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
73 @@ -3130,6 +3130,7 @@ int ath11k_peer_rx_frag_setup(struct ath
74         }
75  
76         peer->tfm_mmic = tfm;
77 +       peer->dp_setup_done = true;
78         spin_unlock_bh(&ab->base_lock);
79  
80         return 0;
81 @@ -3575,6 +3576,13 @@ static int ath11k_dp_rx_frag_h_mpdu(stru
82                 ret = -ENOENT;
83                 goto out_unlock;
84         }
85 +       if (!peer->dp_setup_done) {
86 +               ath11k_warn(ab, "The peer %pM [%d] has uninitialized datapath\n",
87 +                           peer->addr, peer_id);
88 +               ret = -ENOENT;
89 +               goto out_unlock;
90 +       }
91 +
92         rx_tid = &peer->rx_tid[tid];
93  
94         if ((!skb_queue_empty(&rx_tid->rx_frags) && seqno != rx_tid->cur_sn) ||
95 --- a/drivers/net/wireless/ath/ath11k/peer.h
96 +++ b/drivers/net/wireless/ath/ath11k/peer.h
97 @@ -35,6 +35,7 @@ struct ath11k_peer {
98         u16 sec_type;
99         u16 sec_type_grp;
100         bool is_authorized;
101 +       bool dp_setup_done;
102  };
103  
104  void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id);