diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-07-18 12:08:35 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-07-19 16:49:58 -0400 |
commit | 34850ab25d74ab4eead62c3b4a9e8036a25cc669 (patch) | |
tree | c1aa56f2d94851804969b71523ade13bb9db693c /net/wireless/nl80211.c | |
parent | 0b5dd734d3545a9833c0bceeed5088ad9a1ca5e3 (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/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 50 |
1 files changed, 31 insertions, 19 deletions
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] && |