Commit cf7b491d authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Emmanuel Grumbach

iwlwifi: mvm: disallow new TDLS stations when appropriate

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: default avatarArik Nemtsov <arikx.nemtsov@intel.com>
Reviewed-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 003e5236
...@@ -86,6 +86,8 @@ enum { ...@@ -86,6 +86,8 @@ enum {
#define IWL_MVM_STATION_COUNT 16 #define IWL_MVM_STATION_COUNT 16
#define IWL_MVM_TDLS_STA_COUNT 4
/* commands */ /* commands */
enum { enum {
MVM_ALIVE = 0x1, MVM_ALIVE = 0x1,
......
...@@ -1843,6 +1843,26 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, ...@@ -1843,6 +1843,26 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
mutex_unlock(&mvm->mutex); 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, static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
...@@ -1881,6 +1901,16 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, ...@@ -1881,6 +1901,16 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
ret = -EINVAL; ret = -EINVAL;
goto out_unlock; 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); ret = iwl_mvm_add_sta(mvm, vif, sta);
} else if (old_state == IEEE80211_STA_NONE && } else if (old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_AUTH) { new_state == IEEE80211_STA_AUTH) {
......
...@@ -838,6 +838,7 @@ void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, ...@@ -838,6 +838,7 @@ void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm,
struct iwl_mvm_phy_ctxt *ctxt); struct iwl_mvm_phy_ctxt *ctxt);
void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm,
struct iwl_mvm_phy_ctxt *ctxt); struct iwl_mvm_phy_ctxt *ctxt);
int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm);
/* MAC (virtual interface) programming */ /* MAC (virtual interface) programming */
int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
......
...@@ -261,3 +261,29 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) ...@@ -261,3 +261,29 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt)
ctxt->ref--; 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);
}
...@@ -246,30 +246,10 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm, ...@@ -246,30 +246,10 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
IWL_MVM_PS_HEAVY_RX_THLD_PERCENT; 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, static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(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, if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
ETH_ALEN)) ETH_ALEN))
...@@ -291,7 +271,7 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, ...@@ -291,7 +271,7 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
* Avoid using uAPSD if client is in DCM - * Avoid using uAPSD if client is in DCM -
* low latency issue in Miracast * low latency issue in Miracast
*/ */
if (hweight8(phy_ctxt_counter) >= 2) if (iwl_mvm_phy_ctx_count(mvm) >= 2)
return false; return false;
return true; return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment