2 * This file is part of wl1271
4 * Copyright (C) 2009-2010 Nokia Corporation
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 #include <linux/ieee80211.h>
34 void wl1271_scan_complete_work(struct work_struct
*work
)
36 struct delayed_work
*dwork
;
38 struct wl12xx_vif
*wlvif
;
41 dwork
= container_of(work
, struct delayed_work
, work
);
42 wl
= container_of(dwork
, struct wl1271
, scan_complete_work
);
44 wl1271_debug(DEBUG_SCAN
, "Scanning complete");
46 mutex_lock(&wl
->mutex
);
48 if (unlikely(wl
->state
!= WLCORE_STATE_ON
))
51 if (wl
->scan
.state
== WL1271_SCAN_STATE_IDLE
)
54 wlvif
= wl
->scan_wlvif
;
57 * Rearm the tx watchdog just before idling scan. This
58 * prevents just-finished scans from triggering the watchdog
60 wl12xx_rearm_tx_watchdog_locked(wl
);
62 wl
->scan
.state
= WL1271_SCAN_STATE_IDLE
;
63 memset(wl
->scan
.scanned_ch
, 0, sizeof(wl
->scan
.scanned_ch
));
65 wl
->scan_wlvif
= NULL
;
67 ret
= wl1271_ps_elp_wakeup(wl
);
71 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED
, &wlvif
->flags
)) {
72 /* restore hardware connection monitoring template */
73 wl1271_cmd_build_ap_probe_req(wl
, wlvif
, wlvif
->probereq
);
76 wl1271_ps_elp_sleep(wl
);
78 if (wl
->scan
.failed
) {
79 wl1271_info("Scan completed due to error.");
80 wl12xx_queue_recovery_work(wl
);
83 wlcore_cmd_regdomain_config_locked(wl
);
85 ieee80211_scan_completed(wl
->hw
, false);
88 mutex_unlock(&wl
->mutex
);
92 static void wlcore_started_vifs_iter(void *data
, u8
*mac
,
93 struct ieee80211_vif
*vif
)
95 int *count
= (int *)data
;
97 if (!vif
->bss_conf
.idle
)
101 static int wlcore_count_started_vifs(struct wl1271
*wl
)
105 ieee80211_iterate_active_interfaces_atomic(wl
->hw
,
106 IEEE80211_IFACE_ITER_RESUME_ALL
,
107 wlcore_started_vifs_iter
, &count
);
112 wlcore_scan_get_channels(struct wl1271
*wl
,
113 struct ieee80211_channel
*req_channels
[],
116 struct conn_scan_ch_params
*channels
,
117 u32 band
, bool radar
, bool passive
,
118 int start
, int max_channels
,
124 bool force_passive
= !n_ssids
;
125 u32 min_dwell_time_active
, max_dwell_time_active
;
126 u32 dwell_time_passive
, dwell_time_dfs
;
128 /* configure dwell times according to scan type */
129 if (scan_type
== SCAN_TYPE_SEARCH
) {
130 struct conf_scan_settings
*c
= &wl
->conf
.scan
;
131 bool active_vif_exists
= !!wlcore_count_started_vifs(wl
);
133 min_dwell_time_active
= active_vif_exists
?
134 c
->min_dwell_time_active
:
135 c
->min_dwell_time_active_long
;
136 max_dwell_time_active
= active_vif_exists
?
137 c
->max_dwell_time_active
:
138 c
->max_dwell_time_active_long
;
139 dwell_time_passive
= c
->dwell_time_passive
;
140 dwell_time_dfs
= c
->dwell_time_dfs
;
142 struct conf_sched_scan_settings
*c
= &wl
->conf
.sched_scan
;
145 if (band
== IEEE80211_BAND_5GHZ
)
146 delta_per_probe
= c
->dwell_time_delta_per_probe_5
;
148 delta_per_probe
= c
->dwell_time_delta_per_probe
;
150 min_dwell_time_active
= c
->base_dwell_time
+
151 n_ssids
* c
->num_probe_reqs
* delta_per_probe
;
153 max_dwell_time_active
= min_dwell_time_active
+
154 c
->max_dwell_time_delta
;
155 dwell_time_passive
= c
->dwell_time_passive
;
156 dwell_time_dfs
= c
->dwell_time_dfs
;
158 min_dwell_time_active
= DIV_ROUND_UP(min_dwell_time_active
, 1000);
159 max_dwell_time_active
= DIV_ROUND_UP(max_dwell_time_active
, 1000);
160 dwell_time_passive
= DIV_ROUND_UP(dwell_time_passive
, 1000);
161 dwell_time_dfs
= DIV_ROUND_UP(dwell_time_dfs
, 1000);
163 for (i
= 0, j
= start
;
164 i
< n_channels
&& j
< max_channels
;
166 flags
= req_channels
[i
]->flags
;
169 flags
|= IEEE80211_CHAN_PASSIVE_SCAN
;
171 if ((req_channels
[i
]->band
== band
) &&
172 !(flags
& IEEE80211_CHAN_DISABLED
) &&
173 (!!(flags
& IEEE80211_CHAN_RADAR
) == radar
) &&
174 /* if radar is set, we ignore the passive flag */
176 !!(flags
& IEEE80211_CHAN_PASSIVE_SCAN
) == passive
)) {
177 wl1271_debug(DEBUG_SCAN
, "band %d, center_freq %d ",
178 req_channels
[i
]->band
,
179 req_channels
[i
]->center_freq
);
180 wl1271_debug(DEBUG_SCAN
, "hw_value %d, flags %X",
181 req_channels
[i
]->hw_value
,
182 req_channels
[i
]->flags
);
183 wl1271_debug(DEBUG_SCAN
, "max_power %d",
184 req_channels
[i
]->max_power
);
185 wl1271_debug(DEBUG_SCAN
, "min_dwell_time %d max dwell time %d",
186 min_dwell_time_active
,
187 max_dwell_time_active
);
189 if (flags
& IEEE80211_CHAN_RADAR
) {
190 channels
[j
].flags
|= SCAN_CHANNEL_FLAGS_DFS
;
192 channels
[j
].passive_duration
=
193 cpu_to_le16(dwell_time_dfs
);
195 channels
[j
].passive_duration
=
196 cpu_to_le16(dwell_time_passive
);
199 channels
[j
].min_duration
=
200 cpu_to_le16(min_dwell_time_active
);
201 channels
[j
].max_duration
=
202 cpu_to_le16(max_dwell_time_active
);
204 channels
[j
].tx_power_att
= req_channels
[i
]->max_power
;
205 channels
[j
].channel
= req_channels
[i
]->hw_value
;
208 (band
== IEEE80211_BAND_2GHZ
) &&
209 (channels
[j
].channel
>= 12) &&
210 (channels
[j
].channel
<= 14) &&
211 (flags
& IEEE80211_CHAN_PASSIVE_SCAN
) &&
213 /* pactive channels treated as DFS */
214 channels
[j
].flags
= SCAN_CHANNEL_FLAGS_DFS
;
217 * n_pactive_ch is counted down from the end of
218 * the passive channel list
221 wl1271_debug(DEBUG_SCAN
, "n_pactive_ch = %d",
233 wlcore_set_scan_chan_params(struct wl1271
*wl
,
234 struct wlcore_scan_channels
*cfg
,
235 struct ieee80211_channel
*channels
[],
243 wlcore_scan_get_channels(wl
,
254 wlcore_scan_get_channels(wl
,
266 wlcore_scan_get_channels(wl
,
277 wlcore_scan_get_channels(wl
,
289 wlcore_scan_get_channels(wl
,
296 cfg
->passive
[1] + cfg
->dfs
,
301 /* 802.11j channels are not supported yet */
305 cfg
->passive_active
= n_pactive_ch
;
307 wl1271_debug(DEBUG_SCAN
, " 2.4GHz: active %d passive %d",
308 cfg
->active
[0], cfg
->passive
[0]);
309 wl1271_debug(DEBUG_SCAN
, " 5GHz: active %d passive %d",
310 cfg
->active
[1], cfg
->passive
[1]);
311 wl1271_debug(DEBUG_SCAN
, " DFS: %d", cfg
->dfs
);
313 return cfg
->passive
[0] || cfg
->active
[0] ||
314 cfg
->passive
[1] || cfg
->active
[1] || cfg
->dfs
||
315 cfg
->passive
[2] || cfg
->active
[2];
317 EXPORT_SYMBOL_GPL(wlcore_set_scan_chan_params
);
319 int wlcore_scan(struct wl1271
*wl
, struct ieee80211_vif
*vif
,
320 const u8
*ssid
, size_t ssid_len
,
321 struct cfg80211_scan_request
*req
)
323 struct wl12xx_vif
*wlvif
= wl12xx_vif_to_data(vif
);
326 * cfg80211 should guarantee that we don't get more channels
327 * than what we have registered.
329 BUG_ON(req
->n_channels
> WL1271_MAX_CHANNELS
);
331 if (wl
->scan
.state
!= WL1271_SCAN_STATE_IDLE
)
334 wl
->scan
.state
= WL1271_SCAN_STATE_2GHZ_ACTIVE
;
336 if (ssid_len
&& ssid
) {
337 wl
->scan
.ssid_len
= ssid_len
;
338 memcpy(wl
->scan
.ssid
, ssid
, ssid_len
);
340 wl
->scan
.ssid_len
= 0;
343 wl
->scan_wlvif
= wlvif
;
345 memset(wl
->scan
.scanned_ch
, 0, sizeof(wl
->scan
.scanned_ch
));
347 /* we assume failure so that timeout scenarios are handled correctly */
348 wl
->scan
.failed
= true;
349 ieee80211_queue_delayed_work(wl
->hw
, &wl
->scan_complete_work
,
350 msecs_to_jiffies(WL1271_SCAN_TIMEOUT
));
352 wl
->ops
->scan_start(wl
, wlvif
, req
);
356 /* Returns the scan type to be used or a negative value on error */
358 wlcore_scan_sched_scan_ssid_list(struct wl1271
*wl
,
359 struct wl12xx_vif
*wlvif
,
360 struct cfg80211_sched_scan_request
*req
)
362 struct wl1271_cmd_sched_scan_ssid_list
*cmd
= NULL
;
363 struct cfg80211_match_set
*sets
= req
->match_sets
;
364 struct cfg80211_ssid
*ssids
= req
->ssids
;
365 int ret
= 0, type
, i
, j
, n_match_ssids
= 0;
367 wl1271_debug(DEBUG_CMD
, "cmd sched scan ssid list");
369 /* count the match sets that contain SSIDs */
370 for (i
= 0; i
< req
->n_match_sets
; i
++)
371 if (sets
[i
].ssid
.ssid_len
> 0)
374 /* No filter, no ssids or only bcast ssid */
375 if (!n_match_ssids
&&
377 (req
->n_ssids
== 1 && req
->ssids
[0].ssid_len
== 0))) {
378 type
= SCAN_SSID_FILTER_ANY
;
382 cmd
= kzalloc(sizeof(*cmd
), GFP_KERNEL
);
388 cmd
->role_id
= wlvif
->role_id
;
389 if (!n_match_ssids
) {
390 /* No filter, with ssids */
391 type
= SCAN_SSID_FILTER_DISABLED
;
393 for (i
= 0; i
< req
->n_ssids
; i
++) {
394 cmd
->ssids
[cmd
->n_ssids
].type
= (ssids
[i
].ssid_len
) ?
395 SCAN_SSID_TYPE_HIDDEN
: SCAN_SSID_TYPE_PUBLIC
;
396 cmd
->ssids
[cmd
->n_ssids
].len
= ssids
[i
].ssid_len
;
397 memcpy(cmd
->ssids
[cmd
->n_ssids
].ssid
, ssids
[i
].ssid
,
402 type
= SCAN_SSID_FILTER_LIST
;
404 /* Add all SSIDs from the filters */
405 for (i
= 0; i
< req
->n_match_sets
; i
++) {
406 /* ignore sets without SSIDs */
407 if (!sets
[i
].ssid
.ssid_len
)
410 cmd
->ssids
[cmd
->n_ssids
].type
= SCAN_SSID_TYPE_PUBLIC
;
411 cmd
->ssids
[cmd
->n_ssids
].len
= sets
[i
].ssid
.ssid_len
;
412 memcpy(cmd
->ssids
[cmd
->n_ssids
].ssid
,
413 sets
[i
].ssid
.ssid
, sets
[i
].ssid
.ssid_len
);
416 if ((req
->n_ssids
> 1) ||
417 (req
->n_ssids
== 1 && req
->ssids
[0].ssid_len
> 0)) {
419 * Mark all the SSIDs passed in the SSID list as HIDDEN,
420 * so they're used in probe requests.
422 for (i
= 0; i
< req
->n_ssids
; i
++) {
423 if (!req
->ssids
[i
].ssid_len
)
426 for (j
= 0; j
< cmd
->n_ssids
; j
++)
427 if ((req
->ssids
[i
].ssid_len
==
428 cmd
->ssids
[j
].len
) &&
429 !memcmp(req
->ssids
[i
].ssid
,
431 req
->ssids
[i
].ssid_len
)) {
433 SCAN_SSID_TYPE_HIDDEN
;
436 /* Fail if SSID isn't present in the filters */
437 if (j
== cmd
->n_ssids
) {
445 wl1271_dump(DEBUG_SCAN
, "SSID_LIST: ", cmd
, sizeof(*cmd
));
447 ret
= wl1271_cmd_send(wl
, CMD_CONNECTION_SCAN_SSID_CFG
, cmd
,
450 wl1271_error("cmd sched scan ssid list failed");
461 EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_ssid_list
);
463 void wlcore_scan_sched_scan_results(struct wl1271
*wl
)
465 wl1271_debug(DEBUG_SCAN
, "got periodic scan results");
467 ieee80211_sched_scan_results(wl
->hw
);
469 EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_results
);