~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/net/wireless/wl12xx/scan.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
#include "cmd.h"
28
28
#include "scan.h"
29
29
#include "acx.h"
 
30
#include "ps.h"
30
31
 
31
32
void wl1271_scan_complete_work(struct work_struct *work)
32
33
{
40
41
 
41
42
        mutex_lock(&wl->mutex);
42
43
 
43
 
        if (wl->scan.state == WL1271_SCAN_STATE_IDLE) {
44
 
                mutex_unlock(&wl->mutex);
45
 
                return;
46
 
        }
 
44
        if (wl->state == WL1271_STATE_OFF)
 
45
                goto out;
 
46
 
 
47
        if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
 
48
                goto out;
47
49
 
48
50
        wl->scan.state = WL1271_SCAN_STATE_IDLE;
49
 
        kfree(wl->scan.scanned_ch);
50
 
        wl->scan.scanned_ch = NULL;
 
51
        memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
51
52
        wl->scan.req = NULL;
52
53
        ieee80211_scan_completed(wl->hw, false);
53
54
 
54
55
        /* restore hardware connection monitoring template */
55
 
        if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
56
 
                wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
 
56
        if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
 
57
                if (wl1271_ps_elp_wakeup(wl) == 0) {
 
58
                        wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
 
59
                        wl1271_ps_elp_sleep(wl);
 
60
                }
 
61
        }
57
62
 
58
63
        if (wl->scan.failed) {
59
64
                wl1271_info("Scan completed due to error.");
60
65
                ieee80211_queue_work(wl->hw, &wl->recovery_work);
61
66
        }
 
67
 
 
68
out:
62
69
        mutex_unlock(&wl->mutex);
63
70
 
64
71
}
79
86
 
80
87
                flags = req->channels[i]->flags;
81
88
 
82
 
                if (!wl->scan.scanned_ch[i] &&
 
89
                if (!test_bit(i, wl->scan.scanned_ch) &&
83
90
                    !(flags & IEEE80211_CHAN_DISABLED) &&
84
91
                    ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
85
92
                    (req->channels[i]->band == band)) {
116
123
                        memset(&channels[j].bssid_msb, 0xff, 2);
117
124
 
118
125
                        /* Mark the channels we already used */
119
 
                        wl->scan.scanned_ch[i] = true;
 
126
                        set_bit(i, wl->scan.scanned_ch);
120
127
 
121
128
                        j++;
122
129
                }
283
290
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
284
291
                struct cfg80211_scan_request *req)
285
292
{
 
293
        /*
 
294
         * cfg80211 should guarantee that we don't get more channels
 
295
         * than what we have registered.
 
296
         */
 
297
        BUG_ON(req->n_channels > WL1271_MAX_CHANNELS);
 
298
 
286
299
        if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
287
300
                return -EBUSY;
288
301
 
296
309
        }
297
310
 
298
311
        wl->scan.req = req;
 
312
        memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
299
313
 
300
 
        wl->scan.scanned_ch = kcalloc(req->n_channels,
301
 
                                      sizeof(*wl->scan.scanned_ch),
302
 
                                      GFP_KERNEL);
303
314
        /* we assume failure so that timeout scenarios are handled correctly */
304
315
        wl->scan.failed = true;
305
316
        ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
309
320
 
310
321
        return 0;
311
322
}
 
323
 
 
324
static int
 
325
wl1271_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
        bool force_passive = !req->n_ssids;
 
335
 
 
336
        for (i = 0, j = start;
 
337
             i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS;
 
338
             i++) {
 
339
                flags = req->channels[i]->flags;
 
340
 
 
341
                if (force_passive)
 
342
                        flags |= IEEE80211_CHAN_PASSIVE_SCAN;
 
343
 
 
344
                if ((req->channels[i]->band == band) &&
 
345
                    !(flags & IEEE80211_CHAN_DISABLED) &&
 
346
                    (!!(flags & IEEE80211_CHAN_RADAR) == radar) &&
 
347
                    /* if radar is set, we ignore the passive flag */
 
348
                    (radar ||
 
349
                     !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
 
350
                        wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
 
351
                                     req->channels[i]->band,
 
352
                                     req->channels[i]->center_freq);
 
353
                        wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
 
354
                                     req->channels[i]->hw_value,
 
355
                                     req->channels[i]->flags);
 
356
                        wl1271_debug(DEBUG_SCAN, "max_power %d",
 
357
                                     req->channels[i]->max_power);
 
358
 
 
359
                        if (flags & IEEE80211_CHAN_RADAR) {
 
360
                                channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
 
361
                                channels[j].passive_duration =
 
362
                                        cpu_to_le16(c->dwell_time_dfs);
 
363
                        }
 
364
                        else if (flags & IEEE80211_CHAN_PASSIVE_SCAN) {
 
365
                                channels[j].passive_duration =
 
366
                                        cpu_to_le16(c->dwell_time_passive);
 
367
                        } else {
 
368
                                channels[j].min_duration =
 
369
                                        cpu_to_le16(c->min_dwell_time_active);
 
370
                                channels[j].max_duration =
 
371
                                        cpu_to_le16(c->max_dwell_time_active);
 
372
                        }
 
373
                        channels[j].tx_power_att = req->channels[i]->max_power;
 
374
                        channels[j].channel = req->channels[i]->hw_value;
 
375
 
 
376
                        j++;
 
377
                }
 
