iwlwifi: mvm: disallow new TDLS stations when appropriate
authorArik Nemtsov <arik@wizery.com>
Thu, 15 May 2014 08:44:40 +0000 (11:44 +0300)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 7 Jul 2014 18:41:21 +0000 (21:41 +0300)
HW/FW constraints dictate that TDLS should only be used when a single
phy ctx is active. We also support at most 4 TDLS peers. We don't
support TDLS on a P2P vif.

Unify and move a phy-ctx counting implementation from the power-mgmt code
in order to simplify implementation.

Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/iwlwifi/mvm/power.c

index 99329edcd99f78a2cc49fdbfed5c42549bc63b2b..b8e4e78d601b98b6e67a444f5f7cb09985a7bef1 100644 (file)
@@ -86,6 +86,8 @@ enum {
 
 #define IWL_MVM_STATION_COUNT  16
 
+#define IWL_MVM_TDLS_STA_COUNT 4
+
 /* commands */
 enum {
        MVM_ALIVE = 0x1,
index 5ed6fb32087cf07d78cefec8df75a78a160e0c69..57945fe062166b0382a1bc29ca96219e341f331a 100644 (file)
@@ -1843,6 +1843,26 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
        mutex_unlock(&mvm->mutex);
 }
 
+static int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm)
+{
+       struct ieee80211_sta *sta;
+       int count = 0;
+       int i;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
+               sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
+                                               lockdep_is_held(&mvm->mutex));
+               if (!sta || IS_ERR(sta) || !sta->tdls)
+                       continue;
+
+               count++;
+       }
+
+       return count;
+}
+
 static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_sta *sta,
@@ -1881,6 +1901,16 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
                        ret = -EINVAL;
                        goto out_unlock;
                }
+
+               if (sta->tdls &&
+                   (vif->p2p ||
+                    iwl_mvm_tdls_sta_count(mvm) == IWL_MVM_TDLS_STA_COUNT ||
+                    iwl_mvm_phy_ctx_count(mvm) > 1)) {
+                       IWL_DEBUG_MAC80211(mvm, "refusing TDLS sta\n");
+                       ret = -EBUSY;
+                       goto out_unlock;
+               }
+
                ret = iwl_mvm_add_sta(mvm, vif, sta);
        } else if (old_state == IEEE80211_STA_NONE &&
                   new_state == IEEE80211_STA_AUTH) {
index 7b308c4834f66686cad698104a5e4832df7717a8..c75b958736bc819c0eab9d9892c99637a14579d3 100644 (file)
@@ -838,6 +838,7 @@ void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm,
                          struct iwl_mvm_phy_ctxt *ctxt);
 void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm,
                            struct iwl_mvm_phy_ctxt *ctxt);
+int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm);
 
 /* MAC (virtual interface) programming */
 int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
index 539f3a942d437565ab6ba9accd06f71874985af4..6cc243f7cf602b8f926baa11d4a59c30db965e0c 100644 (file)
@@ -261,3 +261,29 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt)
 
        ctxt->ref--;
 }
+
+static void iwl_mvm_binding_iterator(void *_data, u8 *mac,
+                                    struct ieee80211_vif *vif)
+{
+       unsigned long *data = _data;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       if (!mvmvif->phy_ctxt)
+               return;
+
+       if (vif->type == NL80211_IFTYPE_STATION ||
+           vif->type == NL80211_IFTYPE_AP)
+               __set_bit(mvmvif->phy_ctxt->id, data);
+}
+
+int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm)
+{
+       unsigned long phy_ctxt_counter = 0;
+
+       ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
+                                                  iwl_mvm_binding_iterator,
+                                                  &phy_ctxt_counter);
+
+       return hweight8(phy_ctxt_counter);
+}
index c182a8baf685857d3c2857443d53ae978e8646a8..3b582dd6d77fdf1c0eec351f6d4e44eae17d3ad7 100644 (file)
@@ -246,30 +246,10 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
                IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
 }
 
-static void iwl_mvm_binding_iterator(void *_data, u8 *mac,
-                                     struct ieee80211_vif *vif)
-{
-       unsigned long *data = _data;
-       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
-       if (!mvmvif->phy_ctxt)
-               return;
-
-       if (vif->type == NL80211_IFTYPE_STATION ||
-           vif->type == NL80211_IFTYPE_AP)
-               __set_bit(mvmvif->phy_ctxt->id, data);
-}
-
 static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
                                       struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       unsigned long phy_ctxt_counter = 0;
-
-       ieee80211_iterate_active_interfaces_atomic(mvm->hw,
-                                                  IEEE80211_IFACE_ITER_NORMAL,
-                                                  iwl_mvm_binding_iterator,
-                                                  &phy_ctxt_counter);
 
        if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
                    ETH_ALEN))
@@ -291,7 +271,7 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
         * Avoid using uAPSD if client is in DCM -
         * low latency issue in Miracast
         */
-       if (hweight8(phy_ctxt_counter) >= 2)
+       if (iwl_mvm_phy_ctx_count(mvm) >= 2)
                return false;
 
        return true;