1 // SPDX-License-Identifier: GPL-2.0-only
3 * This file is part of wl18xx
5 * Copyright (C) 2012 Texas Instruments. All rights reserved.
8 #include <linux/ieee80211.h>
10 #include "../wlcore/debug.h"
12 static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params
*cmd
,
13 struct wlcore_scan_channels
*cmd_channels
)
15 memcpy(cmd
->passive
, cmd_channels
->passive
, sizeof(cmd
->passive
));
16 memcpy(cmd
->active
, cmd_channels
->active
, sizeof(cmd
->active
));
17 cmd
->dfs
= cmd_channels
->dfs
;
18 cmd
->passive_active
= cmd_channels
->passive_active
;
20 memcpy(cmd
->channels_2
, cmd_channels
->channels_2
,
21 sizeof(cmd
->channels_2
));
22 memcpy(cmd
->channels_5
, cmd_channels
->channels_5
,
23 sizeof(cmd
->channels_5
));
24 /* channels_4 are not supported, so no need to copy them */
27 static int wl18xx_scan_send(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
28 struct cfg80211_scan_request
*req
)
30 struct wl18xx_cmd_scan_params
*cmd
;
31 struct wlcore_scan_channels
*cmd_channels
= NULL
;
34 cmd
= kzalloc(sizeof(*cmd
), GFP_KERNEL
);
40 /* scan on the dev role if the regular one is not started */
41 if (wlcore_is_p2p_mgmt(wlvif
))
42 cmd
->role_id
= wlvif
->dev_role_id
;
44 cmd
->role_id
= wlvif
->role_id
;
46 if (WARN_ON(cmd
->role_id
== WL12XX_INVALID_ROLE_ID
)) {
51 cmd
->scan_type
= SCAN_TYPE_SEARCH
;
52 cmd
->rssi_threshold
= -127;
53 cmd
->snr_threshold
= 0;
55 cmd
->bss_type
= SCAN_BSS_TYPE_ANY
;
57 cmd
->ssid_from_list
= 0;
59 cmd
->add_broadcast
= 0;
64 cmd
->n_probe_reqs
= wl
->conf
.scan
.num_probe_reqs
;
65 cmd
->terminate_after
= 0;
67 /* configure channels */
68 WARN_ON(req
->n_ssids
> 1);
70 cmd_channels
= kzalloc(sizeof(*cmd_channels
), GFP_KERNEL
);
76 wlcore_set_scan_chan_params(wl
, cmd_channels
, req
->channels
,
77 req
->n_channels
, req
->n_ssids
,
79 wl18xx_adjust_channels(cmd
, cmd_channels
);
82 * all the cycles params (except total cycles) should
83 * remain 0 for normal scan
85 cmd
->total_cycles
= 1;
88 cmd
->rate
= WL18XX_SCAN_RATE_6
;
90 cmd
->tag
= WL1271_SCAN_DEFAULT_TAG
;
93 cmd
->ssid_len
= req
->ssids
[0].ssid_len
;
94 memcpy(cmd
->ssid
, req
->ssids
[0].ssid
, cmd
->ssid_len
);
97 /* TODO: per-band ies? */
99 u8 band
= NL80211_BAND_2GHZ
;
100 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
102 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
103 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
110 wl1271_error("2.4GHz PROBE request template failed");
115 if (cmd
->active
[1] || cmd
->dfs
) {
116 u8 band
= NL80211_BAND_5GHZ
;
117 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
119 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
120 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
127 wl1271_error("5GHz PROBE request template failed");
132 wl1271_dump(DEBUG_SCAN
, "SCAN: ", cmd
, sizeof(*cmd
));
134 ret
= wl1271_cmd_send(wl
, CMD_SCAN
, cmd
, sizeof(*cmd
), 0);
136 wl1271_error("SCAN failed");
146 void wl18xx_scan_completed(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
)
148 wl
->scan
.failed
= false;
149 cancel_delayed_work(&wl
->scan_complete_work
);
150 ieee80211_queue_delayed_work(wl
->hw
, &wl
->scan_complete_work
,
151 msecs_to_jiffies(0));
155 int wl18xx_scan_sched_scan_config(struct wl1271
*wl
,
156 struct wl12xx_vif
*wlvif
,
157 struct cfg80211_sched_scan_request
*req
,
158 struct ieee80211_scan_ies
*ies
)
160 struct wl18xx_cmd_scan_params
*cmd
;
161 struct wlcore_scan_channels
*cmd_channels
= NULL
;
162 struct conf_sched_scan_settings
*c
= &wl
->conf
.sched_scan
;
166 wl1271_debug(DEBUG_CMD
, "cmd sched_scan scan config");
168 filter_type
= wlcore_scan_sched_scan_ssid_list(wl
, wlvif
, req
);
172 cmd
= kzalloc(sizeof(*cmd
), GFP_KERNEL
);
178 cmd
->role_id
= wlvif
->role_id
;
180 if (WARN_ON(cmd
->role_id
== WL12XX_INVALID_ROLE_ID
)) {
185 cmd
->scan_type
= SCAN_TYPE_PERIODIC
;
186 cmd
->rssi_threshold
= c
->rssi_threshold
;
187 cmd
->snr_threshold
= c
->snr_threshold
;
189 /* don't filter on BSS type */
190 cmd
->bss_type
= SCAN_BSS_TYPE_ANY
;
192 cmd
->ssid_from_list
= 1;
193 if (filter_type
== SCAN_SSID_FILTER_LIST
)
195 cmd
->add_broadcast
= 0;
200 cmd
->n_probe_reqs
= c
->num_probe_reqs
;
201 /* don't stop scanning automatically when something is found */
202 cmd
->terminate_after
= 0;
204 cmd_channels
= kzalloc(sizeof(*cmd_channels
), GFP_KERNEL
);
210 /* configure channels */
211 wlcore_set_scan_chan_params(wl
, cmd_channels
, req
->channels
,
212 req
->n_channels
, req
->n_ssids
,
214 wl18xx_adjust_channels(cmd
, cmd_channels
);
216 if (c
->num_short_intervals
&& c
->long_interval
&&
217 c
->long_interval
> req
->scan_plans
[0].interval
* MSEC_PER_SEC
) {
218 cmd
->short_cycles_msec
=
219 cpu_to_le16(req
->scan_plans
[0].interval
* MSEC_PER_SEC
);
220 cmd
->long_cycles_msec
= cpu_to_le16(c
->long_interval
);
221 cmd
->short_cycles_count
= c
->num_short_intervals
;
223 cmd
->short_cycles_msec
= 0;
224 cmd
->long_cycles_msec
=
225 cpu_to_le16(req
->scan_plans
[0].interval
* MSEC_PER_SEC
);
226 cmd
->short_cycles_count
= 0;
228 wl1271_debug(DEBUG_SCAN
, "short_interval: %d, long_interval: %d, num_short: %d",
229 le16_to_cpu(cmd
->short_cycles_msec
),
230 le16_to_cpu(cmd
->long_cycles_msec
),
231 cmd
->short_cycles_count
);
233 cmd
->total_cycles
= 0;
235 cmd
->tag
= WL1271_SCAN_DEFAULT_TAG
;
237 /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */
238 cmd
->report_threshold
= 1;
239 cmd
->terminate_on_report
= 0;
241 if (cmd
->active
[0]) {
242 u8 band
= NL80211_BAND_2GHZ
;
243 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
245 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
246 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
253 wl1271_error("2.4GHz PROBE request template failed");
258 if (cmd
->active
[1] || cmd
->dfs
) {
259 u8 band
= NL80211_BAND_5GHZ
;
260 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
262 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
263 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
270 wl1271_error("5GHz PROBE request template failed");
275 wl1271_dump(DEBUG_SCAN
, "SCAN: ", cmd
, sizeof(*cmd
));
277 ret
= wl1271_cmd_send(wl
, CMD_SCAN
, cmd
, sizeof(*cmd
), 0);
279 wl1271_error("SCAN failed");
289 int wl18xx_sched_scan_start(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
290 struct cfg80211_sched_scan_request
*req
,
291 struct ieee80211_scan_ies
*ies
)
293 return wl18xx_scan_sched_scan_config(wl
, wlvif
, req
, ies
);
296 static int __wl18xx_scan_stop(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
299 struct wl18xx_cmd_scan_stop
*stop
;
302 wl1271_debug(DEBUG_CMD
, "cmd periodic scan stop");
304 stop
= kzalloc(sizeof(*stop
), GFP_KERNEL
);
306 wl1271_error("failed to alloc memory to send sched scan stop");
310 stop
->role_id
= wlvif
->role_id
;
311 stop
->scan_type
= scan_type
;
313 ret
= wl1271_cmd_send(wl
, CMD_STOP_SCAN
, stop
, sizeof(*stop
), 0);
315 wl1271_error("failed to send sched scan stop command");
324 void wl18xx_scan_sched_scan_stop(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
)
326 __wl18xx_scan_stop(wl
, wlvif
, SCAN_TYPE_PERIODIC
);
328 int wl18xx_scan_start(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
329 struct cfg80211_scan_request
*req
)
331 return wl18xx_scan_send(wl
, wlvif
, req
);
334 int wl18xx_scan_stop(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
)
336 return __wl18xx_scan_stop(wl
, wlvif
, SCAN_TYPE_SEARCH
);