378
        }
 
379
 
 
380
        return j - start;
 
381
}
 
382
 
 
383
static int
 
384
wl1271_scan_sched_scan_channels(struct wl1271 *wl,
 
385
                                struct cfg80211_sched_scan_request *req,
 
386
                                struct wl1271_cmd_sched_scan_config *cfg)
 
387
{
 
388
        int idx = 0;
 
389
 
 
390
        cfg->passive[0] =
 
391
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
 
392
                                                    IEEE80211_BAND_2GHZ,
 
393
                                                    false, true, idx);
 
394
        idx += cfg->passive[0];
 
395
 
 
396
        cfg->active[0] =
 
397
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
 
398
                                                    IEEE80211_BAND_2GHZ,
 
399
                                                    false, false, idx);
 
400
        /*
 
401
         * 5GHz channels always start at position 14, not immediately
 
402
         * after the last 2.4GHz channel
 
403
         */
 
404
        idx = 14;
 
405
 
 
406
        cfg->passive[1] =
 
407
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
 
408
                                                    IEEE80211_BAND_5GHZ,
 
409
                                                    false, true, idx);
 
410
        idx += cfg->passive[1];
 
411
 
 
412
        cfg->dfs =
 
413
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
 
414
                                                    IEEE80211_BAND_5GHZ,
 
415
                                                    true, true, idx);
 
416
        idx += cfg->dfs;
 
417
 
 
418
        cfg->active[1] =
 
419
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
 
420
                                                    IEEE80211_BAND_5GHZ,
 
421
                                                    false, false, idx);
 
422
        idx += cfg->active[1];
 
423
 
 
424
        wl1271_debug(DEBUG_SCAN, "    2.4GHz: active %d passive %d",
 
425
                     cfg->active[0], cfg->passive[0]);
 
426
        wl1271_debug(DEBUG_SCAN, "    5GHz: active %d passive %d",
 
427
                     cfg->active[1], cfg->passive[1]);
 
428
        wl1271_debug(DEBUG_SCAN, "    DFS: %d", cfg->dfs);
 
429
 
 
430
        return idx;
 
431
}
 
432
 
 
433
int wl1271_scan_sched_scan_config(struct wl1271 *wl,
 
434
                                  struct cfg80211_sched_scan_request *req,
 
435
                                  struct ieee80211_sched_scan_ies *ies)
 
436
{
 
437
        struct wl1271_cmd_sched_scan_config *cfg = NULL;
 
438
        struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
 
439
        int i, total_channels, ret;
 
440
        bool force_passive = !req->n_ssids;
 
441
 
 
442
        wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
 
443
 
 
444
        cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
 
445
        if (!cfg)
 
446
                return -ENOMEM;
 
447
 
 
448
        cfg->rssi_threshold = c->rssi_threshold;
 
449
        cfg->snr_threshold  = c->snr_threshold;
 
450
        cfg->n_probe_reqs = c->num_probe_reqs;
 
451
        /* cycles set to 0 it means infinite (until manually stopped) */
 
452
        cfg->cycles = 0;
 
453
        /* report APs when at least 1 is found */
 
454
        cfg->report_after = 1;
 
455
        /* don't stop scanning automatically when something is found */
 
456
        cfg->terminate = 0;
 
457
        cfg->tag = WL1271_SCAN_DEFAULT_TAG;
 
458
        /* don't filter on BSS type */
 
459
        cfg->bss_type = SCAN_BSS_TYPE_ANY;
 
460
        /* currently NL80211 supports only a single interval */
 
461
        for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
 
462
                cfg->intervals[i] = cpu_to_le32(req->interval);
 
463
 
 
464
        if (!force_passive && req->ssids[0].ssid_len && req->ssids[0].ssid) {
 
465
                cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC;
 
466
                cfg->ssid_len = req->ssids[0].ssid_len;
 
467
                memcpy(cfg->ssid, req->ssids[0].ssid,
 
468
                       req->ssids[0].ssid_len);
 
469
        } else {
 
470
                cfg->filter_type = SCAN_SSID_FILTER_ANY;
 
471
                cfg->ssid_len = 0;
 
472
        }
 
473
 
 
474
        total_channels = wl1271_scan_sched_scan_channels(wl, req, cfg);
 
475
        if (total_channels == 0) {
 
476
                wl1271_error("scan channel list is empty");
 
477
                ret = -EINVAL;
 
478
                goto out;
 
479
        }
 
480
 
 
481
        if (!force_passive && cfg->active[0]) {
 
482
                ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
 
483
                                                 req->ssids[0].ssid_len,
 
484
                                                 ies->ie[IEEE80211_BAND_2GHZ],
 
485
                                                 ies->len[IEEE80211_BAND_2GHZ],
 
486
                                                 IEEE80211_BAND_2GHZ);
 
487
                if (ret < 0) {
 
488
                        wl1271_error("2.4GHz PROBE request template failed");
 
489
                        goto out;
 
490
                }
 
491
        }
 
