From 3d445af13641dced4a555b7ef60e4d5b7fba8aa1 Mon Sep 17 00:00:00 2001 From: Karthik M Date: Thu, 9 Jun 2022 16:44:12 +0530 Subject: [PATCH] ath12k: Avoid NULL ptr access during mgmt tx cleanup Currently 'ar' reference is not added in skb_cb during WMI mgmt tx. Though this is generally not used during tx completion callbacks, on interface removal the remaining idr cleanup callback uses the ar ptr from skb_cb from mgmt txmgmt_idr. Hence fill them during tx call for proper usage. Also free the skb which is missing currently in these callbacks. Crash_info: [19282.489476] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [19282.489515] pgd = 91eb8000 [19282.496702] [00000000] *pgd=00000000 [19282.502524] Internal error: Oops: 5 [#1] PREEMPT SMP ARM [19282.783728] PC is at ath12k_mac_vif_txmgmt_idr_remove+0x28/0xd8 [ath12k] [19282.789170] LR is at idr_for_each+0xa0/0xc8 Link: https://lore.kernel.org/r/1637832614-13831-1-git-send-email-quic_srirrama@quicinc.com Signed-off-by: Sriram R Signed-off-by: Karthik M --- drivers/net/wireless/ath/ath12k/mac.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5962,24 +5962,33 @@ static void ath12k_mgmt_over_wmi_tx_drop wake_up(&ar->txmgmt_empty_waitq); } -int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) +static void ath12k_mac_tx_mgmt_free(struct ath12k *ar, int buf_id) { - struct sk_buff *msdu = skb; + struct sk_buff *msdu; struct ieee80211_tx_info *info; - struct ath12k *ar = ctx; - struct ath12k_base *ab = ar->ab; spin_lock_bh(&ar->txmgmt_idr_lock); - idr_remove(&ar->txmgmt_idr, buf_id); + msdu = idr_remove(&ar->txmgmt_idr, buf_id); spin_unlock_bh(&ar->txmgmt_idr_lock); - dma_unmap_single(ab->dev, ATH12K_SKB_CB(msdu)->paddr, msdu->len, + + if (!msdu) + return; + + dma_unmap_single(ar->ab->dev, ATH12K_SKB_CB(msdu)->paddr, msdu->len, DMA_TO_DEVICE); info = IEEE80211_SKB_CB(msdu); memset(&info->status, 0, sizeof(info->status)); - ath12k_mgmt_over_wmi_tx_drop(ar, skb); + ath12k_mgmt_over_wmi_tx_drop(ar, msdu); +} + +int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) +{ + struct ath12k *ar = ctx; + ath12k_mac_tx_mgmt_free(ar, buf_id); + return 0; } @@ -5987,16 +5996,10 @@ static int ath12k_mac_vif_txmgmt_idr_rem { struct ieee80211_vif *vif = ctx; struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB((struct sk_buff *)skb); - struct sk_buff *msdu = skb; struct ath12k *ar = skb_cb->ar; - struct ath12k_base *ab = ar->ab; if (skb_cb->vif == vif) { - spin_lock_bh(&ar->txmgmt_idr_lock); - idr_remove(&ar->txmgmt_idr, buf_id); - spin_unlock_bh(&ar->txmgmt_idr_lock); - dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, - DMA_TO_DEVICE); + ath12k_mac_tx_mgmt_free(ar, buf_id); } return 0; @@ -6134,7 +6137,7 @@ static int ath12k_mac_mgmt_tx(struct ath skb_queue_tail(q, skb); atomic_inc(&ar->num_pending_mgmt_tx); - ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); + queue_work(ar->ab->workqueue_aux, &ar->wmi_mgmt_tx_work); return 0; }