aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-07-18 12:08:35 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-07-19 16:49:58 -0400
commit34850ab25d74ab4eead62c3b4a9e8036a25cc669 (patch)
treec1aa56f2d94851804969b71523ade13bb9db693c /net
parent0b5dd734d3545a9833c0bceeed5088ad9a1ca5e3 (diff)
cfg80211: allow userspace to control supported rates in scan
Some P2P scans are not allowed to advertise 11b rates, but that is a rather special case so instead of having that, allow userspace to request the rate sets (per band) that are advertised in scan probe request frames. Since it's needed in two places now, factor out some common code parsing a rate array. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/wireless/core.h4
-rw-r--r--net/wireless/nl80211.c50
-rw-r--r--net/wireless/scan.c3
-rw-r--r--net/wireless/util.c35
4 files changed, 73 insertions, 19 deletions
diff --git a/net/wireless/core.h b/net/wireless/core.h
index a570ff9214ec..8672e028022f 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -447,6 +447,10 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
447 447
448u16 cfg80211_calculate_bitrate(struct rate_info *rate); 448u16 cfg80211_calculate_bitrate(struct rate_info *rate);
449 449
450int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
451 const u8 *rates, unsigned int n_rates,
452 u32 *mask);
453
450int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, 454int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
451 u32 beacon_int); 455 u32 beacon_int);
452 456
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 44a3fc2ce38d..20aa390cf338 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -177,6 +177,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
177 [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, 177 [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
178 [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, 178 [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
179 [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, 179 [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
180 [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
180}; 181};
181 182
182/* policy for the key attributes */ 183/* policy for the key attributes */
@@ -3324,7 +3325,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
3324 struct nlattr *attr; 3325 struct nlattr *attr;
3325 struct wiphy *wiphy; 3326 struct wiphy *wiphy;
3326 int err, tmp, n_ssids = 0, n_channels, i; 3327 int err, tmp, n_ssids = 0, n_channels, i;
3327 enum ieee80211_band band;
3328 size_t ie_len; 3328 size_t ie_len;
3329 3329
3330 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3330 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
@@ -3344,6 +3344,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
3344 if (!n_channels) 3344 if (!n_channels)
3345 return -EINVAL; 3345 return -EINVAL;
3346 } else { 3346 } else {
3347 enum ieee80211_band band;
3347 n_channels = 0; 3348 n_channels = 0;
3348 3349
3349 for (band = 0; band < IEEE80211_NUM_BANDS; band++) 3350 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
@@ -3404,6 +3405,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
3404 i++; 3405 i++;
3405 } 3406 }
3406 } else { 3407 } else {
3408 enum ieee80211_band band;
3409
3407 /* all channels */ 3410 /* all channels */
3408 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 3411 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
3409 int j; 3412 int j;
@@ -3450,6 +3453,28 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
3450 request->ie_len); 3453 request->ie_len);
3451 } 3454 }
3452 3455
3456 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
3457 request->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
3458
3459 if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) {
3460 nla_for_each_nested(attr,
3461 info->attrs[NL80211_ATTR_SCAN_SUPP_RATES],
3462 tmp) {
3463 enum ieee80211_band band = nla_type(attr);
3464
3465 if (band < 0 || band > IEEE80211_NUM_BANDS) {
3466 err = -EINVAL;
3467 goto out_free;
3468 }
3469 err = ieee80211_get_ratemask(wiphy->bands[band],
3470 nla_data(attr),
3471 nla_len(attr),
3472 &request->rates[band]);
3473 if (err)
3474 goto out_free;
3475 }
3476 }
3477
3453 request->dev = dev; 3478 request->dev = dev;
3454 request->wiphy = &rdev->wiphy; 3479 request->wiphy = &rdev->wiphy;
3455 3480
@@ -4336,25 +4361,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
4336 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); 4361 nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
4337 struct ieee80211_supported_band *sband = 4362 struct ieee80211_supported_band *sband =
4338 wiphy->bands[ibss.channel->band]; 4363 wiphy->bands[ibss.channel->band];
4339 int i, j; 4364 int err;
4340
4341 if (n_rates == 0)
4342 return -EINVAL;
4343
4344 for (i = 0; i < n_rates; i++) {
4345 int rate = (rates[i] & 0x7f) * 5;
4346 bool found = false;
4347 4365
4348 for (j = 0; j < sband->n_bitrates; j++) { 4366 err = ieee80211_get_ratemask(sband, rates, n_rates,
4349 if (sband->bitrates[j].bitrate == rate) { 4367 &ibss.basic_rates);
4350 found = true; 4368 if (err)
4351 ibss.basic_rates |= BIT(j); 4369 return err;
4352 break;
4353 }
4354 }
4355 if (!found)
4356 return -EINVAL;
4357 }
4358 } 4370 }
4359 4371
4360 if (info->attrs[NL80211_ATTR_MCAST_RATE] && 4372 if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 1c4672e35144..1e7ff949d1aa 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -862,6 +862,9 @@ int cfg80211_wext_siwscan(struct net_device *dev,
862 creq->n_ssids = 0; 862 creq->n_ssids = 0;
863 } 863 }
864 864
865 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
866 creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
867
865 rdev->scan_req = creq; 868 rdev->scan_req = creq;
866 err = rdev->ops->scan(wiphy, dev, creq); 869 err = rdev->ops->scan(wiphy, dev, creq);
867 if (err) { 870 if (err) {
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 4d7b83fbc32f..a329429bfdd8 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1006,3 +1006,38 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
1006 1006
1007 return -EBUSY; 1007 return -EBUSY;
1008} 1008}
1009
1010int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
1011 const u8 *rates, unsigned int n_rates,
1012 u32 *mask)
1013{
1014 int i, j;
1015
1016 if (n_rates == 0 || n_rates > NL80211_MAX_SUPP_RATES)
1017 return -EINVAL;
1018
1019 *mask = 0;
1020
1021 for (i = 0; i < n_rates; i++) {
1022 int rate = (rates[i] & 0x7f) * 5;
1023 bool found = false;
1024
1025 for (j = 0; j < sband->n_bitrates; j++) {
1026 if (sband->bitrates[j].bitrate == rate) {
1027 found = true;
1028 *mask |= BIT(j);
1029 break;
1030 }
1031 }
1032 if (!found)
1033 return -EINVAL;
1034 }
1035
1036 /*
1037 * mask must have at least one bit set here since we
1038 * didn't accept a 0-length rates array nor allowed
1039 * entries in the array that didn't exist
1040 */
1041
1042 return 0;
1043}