2 * This file is part of wl18xx
4 * Copyright (C) 2012 Texas Instruments. All rights reserved.
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.
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.
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
22 #include <linux/ieee80211.h>
24 #include "../wlcore/debug.h"
26 static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params
*cmd
,
27 struct wlcore_scan_channels
*cmd_channels
)
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
;
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 */
41 static int wl18xx_scan_send(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
42 struct cfg80211_scan_request
*req
)
44 struct wl18xx_cmd_scan_params
*cmd
;
45 struct wlcore_scan_channels
*cmd_channels
= NULL
;
48 cmd
= kzalloc(sizeof(*cmd
), GFP_KERNEL
);
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
;
58 cmd
->role_id
= wlvif
->role_id
;
60 if (WARN_ON(cmd
->role_id
== WL12XX_INVALID_ROLE_ID
)) {
65 cmd
->scan_type
= SCAN_TYPE_SEARCH
;
66 cmd
->rssi_threshold
= -127;
67 cmd
->snr_threshold
= 0;
69 cmd
->bss_type
= SCAN_BSS_TYPE_ANY
;
71 cmd
->ssid_from_list
= 0;
73 cmd
->add_broadcast
= 0;
78 cmd
->n_probe_reqs
= wl
->conf
.scan
.num_probe_reqs
;
79 cmd
->terminate_after
= 0;
81 /* configure channels */
82 WARN_ON(req
->n_ssids
> 1);
84 cmd_channels
= kzalloc(sizeof(*cmd_channels
), GFP_KERNEL
);
90 wlcore_set_scan_chan_params(wl
, cmd_channels
, req
->channels
,
91 req
->n_channels
, req
->n_ssids
,
93 wl18xx_adjust_channels(cmd
, cmd_channels
);
96 * all the cycles params (except total cycles) should
97 * remain 0 for normal scan
99 cmd
->total_cycles
= 1;
102 cmd
->rate
= WL18XX_SCAN_RATE_6
;
104 cmd
->tag
= WL1271_SCAN_DEFAULT_TAG
;
107 cmd
->ssid_len
= req
->ssids
[0].ssid_len
;
108 memcpy(cmd
->ssid
, req
->ssids
[0].ssid
, cmd
->ssid_len
);
111 /* TODO: per-band ies? */
112 if (cmd
->active
[0]) {
113 u8 band
= NL80211_BAND_2GHZ
;
114 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
116 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
117 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
124 wl1271_error("2.4GHz PROBE request template failed");
129 if (cmd
->active
[1] || cmd
->dfs
) {
130 u8 band
= NL80211_BAND_5GHZ
;
131 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
133 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
134 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
141 wl1271_error("5GHz PROBE request template failed");
146 wl1271_dump(DEBUG_SCAN
, "SCAN: ", cmd
, sizeof(*cmd
));
148 ret
= wl1271_cmd_send(wl
, CMD_SCAN
, cmd
, sizeof(*cmd
), 0);
150 wl1271_error("SCAN failed");
160 void wl18xx_scan_completed(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
)
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));
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
)
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
;
180 wl1271_debug(DEBUG_CMD
, "cmd sched_scan scan config");
182 filter_type
= wlcore_scan_sched_scan_ssid_list(wl
, wlvif
, req
);
186 cmd
= kzalloc(sizeof(*cmd
), GFP_KERNEL
);
192 cmd
->role_id
= wlvif
->role_id
;
194 if (WARN_ON(cmd
->role_id
== WL12XX_INVALID_ROLE_ID
)) {
199 cmd
->scan_type
= SCAN_TYPE_PERIODIC
;
200 cmd
->rssi_threshold
= c
->rssi_threshold
;
201 cmd
->snr_threshold
= c
->snr_threshold
;
203 /* don't filter on BSS type */
204 cmd
->bss_type
= SCAN_BSS_TYPE_ANY
;
206 cmd
->ssid_from_list
= 1;
207 if (filter_type
== SCAN_SSID_FILTER_LIST
)
209 cmd
->add_broadcast
= 0;
214 cmd
->n_probe_reqs
= c
->num_probe_reqs
;
215 /* don't stop scanning automatically when something is found */
216 cmd
->terminate_after
= 0;
218 cmd_channels
= kzalloc(sizeof(*cmd_channels
), GFP_KERNEL
);
224 /* configure channels */
225 wlcore_set_scan_chan_params(wl
, cmd_channels
, req
->channels
,
226 req
->n_channels
, req
->n_ssids
,
228 wl18xx_adjust_channels(cmd
, cmd_channels
);
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
;
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;
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
);
247 cmd
->total_cycles
= 0;
249 cmd
->tag
= WL1271_SCAN_DEFAULT_TAG
;
251 /* create a PERIODIC_SCAN_REPORT_EVENT whenever we've got a match */
252 cmd
->report_threshold
= 1;
253 cmd
->terminate_on_report
= 0;
255 if (cmd
->active
[0]) {
256 u8 band
= NL80211_BAND_2GHZ
;
257 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
259 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
260 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
267 wl1271_error("2.4GHz PROBE request template failed");
272 if (cmd
->active
[1] || cmd
->dfs
) {
273 u8 band
= NL80211_BAND_5GHZ
;
274 ret
= wl12xx_cmd_build_probe_req(wl
, wlvif
,
276 req
->ssids
? req
->ssids
[0].ssid
: NULL
,
277 req
->ssids
? req
->ssids
[0].ssid_len
: 0,
284 wl1271_error("5GHz PROBE request template failed");
289 wl1271_dump(DEBUG_SCAN
, "SCAN: ", cmd
, sizeof(*cmd
));
291 ret
= wl1271_cmd_send(wl
, CMD_SCAN
, cmd
, sizeof(*cmd
), 0);
293 wl1271_error("SCAN failed");
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
)
307 return wl18xx_scan_sched_scan_config(wl
, wlvif
, req
, ies
);
310 static int __wl18xx_scan_stop(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
313 struct wl18xx_cmd_scan_stop
*stop
;
316 wl1271_debug(DEBUG_CMD
, "cmd periodic scan stop");
318 stop
= kzalloc(sizeof(*stop
), GFP_KERNEL
);
320 wl1271_error("failed to alloc memory to send sched scan stop");
324 stop
->role_id
= wlvif
->role_id
;
325 stop
->scan_type
= scan_type
;
327 ret
= wl1271_cmd_send(wl
, CMD_STOP_SCAN
, stop
, sizeof(*stop
), 0);
329 wl1271_error("failed to send sched scan stop command");
338 void wl18xx_scan_sched_scan_stop(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
)
340 __wl18xx_scan_stop(wl
, wlvif
, SCAN_TYPE_PERIODIC
);
342 int wl18xx_scan_start(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
,
343 struct cfg80211_scan_request
*req
)
345 return wl18xx_scan_send(wl
, wlvif
, req
);
348 int wl18xx_scan_stop(struct wl1271
*wl
, struct wl12xx_vif
*wlvif
)
350 return __wl18xx_scan_stop(wl
, wlvif
, SCAN_TYPE_SEARCH
);