summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>2016-10-10 19:51:18 +0530
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-12-01 09:44:21 +0100
commit5f0de882e77fd578d7c5bb5fbc8c92c1169e80c0 (patch)
treea5d98e3f5d1979390150a6daf0fbe8ec2d5c2835 /drivers/net/wireless/ath
parent272991176af2335b37be8fc3f0ab17ff96cace9d (diff)
ath10k: fix kernel panic due to race in accessing arvif list
commit ebaa4b1620bf69f2bc43cb45ea85fbafdaec23c3 upstream. arvifs list is traversed within data_lock spin_lock in tasklet context to fill channel information from the corresponding vif. This means any access to arvifs list for add/del operations should also be protected with the same spin_lock to avoid the race. Fix this by performing list add/del on arvfis within the data_lock. This could fix kernel panic something like the below. LR is at ath10k_htt_rx_pktlog_completion_handler+0x100/0xb6c [ath10k_core] PC is at ath10k_htt_rx_pktlog_completion_handler+0x1c0/0xb6c [ath10k_core] Internal error: Oops: 17 [#1] PREEMPT SMP ARM [<bf4857f4>] (ath10k_htt_rx_pktlog_completion_handler+0x2f4/0xb6c [ath10k_core]) [<bf487540>] (ath10k_htt_txrx_compl_task+0x8b4/0x1188 [ath10k_core]) [<c00312d4>] (tasklet_action+0x8c/0xec) [<c00309a8>] (__do_softirq+0xdc/0x208) [<c0030d6c>] (irq_exit+0x84/0xe0) [<c005db04>] (__handle_domain_irq+0x80/0xa0) [<c00085c4>] (gic_handle_irq+0x38/0x5c) [<c0009640>] (__irq_svc+0x40/0x74) (gdb) list *(ath10k_htt_rx_pktlog_completion_handler+0x1c0) 0x136c0 is in ath10k_htt_rx_h_channel (drivers/net/wireless/ath/ath10k/htt_rx.c:769) 764 struct cfg80211_chan_def def; 765 766 lockdep_assert_held(&ar->data_lock); 767 768 list_for_each_entry(arvif, &ar->arvifs, list) { 769 if (arvif->vdev_id == vdev_id && 770 ath10k_mac_vif_chan(arvif->vif, &def) == 0) 771 return def.chan; 772 } 773 Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com> Signed-off-by: Amit Pundir <amit.pundir@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 5fe6841b8889..fb632a454fc2 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4967,7 +4967,9 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
}
ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
+ spin_lock_bh(&ar->data_lock);
list_add(&arvif->list, &ar->arvifs);
+ spin_unlock_bh(&ar->data_lock);
/* It makes no sense to have firmware do keepalives. mac80211 already
* takes care of this with idle connection polling.
@@ -5118,7 +5120,9 @@ err_peer_delete:
err_vdev_delete:
ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
ar->free_vdev_map |= 1LL << arvif->vdev_id;
+ spin_lock_bh(&ar->data_lock);
list_del(&arvif->list);
+ spin_unlock_bh(&ar->data_lock);
err:
if (arvif->beacon_buf) {
@@ -5164,7 +5168,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
arvif->vdev_id, ret);
ar->free_vdev_map |= 1LL << arvif->vdev_id;
+ spin_lock_bh(&ar->data_lock);
list_del(&arvif->list);
+ spin_unlock_bh(&ar->data_lock);
if (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {