|
@@ -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;
|
|
|
|
|
@@ -2058,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;
|
|
|
|
|
@@ -2520,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);
|