aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/wl12xx/scan.c')
-rw-r--r--drivers/net/wireless/wl12xx/scan.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index 5d0544c8f3f..f37e5a39197 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -320,3 +320,246 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
320 320
321 return 0; 321 return 0;
322} 322}
323
324static int
325wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
326 struct cfg80211_sched_scan_request *req,
327 struct conn_scan_ch_params *channels,
328 u32 band, bool radar, bool passive,
329 int start)
330{
331 struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
332 int i, j;
333 u32 flags;
334
335 for (i = 0, j = start;
336 i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS;
337 i++) {
338 flags = req->channels[i]->flags;
339
340 if (!(flags & IEEE80211_CHAN_DISABLED) &&
341 ((flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive) &&
342 ((flags & IEEE80211_CHAN_RADAR) == radar) &&
343 (req->channels[i]->band == band)) {
344 wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
345 req->channels[i]->band,
346 req->channels[i]->center_freq);
347 wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
348 req->channels[i]->hw_value,
349 req->channels[i]->flags);
350 wl1271_debug(DEBUG_SCAN, "max_power %d",
351 req->channels[i]->max_power);
352
353 if (flags & IEEE80211_CHAN_PASSIVE_SCAN) {
354 channels[j].passive_duration =
355 cpu_to_le16(c->dwell_time_passive);
356 } else {
357 channels[j].min_duration =
358 cpu_to_le16(c->min_dwell_time_active);
359 channels[j].max_duration =
360 cpu_to_le16(c->max_dwell_time_active);
361 }
362 channels[j].tx_power_att = req->channels[j]->max_power;
363 channels[j].channel = req->channels[i]->hw_value;
364
365 j++;
366 }
367 }
368
369 return j - start;
370}
371
372static int
373wl1271_scan_sched_scan_channels(struct wl1271 *wl,
374 struct cfg80211_sched_scan_request *req,
375 struct wl1271_cmd_sched_scan_config *cfg)
376{
377 int idx = 0;
378
379 cfg->passive[0] =
380 wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
381 IEEE80211_BAND_2GHZ,
382 false, true, idx);
383 idx += cfg->passive[0];
384
385 cfg->active[0] =
386 wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
387 IEEE80211_BAND_2GHZ,
388 false, false, idx);
389 idx += cfg->active[0];
390
391 cfg->passive[1] =
392 wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
393 IEEE80211_BAND_5GHZ,
394 false, true, idx);
395 idx += cfg->passive[1];
396
397 cfg->active[1] =
398 wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
399 IEEE80211_BAND_5GHZ,
400 false, false, 14);
401 idx += cfg->active[1];
402
403 cfg->dfs =
404 wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
405 IEEE80211_BAND_5GHZ,
406 true, false, idx);
407 idx += cfg->dfs;
408
409 wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d",
410 cfg->active[0], cfg->passive[0]);
411 wl1271_debug(DEBUG_SCAN, " 5GHz: active %d passive %d",
412 cfg->active[1], cfg->passive[1]);
413
414 return idx;
415}
416
417int wl1271_scan_sched_scan_config(struct wl1271 *wl,
418 struct cfg80211_sched_scan_request *req,
419 struct ieee80211_sched_scan_ies *ies)
420{
421 struct wl1271_cmd_sched_scan_config *cfg = NULL;
422 struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
423 int i, total_channels, ret;
424
425 wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
426
427 cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
428 if (!cfg)
429 return -ENOMEM;
430
431 cfg->rssi_threshold = c->rssi_threshold;
432 cfg->snr_threshold = c->snr_threshold;
433 cfg->n_probe_reqs = c->num_probe_reqs;
434 /* cycles set to 0 it means infinite (until manually stopped) */
435 cfg->cycles = 0;
436 /* report APs when at least 1 is found */
437 cfg->report_after = 1;
438 /* don't stop scanning automatically when something is found */
439 cfg->terminate = 0;
440 cfg->tag = WL1271_SCAN_DEFAULT_TAG;
441 /* don't filter on BSS type */
442 cfg->bss_type = SCAN_BSS_TYPE_ANY;
443 /* currently NL80211 supports only a single interval */
444 for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
445 cfg->intervals[i] = cpu_to_le32(req->interval);
446
447 if (req->ssids[0].ssid_len && req->ssids[0].ssid) {
448 cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC;
449 cfg->ssid_len = req->ssids[0].ssid_len;
450 memcpy(cfg->ssid, req->ssids[0].ssid,
451 req->ssids[0].ssid_len);
452 } else {
453 cfg->filter_type = SCAN_SSID_FILTER_ANY;
454 cfg->ssid_len = 0;
455 }
456
457 total_channels = wl1271_scan_sched_scan_channels(wl, req, cfg);
458 if (total_channels == 0) {
459 wl1271_error("scan channel list is empty");
460 ret = -EINVAL;
461 goto out;
462 }
463
464 if (cfg->active[0]) {
465 ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
466 req->ssids[0].ssid_len,
467 ies->ie[IEEE80211_BAND_2GHZ],
468 ies->len[IEEE80211_BAND_2GHZ],
469 IEEE80211_BAND_2GHZ);
470 if (ret < 0) {
471 wl1271_error("2.4GHz PROBE request template failed");
472 goto out;
473 }
474 }
475
476 if (cfg->active[1]) {
477 ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
478 req->ssids[0].ssid_len,
479 ies->ie[IEEE80211_BAND_5GHZ],
480 ies->len[IEEE80211_BAND_5GHZ],
481 IEEE80211_BAND_5GHZ);
482 if (ret < 0) {
483 wl1271_error("5GHz PROBE request template failed");
484 goto out;
485 }
486 }
487
488 wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg));
489
490 ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg,
491 sizeof(*cfg), 0);
492 if (ret < 0) {
493 wl1271_error("SCAN configuration failed");
494 goto out;
495 }
496out:
497 kfree(cfg);
498 return ret;
499}
500
501int wl1271_scan_sched_scan_start(struct wl1271 *wl)
502{
503 struct wl1271_cmd_sched_scan_start *start;
504 int ret = 0;
505
506 wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
507
508 if (wl->bss_type != BSS_TYPE_STA_BSS)
509 return -EOPNOTSUPP;
510
511 if (!test_bit(WL1271_FLAG_IDLE, &wl->flags))
512 return -EBUSY;
513
514 start = kzalloc(sizeof(*start), GFP_KERNEL);
515 if (!start)
516 return -ENOMEM;
517
518 start->tag = WL1271_SCAN_DEFAULT_TAG;
519
520 ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
521 sizeof(*start), 0);
522 if (ret < 0) {
523 wl1271_error("failed to send scan start command");
524 goto out_free;
525 }
526
527out_free:
528 kfree(start);
529 return ret;
530}
531
532void wl1271_scan_sched_scan_results(struct wl1271 *wl)
533{
534 wl1271_debug(DEBUG_SCAN, "got periodic scan results");
535
536 ieee80211_sched_scan_results(wl->hw);
537}
538
539void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
540{
541 struct wl1271_cmd_sched_scan_stop *stop;
542 int ret = 0;
543
544 wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
545
546 /* FIXME: what to do if alloc'ing to stop fails? */
547 stop = kzalloc(sizeof(*stop), GFP_KERNEL);
548 if (!stop) {
549 wl1271_error("failed to alloc memory to send sched scan stop");
550 return;
551 }
552
553 stop->tag = WL1271_SCAN_DEFAULT_TAG;
554
555 ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
556 sizeof(*stop), 0);
557 if (ret < 0) {
558 wl1271_error("failed to send sched scan stop command");
559 goto out_free;
560 }
561 wl->sched_scanning = false;
562
563out_free:
564 kfree(stop);
565}