aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r--net/mac80211/scan.c118
1 files changed, 77 insertions, 41 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index f40661eb75b5..a0a938145dcc 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -235,38 +235,51 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
235{ 235{
236 struct cfg80211_scan_request *req = local->scan_req; 236 struct cfg80211_scan_request *req = local->scan_req;
237 struct cfg80211_chan_def chandef; 237 struct cfg80211_chan_def chandef;
238 enum ieee80211_band band; 238 u8 bands_used = 0;
239 int i, ielen, n_chans; 239 int i, ielen, n_chans;
240 240
241 if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) 241 if (test_bit(SCAN_HW_CANCELLED, &local->scanning))
242 return false; 242 return false;
243 243
244 do { 244 if (local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) {
245 if (local->hw_scan_band == IEEE80211_NUM_BANDS)
246 return false;
247
248 band = local->hw_scan_band;
249 n_chans = 0;
250 for (i = 0; i < req->n_channels; i++) { 245 for (i = 0; i < req->n_channels; i++) {
251 if (req->channels[i]->band == band) { 246 local->hw_scan_req->req.channels[i] = req->channels[i];
252 local->hw_scan_req->channels[n_chans] = 247 bands_used |= BIT(req->channels[i]->band);
248 }
249
250 n_chans = req->n_channels;
251 } else {
252 do {
253 if (local->hw_scan_band == IEEE80211_NUM_BANDS)
254 return false;
255
256 n_chans = 0;
257
258 for (i = 0; i < req->n_channels; i++) {
259 if (req->channels[i]->band !=
260 local->hw_scan_band)
261 continue;
262 local->hw_scan_req->req.channels[n_chans] =
253 req->channels[i]; 263 req->channels[i];
254 n_chans++; 264 n_chans++;
265 bands_used |= BIT(req->channels[i]->band);
255 } 266 }
256 }
257 267
258 local->hw_scan_band++; 268 local->hw_scan_band++;
259 } while (!n_chans); 269 } while (!n_chans);
270 }
260 271
261 local->hw_scan_req->n_channels = n_chans; 272 local->hw_scan_req->req.n_channels = n_chans;
262 ieee80211_prepare_scan_chandef(&chandef, req->scan_width); 273 ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
263 274
264 ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie, 275 ielen = ieee80211_build_preq_ies(local,
276 (u8 *)local->hw_scan_req->req.ie,
265 local->hw_scan_ies_bufsize, 277 local->hw_scan_ies_bufsize,
266 req->ie, req->ie_len, band, 278 &local->hw_scan_req->ies,
267 req->rates[band], &chandef); 279 req->ie, req->ie_len,
268 local->hw_scan_req->ie_len = ielen; 280 bands_used, req->rates, &chandef);
269 local->hw_scan_req->no_cck = req->no_cck; 281 local->hw_scan_req->req.ie_len = ielen;
282 local->hw_scan_req->req.no_cck = req->no_cck;
270 283
271 return true; 284 return true;
272} 285}
@@ -291,7 +304,9 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
291 if (WARN_ON(!local->scan_req)) 304 if (WARN_ON(!local->scan_req))
292 return; 305 return;
293 306
294 if (hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { 307 if (hw_scan && !aborted &&
308 !(local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) &&
309 ieee80211_prep_hw_scan(local)) {
295 int rc; 310 int rc;
296 311
297 rc = drv_hw_scan(local, 312 rc = drv_hw_scan(local,
@@ -473,6 +488,21 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
473 u8 *ies; 488 u8 *ies;
474 489
475 local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len; 490 local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len;
491
492 if (local->hw.flags & IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS) {
493 int i, n_bands = 0;
494 u8 bands_counted = 0;
495
496 for (i = 0; i < req->n_channels; i++) {
497 if (bands_counted & BIT(req->channels[i]->band))
498 continue;
499 bands_counted |= BIT(req->channels[i]->band);
500 n_bands++;
501 }
502
503 local->hw_scan_ies_bufsize *= n_bands;
504 }
505
476 local->hw_scan_req = kmalloc( 506 local->hw_scan_req = kmalloc(
477 sizeof(*local->hw_scan_req) + 507 sizeof(*local->hw_scan_req) +
478 req->n_channels * sizeof(req->channels[0]) + 508 req->n_channels * sizeof(req->channels[0]) +
@@ -480,13 +510,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
480 if (!local->hw_scan_req) 510 if (!local->hw_scan_req)
481 return -ENOMEM; 511 return -ENOMEM;
482 512
483 local->hw_scan_req->ssids = req->ssids; 513 local->hw_scan_req->req.ssids = req->ssids;
484 local->hw_scan_req->n_ssids = req->n_ssids; 514 local->hw_scan_req->req.n_ssids = req->n_ssids;
485 ies = (u8 *)local->hw_scan_req + 515 ies = (u8 *)local->hw_scan_req +
486 sizeof(*local->hw_scan_req) + 516 sizeof(*local->hw_scan_req) +
487 req->n_channels * sizeof(req->channels[0]); 517 req->n_channels * sizeof(req->channels[0]);
488 local->hw_scan_req->ie = ies; 518 local->hw_scan_req->req.ie = ies;
489 local->hw_scan_req->flags = req->flags; 519 local->hw_scan_req->req.flags = req->flags;
490 520
491 local->hw_scan_band = 0; 521 local->hw_scan_band = 0;
492 522
@@ -973,9 +1003,13 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
973 struct cfg80211_sched_scan_request *req) 1003 struct cfg80211_sched_scan_request *req)
974{ 1004{
975 struct ieee80211_local *local = sdata->local; 1005 struct ieee80211_local *local = sdata->local;
976 struct ieee80211_sched_scan_ies sched_scan_ies = {}; 1006 struct ieee80211_scan_ies sched_scan_ies = {};
977 struct cfg80211_chan_def chandef; 1007 struct cfg80211_chan_def chandef;
978 int ret, i, iebufsz; 1008 int ret, i, iebufsz, num_bands = 0;
1009 u32 rate_masks[IEEE80211_NUM_BANDS] = {};
1010 u8 bands_used = 0;
1011 u8 *ie;
1012 size_t len;
979 1013
980 iebufsz = local->scan_ies_len + req->ie_len; 1014 iebufsz = local->scan_ies_len + req->ie_len;
981 1015
@@ -985,33 +1019,35 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
985 return -ENOTSUPP; 1019 return -ENOTSUPP;
986 1020
987 for (i = 0; i < IEEE80211_NUM_BANDS; i++) { 1021 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
988 if (!local->hw.wiphy->bands[i]) 1022 if (local->hw.wiphy->bands[i]) {
989 continue; 1023 bands_used |= BIT(i);
990 1024 rate_masks[i] = (u32) -1;
991 sched_scan_ies.ie[i] = kzalloc(iebufsz, GFP_KERNEL); 1025 num_bands++;
992 if (!sched_scan_ies.ie[i]) {
993 ret = -ENOMEM;
994 goto out_free;
995 } 1026 }
1027 }
996 1028
997 ieee80211_prepare_scan_chandef(&chandef, req->scan_width); 1029 ie = kzalloc(num_bands * iebufsz, GFP_KERNEL);
998 1030 if (!ie) {
999 sched_scan_ies.len[i] = 1031 ret = -ENOMEM;
1000 ieee80211_build_preq_ies(local, sched_scan_ies.ie[i], 1032 goto out;
1001 iebufsz, req->ie, req->ie_len,
1002 i, (u32) -1, &chandef);
1003 } 1033 }
1004 1034
1035 ieee80211_prepare_scan_chandef(&chandef, req->scan_width);
1036
1037 len = ieee80211_build_preq_ies(local, ie, num_bands * iebufsz,
1038 &sched_scan_ies, req->ie,
1039 req->ie_len, bands_used,
1040 rate_masks, &chandef);
1041
1005 ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); 1042 ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
1006 if (ret == 0) { 1043 if (ret == 0) {
1007 rcu_assign_pointer(local->sched_scan_sdata, sdata); 1044 rcu_assign_pointer(local->sched_scan_sdata, sdata);
1008 local->sched_scan_req = req; 1045 local->sched_scan_req = req;
1009 } 1046 }
1010 1047
1011out_free: 1048 kfree(ie);
1012 while (i > 0)
1013 kfree(sched_scan_ies.ie[--i]);
1014 1049
1050out:
1015 if (ret) { 1051 if (ret) {
1016 /* Clean in case of failure after HW restart or upon resume. */ 1052 /* Clean in case of failure after HW restart or upon resume. */
1017 RCU_INIT_POINTER(local->sched_scan_sdata, NULL); 1053 RCU_INIT_POINTER(local->sched_scan_sdata, NULL);