wlan-ap-Telecominfraproject/feeds/ipq95xx/mac80211/patches/qca/762-ath12k-Fix-memory-leak-during-peer-frag-setup.patch
John Crispin 144c5d00f4 ipq95xx/mac80211: update to ATH12.3-CS
Signed-off-by: John Crispin <john@phrozen.org>
2024-02-28 18:56:21 +01:00

299 lines
9.4 KiB
Diff

From 7ff6bbe962cbf2ff69e834e73d8a451dc7546729 Mon Sep 17 00:00:00 2001
From: P Praneesh <quic_ppranees@quicinc.com>
Date: Thu, 6 Apr 2023 22:01:21 +0530
Subject: [PATCH] ath12k: Fix memory leak during peer frag setup
For 2-link MLO, peer frag setup is expected to set for primary link alone.
So, for the non primary link, crypto_alloc_shash allocates memory through
kmalloc which is not getting released before returning from the function.
Similarly, if peer find fails, needs to handle the memory allocated through
crypto_alloc_shash should be released.
Fix it by moving the peer find logic out of ath12k_dp_rx_peer_frag_setup.
So that it can be called only for the primary link. Also it avoids
unnecessary peer look up and crypto allocation.
Fixes: Id27da363fd12 (ath12k: Fixes for Multi link bringup and handling)
Signed-off-by: P Praneesh <quic_ppranees@quicinc.com>
---
drivers/net/wireless/ath/ath12k/dp.c | 34 ++++++++-------
drivers/net/wireless/ath/ath12k/dp_rx.c | 55 +++++++++----------------
drivers/net/wireless/ath/ath12k/dp_rx.h | 5 ++-
3 files changed, 42 insertions(+), 52 deletions(-)
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -93,44 +93,53 @@ int ath12k_dp_peer_setup(struct ath12k *
{
struct ath12k_base *ab = ar->ab;
struct ath12k_peer *peer;
+ struct crypto_shash *tfm;
int ret = 0, tid;
- /* TODO setup resources only for primary link peer for ML case */
+ tfm = crypto_alloc_shash("michael_mic", 0, 0);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ spin_lock_bh(&ab->base_lock);
+ peer = ath12k_peer_find(ab, arvif->vdev_id, arsta->addr);
+ if (!peer) {
+ ath12k_warn(ab, "failed to lookup peer %pM on vdev %d\n",
+ arsta->addr, arvif->vdev_id);
+ ret = -ENOENT;
+ goto free_shash;
+ }
+
+ if (!peer->primary_link) {
+ ret = 0;
+ goto free_shash;
+ }
for (tid = 0; tid <= IEEE80211_NUM_TIDS; tid++) {
- ret = ath12k_dp_rx_peer_tid_setup(ar, arsta->addr, arvif->vdev_id,
- tid, 1, 0, HAL_PN_TYPE_NONE);
+ ret = ath12k_dp_rx_peer_tid_setup(ar, tid, 1, 0, HAL_PN_TYPE_NONE, peer);
if (ret) {
ath12k_warn(ab, "failed to setup rxd tid queue for tid %d: %d\n",
tid, ret);
- goto peer_clean;
+ goto peer_tid_clean;
}
}
- ret = ath12k_dp_rx_peer_frag_setup(ar, arsta->addr, arvif->vdev_id);
+ ret = ath12k_dp_rx_peer_frag_setup(ar, peer, tfm);
if (ret) {
ath12k_warn(ab, "failed to setup rx defrag context\n");
- tid--;
- goto peer_clean;
+ goto peer_tid_clean;
}
+ spin_unlock_bh(&ab->base_lock);
/* TODO: Setup other peer specific resource used in data path */
return 0;
-peer_clean:
- spin_lock_bh(&ab->base_lock);
-
- peer = ath12k_peer_find(ab, arvif->vdev_id, arsta->addr);
- if (!peer) {
- ath12k_warn(ab, "failed to find the peer to del rx tid\n");
- spin_unlock_bh(&ab->base_lock);
- return -ENOENT;
- }
-
- for (; tid >= 0; tid--)
+peer_tid_clean:
+ for (tid--; tid >= 0; tid--)
ath12k_dp_rx_peer_tid_delete(ar, peer, tid);
+free_shash:
+ crypto_free_shash(tfm);
spin_unlock_bh(&ab->base_lock);
return ret;
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -1075,13 +1075,11 @@ static int ath12k_peer_rx_tid_reo_update
return 0;
}
-int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id,
- u8 tid, u32 ba_win_sz, u16 ssn,
- enum hal_pn_type pn_type)
+int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, u8 tid, u32 ba_win_sz, u16 ssn,
+ enum hal_pn_type pn_type, struct ath12k_peer *peer)
{
struct ath12k_base *ab = ar->ab;
struct ath12k_dp *dp = &ab->dp;
- struct ath12k_peer *peer;
struct ath12k_dp_rx_tid *rx_tid;
u32 hw_desc_sz;
u32 *addr_aligned;
@@ -1089,22 +1087,7 @@ int ath12k_dp_rx_peer_tid_setup(struct a
dma_addr_t paddr;
int ret;
- spin_lock_bh(&ab->base_lock);
-
- peer = ath12k_peer_find(ab, vdev_id, peer_mac);
- if (!peer) {
- spin_unlock_bh(&ab->base_lock);
- ath12k_warn(ab, "failed to find the peer to set up rx tid\n");
- return -ENOENT;
- }
-
- if (!peer->primary_link) {
- spin_unlock_bh(&ab->base_lock);
- return 0;
- }
-
if (ab->hw_params->reoq_lut_support && (!dp->reoq_lut.vaddr || !dp->ml_reoq_lut.vaddr)) {
- spin_unlock_bh(&ab->base_lock);
ath12k_warn(ab, "reo qref table is not setup\n");
return -EINVAL;
}
@@ -1112,7 +1095,6 @@ int ath12k_dp_rx_peer_tid_setup(struct a
if (peer->peer_id > DP_MAX_PEER_ID || tid > IEEE80211_NUM_TIDS) {
ath12k_warn(ab, "peer id of peer %d or tid %d doesn't allow reoq setup\n",
peer->peer_id, tid);
- spin_unlock_bh(&ab->base_lock);
return -EINVAL;
}
@@ -1122,10 +1104,9 @@ int ath12k_dp_rx_peer_tid_setup(struct a
paddr = rx_tid->paddr;
ret = ath12k_peer_rx_tid_reo_update(ar, peer, rx_tid,
ba_win_sz, ssn, true);
- spin_unlock_bh(&ab->base_lock);
if (ret) {
ath12k_warn(ab, "failed to update reo for peer %pM rx tid %d\n",
- peer_mac, tid);
+ peer->addr, tid);
return ret;
}
@@ -1146,7 +1127,6 @@ int ath12k_dp_rx_peer_tid_setup(struct a
vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_ATOMIC);
if (!vaddr) {
- spin_unlock_bh(&ab->base_lock);
return -ENOMEM;
}
@@ -1160,9 +1140,8 @@ int ath12k_dp_rx_peer_tid_setup(struct a
ret = dma_mapping_error(ab->dev, paddr);
if (ret) {
- spin_unlock_bh(&ab->base_lock);
ath12k_warn(ab, "failed to dma map for peer %pM rx tid :%d setup\n",
- peer_mac, tid);
+ peer->addr, tid);
goto err_mem_free;
}
@@ -1179,11 +1158,11 @@ int ath12k_dp_rx_peer_tid_setup(struct a
ath12k_peer_rx_tid_qref_setup(ab, peer->ml_peer_id, tid, paddr);
else
ath12k_peer_rx_tid_qref_setup(ab, peer->peer_id, tid, paddr);
- spin_unlock_bh(&ab->base_lock);
} else {
spin_unlock_bh(&ab->base_lock);
- ret = ath12k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac,
+ ret = ath12k_wmi_peer_rx_reorder_queue_setup(ar, peer->vdev_id, peer->addr,
paddr, tid, 1, ba_win_sz);
+ spin_lock_bh(&ab->base_lock);
}
return ret;
@@ -1201,6 +1180,7 @@ int ath12k_dp_rx_ampdu_start(struct ath1
struct ath12k_base *ab = ar->ab;
struct ath12k_sta *ahsta = (void *)params->sta->drv_priv;
struct ath12k_link_sta *arsta;
+ struct ath12k_peer *peer;
int vdev_id;
int ret;
@@ -1211,12 +1191,26 @@ int ath12k_dp_rx_ampdu_start(struct ath1
vdev_id = arsta->arvif->vdev_id;
- ret = ath12k_dp_rx_peer_tid_setup(ar, arsta->addr, vdev_id,
- params->tid, params->buf_size,
- params->ssn, ahsta->pn_type);
+ spin_lock_bh(&ab->base_lock);
+ peer = ath12k_peer_find(ab, vdev_id, arsta->addr);
+ if (!peer) {
+ ath12k_warn(ab, "failed to lookup peer %pM on vdev %d\n",
+ arsta->addr, vdev_id);
+ spin_unlock_bh(&ab->base_lock);
+ return -ENOENT;
+ }
+
+ if (!peer->primary_link) {
+ spin_unlock_bh(&ab->base_lock);
+ return 0;
+ }
+
+ ret = ath12k_dp_rx_peer_tid_setup(ar, params->tid, params->buf_size,
+ params->ssn, ahsta->pn_type, peer);
if (ret)
ath12k_warn(ab, "failed to setup rx tid %d\n", ret);
+ spin_unlock_bh(&ab->base_lock);
return ret;
}
@@ -3519,32 +3513,13 @@ static void ath12k_dp_rx_frag_timer(stru
spin_unlock_bh(&rx_tid->ab->base_lock);
}
-int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id)
+int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, struct ath12k_peer *peer,
+ struct crypto_shash *tfm)
{
struct ath12k_base *ab = ar->ab;
- struct crypto_shash *tfm;
- struct ath12k_peer *peer;
struct ath12k_dp_rx_tid *rx_tid;
int i;
- tfm = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(tfm))
- return PTR_ERR(tfm);
-
- spin_lock_bh(&ab->base_lock);
-
- peer = ath12k_peer_find(ab, vdev_id, peer_mac);
- if (!peer) {
- ath12k_warn(ab, "failed to find the peer to set up fragment info\n");
- spin_unlock_bh(&ab->base_lock);
- return -ENOENT;
- }
-
- if (!peer->primary_link) {
- spin_unlock_bh(&ab->base_lock);
- return 0;
- }
-
for (i = 0; i <= IEEE80211_NUM_TIDS; i++) {
rx_tid = &peer->rx_tid[i];
rx_tid->ab = ab;
@@ -3554,7 +3529,6 @@ int ath12k_dp_rx_peer_frag_setup(struct
peer->tfm_mmic = tfm;
peer->dp_setup_done = true;
- spin_unlock_bh(&ab->base_lock);
return 0;
}
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -135,9 +135,8 @@ int ath12k_dp_rx_peer_pn_replay_config(s
void ath12k_dp_rx_peer_tid_cleanup(struct ath12k *ar, struct ath12k_peer *peer);
void ath12k_dp_rx_peer_tid_delete(struct ath12k *ar,
struct ath12k_peer *peer, u8 tid);
-int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id,
- u8 tid, u32 ba_win_sz, u16 ssn,
- enum hal_pn_type pn_type);
+int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, u8 tid, u32 ba_win_sz, u16 ssn,
+ enum hal_pn_type pn_type, struct ath12k_peer *peer);
void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab,
struct sk_buff *skb);
int ath12k_dp_rx_pdev_reo_setup(struct ath12k_base *ab);
@@ -167,8 +166,8 @@ int ath12k_dp_htt_tlv_iter(struct ath12k
void *data);
int ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar);
void ath12k_dp_rx_pdev_mon_detach(struct ath12k_base *ab, const int pdev_idx);
-int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id);
-
+int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, struct ath12k_peer *peer,
+ struct crypto_shash *tfm);
int ath12k_dp_rx_pktlog_start(struct ath12k_base *ab);
int ath12k_dp_rx_pktlog_stop(struct ath12k_base *ab, bool stop_timer);
u8 ath12k_dp_rx_h_l3pad(struct ath12k_base *ab,