1
0

0060-wifi-ath11k-Ignore-frags-from-uninitialized-peer-in-.patch 3.4 KB

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