Commit b7064676 authored by Rakesh Pillai's avatar Rakesh Pillai Committed by Wang Liang
Browse files

ath10k: Remove msdu from idr when management pkt send fails

stable inclusion
from stable-v4.19.129
commit 2bc8b1816cf4908ae0a04c3e87e167d2dcb60f38
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IB37AQ
CVE: CVE-2024-50236

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=2bc8b1816cf4908ae0a04c3e87e167d2dcb60f38



--------------------------------

[ Upstream commit c730c477 ]

Currently when the sending of any management pkt
via wmi command fails, the packet is being unmapped
freed in the error handling. But the idr entry added,
which is used to track these packet is not getting removed.

Hence, during unload, in wmi cleanup, all the entries
in IDR are removed and the corresponding buffer is
attempted to be freed. This can cause a situation where
one packet is attempted to be freed twice.

Fix this error by rmeoving the msdu from the idr
list when the sending of a management packet over
wmi fails.

Tested HW: WCN3990
Tested FW: WLAN.HL.3.1-01040-QCAHLSWMTPLZ-1

Fixes: 1807da49 ("ath10k: wmi: add management tx by reference support over wmi")
Signed-off-by: default avatarRakesh Pillai <pillair@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1588667015-25490-1-git-send-email-pillair@codeaurora.org


Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarWang Liang <wangliang74@huawei.com>
parent b5504db0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -3852,6 +3852,9 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
			if (ret) {
				ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n",
					    ret);
				/* remove this msdu from idr tracking */
				ath10k_wmi_cleanup_mgmt_tx_send(ar, skb);

				dma_unmap_single(ar->dev, paddr, skb->len,
						 DMA_FROM_DEVICE);
				ieee80211_free_txskb(ar->hw, skb);
+10 −0
Original line number Diff line number Diff line
@@ -139,6 +139,7 @@ struct wmi_ops {
	struct sk_buff *(*gen_mgmt_tx_send)(struct ath10k *ar,
					    struct sk_buff *skb,
					    dma_addr_t paddr);
	int (*cleanup_mgmt_tx_send)(struct ath10k *ar, struct sk_buff *msdu);
	struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u64 module_enable,
					  u32 log_level);
	struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter);
@@ -431,6 +432,15 @@ ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar)
	return ar->wmi.ops->get_txbf_conf_scheme(ar);
}

static inline int
ath10k_wmi_cleanup_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu)
{
	if (!ar->wmi.ops->cleanup_mgmt_tx_send)
		return -EOPNOTSUPP;

	return ar->wmi.ops->cleanup_mgmt_tx_send(ar, msdu);
}

static inline int
ath10k_wmi_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
			dma_addr_t paddr)
+15 −0
Original line number Diff line number Diff line
@@ -2642,6 +2642,18 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
	return skb;
}

static int
ath10k_wmi_tlv_op_cleanup_mgmt_tx_send(struct ath10k *ar,
				       struct sk_buff *msdu)
{
	struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
	struct ath10k_wmi *wmi = &ar->wmi;

	idr_remove(&wmi->mgmt_pending_tx, cb->msdu_id);

	return 0;
}

static int
ath10k_wmi_mgmt_tx_alloc_msdu_id(struct ath10k *ar, struct sk_buff *skb,
				 dma_addr_t paddr)
@@ -2714,6 +2726,8 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
	if (desc_id < 0)
		goto err_free_skb;

	cb->msdu_id = desc_id;

	ptr = (void *)skb->data;
	tlv = ptr;
	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_MGMT_TX_CMD);
@@ -3953,6 +3967,7 @@ static const struct wmi_ops wmi_tlv_ops = {
	.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
	/* .gen_mgmt_tx = not implemented; HTT is used */
	.gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send,
	.cleanup_mgmt_tx_send = ath10k_wmi_tlv_op_cleanup_mgmt_tx_send,
	.gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
	.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
	.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,