summaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2016-09-19 09:44:44 +0200
committerJohannes Berg <johannes.berg@intel.com>2016-09-26 10:23:48 +0200
commit8564e38206de2ff005a27c8d7c2ce3869a44f0dd (patch)
tree2c6a9ae667d5bf80a6789d1201dfb9a492ea99d1 /net/wireless
parentcfg80211: Add support to configure a beacon data rate (diff)
downloadlinux-8564e38206de2ff005a27c8d7c2ce3869a44f0dd.tar.xz
linux-8564e38206de2ff005a27c8d7c2ce3869a44f0dd.zip
cfg80211: add checks for beacon rate, extend to mesh
The previous commit added support for specifying the beacon rate for AP mode. Add features checks to this, and extend it to also support the rate configuration for mesh networks. For IBSS it's not as simple due to joining etc., so that's not yet supported. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/nl80211.c46
1 files changed, 35 insertions, 11 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a10484da60c0..b8441e60b0f6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3569,13 +3569,12 @@ out:
return 0;
}
-static int validate_beacon_tx_rate(struct cfg80211_ap_settings *params)
+static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
+ enum nl80211_band band,
+ struct cfg80211_bitrate_mask *beacon_rate)
{
- u32 rate, count_ht, count_vht, i;
- enum nl80211_band band;
-
- band = params->chandef.chan->band;
- rate = params->beacon_rate.control[band].legacy;
+ u32 count_ht, count_vht, i;
+ u32 rate = beacon_rate->control[band].legacy;
/* Allow only one rate */
if (hweight32(rate) > 1)
@@ -3583,9 +3582,9 @@ static int validate_beacon_tx_rate(struct cfg80211_ap_settings *params)
count_ht = 0;
for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
- if (hweight8(params->beacon_rate.control[band].ht_mcs[i]) > 1) {
+ if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
return -EINVAL;
- } else if (params->beacon_rate.control[band].ht_mcs[i]) {
+ } else if (beacon_rate->control[band].ht_mcs[i]) {
count_ht++;
if (count_ht > 1)
return -EINVAL;
@@ -3596,9 +3595,9 @@ static int validate_beacon_tx_rate(struct cfg80211_ap_settings *params)
count_vht = 0;
for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
- if (hweight16(params->beacon_rate.control[band].vht_mcs[i]) > 1) {
+ if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) {
return -EINVAL;
- } else if (params->beacon_rate.control[band].vht_mcs[i]) {
+ } else if (beacon_rate->control[band].vht_mcs[i]) {
count_vht++;
if (count_vht > 1)
return -EINVAL;
@@ -3610,6 +3609,19 @@ static int validate_beacon_tx_rate(struct cfg80211_ap_settings *params)
if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
return -EINVAL;
+ if (rate &&
+ !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
+ return -EINVAL;
+ if (count_ht &&
+ !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_BEACON_RATE_HT))
+ return -EINVAL;
+ if (count_vht &&
+ !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_BEACON_RATE_VHT))
+ return -EINVAL;
+
return 0;
}
@@ -3847,7 +3859,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
- err = validate_beacon_tx_rate(&params);
+ err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
+ &params.beacon_rate);
if (err)
return err;
}
@@ -9406,6 +9419,17 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
return err;
}
+ if (info->attrs[NL80211_ATTR_TX_RATES]) {
+ err = nl80211_parse_tx_bitrate_mask(info, &setup.beacon_rate);
+ if (err)
+ return err;
+
+ err = validate_beacon_tx_rate(rdev, setup.chandef.chan->band,
+ &setup.beacon_rate);
+ if (err)
+ return err;
+ }
+
return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
}