aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h7
-rw-r--r--include/net/cfg80211.h3
-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
6 files changed, 83 insertions, 19 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 7ba71e42449e..e4da76c9e4d9 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1014,6 +1014,11 @@ enum nl80211_commands {
1014 * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information 1014 * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
1015 * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data. 1015 * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
1016 * 1016 *
1017 * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan,
1018 * nested array attribute containing an entry for each band, with the entry
1019 * being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but
1020 * without the length restriction (at most %NL80211_MAX_SUPP_RATES).
1021 *
1017 * @NL80211_ATTR_MAX: highest attribute number currently defined 1022 * @NL80211_ATTR_MAX: highest attribute number currently defined
1018 * @__NL80211_ATTR_AFTER_LAST: internal use 1023 * @__NL80211_ATTR_AFTER_LAST: internal use
1019 */ 1024 */
@@ -1217,6 +1222,8 @@ enum nl80211_attrs {
1217 NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, 1222 NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
1218 NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, 1223 NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
1219 1224
1225 NL80211_ATTR_SCAN_SUPP_RATES,
1226
1220 /* add attributes here, update the policy in nl80211.c */ 1227 /* add attributes here, update the policy in nl80211.c */
1221 1228
1222 __NL80211_ATTR_AFTER_LAST, 1229 __NL80211_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 930c783286fc..d17f47fc9e31 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -777,6 +777,7 @@ struct cfg80211_ssid {
777 * @n_channels: total number of channels to scan 777 * @n_channels: total number of channels to scan
778 * @ie: optional information element(s) to add into Probe Request or %NULL 778 * @ie: optional information element(s) to add into Probe Request or %NULL
779 * @ie_len: length of ie in octets 779 * @ie_len: length of ie in octets
780 * @rates: bitmap of rates to advertise for each band
780 * @wiphy: the wiphy this was for 781 * @wiphy: the wiphy this was for
781 * @dev: the interface 782 * @dev: the interface
782 * @aborted: (internal) scan request was notified as aborted 783 * @aborted: (internal) scan request was notified as aborted
@@ -788,6 +789,8 @@ struct cfg80211_scan_request {
788 const u8 *ie; 789 const u8 *ie;
789 size_t ie_len; 790 size_t ie_len;
790 791
792 u32 rates[IEEE80211_NUM_BANDS];
793
791 /* internal */ 794 /* internal */
792 struct wiphy *wiphy; 795 struct wiphy *wiphy;
793 struct net_device *dev; 796 struct net_device *dev;
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}