mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-20 10:51:27 +00:00
299 lines
9.4 KiB
Diff
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,
|