diff options
author | Johannes Berg <johannes.berg@intel.com> | 2017-04-12 11:46:13 +0300 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2017-04-13 14:41:38 +0300 |
commit | 8c5e68894450d3bb7471e426e2eec9a8472bb660 (patch) | |
tree | e50b313dc665332967fff2740427749078df4095 /net/mac80211/cfg.c | |
parent | b0265024b8b5fb35d1e1a1da6be65399e33e122e (diff) | |
download | linux-8c5e68894450d3bb7471e426e2eec9a8472bb660.tar.xz |
mac80211: correct MU-MIMO monitor follow functionality
The MU-MIMO monitor follow functionality is broken because it
doesn't clear the MU-MIMO owner even if both follow features
are disabled. Fix that, and while at it move the code into a
new helper function. Call this also when creating a new monitor
interface to prepare for an upcoming cfg80211 change allowing
that.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 78 |
1 files changed, 58 insertions, 20 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ef7de9eb94b1..e276b8cb24a4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -22,6 +22,49 @@ #include "mesh.h" #include "wme.h" +static int ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata, + struct vif_params *params) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_sub_if_data *monitor_sdata; + bool mu_mimo_groups = false; + bool mu_mimo_follow = false; + + monitor_sdata = rtnl_dereference(local->monitor_sdata); + + if (!monitor_sdata) + return -EOPNOTSUPP; + + if (params->vht_mumimo_groups) { + u64 membership; + + BUILD_BUG_ON(sizeof(membership) != WLAN_MEMBERSHIP_LEN); + + memcpy(monitor_sdata->vif.bss_conf.mu_group.membership, + params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN); + memcpy(monitor_sdata->vif.bss_conf.mu_group.position, + params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN, + WLAN_USER_POSITION_LEN); + ieee80211_bss_info_change_notify(monitor_sdata, + BSS_CHANGED_MU_GROUPS); + /* don't care about endianness - just check for 0 */ + memcpy(&membership, params->vht_mumimo_groups, + WLAN_MEMBERSHIP_LEN); + mu_mimo_groups = membership != 0; + } + + if (params->vht_mumimo_follow_addr) { + mu_mimo_follow = + is_valid_ether_addr(params->vht_mumimo_follow_addr); + ether_addr_copy(monitor_sdata->u.mntr.mu_follow_addr, + params->vht_mumimo_follow_addr); + } + + monitor_sdata->vif.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow; + + return 0; +} + static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, const char *name, unsigned char name_assign_type, @@ -38,9 +81,17 @@ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, if (err) return ERR_PTR(err); - if (type == NL80211_IFTYPE_MONITOR && flags) { - sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); - sdata->u.mntr.flags = *flags; + sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + + if (type == NL80211_IFTYPE_MONITOR) { + err = ieee80211_set_mu_mimo_follow(sdata, params); + if (err) { + ieee80211_if_remove(sdata); + return NULL; + } + + if (flags) + sdata->u.mntr.flags = *flags; } return wdev; @@ -76,24 +127,11 @@ static int ieee80211_change_iface(struct wiphy *wiphy, if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { struct ieee80211_local *local = sdata->local; - struct ieee80211_sub_if_data *monitor_sdata; - u32 mu_mntr_cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER; - - monitor_sdata = rtnl_dereference(local->monitor_sdata); - if (monitor_sdata && params->vht_mumimo_groups) { - memcpy(monitor_sdata->vif.bss_conf.mu_group.membership, - params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN); - memcpy(monitor_sdata->vif.bss_conf.mu_group.position, - params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN, - WLAN_USER_POSITION_LEN); - monitor_sdata->vif.mu_mimo_owner = true; - ieee80211_bss_info_change_notify(monitor_sdata, - BSS_CHANGED_MU_GROUPS); - } + int err; - if (monitor_sdata && params->vht_mumimo_follow_addr) - ether_addr_copy(monitor_sdata->u.mntr.mu_follow_addr, - params->vht_mumimo_follow_addr); + err = ieee80211_set_mu_mimo_follow(sdata, params); + if (err) + return err; if (!flags) return 0; |