aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorLuciano Coelho <coelho@ti.com>2011-05-10 07:38:59 -0400
committerLuciano Coelho <coelho@ti.com>2011-05-12 17:06:33 -0400
commit95feadca6dca909ae0f6e65665b782c7ca9d5122 (patch)
tree5d76b5ef0e4c8e451a9e6009d3afde5c2ca70487 /drivers/net
parent6394c01b61f8ab66a6af1a24ff05f2429130afcd (diff)
wl12xx: add scheduled scan structures and commands
Add firmware command structures, definitions and code to to configure, start and stop scheduled scans. Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/wl12xx/scan.c233
-rw-r--r--drivers/net/wireless/wl12xx/scan.h114
2 files changed, 347 insertions, 0 deletions
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index 5d0544c8f3f5..d78044f00810 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -320,3 +320,236 @@ 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 start = kzalloc(sizeof(*start), GFP_KERNEL);
509 if (!start)
510 return -ENOMEM;
511
512 start->tag = WL1271_SCAN_DEFAULT_TAG;
513
514 ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
515 sizeof(*start), 0);
516 if (ret < 0) {
517 wl1271_error("failed to send scan start command");
518 goto out_free;
519 }
520
521out_free:
522 kfree(start);
523 return ret;
524}
525
526void wl1271_scan_sched_scan_results(struct wl1271 *wl)
527{
528 wl1271_debug(DEBUG_SCAN, "got periodic scan results");
529
530 ieee80211_sched_scan_results(wl->hw);
531}
532
533void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
534{
535 struct wl1271_cmd_sched_scan_stop *stop;
536 int ret = 0;
537
538 wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
539
540 /* FIXME: what to do if alloc'ing to stop fails? */
541 stop = kzalloc(sizeof(*stop), GFP_KERNEL);
542 if (!stop) {
543 wl1271_error("failed to alloc memory to send sched scan stop");
544 return;
545 }
546
547 stop->tag = WL1271_SCAN_DEFAULT_TAG;
548
549 ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
550 sizeof(*stop), 0);
551 if (ret < 0)
552 wl1271_error("failed to send sched scan stop command");
553
554 kfree(stop);
555}
diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h
index 421a750add5a..c83319579ca3 100644
--- a/drivers/net/wireless/wl12xx/scan.h
+++ b/drivers/net/wireless/wl12xx/scan.h
@@ -33,6 +33,12 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl,
33 const u8 *ie, size_t ie_len, u8 band); 33 const u8 *ie, size_t ie_len, u8 band);
34void wl1271_scan_stm(struct wl1271 *wl); 34void wl1271_scan_stm(struct wl1271 *wl);
35void wl1271_scan_complete_work(struct work_struct *work); 35void wl1271_scan_complete_work(struct work_struct *work);
36int wl1271_scan_sched_scan_config(struct wl1271 *wl,
37 struct cfg80211_sched_scan_request *req,
38 struct ieee80211_sched_scan_ies *ies);
39int wl1271_scan_sched_scan_start(struct wl1271 *wl);
40void wl1271_scan_sched_scan_stop(struct wl1271 *wl);
41void wl1271_scan_sched_scan_results(struct wl1271 *wl);
36 42
37#define WL1271_SCAN_MAX_CHANNELS 24 43#define WL1271_SCAN_MAX_CHANNELS 24
38#define WL1271_SCAN_DEFAULT_TAG 1 44#define WL1271_SCAN_DEFAULT_TAG 1
@@ -106,4 +112,112 @@ struct wl1271_cmd_trigger_scan_to {
106 __le32 timeout; 112 __le32 timeout;
107} __packed; 113} __packed;
108 114
115#define MAX_CHANNELS_ALL_BANDS 41
116#define SCAN_MAX_CYCLE_INTERVALS 16
117#define SCAN_MAX_BANDS 3
118
119enum {
120 SCAN_CHANNEL_TYPE_2GHZ_PASSIVE,
121 SCAN_CHANNEL_TYPE_2GHZ_ACTIVE,
122 SCAN_CHANNEL_TYPE_5GHZ_PASSIVE,
123 SCAN_CHANNEL_TYPE_5GHZ_ACTIVE,
124 SCAN_CHANNEL_TYPE_5GHZ_DFS,
125};
126
127enum {
128 SCAN_SSID_FILTER_ANY = 0,
129 SCAN_SSID_FILTER_SPECIFIC = 1,
130 SCAN_SSID_FILTER_LIST = 2,
131 SCAN_SSID_FILTER_DISABLED = 3
132};
133
134enum {
135 SCAN_BSS_TYPE_INDEPENDENT,
136 SCAN_BSS_TYPE_INFRASTRUCTURE,
137 SCAN_BSS_TYPE_ANY,
138};
139
140struct conn_scan_ch_params {
141 __le16 min_duration;
142 __le16 max_duration;
143 __le16 passive_duration;
144
145 u8 channel;
146 u8 tx_power_att;
147
148 /* bit 0: DFS channel; bit 1: DFS enabled */
149 u8 flags;
150
151 u8 padding[3];
152} __packed;
153
154struct wl1271_cmd_sched_scan_config {
155 struct wl1271_cmd_header header;
156
157 __le32 intervals[SCAN_MAX_CYCLE_INTERVALS];
158
159 s8 rssi_threshold; /* for filtering (in dBm) */
160 s8 snr_threshold; /* for filtering (in dB) */
161
162 u8 cycles; /* maximum number of scan cycles */
163 u8 report_after; /* report when this number of results are received */
164 u8 terminate; /* stop scanning after reporting */
165
166 u8 tag;
167 u8 bss_type; /* for filtering */
168 u8 filter_type;
169
170 u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */
171 u8 ssid[IW_ESSID_MAX_SIZE];
172
173 u8 n_probe_reqs; /* Number of probes requests per channel */
174
175 u8 passive[SCAN_MAX_BANDS];
176 u8 active[SCAN_MAX_BANDS];
177
178 u8 dfs;
179
180 u8 padding[3];
181
182 struct conn_scan_ch_params channels[MAX_CHANNELS_ALL_BANDS];
183} __packed;
184
185
186#define SCHED_SCAN_MAX_SSIDS 8
187
188enum {
189 SCAN_SSID_TYPE_PUBLIC = 0,
190 SCAN_SSID_TYPE_HIDDEN = 1,
191};
192
193struct wl1271_ssid {
194 u8 type;
195 u8 len;
196 u8 ssid[IW_ESSID_MAX_SIZE];
197 /* u8 padding[2]; */
198} __packed;
199
200struct wl1271_cmd_sched_scan_ssid_list {
201 struct wl1271_cmd_header header;
202
203 u8 n_ssids;
204 struct wl1271_ssid ssids[SCHED_SCAN_MAX_SSIDS];
205 u8 padding[3];
206} __packed;
207
208struct wl1271_cmd_sched_scan_start {
209 struct wl1271_cmd_header header;
210
211 u8 tag;
212 u8 padding[3];
213} __packed;
214
215struct wl1271_cmd_sched_scan_stop {
216 struct wl1271_cmd_header header;
217
218 u8 tag;
219 u8 padding[3];
220} __packed;
221
222
109#endif /* __WL1271_SCAN_H__ */ 223#endif /* __WL1271_SCAN_H__ */