@@ -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
@@ -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
*
@@ -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