]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/ti/wl18xx/scan.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[karo-tx-linux.git] / drivers / net / wireless / ti / wl18xx / scan.c
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
26 static 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_5));
38         /* channels_4 are not supported, so no need to copy them */
39 }
40
41 static 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         /* scan on the dev role if the regular one is not started */
55         if (wlcore_is_p2p_mgmt(wlvif))
56                 cmd->role_id = wlvif->dev_role_id;
57         else
58                 cmd->role_id = wlvif->role_id;
59
60         if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
61                 ret = -EINVAL;
62                 goto out;
63         }
64
65         cmd->scan_type = SCAN_TYPE_SEARCH;
66         cmd->rssi_threshold = -127;
67         cmd->snr_threshold = 0;
68
69         cmd->bss_type = SCAN_BSS_TYPE_ANY;
70
71         cmd->ssid_from_list = 0;
72         cmd->filter = 0;
73         cmd->add_broadcast = 0;
74
75         cmd->urgency = 0;
76         cmd->protect = 0;
77
78         cmd->n_probe_reqs = wl->conf.scan.num_probe_reqs;
79         cmd->terminate_after = 0;
80
81         /* configure channels */
82         WARN_ON(req->n_ssids > 1);
83
84         cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
85         if (!cmd_channels) {
86                 ret = -ENOMEM;
87                 goto out;
88         }
89
90         wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
91                                     req->n_channels, req->n_ssids,
92                                     SCAN_TYPE_SEARCH);
93         wl18xx_adjust_channels(cmd, cmd_channels);
94
95         /*
96          * all the cycles params (except total cycles) should
97          * remain 0 for normal scan
98          */
99         cmd->total_cycles = 1;
100
101         if (req->no_cck)
102                 cmd->rate = WL18XX_SCAN_RATE_6;
103
104         cmd->tag = WL1271_SCAN_DEFAULT_TAG;
105
106         if (req->n_ssids) {
107                 cmd->ssid_len = req->ssids[0].ssid_len;
108                 memcpy(cmd->ssid, req->ssids[0].ssid, cmd->ssid_len);
109         }
110
111         /* TODO: per-band ies? */
112         if (cmd->active[0]) {
113                 u8 band = IEEE80211_BAND_2GHZ;
114                 ret = wl12xx_cmd_build_probe_req(wl, wlvif,
115                                  cmd->role_id, band,
116                                  req->ssids ? req->ssids[0].ssid : NULL,
117                                  req->ssids ? req->ssids[0].ssid_len : 0,
118                                  req->ie,
119                                  req->ie_len,
120                                  NULL,
121                                  0,
122                                  false);
123                 if (ret < 0) {
124                         wl1271_error("2.4GHz PROBE request template failed");
125                         goto out;
126                 }
127         }
128
129         if (cmd->active[1] || cmd->dfs) {
130                 u8 band = IEEE80211_BAND_5GHZ;
131                 ret = wl12xx_cmd_build_probe_req(wl, wlvif,
132                                  cmd->role_id, band,
133                                  req->ssids ? req->ssids[0].ssid : NULL,
134                                  req->ssids ? req->ssids[0].ssid_len : 0,
135                                  req->ie,
136                                  req->ie_len,
137                                  NULL,
138                                  0,
139                                  false);
140                 if (ret < 0) {
141                         wl1271_error("5GHz PROBE request template failed");
142                         goto out;
143                 }
144         }
145
146         wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
147
148         ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
149         if (ret < 0) {
150                 wl1271_error("SCAN failed");
151                 goto out;
152         }
153
154 out:
155         kfree(cmd_channels);
156         kfree(cmd);
157         return ret;
158 }
159
160 void wl18xx_scan_completed(struct wl1271 *wl, struct wl12xx_vif *wlvif)
161 {
162         wl->scan.failed = false;
163         cancel_delayed_work(&wl->scan_complete_work);
164         ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
165                                      msecs_to_jiffies(0));
166 }
167
168 static
169 int wl18xx_scan_sched_scan_config(struct wl1271 *wl,
170                                   struct wl12xx_vif *wlvif,
171                                   struct cfg80211_sched_scan_request *req,
172                                   struct ieee80211_scan_ies *ies)
173 {
174         struct wl18xx_cmd_scan_params *cmd;
175         struct wlcore_scan_channels *cmd_channels = NULL;
176         struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
177         int ret;
178         int filter_type;
179
180         wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
181
182         filter_type = wlcore_scan_sched_scan_ssid_list(wl, wlvif, req);
183         if (filter_type < 0)
184                 return filter_type;
185
186         cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
187         if (!cmd) {
188                 ret = -ENOMEM;
189                 goto out;
190         }
191
192         cmd->role_id = wlvif->role_id;
193
194         if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) {
195                 ret = -EINVAL;
196                 goto out;
197         }
198
199         cmd->scan_type = SCAN_TYPE_PERIODIC;
200         cmd->rssi_threshold = c->rssi_threshold;
201         cmd->snr_threshold = c->snr_threshold;
202
203         /* don't filter on BSS type */
204         cmd->bss_type = SCAN_BSS_TYPE_ANY;
205
206         cmd->ssid_from_list = 1;
207         if (filter_type == SCAN_SSID_FILTER_LIST)
208                 cmd->filter = 1;
209         cmd->add_broadcast = 0;
210
211         cmd->urgency = 0;
212         cmd->protect = 0;
213
214         cmd->n_probe_reqs = c->num_probe_reqs;
215         /* don't stop scanning automatically when something is found */
216         cmd->terminate_after = 0;
217
218         cmd_channels = kzalloc(sizeof(*cmd_channels), GFP_KERNEL);
219         if (!cmd_channels) {
220                 ret = -ENOMEM;
221                 goto out;
222         }
223
224         /* configure channels */
225         wlcore_set_scan_chan_params(wl, cmd_channels, req->channels,
226                                     req->n_channels, req->n_ssids,
227                                     SCAN_TYPE_PERIODIC);
228         wl18xx_adjust_channels(cmd, cmd_channels);
229
230         if (c->num_short_intervals && c->long_interval &&
231             c->long_interval > req->scan_plans[0].interval * MSEC_PER_SEC) {
232                 cmd->short_cycles_msec =
233                         cpu_to_le16(req->scan_plans[0].interval * MSEC_PER_SEC);
234                 cmd->long_cycles_msec = cpu_to_le16(c->long_interval);
235                 cmd->short_cycles_count = c->num_short_intervals;
236         } else {
237                 cmd->short_cycles_msec = 0;
238                 cmd->long_cycles_msec =
239                         cpu_to_le16(req->scan_plans[0].interval * MSEC_PER_SEC);
240                 cmd->short_cycles_count = 0;
241         }
242         wl1271_debug(DEBUG_SCAN, "short_interval: %d, long_interval: %d, num_short: %d",
243                      le16_to_cpu(cmd->short_cycles_msec),
244                      le16_to_cpu(cmd->long_cycles_msec),
245                      cmd->short_cycles_count);
246
247         cmd->total_cycles = 0;
248
249         cmd->tag = WL1271_SCAN_DEFAULT_TAG;
250
251         /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */
252         cmd->report_threshold = 1;
253         cmd->terminate_on_report = 0;
254
255         if (cmd->active[0]) {
256                 u8 band = IEEE80211_BAND_2GHZ;
257                 ret = wl12xx_cmd_build_probe_req(wl, wlvif,
258                                  cmd->role_id, band,
259                                  req->ssids ? req->ssids[0].ssid : NULL,
260                                  req->ssids ? req->ssids[0].ssid_len : 0,
261                                  ies->ies[band],
262                                  ies->len[band],
263                                  ies->common_ies,
264                                  ies->common_ie_len,
265                                  true);
266                 if (ret < 0) {
267                         wl1271_error("2.4GHz PROBE request template failed");
268                         goto out;
269                 }
270         }
271
272         if (cmd->active[1] || cmd->dfs) {
273                 u8 band = IEEE80211_BAND_5GHZ;
274                 ret = wl12xx_cmd_build_probe_req(wl, wlvif,
275                                  cmd->role_id, band,
276                                  req->ssids ? req->ssids[0].ssid : NULL,
277                                  req->ssids ? req->ssids[0].ssid_len : 0,
278                                  ies->ies[band],
279                                  ies->len[band],
280                                  ies->common_ies,
281                                  ies->common_ie_len,
282                                  true);
283                 if (ret < 0) {
284                         wl1271_error("5GHz PROBE request template failed");
285                         goto out;
286                 }
287         }
288
289         wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
290
291         ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
292         if (ret < 0) {
293                 wl1271_error("SCAN failed");
294                 goto out;
295         }
296
297 out:
298         kfree(cmd_channels);
299         kfree(cmd);
300         return ret;
301 }
302
303 int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
304                             struct cfg80211_sched_scan_request *req,
305                             struct ieee80211_scan_ies *ies)
306 {
307         return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies);
308 }
309
310 static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif,
311                                u8 scan_type)
312 {
313         struct wl18xx_cmd_scan_stop *stop;
314         int ret;
315
316         wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
317
318         stop = kzalloc(sizeof(*stop), GFP_KERNEL);
319         if (!stop) {
320                 wl1271_error("failed to alloc memory to send sched scan stop");
321                 return -ENOMEM;
322         }
323
324         stop->role_id = wlvif->role_id;
325         stop->scan_type = scan_type;
326
327         ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0);
328         if (ret < 0) {
329                 wl1271_error("failed to send sched scan stop command");
330                 goto out_free;
331         }
332
333 out_free:
334         kfree(stop);
335         return ret;
336 }
337
338 void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
339 {
340         __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC);
341 }
342 int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
343                       struct cfg80211_scan_request *req)
344 {
345         return wl18xx_scan_send(wl, wlvif, req);
346 }
347
348 int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
349 {
350         return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH);
351 }