Merge tag 'ntb-4.3' of git://github.com/jonmason/ntb
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / mlme.c
index 9b2cc278ac2afc60920ebec3083bebc35c497b61..cd7e55e08a238c23f546ce7d6860759345eff371 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright (C) 2015 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -538,11 +539,16 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
        ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);
 }
 
+/* This function determines vht capability flags for the association
+ * and builds the IE.
+ * Note - the function may set the owner of the MU-MIMO capability
+ */
 static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
                                 struct sk_buff *skb,
                                 struct ieee80211_supported_band *sband,
                                 struct ieee80211_vht_cap *ap_vht_cap)
 {
+       struct ieee80211_local *local = sdata->local;
        u8 *pos;
        u32 cap;
        struct ieee80211_sta_vht_cap vht_cap;
@@ -576,7 +582,34 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
         */
        if (!(ap_vht_cap->vht_cap_info &
                        cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)))
-               cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+               cap &= ~(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+                        IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+       else if (!(ap_vht_cap->vht_cap_info &
+                       cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)))
+               cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+       /*
+        * If some other vif is using the MU-MIMO capablity we cannot associate
+        * using MU-MIMO - this will lead to contradictions in the group-id
+        * mechanism.
+        * Ownership is defined since association request, in order to avoid
+        * simultaneous associations with MU-MIMO.
+        */
+       if (cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) {
+               bool disable_mu_mimo = false;
+               struct ieee80211_sub_if_data *other;
+
+               list_for_each_entry_rcu(other, &local->interfaces, list) {
+                       if (other->flags & IEEE80211_SDATA_MU_MIMO_OWNER) {
+                               disable_mu_mimo = true;
+                               break;
+                       }
+               }
+               if (disable_mu_mimo)
+                       cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+               else
+                       sdata->flags |= IEEE80211_SDATA_MU_MIMO_OWNER;
+       }
 
        mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
 
@@ -1096,24 +1129,6 @@ static void ieee80211_chswitch_timer(unsigned long data)
        ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
 }
 
-static void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata)
-{
-       struct sta_info *sta;
-       u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
-               if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded ||
-                   !test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-                       continue;
-
-               ieee80211_tdls_oper_request(&sdata->vif, sta->sta.addr,
-                                           NL80211_TDLS_TEARDOWN, reason,
-                                           GFP_ATOMIC);
-       }
-       rcu_read_unlock();
-}
-
 static void
 ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                 u64 timestamp, u32 device_timestamp,
@@ -2076,6 +2091,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
        memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa));
        memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask));
+       sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
 
        sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
 
@@ -2538,6 +2554,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
                eth_zero_addr(sdata->u.mgd.bssid);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
                sdata->u.mgd.flags = 0;
+               sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
                mutex_lock(&sdata->local->mtx);
                ieee80211_vif_release_channel(sdata);
                mutex_unlock(&sdata->local->mtx);
@@ -3034,12 +3051,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
 
        rate_control_rate_init(sta);
 
-       if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) {
+       if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
                set_sta_flag(sta, WLAN_STA_MFP);
-               sta->sta.mfp = true;
-       } else {
-               sta->sta.mfp = false;
-       }
 
        sta->sta.wme = elems.wmm_param && local->hw.queues >= IEEE80211_NUM_ACS;
 
@@ -4254,6 +4267,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_supported_band *sband;
        struct cfg80211_chan_def chandef;
        int ret;
+       u32 i;
+       bool have_80mhz;
 
        sband = local->hw.wiphy->bands[cbss->channel->band];
 
@@ -4304,6 +4319,20 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                }
        }
 
+       /* Allow VHT if at least one channel on the sband supports 80 MHz */
+       have_80mhz = false;
+       for (i = 0; i < sband->n_channels; i++) {
+               if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED |
+                                               IEEE80211_CHAN_NO_80MHZ))
+                       continue;
+
+               have_80mhz = true;
+               break;
+       }
+
+       if (!have_80mhz)
+               ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+
        ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
                                                     cbss->channel,
                                                     ht_cap, ht_oper, vht_oper,