]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/ti/wl18xx/scan.c
Merge branch 'drm-fixes-4.3' of git://people.freedesktop.org/~agd5f/linux into drm...
[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->interval) {
232                 cmd->short_cycles_msec = cpu_to_le16(req->interval);
233                 cmd->long_cycles_msec = cpu_to_le16(c->long_interval);
234                 cmd->short_cycles_count = c->num_short_intervals;
235         } else {
236                 cmd->short_cycles_msec = 0;
237                 cmd->long_cycles_msec = cpu_to_le16(req->interval);
238                 cmd->short_cycles_count = 0;
239         }
240         wl1271_debug(DEBUG_SCAN, "short_interval: %d, long_interval: %d, num_short: %d",
241                      le16_to_cpu(cmd->short_cycles_msec),
242                      le16_to_cpu(cmd->long_cycles_msec),
243                      cmd->short_cycles_count);
244
245         cmd->total_cycles = 0;
246
247         cmd->tag = WL1271_SCAN_DEFAULT_TAG;
248
249         /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */
250         cmd->report_threshold = 1;
251         cmd->terminate_on_report = 0;
252
253         if (cmd->active[0]) {
254                 u8 band = IEEE80211_BAND_2GHZ;
255                 ret = wl12xx_cmd_build_probe_req(wl, wlvif,
256                                  cmd->role_id, band,
257                                  req->ssids ? req->ssids[0].ssid : NULL,
258                                  req->ssids ? req->ssids[0].ssid_len : 0,
259                                  ies->ies[band],
260                                  ies->len[band],
261                                  ies->common_ies,
262                                  ies->common_ie_len,
263                                  true);
264                 if (ret < 0) {
265                         wl1271_error("2.4GHz PROBE request template failed");
266                         goto out;
267                 }
268         }
269
270         if (cmd->active[1] || cmd->dfs) {
271                 u8 band = IEEE80211_BAND_5GHZ;
272                 ret = wl12xx_cmd_build_probe_req(wl, wlvif,
273                                  cmd->role_id, band,
274                                  req->ssids ? req->ssids[0].ssid : NULL,
275                                  req->ssids ? req->ssids[0].ssid_len : 0,
276                                  ies->ies[band],
277                                  ies->len[band],
278                                  ies->common_ies,
279                                  ies->common_ie_len,
280                                  true);
281                 if (ret < 0) {
282                         wl1271_error("5GHz PROBE request template failed");
283                         goto out;
284                 }
285         }
286
287         wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
288
289         ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
290         if (ret < 0) {
291                 wl1271_error("SCAN failed");
292                 goto out;
293         }
294
295 out:
296         kfree(cmd_channels);
297         kfree(cmd);
298         return ret;
299 }
300
301 int wl18xx_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
302                             struct cfg80211_sched_scan_request *req,
303                             struct ieee80211_scan_ies *ies)
304 {
305         return wl18xx_scan_sched_scan_config(wl, wlvif, req, ies);
306 }
307
308 static int __wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif,
309                                u8 scan_type)
310 {
311         struct wl18xx_cmd_scan_stop *stop;
312         int ret;
313
314         wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
315
316         stop = kzalloc(sizeof(*stop), GFP_KERNEL);
317         if (!stop) {
318                 wl1271_error("failed to alloc memory to send sched scan stop");
319                 return -ENOMEM;
320         }
321
322         stop->role_id = wlvif->role_id;
323         stop->scan_type = scan_type;
324
325         ret = wl1271_cmd_send(wl, CMD_STOP_SCAN, stop, sizeof(*stop), 0);
326         if (ret < 0) {
327                 wl1271_error("failed to send sched scan stop command");
328                 goto out_free;
329         }
330
331 out_free:
332         kfree(stop);
333         return ret;
334 }
335
336 void wl18xx_scan_sched_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
337 {
338         __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_PERIODIC);
339 }
340 int wl18xx_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif,
341                       struct cfg80211_scan_request *req)
342 {
343         return wl18xx_scan_send(wl, wlvif, req);
344 }
345
346 int wl18xx_scan_stop(struct wl1271 *wl, struct wl12xx_vif *wlvif)
347 {
348         return __wl18xx_scan_stop(wl, wlvif, SCAN_TYPE_SEARCH);
349 }