aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ti/wl18xx/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ti/wl18xx/scan.c')
-rw-r--r--drivers/net/wireless/ti/wl18xx/scan.c326
1 files changed, 326 insertions, 0 deletions
diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c
new file mode 100644
index 000000000000..09d944505ac0
--- /dev/null
+++ b/drivers/net/wireless/ti/wl18xx/scan.c
@@ -0,0 +1,326 @@
1/*
2 * This file is part of wl18xx
3 *
4 * Copyright (C) 2012 Texas Instruments. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 *
20 */
21
22#include <linux/ieee80211.h>
23#include "scan.h"
24#include "../wlcore/debug.h"
25
26static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
27 struct wlcore_scan_channels *cmd_channels)
28{
29 memcpy(cmd->passive, cmd_channels->passive, sizeof(cmd->passive));
30 memcpy(cmd->active, cmd_channels->active, sizeof(cmd->active));
31 cmd->dfs = cmd_channels->dfs;
32 cmd->passive_active = cmd_channels->passive_active;
33
34 memcpy(cmd->channels_2, cmd_channels->channels_2,
35 sizeof(cmd->channels_2));
36 memcpy(cmd->channels_5, cmd_channels->channels_5,
37 sizeof(cmd->channels_2));
38 /* channels_4 are not supported, so no need to copy them */
39}
40
41static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif,
42 struct cfg80211_scan_request *req)
43{
44 struct wl18xx_cmd_scan_params *cmd;
45 struct wlcore_scan_channels *cmd_channels = NULL;
46 int ret;
47
48 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
49 if (!cmd) {
50 ret = -ENOMEM;
51 goto out;
52 }
53
54 cmd->role_id = wlvif->role_id;
55
56 if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
57 ret = -EINVAL;
58 goto out;
59 }
60
61 cmd->scan_type = SCAN_TYPE_SEARCH;
62 cmd->rssi_threshold = -127;
63 cmd->snr_threshold = 0;
64
65 cmd->bss_type = SCAN_BSS_TYPE_ANY;
66
67 cmd->ssid_from_list = 0;
68 cmd->filter = 0;
69 cmd->add_broadcast = 0;
70
71 cmd->urgency = 0;
72 cmd->protect = 0;
73
74 cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs;
75 cmd->terminate_after = 0;
76
77 /* configure channels */
78 WARN_ON(req->n_ssids > 1);
79
80 cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
81 if (!cmd_channels) {
82 ret = -ENOMEM;
83 goto out;
84 }
85
86 wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
87 req->n_channels, req->n_ssids,
88 SCAN_TYPE_SEARCH);
89 wl18xx_adjust_channels(cmd, cmd_channels);
90
91 /*
92 * all the cycles params (except total cycles) should
93 * remain 0 for normal scan
94 */
95 cmd->total_cycles = 1;
96
97 if (req->no_cck)
98 cmd->rate = WL18XX_SCAN_RATE_6;
99
100 cmd->tag = WL1271_SCAN_DEFAULT_TAG;
101
102 if (req->n_ssids) {
103 cmd->ssid_len = req->ssids[0].ssid_len;
104 memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len);
105 }
106
107 /* TODO: per-band ies? */
108 if (cmd->active[0]) {
109 u8 band = IEEE80211_BAND_2GHZ;
110 ret = wl12xx_cmd_build_probe_req(wl, wlvif,
111 cmd->role_id, band,
112 req->ssids ? req->ssids[0].ssid : NULL,
113 req->ssids ? req->ssids[0].ssid_len : 0,
114 req->ie,
115 req->ie_len,
116 false);
117 if (ret < 0) {
118 wl1271_error("2.4GHz PROBE request template failed");
119 goto out;
120 }
121 }
122
123 if (cmd->active[1] || cmd->dfs) {
124 u8 band = IEEE80211_BAND_5GHZ;
125 ret = wl12xx_cmd_build_probe_req(wl, wlvif,
126 cmd->role_id, band,
127 req->ssids ? req->ssids[0].ssid : NULL,
128 req->ssids ? req->ssids[0].ssid_len : 0,
129 req->ie,
130 req->ie_len,
131 false);
132 if (ret < 0) {
133 wl1271_error("5GHz PROBE request template failed");
134 goto out;
135 }
136 }
137
138 wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
139
140 ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
141 if (ret < 0) {
142 wl1271_error("SCAN failed");
143 goto out;
144 }
145
146out:
147 kfree(cmd_channels);
148 kfree(cmd);
149 return ret;
150}
151
152void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif)
153{
154 wl->scan.failed = false;
155 cancel_delayed_work(&wl->scan_complete_work);
156 ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
157 msecs_to_jiffies(0));
158}
159
160static
161int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
162 struct wl12xx_vif *wlvif,
163 struct cfg80211_sched_scan_request *req,
164 struct ieee80211_sched_scan_ies *ies)
165{
166 struct wl18xx_cmd_scan_params *cmd;
167 struct wlcore_scan_channels *cmd_channels = NULL;
168 struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
169 int ret;
170 int filter_type;
171
172 wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
173
174 filter_type = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
175 if (filter_type < 0)
176 return filter_type;
177
178 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
179 if (!cmd) {
180 ret = -ENOMEM;
181 goto out;
182 }
183
184 cmd->role_id = wlvif->role_id;
185
186 if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
187 ret = -EINVAL;
188 goto out;
189 }
190
191 cmd->scan_type = SCAN_TYPE_PERIODIC;
192 cmd->rssi_threshold = c->rssi_threshold;
193 cmd->snr_threshold = c->snr_threshold;
194
195 /* don't filter on BSS type */
196 cmd->bss_type = SCAN_BSS_TYPE_ANY;
197
198 cmd->ssid_from_list = 1;
199 if (filter_type == SCAN_SSID_FILTER_LIST)
200 cmd->filter = 1;
201 cmd->add_broadcast = 0;
202
203 cmd->urgency = 0;
204 cmd->protect = 0;
205
206 cmd->n_probe_reqs = c->num_probe_reqs;
207 /* don't stop scanning automatically when something is found */
208 cmd->terminate_after = 0;
209
210 cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
211 if (!cmd_channels) {
212 ret = -ENOMEM;
213 goto out;
214 }
215
216 /* configure channels */
217 wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
218 req->n_channels, req->n_ssids,
219 SCAN_TYPE_PERIODIC);
220 wl18xx_adjust_channels(cmd, cmd_channels);
221
222 cmd->short_cycles_sec = 0;
223 cmd->long_cycles_sec = cpu_to_le16(req->interval);
224 cmd->short_cycles_count = 0;
225
226 cmd->total_cycles = 0;
227
228 cmd->tag = WL1271_SCAN_DEFAULT_TAG;
229
230 /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */
231 cmd->report_threshold = 1;
232 cmd->terminate_on_report = 0;
233
234 if (cmd->active[0]) {
235 u8 band = IEEE80211_BAND_2GHZ;
236 ret = wl12xx_cmd_build_probe_req(wl, wlvif,
237 cmd->role_id, band,
238 req->ssids ? req->ssids[0].ssid : NULL,
239 req->ssids ? req->ssids[0].ssid_len : 0,
240 ies->ie[band],
241 ies->len[band],
242 true);
243 if (ret < 0) {
244 wl1271_error("2.4GHz PROBE request template failed");
245 goto out;
246 }
247 }
248
249 if (cmd->active[1] || cmd->dfs) {
250 u8 band = IEEE80211_BAND_5GHZ;
251 ret = wl12xx_cmd_build_probe_req(wl, wlvif,
252 cmd->role_id, band,
253 req->ssids ? req->ssids[0].ssid : NULL,
254 req->ssids ? req->ssids[0].ssid_len : 0,
255 ies->ie[band],
256 ies->len[band],
257 true);
258 if (ret < 0) {
259 wl1271_error("5GHz PROBE request template failed");
260 goto out;
261 }
262 }
263
264 wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
265
266 ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
267 if (ret < 0) {
268 wl1271_error("SCAN failed");
269 goto out;
270 }
271
272out:
273 kfree(cmd_channels);
274 kfree(cmd);
275 return ret;
276}
277
278int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
279 struct cfg80211_sched_scan_request *req,
280 struct ieee80211_sched_scan_ies *ies)
281{
282 return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies);
283}
284
285static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif,
286 u8 scan_type)
287{
288 struct wl18xx_cmd_scan_stop *stop;
289 int ret;
290
291 wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
292
293 stop = kzalloc(sizeof(*stop), GFP_KERNEL);
294 if (!stop) {
295 wl1271_error("failed to alloc memory to send sched scan stop");
296 return -ENOMEM;
297 }
298
299 stop->role_id = wlvif->role_id;
300 stop->scan_type = scan_type;
301
302 ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0);
303 if (ret < 0) {
304 wl1271_error("failed to send sched scan stop command");
305 goto out_free;
306 }
307
308out_free:
309 kfree(stop);
310 return ret;
311}
312
313void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
314{
315 __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC);
316}
317int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
318 struct cfg80211_scan_request *req)
319{
320 return wl18xx_scan_send(wl, wlvif, req);
321}
322
323int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
324{
325 return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH);
326}