492
 
 
493
        if (!force_passive && cfg->active[1]) {
 
494
                ret = wl1271_cmd_build_probe_req(wl,  req->ssids[0].ssid,
 
495
                                                 req->ssids[0].ssid_len,
 
496
                                                 ies->ie[IEEE80211_BAND_5GHZ],
 
497
                                                 ies->len[IEEE80211_BAND_5GHZ],
 
498
                                                 IEEE80211_BAND_5GHZ);
 
499
                if (ret < 0) {
 
500
                        wl1271_error("5GHz PROBE request template failed");
 
501
                        goto out;
 
502
                }
 
503
        }
 
504
 
 
505
        wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg));
 
506
 
 
507
        ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg,
 
508
                              sizeof(*cfg), 0);
 
509
        if (ret < 0) {
 
510
                wl1271_error("SCAN configuration failed");
 
511
                goto out;
 
512
        }
 
513
out:
 
514
        kfree(cfg);
 
515
        return ret;
 
516
}
 
517
 
 
518
int wl1271_scan_sched_scan_start(struct wl1271 *wl)
 
519
{
 
520
        struct wl1271_cmd_sched_scan_start *start;
 
521
        int ret = 0;
 
522
 
 
523
        wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
 
524
 
 
525
        if (wl->bss_type != BSS_TYPE_STA_BSS)
 
526
                return -EOPNOTSUPP;
 
527
 
 
528
        if (!test_bit(WL1271_FLAG_IDLE, &wl->flags))
 
529
                return -EBUSY;
 
530
 
 
531
        start = kzalloc(sizeof(*start), GFP_KERNEL);
 
532
        if (!start)
 
533
                return -ENOMEM;
 
534
 
 
535
        start->tag = WL1271_SCAN_DEFAULT_TAG;
 
536
 
 
537
        ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
 
538
                              sizeof(*start), 0);
 
539
        if (ret < 0) {
 
540
                wl1271_error("failed to send scan start command");
 
541
                goto out_free;
 
542
        }
 
543
 
 
544
out_free:
 
545
        kfree(start);
 
546
        return ret;
 
547
}
 
548
 
 
549
void wl1271_scan_sched_scan_results(struct wl1271 *wl)
 
550
{
 
551
        wl1271_debug(DEBUG_SCAN, "got periodic scan results");
 
552
 
 
553
        ieee80211_sched_scan_results(wl->hw);
 
554
}
 
555
 
 
556
void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
 
557
{
 
558
        struct wl1271_cmd_sched_scan_stop *stop;
 
559
        int ret = 0;
 
560
 
 
561
        wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
 
562
 
 
563
        /* FIXME: what to do if alloc'ing to stop fails? */
 
564
        stop = kzalloc(sizeof(*stop), GFP_KERNEL);
 
565
        if (!stop) {
 
566
                wl1271_error("failed to alloc memory to send sched scan stop");
 
567
                return;
 
568
        }
 
569
 
 
570
        stop->tag = WL1271_SCAN_DEFAULT_TAG;
 
571
 
 
572
        ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
 
573
                              sizeof(*stop), 0);
 
574
        if (ret < 0) {
 
575
                wl1271_error("failed to send sched scan stop command");
 
576
                goto out_free;
 
577
        }
 
578
        wl->sched_scanning = false;
 
579
 
 
580
out_free:
 
581
        kfree(stop);
 
582
}