diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 330cd3b..9c41071 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -17,23 +17,29 @@
 #include "ath9k.h"
 
 static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc,
-					     struct ieee80211_hdr *hdr)
+					     struct ieee80211_hdr *hdr,
+					     struct ieee80211_vif **vif)
 {
 	struct ieee80211_hw *hw = sc->pri_wiphy->hw;
 	int i;
 
+	*vif = ieee80211_get_vif_by_mac_atomic(hw, hdr->addr1);
+	if (*vif)
+		return hw;
+
 	spin_lock_bh(&sc->wiphy_lock);
 	for (i = 0; i < sc->num_sec_wiphy; i++) {
 		struct ath_wiphy *aphy = sc->sec_wiphy[i];
-		if (aphy == NULL)
+		if (!aphy)
 			continue;
-		if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr)
-		    == 0) {
+		*vif = ieee80211_get_vif_by_mac_atomic(aphy->hw, hdr->addr1);
+		if (*vif) {
 			hw = aphy->hw;
 			break;
 		}
 	}
 	spin_unlock_bh(&sc->wiphy_lock);
+
 	return hw;
 }
 
@@ -662,6 +668,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 	struct ieee80211_rx_status rx_status;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
+	struct ieee80211_vif *vif;
 	/*
 	 * The hw can techncically differ from common->hw when using ath9k
 	 * virtual wiphy so to account for that we iterate over the active
@@ -748,7 +755,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 				DMA_FROM_DEVICE);
 
 		hdr = (struct ieee80211_hdr *) skb->data;
-		hw = ath_get_virt_hw(sc, hdr);
+		hw = ath_get_virt_hw(sc, hdr, &vif);
 
 		/*
 		 * If we're asked to flush receive queue, directly
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e12293e..1d2bb0a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1999,6 +1999,12 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
 						    struct ieee80211_vif *vif),
 						void *data);
 
+struct ieee80211_vif *ieee80211_get_vif_by_mac(struct ieee80211_hw *hw,
+					       u8 *mac);
+
+struct ieee80211_vif *ieee80211_get_vif_by_mac_atomic(struct ieee80211_hw *hw,
+					       u8 *mac);
+
 /**
  * ieee80211_queue_work - add work onto the mac80211 workqueue
  *
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index aedbaaa..f3f5a8b 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -511,6 +511,107 @@ void ieee80211_iterate_active_interfaces_atomic(
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
 
+static struct ieee80211_vif *ieee80211_get_first_mon_vif(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_vif *vif = NULL;
+
+	if (likely(!local->monitors && local->cooked_mntrs++))
+		return NULL;
+
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+			vif = &sdata->vif;
+			break;
+		}
+	}
+
+	return vif;
+}
+
+struct ieee80211_vif *ieee80211_get_vif_by_mac(struct ieee80211_hw *hw,
+					       u8 *mac)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_vif *vif = NULL;
+
+	mutex_lock(&local->iflist_mtx);
+
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		switch (sdata->vif.type) {
+		case __NL80211_IFTYPE_AFTER_LAST:
+		case NL80211_IFTYPE_UNSPECIFIED:
+		case NL80211_IFTYPE_MONITOR:
+		case NL80211_IFTYPE_AP_VLAN:
+			continue;
+		case NL80211_IFTYPE_AP:
+		case NL80211_IFTYPE_STATION:
+		case NL80211_IFTYPE_ADHOC:
+		case NL80211_IFTYPE_WDS:
+		case NL80211_IFTYPE_MESH_POINT:
+			break;
+		}
+
+		if (compare_ether_addr(mac, sdata->dev->dev_addr) == 0) {
+			vif = &sdata->vif;
+			break;
+		}
+	}
+
+	if (!vif) {
+		vif = ieee80211_get_first_mon_vif(hw);
+		WARN_ON(!vif);
+	}
+
+	mutex_unlock(&local->iflist_mtx);
+
+	return vif;
+}
+EXPORT_SYMBOL_GPL(ieee80211_get_vif_by_mac);
+
+struct ieee80211_vif *ieee80211_get_vif_by_mac_atomic(struct ieee80211_hw *hw,
+						      u8 *mac)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_vif *vif = NULL;
+
+	rcu_read_lock();
+
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		switch (sdata->vif.type) {
+		case __NL80211_IFTYPE_AFTER_LAST:
+		case NL80211_IFTYPE_UNSPECIFIED:
+		case NL80211_IFTYPE_MONITOR:
+		case NL80211_IFTYPE_AP_VLAN:
+			continue;
+		case NL80211_IFTYPE_AP:
+		case NL80211_IFTYPE_STATION:
+		case NL80211_IFTYPE_ADHOC:
+		case NL80211_IFTYPE_WDS:
+		case NL80211_IFTYPE_MESH_POINT:
+			break;
+		}
+
+		if (compare_ether_addr(mac, sdata->dev->dev_addr) == 0) {
+			vif = &sdata->vif;
+			break;
+		}
+	}
+
+	if (!vif) {
+		vif = ieee80211_get_first_mon_vif(hw);
+		WARN_ON(!vif);
+	}
+
+	rcu_read_unlock();
+
+	return vif;
+}
+EXPORT_SYMBOL_GPL(ieee80211_get_vif_by_mac_atomic);
+
 /*
  * Nothing should have been stuffed into the workqueue during
  * the suspend->resume cycle. If this WARN is seen then there
