@@ -416,6 +416,7 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
/* configure bssid mask */
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+ /* NOTE: Maybe this should be ath9k_set_bssid_mask?? */
ath_hw_setbssidmask(common);
/* configure operational mode */
@@ -110,7 +110,6 @@ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
static void ath_opmode_init(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
u32 rfilt, mfilt[2];
@@ -118,9 +117,15 @@ static void ath_opmode_init(struct ath_softc *sc)
rfilt = ath_calcrxfilter(sc);
ath9k_hw_setrxfilter(ah, rfilt);
- /* configure bssid mask */
- if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
- ath_hw_setbssidmask(common);
+ /* configure bssid mask, if ah->hw is configured.
+ * it is NOT configured when mac80211 is calling
+ * ieee80211_do_open, but probably just as well since
+ * this STA isn't in the list yet.
+ */
+ if (ah->hw) {
+ if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+ ath9k_set_bssid_mask(ah->hw);
+ }
/* configure operational mode */
ath9k_hw_setopmode(ah);
@@ -426,6 +431,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
u32 rfilt;
+ int avifs = ieee80211_count_sta_atomic(sc->hw);
rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE)
| ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
@@ -448,7 +454,11 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->rx.rxfilter & FIF_CONTROL)
rfilt |= ATH9K_RX_FILTER_CONTROL;
+ /* If we have more than one active STA, then we need to
+ * accept more than just MYBEACON.
+ */
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
+ (avifs <= 1) &&
!(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC))
rfilt |= ATH9K_RX_FILTER_MYBEACON;
else
@@ -463,9 +473,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (conf_is_ht(&sc->hw->conf))
rfilt |= ATH9K_RX_FILTER_COMP_BAR;
- if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
- /* TODO: only needed if more than one BSSID is in use in
- * station/adhoc mode */
+ if (sc->sec_wiphy || (avifs > 1) || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
/* The following may also be needed for other older chips */
if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
rfilt |= ATH9K_RX_FILTER_PROM;
@@ -59,15 +59,17 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
} else
iter_data.count = 0;
- /* Get list of all active MAC addresses */
+ /* Get list of all MAC addresses for STA and ADHOC interfaces. */
spin_lock_bh(&sc->wiphy_lock);
- ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,
- &iter_data);
+ ieee80211_iterate_interfaces_helper(sc->hw, true, false,
+ ath9k_vif_iter,
+ &iter_data);
for (i = 0; i < sc->num_sec_wiphy; i++) {
if (sc->sec_wiphy[i] == NULL)
continue;
- ieee80211_iterate_active_interfaces_atomic(
- sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data);
+ ieee80211_iterate_interfaces_helper(
+ sc->sec_wiphy[i]->hw, true, false,
+ ath9k_vif_iter, &iter_data);
}
spin_unlock_bh(&sc->wiphy_lock);
@@ -2320,6 +2320,35 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
u8 *mac,
struct ieee80211_vif *vif),
void *data);
+/**
+ * ieee80211_iterate_interfaces_helper - iterate interfaces
+ *
+ * This function iterates over the interfaces associated with a given
+ * hardware and calls the callback for them. If do_atomic is true,
+ * this function requires the iterator callback function to be atomic,
+ * if that is not desired, set do_atomic to false.
+ * If you want only active interfaces, set active_only to true.
+ * See also: @ieee80211_iterate_active_interfaces
+ * @ieee80211_iterate_active_interfaces_atomic
+ *
+ * Returns number of interfaces to be filtered.
+ * @hw: the hardware struct of which the interfaces should be iterated over
+ * @do_atomic: Should iterator be treated as atomic or not.
+ * @active_only: Should we only iterate over active interfaces.
+ * @iterator: the iterator function to call, cannot sleep
+ * @data: first argument of the iterator function
+ */
+int ieee80211_iterate_interfaces_helper(struct ieee80211_hw *hw,
+ bool do_atomic,
+ bool active_only,
+ void (*iterator)(void *data, u8 *mac,
+ struct ieee80211_vif *vif),
+ void *data);
+
+/** Return a count of all station-like interfaces for
+ * this hardware. Running/Stopped state has no affect.
+ */
+int ieee80211_count_sta_atomic(struct ieee80211_hw *hw);
/**
* ieee80211_queue_work - add work onto the mac80211 workqueue
@@ -440,7 +440,7 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
spin_lock_irqsave(&local->sta_lock, flags);
/* check if STA exists already */
- if (sta_info_get_bss(sdata, sta->sta.addr)) {
+ if (sta_info_get(sdata, sta->sta.addr)) {
spin_unlock_irqrestore(&local->sta_lock, flags);
mutex_unlock(&local->sta_mtx);
rcu_read_lock();
@@ -461,37 +461,75 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(ieee80211_wake_queues);
-void ieee80211_iterate_active_interfaces(
+static int _iter_loop_helper(
+ struct ieee80211_sub_if_data *sdata,
+ bool active_only,
+ void (*iterator)(void *data, u8 *mac,
+ struct ieee80211_vif *vif),
+ void *data)
+{
+ switch (sdata->vif.type) {
+ case NUM_NL80211_IFTYPES:
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_AP_VLAN:
+ return 0;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
+ break;
+ }
+ if (ieee80211_sdata_running(sdata) || !active_only) {
+ if (iterator)
+ iterator(data, sdata->vif.addr,
+ &sdata->vif);
+ return 1;
+ }
+ return 0;
+}
+
+int ieee80211_iterate_interfaces_helper(
struct ieee80211_hw *hw,
+ bool do_atomic,
+ bool active_only,
void (*iterator)(void *data, u8 *mac,
struct ieee80211_vif *vif),
void *data)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
+ int cnt = 0;
- mutex_lock(&local->iflist_mtx);
+ if (do_atomic) {
+ rcu_read_lock();
- list_for_each_entry(sdata, &local->interfaces, list) {
- switch (sdata->vif.type) {
- case NUM_NL80211_IFTYPES:
- 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;
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ cnt += _iter_loop_helper(sdata, active_only,
+ iterator, data);
}
- if (ieee80211_sdata_running(sdata))
- iterator(data, sdata->vif.addr,
- &sdata->vif);
+ rcu_read_unlock();
+ } else {
+ mutex_lock(&local->iflist_mtx);
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ cnt += _iter_loop_helper(sdata, active_only,
+ iterator, data);
+ }
+ mutex_unlock(&local->iflist_mtx);
}
+ return cnt;
+}
+EXPORT_SYMBOL_GPL(ieee80211_iterate_interfaces_helper);
+
- mutex_unlock(&local->iflist_mtx);
+void ieee80211_iterate_active_interfaces(
+ struct ieee80211_hw *hw,
+ void (*iterator)(void *data, u8 *mac,
+ struct ieee80211_vif *vif),
+ void *data)
+{
+ ieee80211_iterate_interfaces_helper(hw, false, false, iterator, data);
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
@@ -501,33 +539,20 @@ void ieee80211_iterate_active_interfaces_atomic(
struct ieee80211_vif *vif),
void *data)
{
- struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata;
+ ieee80211_iterate_interfaces_helper(hw, true, false, iterator, data);
+}
+EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
- rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- switch (sdata->vif.type) {
- case NUM_NL80211_IFTYPES:
- 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 (ieee80211_sdata_running(sdata))
- iterator(data, sdata->vif.addr,
- &sdata->vif);
- }
- rcu_read_unlock();
+/** Return a count of all station-like interfaces for
+ * this hardware. Running/Stopped state has no affect.
+ */
+int ieee80211_count_sta_atomic(struct ieee80211_hw *hw)
+{
+ return ieee80211_iterate_interfaces_helper(hw, true, false, NULL, NULL);
}
-EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
+EXPORT_SYMBOL_GPL(ieee80211_count_sta_atomic);
/*
* Nothing should have been stuffed into the workqueue during