GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / net / wireless / ti / wlcore / scan.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * This file is part of wl1271
4  *
5  * Copyright (C) 2009-2010 Nokia Corporation
6  *
7  * Contact: Luciano Coelho <luciano.coelho@nokia.com>
8  */
9
10 #include <linux/ieee80211.h>
11 #include <linux/pm_runtime.h>
12
13 #include "wlcore.h"
14 #include "debug.h"
15 #include "cmd.h"
16 #include "scan.h"
17 #include "acx.h"
18 #include "tx.h"
19
20 void wl1271_scan_complete_work(struct work_struct *work)
21 {
22         struct delayed_work *dwork;
23         struct wl1271 *wl;
24         struct wl12xx_vif *wlvif;
25         struct cfg80211_scan_info info = {
26                 .aborted = false,
27         };
28         int ret;
29
30         dwork = to_delayed_work(work);
31         wl = container_of(dwork, struct wl1271, scan_complete_work);
32
33         wl1271_debug(DEBUG_SCAN, "Scanning complete");
34
35         mutex_lock(&wl->mutex);
36
37         if (unlikely(wl->state != WLCORE_STATE_ON))
38                 goto out;
39
40         if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
41                 goto out;
42
43         wlvif = wl->scan_wlvif;
44
45         /*
46          * Rearm the tx watchdog just before idling scan. This
47          * prevents just-finished scans from triggering the watchdog
48          */
49         wl12xx_rearm_tx_watchdog_locked(wl);
50
51         wl->scan.state = WL1271_SCAN_STATE_IDLE;
52         memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
53         wl->scan.req = NULL;
54         wl->scan_wlvif = NULL;
55
56         ret = pm_runtime_resume_and_get(wl->dev);
57         if (ret < 0)
58                 goto out;
59
60         if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
61                 /* restore hardware connection monitoring template */
62                 wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq);
63         }
64
65         if (wl->scan.failed) {
66                 wl1271_info("Scan completed due to error.");
67                 wl12xx_queue_recovery_work(wl);
68         }
69
70         wlcore_cmd_regdomain_config_locked(wl);
71
72         pm_runtime_mark_last_busy(wl->dev);
73         pm_runtime_put_autosuspend(wl->dev);
74
75         ieee80211_scan_completed(wl->hw, &info);
76
77 out:
78         mutex_unlock(&wl->mutex);
79
80 }
81
82 static void wlcore_started_vifs_iter(void *data, u8 *mac,
83                                      struct ieee80211_vif *vif)
84 {
85         struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
86         bool active = false;
87         int *count = (int *)data;
88
89         /*
90          * count active interfaces according to interface type.
91          * checking only bss_conf.idle is bad for some cases, e.g.
92          * we don't want to count sta in p2p_find as active interface.
93          */
94         switch (wlvif->bss_type) {
95         case BSS_TYPE_STA_BSS:
96                 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
97                         active = true;
98                 break;
99
100         case BSS_TYPE_AP_BSS:
101                 if (wlvif->wl->active_sta_count > 0)
102                         active = true;
103                 break;
104
105         default:
106                 break;
107         }
108
109         if (active)
110                 (*count)++;
111 }
112
113 static int wlcore_count_started_vifs(struct wl1271 *wl)
114 {
115         int count = 0;
116
117         ieee80211_iterate_active_interfaces_atomic(wl->hw,
118                                         IEEE80211_IFACE_ITER_RESUME_ALL,
119                                         wlcore_started_vifs_iter, &count);
120         return count;
121 }
122
123 static int
124 wlcore_scan_get_channels(struct wl1271 *wl,
125                          struct ieee80211_channel *req_channels[],
126                          u32 n_channels,
127                          u32 n_ssids,
128                          struct conn_scan_ch_params *channels,
129                          u32 band, bool radar, bool passive,
130                          int start, int max_channels,
131                          u8 *n_pactive_ch,
132                          int scan_type)
133 {
134         int i, j;
135         u32 flags;
136         bool force_passive = !n_ssids;
137         u32 min_dwell_time_active, max_dwell_time_active;
138         u32 dwell_time_passive, dwell_time_dfs;
139
140         /* configure dwell times according to scan type */
141         if (scan_type == SCAN_TYPE_SEARCH) {
142                 struct conf_scan_settings *c = &wl->conf.scan;
143                 bool active_vif_exists = !!wlcore_count_started_vifs(wl);
144
145                 min_dwell_time_active = active_vif_exists ?
146                         c->min_dwell_time_active :
147                         c->min_dwell_time_active_long;
148                 max_dwell_time_active = active_vif_exists ?
149                         c->max_dwell_time_active :
150                         c->max_dwell_time_active_long;
151                 dwell_time_passive = c->dwell_time_passive;
152                 dwell_time_dfs = c->dwell_time_dfs;
153         } else {
154                 struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
155                 u32 delta_per_probe;
156
157                 if (band == NL80211_BAND_5GHZ)
158                         delta_per_probe = c->dwell_time_delta_per_probe_5;
159                 else
160                         delta_per_probe = c->dwell_time_delta_per_probe;
161
162                 min_dwell_time_active = c->base_dwell_time +
163                          n_ssids * c->num_probe_reqs * delta_per_probe;
164
165                 max_dwell_time_active = min_dwell_time_active +
166                                         c->max_dwell_time_delta;
167                 dwell_time_passive = c->dwell_time_passive;
168                 dwell_time_dfs = c->dwell_time_dfs;
169         }
170         min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000);
171         max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000);
172         dwell_time_passive = DIV_ROUND_UP(dwell_time_passive, 1000);
173         dwell_time_dfs = DIV_ROUND_UP(dwell_time_dfs, 1000);
174
175         for (i = 0, j = start;
176              i < n_channels && j < max_channels;
177              i++) {
178                 flags = req_channels[i]->flags;
179
180                 if (force_passive)
181                         flags |= IEEE80211_CHAN_NO_IR;
182
183                 if ((req_channels[i]->band == band) &&
184                     !(flags & IEEE80211_CHAN_DISABLED) &&
185                     (!!(flags & IEEE80211_CHAN_RADAR) == radar) &&
186                     /* if radar is set, we ignore the passive flag */
187                     (radar ||
188                      !!(flags & IEEE80211_CHAN_NO_IR) == passive)) {
189                         if (flags & IEEE80211_CHAN_RADAR) {
190                                 channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
191
192                                 channels[j].passive_duration =
193                                         cpu_to_le16(dwell_time_dfs);
194                         } else {
195                                 channels[j].passive_duration =
196                                         cpu_to_le16(dwell_time_passive);
197                         }
198
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);
203
204                         channels[j].tx_power_att = req_channels[i]->max_power;
205                         channels[j].channel = req_channels[i]->hw_value;
206
207                         if (n_pactive_ch &&
208                             (band == NL80211_BAND_2GHZ) &&
209                             (channels[j].channel >= 12) &&
210                             (channels[j].channel <= 14) &&
211                             (flags & IEEE80211_CHAN_NO_IR) &&
212                             !force_passive) {
213                                 /* pactive channels treated as DFS */
214                                 channels[j].flags = SCAN_CHANNEL_FLAGS_DFS;
215
216                                 /*
217                                  * n_pactive_ch is counted down from the end of
218                                  * the passive channel list
219                                  */
220                                 (*n_pactive_ch)++;
221                                 wl1271_debug(DEBUG_SCAN, "n_pactive_ch = %d",
222                                              *n_pactive_ch);
223                         }
224
225                         wl1271_debug(DEBUG_SCAN, "freq %d, ch. %d, flags 0x%x, power %d, min/max_dwell %d/%d%s%s",
226                                      req_channels[i]->center_freq,
227                                      req_channels[i]->hw_value,
228                                      req_channels[i]->flags,
229                                      req_channels[i]->max_power,
230                                      min_dwell_time_active,
231                                      max_dwell_time_active,
232                                      flags & IEEE80211_CHAN_RADAR ?
233                                         ", DFS" : "",
234                                      flags & IEEE80211_CHAN_NO_IR ?
235                                         ", NO-IR" : "");
236                         j++;
237                 }
238         }
239
240         return j - start;
241 }
242
243 bool
244 wlcore_set_scan_chan_params(struct wl1271 *wl,
245                             struct wlcore_scan_channels *cfg,
246                             struct ieee80211_channel *channels[],
247                             u32 n_channels,
248                             u32 n_ssids,
249                             int scan_type)
250 {
251         u8 n_pactive_ch = 0;
252
253         cfg->passive[0] =
254                 wlcore_scan_get_channels(wl,
255                                          channels,
256                                          n_channels,
257                                          n_ssids,
258                                          cfg->channels_2,
259                                          NL80211_BAND_2GHZ,
260                                          false, true, 0,
261                                          MAX_CHANNELS_2GHZ,
262                                          &n_pactive_ch,
263                                          scan_type);
264         cfg->active[0] =
265                 wlcore_scan_get_channels(wl,
266                                          channels,
267                                          n_channels,
268                                          n_ssids,
269                                          cfg->channels_2,
270                                          NL80211_BAND_2GHZ,
271                                          false, false,
272                                          cfg->passive[0],
273                                          MAX_CHANNELS_2GHZ,
274                                          &n_pactive_ch,
275                                          scan_type);
276         cfg->passive[1] =
277                 wlcore_scan_get_channels(wl,
278                                          channels,
279                                          n_channels,
280                                          n_ssids,
281                                          cfg->channels_5,
282                                          NL80211_BAND_5GHZ,
283                                          false, true, 0,
284                                          wl->max_channels_5,
285                                          &n_pactive_ch,
286                                          scan_type);
287         cfg->dfs =
288                 wlcore_scan_get_channels(wl,
289                                          channels,
290                                          n_channels,
291                                          n_ssids,
292                                          cfg->channels_5,
293                                          NL80211_BAND_5GHZ,
294                                          true, true,
295                                          cfg->passive[1],
296                                          wl->max_channels_5,
297                                          &n_pactive_ch,
298                                          scan_type);
299         cfg->active[1] =
300                 wlcore_scan_get_channels(wl,
301                                          channels,
302                                          n_channels,
303                                          n_ssids,
304                                          cfg->channels_5,
305                                          NL80211_BAND_5GHZ,
306                                          false, false,
307                                          cfg->passive[1] + cfg->dfs,
308                                          wl->max_channels_5,
309                                          &n_pactive_ch,
310                                          scan_type);
311
312         /* 802.11j channels are not supported yet */
313         cfg->passive[2] = 0;
314         cfg->active[2] = 0;
315
316         cfg->passive_active = n_pactive_ch;
317
318         wl1271_debug(DEBUG_SCAN, "    2.4GHz: active %d passive %d",
319                      cfg->active[0], cfg->passive[0]);
320         wl1271_debug(DEBUG_SCAN, "    5GHz: active %d passive %d",
321                      cfg->active[1], cfg->passive[1]);
322         wl1271_debug(DEBUG_SCAN, "    DFS: %d", cfg->dfs);
323
324         return  cfg->passive[0] || cfg->active[0] ||
325                 cfg->passive[1] || cfg->active[1] || cfg->dfs ||
326                 cfg->passive[2] || cfg->active[2];
327 }
328 EXPORT_SYMBOL_GPL(wlcore_set_scan_chan_params);
329
330 int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
331                 const u8 *ssid, size_t ssid_len,
332                 struct cfg80211_scan_request *req)
333 {
334         struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
335
336         /*
337          * cfg80211 should guarantee that we don't get more channels
338          * than what we have registered.
339          */
340         BUG_ON(req->n_channels > WL1271_MAX_CHANNELS);
341
342         if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
343                 return -EBUSY;
344
345         wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
346
347         if (ssid_len && ssid) {
348                 wl->scan.ssid_len = ssid_len;
349                 memcpy(wl->scan.ssid, ssid, ssid_len);
350         } else {
351                 wl->scan.ssid_len = 0;
352         }
353
354         wl->scan_wlvif = wlvif;
355         wl->scan.req = req;
356         memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
357
358         /* we assume failure so that timeout scenarios are handled correctly */
359         wl->scan.failed = true;
360         ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
361                                      msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
362
363         wl->ops->scan_start(wl, wlvif, req);
364
365         return 0;
366 }
367 /* Returns the scan type to be used or a negative value on error */
368 int
369 wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
370                                  struct wl12xx_vif *wlvif,
371                                  struct cfg80211_sched_scan_request *req)
372 {
373         struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL;
374         struct cfg80211_match_set *sets = req->match_sets;
375         struct cfg80211_ssid *ssids = req->ssids;
376         int ret = 0, type, i, j, n_match_ssids = 0;
377
378         wl1271_debug((DEBUG_CMD | DEBUG_SCAN), "cmd sched scan ssid list");
379
380         /* count the match sets that contain SSIDs */
381         for (i = 0; i < req->n_match_sets; i++)
382                 if (sets[i].ssid.ssid_len > 0)
383                         n_match_ssids++;
384
385         /* No filter, no ssids or only bcast ssid */
386         if (!n_match_ssids &&
387             (!req->n_ssids ||
388              (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) {
389                 type = SCAN_SSID_FILTER_ANY;
390                 goto out;
391         }
392
393         cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
394         if (!cmd) {
395                 ret = -ENOMEM;
396                 goto out;
397         }
398
399         cmd->role_id = wlvif->role_id;
400         if (!n_match_ssids) {
401                 /* No filter, with ssids */
402                 type = SCAN_SSID_FILTER_DISABLED;
403
404                 for (i = 0; i < req->n_ssids; i++) {
405                         cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ?
406                                 SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC;
407                         cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len;
408                         memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid,
409                                ssids[i].ssid_len);
410                         cmd->n_ssids++;
411                 }
412         } else {
413                 type = SCAN_SSID_FILTER_LIST;
414
415                 /* Add all SSIDs from the filters */
416                 for (i = 0; i < req->n_match_sets; i++) {
417                         /* ignore sets without SSIDs */
418                         if (!sets[i].ssid.ssid_len)
419                                 continue;
420
421                         cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC;
422                         cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len;
423                         memcpy(cmd->ssids[cmd->n_ssids].ssid,
424                                sets[i].ssid.ssid, sets[i].ssid.ssid_len);
425                         cmd->n_ssids++;
426                 }
427                 if ((req->n_ssids > 1) ||
428                     (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) {
429                         /*
430                          * Mark all the SSIDs passed in the SSID list as HIDDEN,
431                          * so they're used in probe requests.
432                          */
433                         for (i = 0; i < req->n_ssids; i++) {
434                                 if (!req->ssids[i].ssid_len)
435                                         continue;
436
437                                 for (j = 0; j < cmd->n_ssids; j++)
438                                         if ((req->ssids[i].ssid_len ==
439                                              cmd->ssids[j].len) &&
440                                             !memcmp(req->ssids[i].ssid,
441                                                    cmd->ssids[j].ssid,
442                                                    req->ssids[i].ssid_len)) {
443                                                 cmd->ssids[j].type =
444                                                         SCAN_SSID_TYPE_HIDDEN;
445                                                 break;
446                                         }
447                                 /* Fail if SSID isn't present in the filters */
448                                 if (j == cmd->n_ssids) {
449                                         ret = -EINVAL;
450                                         goto out_free;
451                                 }
452                         }
453                 }
454         }
455
456         ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd,
457                               sizeof(*cmd), 0);
458         if (ret < 0) {
459                 wl1271_error("cmd sched scan ssid list failed");
460                 goto out_free;
461         }
462
463 out_free:
464         kfree(cmd);
465 out:
466         if (ret < 0)
467                 return ret;
468         return type;
469 }
470 EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_ssid_list);
471
472 void wlcore_scan_sched_scan_results(struct wl1271 *wl)
473 {
474         wl1271_debug(DEBUG_SCAN, "got periodic scan results");
475
476         ieee80211_sched_scan_results(wl->hw);
477 }
478 EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_results);